The BERG Cloud connection library for mbed. This works in conjunction with the BERG Cloud Devshield available via http://bergcloud.com/platform/devkit/
Dependents: LittleCounter-Example
Revision 6:79100379d4b4, committed 2014-04-16
- Comitter:
- nickludlam
- Date:
- Wed Apr 16 14:38:12 2014 +0000
- Parent:
- 5:2e04a8b3fc25
- Commit message:
- Updated to support the Berg V2 API. Please see http://bergcloud.com/devcenter/api/v2/device-v2 for more details.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BERGCloud.h Wed Apr 16 14:38:12 2014 +0000 @@ -0,0 +1,37 @@ +/* + +BERGCloud library + +Copyright (c) 2013 BERG Ltd. http://bergcloud.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef BERGCLOUD_H +#define BERGCLOUD_H + +#ifdef ARDUINO +#include "BERGCloudArduino.h" +#else +#error Please #include "BERGCloudMbed.h" or "BERGCloudLinux.h" instead. +#endif + +#endif // #ifndef BERGCLOUD_H +
--- a/BERGCloudBase.cpp Tue Nov 26 17:45:12 2013 +0000 +++ b/BERGCloudBase.cpp Wed Apr 16 14:38:12 2014 +0000 @@ -28,7 +28,7 @@ #define __STDC_LIMIT_MACROS /* Include C99 stdint defines in C++ code */ #include <stdint.h> #include <stddef.h> -#include <string.h> /* For memcpy() */ +#include <string.h> /* For memset() */ #include "BERGCloudBase.h" @@ -37,6 +37,11 @@ #define CONNECT_POLL_RATE_MS 250 +/* MessagePack for named commands and events */ +#define _MP_FIXRAW_MIN 0xa0 +#define _MP_FIXRAW_MAX 0xbf +#define _MAX_FIXRAW (_MP_FIXRAW_MAX - _MP_FIXRAW_MIN) + uint8_t BERGCloudBase::nullKey[BC_KEY_SIZE_BYTES] = {0}; bool BERGCloudBase::_transaction(_BC_SPI_TRANSACTION *tr) @@ -276,6 +281,8 @@ { /* Returns TRUE if a valid command has been received */ + _LOG("pollForCommand() methods returning a command ID number have been deprecated.\r\n"); + _BC_SPI_TRANSACTION tr; uint8_t cmdID[2] = {0}; uint16_t cmdIDSize = 0; @@ -303,11 +310,80 @@ return false; } +bool BERGCloudBase::pollForCommand(uint8_t *commandBuffer, uint16_t commandBufferSize, uint16_t& commandSize, char *commandName, uint8_t commandNameMaxSize) +{ + /* Returns TRUE if a valid command has been received */ + + _BC_SPI_TRANSACTION tr; + uint8_t cmdID[2] = {0}; + uint16_t cmdIDSize = 0; + uint8_t commandNameSize; + uint8_t originalCommandNameSize; + uint8_t msgPackByte; + uint16_t command; + + if ((commandName == NULL) || (commandNameMaxSize < 2)) + { + return false; + } + + initTransaction(&tr); + + tr.command = SPI_CMD_POLL_FOR_COMMAND; + + tr.rx[0].buffer = cmdID; + tr.rx[0].bufferSize = sizeof(cmdID); + tr.rx[0].dataSize = &cmdIDSize; + + tr.rx[1].buffer = commandBuffer; + tr.rx[1].bufferSize = commandBufferSize; + tr.rx[1].dataSize = &commandSize; + + if (transaction(&tr)) + { + command = (cmdID[0] << 8) | cmdID[1]; + if (command == BC_COMMAND_NAMED_PACKED) + { + /* Get command name string size */ + msgPackByte = *commandBuffer; + + if ((msgPackByte <_MP_FIXRAW_MIN) || (msgPackByte > _MP_FIXRAW_MAX)) + { + /* Invalid */ + return false; + } + + commandNameSize = originalCommandNameSize = msgPackByte - _MP_FIXRAW_MIN; + + /* Limit to the size of the buffer provided */ + if (commandNameSize > (commandNameMaxSize-1)) /* -1 for null terminator */ + { + commandNameSize = (commandNameMaxSize-1); + } + + /* Copy command name string as a null-terminated C string */ + bytecpy((uint8_t *)commandName, (commandBuffer+1), commandNameSize); /* +1 for messagePack fixraw byte */ + commandName[commandNameSize] = '\0'; + + /* Move up remaining packed data, update size */ + commandSize -= (originalCommandNameSize + 1); /* +1 for messagePack fixraw byte */ + bytecpy(commandBuffer, commandBuffer + (originalCommandNameSize + 1), commandSize); + return true; + } + } + + *commandName = '\0'; + commandSize = 0; + return false; +} + #ifdef BERGCLOUD_PACK_UNPACK bool BERGCloudBase::pollForCommand(BERGCloudMessageBuffer& buffer, uint8_t& commandID) { /* Returns TRUE if a valid command has been received */ + _LOG("pollForCommand() methods returning a command ID number have been deprecated.\r\n"); + _BC_SPI_TRANSACTION tr; uint8_t cmdID[2] = {0}; uint16_t cmdIDSize = 0; @@ -337,12 +413,85 @@ buffer.used(0); return false; } + +bool BERGCloudBase::pollForCommand(BERGCloudMessageBuffer& buffer, char *commandName, uint8_t commandNameMaxSize) +{ + /* Returns TRUE if a valid command has been received */ + + _BC_SPI_TRANSACTION tr; + uint8_t cmdID[2] = {0}; + uint16_t cmdIDSize = 0; + uint16_t dataSize = 0; + uint8_t commandNameSize; + uint8_t originalCommandNameSize; + uint8_t msgPackByte; + uint16_t command; + + if ((commandName == NULL) || (commandNameMaxSize < 2)) + { + return false; + } + + initTransaction(&tr); + buffer.clear(); + + tr.command = SPI_CMD_POLL_FOR_COMMAND; + + tr.rx[0].buffer = cmdID; + tr.rx[0].bufferSize = sizeof(cmdID); + tr.rx[0].dataSize = &cmdIDSize; + + tr.rx[1].buffer = buffer.ptr(); + tr.rx[1].bufferSize = buffer.size(); + tr.rx[1].dataSize = &dataSize; + + if (transaction(&tr)) + { + command = (cmdID[0] << 8) | cmdID[1]; + if (command == BC_COMMAND_NAMED_PACKED) + { + /* Get command name string size */ + msgPackByte = *buffer.ptr(); + + if ((msgPackByte <_MP_FIXRAW_MIN) || (msgPackByte > _MP_FIXRAW_MAX)) + { + /* Invalid */ + return false; + } + + commandNameSize = originalCommandNameSize = msgPackByte - _MP_FIXRAW_MIN; + + /* Limit to the size of the buffer provided */ + if (commandNameSize > (commandNameMaxSize-1)) /* -1 for null terminator */ + { + commandNameSize = (commandNameMaxSize-1); + } + + /* Copy command name string as a null-terminated C string */ + bytecpy((uint8_t *)commandName, (buffer.ptr()+1), commandNameSize); /* +1 for messagePack fixraw byte */ + commandName[commandNameSize] = '\0'; + + /* Move up remaining packed data, update size */ + dataSize -= (originalCommandNameSize + 1); /* +1 for messagePack fixraw byte */ + bytecpy(buffer.ptr(), buffer.ptr() + (originalCommandNameSize + 1), dataSize); + + buffer.used(dataSize); + return true; + } + } + + buffer.used(0); + *commandName = '\0'; + return false; +} #endif bool BERGCloudBase::_sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize, uint8_t command) { /* Returns TRUE if the event is sent successfully */ + _LOG("sendEvent() methods using an eventCode number have been deprecated.\r\n"); + _BC_SPI_TRANSACTION tr; uint8_t header[4] = {0}; @@ -367,9 +516,62 @@ bool BERGCloudBase::sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize, bool packed) { + return _sendEvent(eventCode, eventBuffer, eventSize, packed ? SPI_CMD_SEND_EVENT_PACKED : SPI_CMD_SEND_EVENT_RAW); } +bool BERGCloudBase::sendEvent(const char *eventName, uint8_t *eventBuffer, uint16_t eventSize, bool packed) +{ + /* Returns TRUE if the event is sent successfully */ + + _BC_SPI_TRANSACTION tr; + uint8_t headerSize = 5; /* Four bytes of SPI header, one byte of messagePack type */ + uint8_t header[5 + _MAX_FIXRAW] = {0}; /* Header size plus maximum name string size */ + + if (!packed) + { + /* We only support packed data now */ + return false; + } + + if ((eventName == NULL) || (eventName[0] == '\0')) + { + _LOG("Event name must be at least one character.\r\n"); + return false; + } + + /* Create SPI header */ + header[0] = BC_EVENT_NAMED_PACKED & BC_EVENT_ID_MASK; + header[1] = 0; + header[2] = 0; + header[3] = 0; + + /* Create string header in messagePack format */ + header[4] = _MP_FIXRAW_MIN; + while ((*eventName != '\0') && (headerSize < sizeof(header))) + { + /* Copy string, update messagePack byte */ + header[4]++; + header[headerSize++] = *eventName++; + } + + if (eventSize > ((uint16_t)SPI_MAX_PAYLOAD_SIZE_BYTES - headerSize)) + { + _LOG("Event is too big.\r\n"); + return false; + } + + initTransaction(&tr); + + tr.command = SPI_CMD_SEND_EVENT_PACKED; + tr.tx[0].buffer = (uint8_t *)header; + tr.tx[0].dataSize = headerSize; + tr.tx[1].buffer = eventBuffer; + tr.tx[1].dataSize = eventSize; + + return transaction(&tr); +} + #ifdef BERGCLOUD_PACK_UNPACK bool BERGCloudBase::sendEvent(uint8_t eventCode, BERGCloudMessageBuffer& buffer) { @@ -380,6 +582,52 @@ buffer.clear(); return result; } + +bool BERGCloudBase::sendEvent(const char *eventName, BERGCloudMessageBuffer& buffer) +{ + /* Returns TRUE if the event is sent successfully */ + + _BC_SPI_TRANSACTION tr; + uint8_t headerSize = 5; /* Four bytes of SPI header, one byte of messagePack type */ + uint8_t header[5 + _MAX_FIXRAW] = {0}; /* Header size plus maximum name string size */ + + if ((eventName == NULL) || (eventName[0] == '\0')) + { + _LOG("Event name must be at least one character.\r\n"); + return false; + } + + /* Create SPI header */ + header[0] = BC_EVENT_NAMED_PACKED & BC_EVENT_ID_MASK; + header[1] = 0; + header[2] = 0; + header[3] = 0; + + /* Create string header in messagePack format */ + header[4] = _MP_FIXRAW_MIN; + while ((*eventName != '\0') && (headerSize < sizeof(header))) + { + /* Copy string, update messagePack byte */ + header[4]++; + header[headerSize++] = *eventName++; + } + + if (buffer.used() > ((uint16_t)SPI_MAX_PAYLOAD_SIZE_BYTES - headerSize)) + { + _LOG("Event is too big.\r\n"); + return false; + } + + initTransaction(&tr); + + tr.command = SPI_CMD_SEND_EVENT_PACKED; + tr.tx[0].buffer = (uint8_t *)header; + tr.tx[0].dataSize = headerSize; + tr.tx[1].buffer = buffer.ptr(); + tr.tx[1].dataSize = buffer.used(); + + return transaction(&tr); +} #endif bool BERGCloudBase::getConnectionState(uint8_t& state) @@ -479,6 +727,31 @@ return true; } +bool BERGCloudBase::connect(const char *key, uint16_t version, bool waitForConnected) +{ + unsigned int tmp_key[BC_KEY_SIZE_BYTES] = {0}; + uint8_t _key[BC_KEY_SIZE_BYTES] = {0}; + uint8_t i; + + /* Convert key from ASCII */ + if (key != NULL) + { + if (sscanf(key, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", + &tmp_key[0], &tmp_key[1], &tmp_key[2], &tmp_key[3], + &tmp_key[4], &tmp_key[5], &tmp_key[6], &tmp_key[7], + &tmp_key[8], &tmp_key[9], &tmp_key[10], &tmp_key[11], + &tmp_key[12], &tmp_key[13], &tmp_key[14], &tmp_key[15]) == 16) + { + for (i=0; i<sizeof(_key); i++) + { + _key[i] = (uint8_t)tmp_key[i]; + } + } + } + + return connect(_key, version, waitForConnected); +} + bool BERGCloudBase::getClaimingState(uint8_t& state) { _BC_SPI_TRANSACTION tr; @@ -610,9 +883,25 @@ { synced = false; lastResponse = SPI_RSP_SUCCESS; + + /* Print library version */ + _LOG("\r\nBERGCloud library version "); + _LOG_HEX(BERGCLOUD_LIB_VERSION >> 8); + _LOG("."); + _LOG_HEX(BERGCLOUD_LIB_VERSION & 0xff); + _LOG("\r\n"); } void BERGCloudBase::end(void) { } + +void BERGCloudBase::bytecpy(uint8_t *dst, uint8_t *src, uint16_t size) +{ + /* memcpy() cannot be used when buffers overlap */ + while (size-- > 0) + { + *dst++ = *src++; + } +}
--- a/BERGCloudBase.h Tue Nov 26 17:45:12 2013 +0000 +++ b/BERGCloudBase.h Wed Apr 16 14:38:12 2014 +0000 @@ -36,7 +36,7 @@ #include "BERGCloudMessageBuffer.h" #endif -#define BERGCLOUD_LIB_VERSION (0x0100) +#define BERGCLOUD_LIB_VERSION (0x0200) #define _TX_GROUPS (2) #define _RX_GROUPS (2) @@ -63,13 +63,17 @@ public: /* Check for a command */ bool pollForCommand(uint8_t *commandBuffer, uint16_t commandBufferSize, uint16_t& commandSize, uint8_t& commandID); + bool pollForCommand(uint8_t *commandBuffer, uint16_t commandBufferSize, uint16_t& commandSize, char *commandName, uint8_t commandNameMaxSize); #ifdef BERGCLOUD_PACK_UNPACK bool pollForCommand(BERGCloudMessageBuffer& buffer, uint8_t& commandID); + bool pollForCommand(BERGCloudMessageBuffer& buffer, char *commandName, uint8_t commandNameMaxSize); #endif /* Send an event */ - bool sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize, bool packed = false); + bool sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize, bool packed = true); + bool sendEvent(const char *eventName, uint8_t *eventBuffer, uint16_t eventSize, bool packed = true); #ifdef BERGCLOUD_PACK_UNPACK bool sendEvent(uint8_t eventCode, BERGCloudMessageBuffer& buffer); + bool sendEvent(const char *eventName, BERGCloudMessageBuffer& buffer); #endif /* Get the connection state */ bool getConnectionState(uint8_t& state); @@ -77,6 +81,7 @@ bool getSignalQuality(int8_t& rssi, uint8_t& lqi); /* Connect */ virtual bool connect(const uint8_t (&key)[BC_KEY_SIZE_BYTES] = nullKey, uint16_t version = 0, bool waitForConnected = false); + virtual bool connect(const char *key = NULL, uint16_t version = 0, bool waitForConnected = false); /* Check if the device has been claimed */ bool getClaimingState(uint8_t& state); /* Get the current claimcode */ @@ -110,6 +115,7 @@ bool _transaction(_BC_SPI_TRANSACTION *tr); bool transaction(_BC_SPI_TRANSACTION *tr); bool _sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize, uint8_t command); + void bytecpy(uint8_t *dst, uint8_t *src, uint16_t size); void lockTake(void); void lockRelease(void); bool synced;
--- a/BERGCloudConst.h Tue Nov 26 17:45:12 2013 +0000 +++ b/BERGCloudConst.h Wed Apr 16 14:38:12 2014 +0000 @@ -43,6 +43,7 @@ #define BC_COMMAND_START_RAW 0xC000 #define BC_COMMAND_START_PACKED 0xC100 +#define BC_COMMAND_NAMED_PACKED 0xC17F #define BC_COMMAND_ID_MASK 0x00FF #define BC_COMMAND_FORMAT_MASK 0xFF00 @@ -51,6 +52,7 @@ #define BC_EVENT_START_RAW 0xE000 #define BC_EVENT_START_PACKED 0xE100 +#define BC_EVENT_NAMED_PACKED 0xE17F #define BC_EVENT_ID_MASK 0x00FF #define BC_EVENT_FORMAT_MASK 0xFF00
--- a/BERGCloudMbed.cpp Tue Nov 26 17:45:12 2013 +0000 +++ b/BERGCloudMbed.cpp Wed Apr 16 14:38:12 2014 +0000 @@ -168,5 +168,21 @@ return true; } +bool BERGCloudMbed::pollForCommand(BERGCloudMessageBuffer& buffer, string &commandName) +{ + bool result = false; + char tmp[31 + 1]; /* +1 for null terminator */ + + commandName = ""; /* Empty string */ + result = pollForCommand(buffer, tmp, sizeof(tmp)); + + if (result) + { + commandName = string(tmp); + } + + return result; +} + #endif // #ifdef BERGCLOUD_PACK_UNPACK
--- a/BERGCloudMbed.h Tue Nov 26 17:45:12 2013 +0000 +++ b/BERGCloudMbed.h Wed Apr 16 14:38:12 2014 +0000 @@ -40,9 +40,11 @@ public: void begin(PinName _MOSIPin, PinName _MISOPin, PinName _SCLKPin, PinName _nSSELPin); void end(); + /* Methods using std::string class */ using BERGCloudBase::display; - /* Methods using std::string class */ bool display(std::string& s); + using BERGCloudBase::pollForCommand; + bool pollForCommand(BERGCloudMessageBuffer& buffer, string &commandName); private: virtual uint16_t SPITransaction(uint8_t *dataOut, uint8_t *dataIn, uint16_t dataSize, bool finalCS); virtual void timerReset(void);