Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: LittleCounter-Example
Revision 0:b4ccb530b9eb, committed 2013-11-12
- Comitter:
- nickludlam
- Date:
- Tue Nov 12 14:38:30 2013 +0000
- Child:
- 1:93c28642660c
- Commit message:
- Initial commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BERGCloud.h Tue Nov 12 14:38:30 2013 +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 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudBase.cpp Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,600 @@
+/*
+
+BERGCloud library common API
+
+Copyright (c) 2013 BERG Cloud 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.
+
+*/
+
+
+#define __STDC_LIMIT_MACROS /* Include C99 stdint defines in C++ code */
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h> /* For memcpy() */
+
+#include "BERGCloudBase.h"
+
+#define SPI_POLL_TIMEOUT_MS 1000
+#define SPI_SYNC_TIMEOUT_MS 10000
+
+#define CONNECT_POLL_RATE_MS 250
+
+uint8_t BERGCloudBase::nullProductKey[BC_PRODUCT_KEY_SIZE_BYTES] = {0};
+
+bool BERGCloudBase::transaction(_BC_SPI_TRANSACTION *tr)
+{
+ uint16_t i, j;
+ uint8_t rxByte;
+ bool timeout;
+ uint8_t dataSize;
+ uint16_t groupSize;
+ uint16_t dataCRC;
+ uint16_t calcCRC;
+ uint8_t header[SPI_HEADER_SIZE_BYTES];
+ uint8_t footer[SPI_FOOTER_SIZE_BYTES];
+
+ /* Check synchronisation */
+ if (!synced)
+ {
+ timerReset();
+
+ do {
+ rxByte = SPITransaction(SPI_PROTOCOL_PAD, true);
+ timeout = timerRead_mS() > SPI_SYNC_TIMEOUT_MS;
+
+ } while ((rxByte != SPI_PROTOCOL_RESET) && !timeout);
+
+ if (timeout)
+ {
+ _LOG("Timeout, sync (BERGCloudBase::transaction)\r\n");
+ return false;
+ }
+
+ /* Resynchronisation successful */
+ synced = true;
+ }
+
+ /* Calculate total data size */
+ dataSize = 0;
+
+ for (i=0; i<_TX_GROUPS; i++)
+ {
+ dataSize += tr->tx[i].dataSize;
+ }
+
+ /* Initialise CRC */
+ calcCRC = 0xffff;
+
+ /* Create header */
+ header[0] = tr->command;
+ header[1] = 0x00; /* Reserved */
+ header[2] = 0x00; /* Reserved */
+ header[3] = dataSize;
+
+ /* Send header */
+ for (i=0; i<sizeof(header); i++)
+ {
+
+ calcCRC = Crc16(header[i], calcCRC);
+ rxByte = SPITransaction(header[i], false);
+
+ if (rxByte == SPI_PROTOCOL_RESET)
+ {
+ _LOG("Reset, send header (BERGCloudBase::transaction)\r\n");
+ return false;
+ }
+
+ if (rxByte != SPI_PROTOCOL_PAD)
+ {
+ _LOG("SyncErr, send header (BERGCloudBase::transaction)\r\n");
+ synced = false;
+ return false;
+ }
+ }
+
+ /* Send data groups */
+ for (i=0; i<_TX_GROUPS; i++)
+ {
+ for (j=0; j<tr->tx[i].dataSize; j++)
+ {
+ calcCRC = Crc16(tr->tx[i].buffer[j], calcCRC);
+ rxByte = SPITransaction(tr->tx[i].buffer[j], false);
+
+ if (rxByte == SPI_PROTOCOL_RESET)
+ {
+ _LOG("Reset, send data (BERGCloudBase::transaction)\r\n");
+ return false;
+ }
+
+ if (rxByte != SPI_PROTOCOL_PAD)
+ {
+ _LOG("SyncErr, send data (BERGCloudBase::transaction)\r\n");
+ synced = false;
+ return false;
+ }
+ }
+ }
+
+ /* Create footer */
+ footer[0] = calcCRC >> 8;
+ footer[1] = calcCRC & 0xff;
+
+ /* Send footer */
+ for (i=0; i<sizeof(footer); i++)
+ {
+ rxByte = SPITransaction(footer[i], false);
+
+ if (rxByte == SPI_PROTOCOL_RESET)
+ {
+ _LOG("Reset, send footer (BERGCloudBase::transaction)\r\n");
+ return false;
+ }
+
+ if (rxByte != SPI_PROTOCOL_PAD)
+ {
+ _LOG("SyncErr, send footer (BERGCloudBase::transaction)\r\n");
+ synced = false;
+ return false;
+ }
+ }
+
+ /* Poll for response */
+ timerReset();
+
+ do {
+ rxByte = SPITransaction(SPI_PROTOCOL_PAD, false);
+
+ if (rxByte == SPI_PROTOCOL_RESET)
+ {
+ _LOG("Reset, poll (BERGCloudBase::transaction)\r\n");
+ return false;
+ }
+
+ if (rxByte == SPI_PROTOCOL_PENDING)
+ {
+ /* Waiting for data; reset timeout */
+ timerReset();
+ }
+
+ timeout = timerRead_mS() > SPI_POLL_TIMEOUT_MS;
+
+ } while (((rxByte == SPI_PROTOCOL_PAD) || (rxByte == SPI_PROTOCOL_PENDING)) && !timeout);
+
+ if (timeout)
+ {
+ _LOG("Timeout, poll (BERGCloudBase::transaction)\r\n");
+ synced = false;
+ return false;
+ }
+
+ /* Initialise CRC */
+ calcCRC = 0xffff;
+
+ /* Read header, we already have the first byte */
+ header[0] = rxByte;
+ calcCRC = Crc16(header[0], calcCRC);
+
+ for (i=1; i < SPI_HEADER_SIZE_BYTES; i++)
+ {
+ header[i] = SPITransaction(SPI_PROTOCOL_PAD, false);
+ calcCRC = Crc16(header[i], calcCRC);
+ }
+
+ /* Get data size */
+ dataSize = header[3];
+
+ /* Read data groups */
+ for (i=0; i<_RX_GROUPS; i++)
+ {
+ groupSize = tr->rx[i].bufferSize;
+ j = 0; /* Start of the group buffer */
+
+ while((dataSize > 0) && (groupSize > 0))
+ {
+ tr->rx[i].buffer[j] = SPITransaction(SPI_PROTOCOL_PAD, false);
+ calcCRC = Crc16(tr->rx[i].buffer[j], calcCRC);
+
+ /* Next */
+ j++;
+
+ /* Update the total data remaining and the space remaining in this group. */
+ dataSize--;
+ groupSize--;
+ }
+
+ if (tr->rx[i].dataSize != NULL)
+ {
+ /* Return the number of bytes used in this buffer */
+ *tr->rx[i].dataSize = tr->rx[i].bufferSize - groupSize;
+ }
+ }
+
+ if (dataSize > 0)
+ {
+ /* Too much data sent */
+ _LOG("SizeErr, read data (BERGCloudBase::transaction)\r\n");
+ synced = false;
+ return false;
+ }
+
+ /* Read CRC; set nCS high */
+ dataCRC = SPITransaction(SPI_PROTOCOL_PAD, false); /* MSByte */
+ dataCRC <<= 8;
+ dataCRC |= SPITransaction(SPI_PROTOCOL_PAD, true /* nCS -> high */); /* LSByte */
+
+ /* Compare with calculated CRC */
+ if (calcCRC != dataCRC)
+ {
+ /* Invalid CRC */
+ _LOG("CRCErr, read data (BERGCloudBase::transaction)\r\n");
+ synced = false;
+ return false;
+ }
+
+ /* Get reponse code */
+ lastResponse = header[0];
+
+ return (lastResponse == SPI_RSP_SUCCESS);
+}
+
+void BERGCloudBase::initTransaction(_BC_SPI_TRANSACTION *tr)
+{
+ memset(tr, 0x00, sizeof(_BC_SPI_TRANSACTION));
+}
+
+bool BERGCloudBase::pollForCommand(uint8_t *commandBuffer, uint16_t commandBufferSize, uint16_t& commandSize, uint8_t& commandID)
+{
+ /* Returns TRUE if a valid command has been received */
+
+ _BC_SPI_TRANSACTION tr;
+ uint8_t cmdID[2] = {0};
+ uint16_t cmdIDSize = 0;
+
+ 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))
+ {
+ commandID = cmdID[1];
+ return true;
+ }
+
+ commandID = 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 */
+
+ _BC_SPI_TRANSACTION tr;
+ uint8_t cmdID[2] = {0};
+ uint16_t cmdIDSize = 0;
+ uint16_t dataSize = 0;
+
+ 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))
+ {
+ commandID = cmdID[1];
+ buffer.used(dataSize);
+ return true;
+ }
+
+ commandID = 0;
+ buffer.used(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 */
+
+ _BC_SPI_TRANSACTION tr;
+ uint8_t header[4] = {0};
+
+ if (eventSize > (SPI_MAX_PAYLOAD_SIZE_BYTES - sizeof(header)))
+ {
+ /* Too big */
+ return false;
+ }
+
+ header[0] = eventCode;
+
+ initTransaction(&tr);
+
+ tr.command = command;
+ tr.tx[0].buffer = (uint8_t *)header;
+ tr.tx[0].dataSize = sizeof(header);
+ tr.tx[1].buffer = eventBuffer;
+ tr.tx[1].dataSize = (uint8_t)eventSize;
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize)
+{
+ return _sendEvent(eventCode, eventBuffer, eventSize, SPI_CMD_SEND_EVENT_RAW);
+}
+
+#ifdef BERGCLOUD_PACK_UNPACK
+bool BERGCloudBase::sendEvent(uint8_t eventCode, BERGCloudMessageBuffer& buffer)
+{
+ bool result;
+
+ result = _sendEvent(eventCode, buffer.ptr(), buffer.used(), SPI_CMD_SEND_EVENT_PACKED);
+
+ buffer.clear();
+ return result;
+}
+#endif
+
+bool BERGCloudBase::getConnectionState(uint8_t& state)
+{
+ _BC_SPI_TRANSACTION tr;
+
+ initTransaction(&tr);
+
+ tr.command = SPI_CMD_GET_CONNECT_STATE;
+ tr.rx[0].buffer = &state;
+ tr.rx[0].bufferSize = sizeof(state);
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::getSignalQuality(int8_t& rssi, uint8_t& lqi)
+{
+ _BC_SPI_TRANSACTION tr;
+
+ initTransaction(&tr);
+
+ tr.command = SPI_CMD_GET_SIGNAL_QUALITY;
+ tr.rx[0].buffer = (uint8_t *)&rssi;
+ tr.rx[0].bufferSize = sizeof(rssi);
+ tr.rx[1].buffer = &lqi;
+ tr.rx[1].bufferSize = sizeof(lqi);
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::connect(const uint8_t (&productKey)[BC_PRODUCT_KEY_SIZE_BYTES], uint16_t version, bool waitForConnected)
+{
+ _BC_SPI_TRANSACTION tr;
+ uint16_t hostType = BC_HOST_UNKNOWN;
+ uint8_t connectData [sizeof(version) + sizeof(hostType)];
+
+ uint8_t lastState = BC_CONNECT_STATE_DISCONNECTED;
+ uint8_t state;
+
+#ifndef BERGCLOUD_NO_HOST_TYPE
+ /* Get host type */
+ hostType = getHostType();
+#endif
+
+ initTransaction(&tr);
+
+ connectData[0] = hostType;
+ connectData[1] = hostType >> 8;
+ connectData[2] = version;
+ connectData[3] = version >> 8;
+
+ tr.command = SPI_CMD_SEND_PRODUCT_ANNOUNCE;
+ tr.tx[0].buffer = (uint8_t *)productKey;
+ tr.tx[0].dataSize = sizeof(productKey);
+ tr.tx[1].buffer = connectData;
+ tr.tx[1].dataSize = sizeof(connectData);
+
+ if (!transaction(&tr))
+ {
+ return false;
+ }
+
+ if (waitForConnected)
+ {
+ /* Poll until connected */
+ do {
+ timerReset();
+ while (timerRead_mS() < CONNECT_POLL_RATE_MS);
+
+ if (!getConnectionState(state))
+ {
+ return false;
+ }
+
+ if (state != lastState)
+ {
+ switch (state)
+ {
+ case BC_CONNECT_STATE_CONNECTED:
+ _LOG("connect: Connected\r\n");
+ break;
+ case BC_CONNECT_STATE_CONNECTING:
+ _LOG("connect: Connecting...\r\n");
+ break;
+ default:
+ case BC_CONNECT_STATE_DISCONNECTED:
+ _LOG("connect: Disconnected\r\n");
+ break;
+ }
+
+ lastState = state;
+ }
+
+ } while (state != BC_CONNECT_STATE_CONNECTED);
+ }
+
+ return true;
+}
+
+bool BERGCloudBase::getClaimingState(uint8_t& state)
+{
+ _BC_SPI_TRANSACTION tr;
+
+ initTransaction(&tr);
+
+ tr.command = SPI_CMD_GET_CLAIM_STATE;
+ tr.rx[0].buffer = &state;
+ tr.rx[0].bufferSize = sizeof(state);
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::getClaimcode(const char (&claimcode)[BC_CLAIMCODE_SIZE_BYTES])
+{
+ _BC_SPI_TRANSACTION tr;
+
+ initTransaction(&tr);
+
+ tr.command = SPI_CMD_GET_CLAIMCODE;
+ tr.rx[0].buffer = (uint8_t *)claimcode;
+ tr.rx[0].bufferSize = sizeof(claimcode);
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::getEUI64(uint8_t type, uint8_t (&eui64)[BC_EUI64_SIZE_BYTES])
+{
+ _BC_SPI_TRANSACTION tr;
+
+ initTransaction(&tr);
+
+ tr.command = SPI_CMD_GET_EUI64;
+ tr.tx[0].buffer = &type;
+ tr.tx[0].dataSize = sizeof(uint8_t);
+ tr.rx[0].buffer = eui64;
+ tr.rx[0].bufferSize = sizeof(eui64);
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::getDeviceAddress(uint8_t (&address)[BC_ADDRESS_SIZE_BYTES])
+{
+ _BC_SPI_TRANSACTION tr;
+
+ initTransaction(&tr);
+
+ tr.command = SPI_CMD_GET_ADDRESS;
+ tr.rx[0].buffer = address;
+ tr.rx[0].bufferSize = sizeof(address);
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::setDisplayStyle(uint8_t style)
+{
+ _BC_SPI_TRANSACTION tr;
+
+ initTransaction(&tr);
+
+ tr.command = SPI_CMD_SET_DISPLAY_STYLE;
+ tr.tx[0].buffer = &style;
+ tr.tx[0].dataSize = sizeof(style);
+
+ return transaction(&tr);
+}
+
+bool BERGCloudBase::clearDisplay(void)
+{
+ return setDisplayStyle(BC_DISPLAY_CLEAR);
+}
+
+bool BERGCloudBase::display(const char *text)
+{
+ _BC_SPI_TRANSACTION tr;
+ uint8_t strLen = 0;
+ const char *tmp = text;
+
+ if (text == NULL)
+ {
+ return false;
+ }
+
+ initTransaction(&tr);
+
+ /* Get string length excluding terminator */
+ while ((*tmp++ != '\0') && (strLen < UINT8_MAX))
+ {
+ strLen++;
+ }
+
+ tr.command = SPI_CMD_DISPLAY_PRINT;
+ tr.tx[0].buffer = (uint8_t *)text;
+ tr.tx[0].dataSize = strLen;
+
+ return transaction(&tr);
+}
+
+uint16_t BERGCloudBase::Crc16(uint8_t data, uint16_t crc)
+{
+ /* From Ember's code */
+ crc = (crc >> 8) | (crc << 8);
+ crc ^= data;
+ crc ^= (crc & 0xff) >> 4;
+ crc ^= (crc << 8) << 4;
+
+ crc ^= ( (uint8_t) ( (uint8_t) ( (uint8_t) (crc & 0xff) ) << 5)) |
+ ((uint16_t) ( (uint8_t) ( (uint8_t) (crc & 0xff)) >> 3) << 8);
+
+ return crc;
+}
+
+uint8_t BERGCloudBase::SPITransaction(uint8_t dataOut, bool finalCS)
+{
+ uint8_t dataIn = 0;
+
+ SPITransaction(&dataOut, &dataIn, (uint16_t)1, finalCS);
+
+ return dataIn;
+}
+
+void BERGCloudBase::begin(void)
+{
+ synced = false;
+ lastResponse = SPI_RSP_SUCCESS;
+}
+
+void BERGCloudBase::end(void)
+{
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudBase.h Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,116 @@
+/*
+
+BERGCloud library common API
+
+Copyright (c) 2013 BERG Cloud 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 BERGCLOUDBASE_H
+#define BERGCLOUDBASE_H
+
+#include "BERGCloudConfig.h"
+#include "BERGCloudConst.h"
+#include "BERGCloudLogPrint.h"
+
+#ifdef BERGCLOUD_PACK_UNPACK
+#include "BERGCloudMessageBuffer.h"
+#endif
+
+#define BERGCLOUD_LIB_VERSION (0x0100)
+
+#define _TX_GROUPS (2)
+#define _RX_GROUPS (2)
+
+typedef struct {
+ uint8_t *buffer;
+ uint16_t dataSize;
+} _BC_TX_GROUP;
+
+typedef struct {
+ uint8_t *buffer;
+ uint16_t bufferSize;
+ uint16_t *dataSize;
+} _BC_RX_GROUP;
+
+typedef struct {
+ uint8_t command;
+ _BC_TX_GROUP tx[_TX_GROUPS];
+ _BC_RX_GROUP rx[_RX_GROUPS];
+} _BC_SPI_TRANSACTION;
+
+class BERGCloudBase
+{
+public:
+ /* Check for a command */
+ bool pollForCommand(uint8_t *commandBuffer, uint16_t commandBufferSize, uint16_t& commandSize, uint8_t& commandID);
+#ifdef BERGCLOUD_PACK_UNPACK
+ bool pollForCommand(BERGCloudMessageBuffer& buffer, uint8_t& commandID);
+#endif
+ /* Send an event */
+ bool sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize);
+#ifdef BERGCLOUD_PACK_UNPACK
+ bool sendEvent(uint8_t eventCode, BERGCloudMessageBuffer& buffer);
+#endif
+ /* Get the connection state */
+ bool getConnectionState(uint8_t& state);
+ /* Get the last-hop signal quality */
+ bool getSignalQuality(int8_t& rssi, uint8_t& lqi);
+ /* Connect */
+ bool connect(const uint8_t (&productKey)[BC_PRODUCT_KEY_SIZE_BYTES] = nullProductKey, uint16_t version = 0, bool waitForConnected = false);
+ /* Check if the device has been claimed */
+ bool getClaimingState(uint8_t& state);
+ /* Get the current claimcode */
+ bool getClaimcode(const char (&claimcode)[BC_CLAIMCODE_SIZE_BYTES]);
+ /* Get the EUI64 identifier for this node, its parent or the network coordinator */
+ bool getEUI64(uint8_t type, uint8_t (&eui64)[BC_EUI64_SIZE_BYTES]);
+ /* Get the Device Address */
+ bool getDeviceAddress(uint8_t (&address)[BC_ADDRESS_SIZE_BYTES]);
+ /* Set the display style for the OLED display. This also clears the display. */
+ bool setDisplayStyle(uint8_t style);
+ /* Clear the OLED display */
+ bool clearDisplay(void);
+ /* Display a line of text on the OLED display */
+ bool display(const char *text);
+
+ /* Internal methods */
+public:
+ uint8_t lastResponse;
+ static uint8_t nullProductKey[BC_PRODUCT_KEY_SIZE_BYTES];
+protected:
+ void begin(void);
+ void end(void);
+ uint16_t Crc16(uint8_t data, uint16_t crc);
+ virtual uint16_t SPITransaction(uint8_t *dataOut, uint8_t *dataIn, uint16_t dataSize, bool finalCS) = 0;
+ virtual void timerReset(void) = 0;
+ virtual uint32_t timerRead_mS(void) = 0;
+ virtual uint16_t getHostType(void) = 0;
+private:
+ uint8_t SPITransaction(uint8_t data, bool finalCS);
+ void initTransaction(_BC_SPI_TRANSACTION *tr);
+ bool transaction(_BC_SPI_TRANSACTION *tr);
+ bool _sendEvent(uint8_t eventCode, uint8_t *eventBuffer, uint16_t eventSize, uint8_t command);
+ bool synced;
+};
+
+#endif // #ifndef BERGCLOUDBASE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BERGCloudConfig.h Tue Nov 12 14:38:30 2013 +0000 @@ -0,0 +1,40 @@ +/* + +BERGCloud compile-time configuration options + +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 BERGCLOUDCONFIG_H +#define BERGCLOUDCONFIG_H + +/* Include debug logging */ +#define BERGCLOUD_LOG + +/* Include pack/unpack */ +#ifndef LINUX +#define BERGCLOUD_PACK_UNPACK +#endif + +#endif // #ifndef BERGCLOUDCONFIG_H +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BERGCloudConst.h Tue Nov 12 14:38:30 2013 +0000 @@ -0,0 +1,129 @@ +/* + +BERGCloud constant definitions + +Copyright (c) 2013 BERG Cloud 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. + +*/ + +/* + * Sizes of things + */ + +#define BC_EUI64_SIZE_BYTES 8 +#define BC_ADDRESS_SIZE_BYTES 8 +#define BC_CLAIMCODE_SIZE_BYTES 20 +#define BC_PRODUCT_KEY_SIZE_BYTES 16 +#define BC_PRINT_MAX_CHARS 26 + +/* + * Network commands + */ + +#define BC_EVENT_PRODUCT_ANNOUNCE 0xA000 +#define BC_COMMAND_SET_ADDRESS 0xB000 + +#define BC_COMMAND_START_RAW 0xC000 +#define BC_COMMAND_START_PACKED 0xC100 +#define BC_COMMAND_ID_MASK 0x00FF +#define BC_COMMAND_FORMAT_MASK 0xFF00 + +#define BC_COMMAND_DISPLAY_IMAGE 0xD000 +#define BC_COMMAND_DISPLAY_TEXT 0xD001 + +#define BC_EVENT_START_RAW 0xE000 +#define BC_EVENT_START_PACKED 0xE100 +#define BC_EVENT_ID_MASK 0x00FF +#define BC_EVENT_FORMAT_MASK 0xFF00 + +#define BC_COMMAND_FIRMWARE_ARDUINO 0xF010 +#define BC_COMMAND_FIRMWARE_MBED 0xF020 + +/* + * SPI bus commands + */ + +#define SPI_CMD_GET_CONNECT_STATE 0x80 +#define SPI_CMD_GET_CLAIMCODE 0x81 +#define SPI_CMD_GET_CLAIM_STATE 0x82 +#define SPI_CMD_GET_SIGNAL_QUALITY 0x83 +#define SPI_CMD_GET_EUI64 0x90 + +#define SPI_CMD_SEND_PRODUCT_ANNOUNCE 0xA0 +#define SPI_CMD_GET_ADDRESS 0xB0 +#define SPI_CMD_POLL_FOR_COMMAND 0xC0 +#define SPI_CMD_SET_DISPLAY_STYLE 0xD0 +#define SPI_CMD_DISPLAY_PRINT 0xD1 +#define SPI_CMD_SEND_EVENT_RAW 0xE0 +#define SPI_CMD_SEND_EVENT_PACKED 0xE1 + +#define SPI_PROTOCOL_PAD 0xff +#define SPI_PROTOCOL_PENDING 0xfa +#define SPI_PROTOCOL_RESET 0xf5 + +/* For SPI_CMD_GET_CONNECT_STATE */ +#define BC_CONNECT_STATE_CONNECTED 0x00 +#define BC_CONNECT_STATE_CONNECTING 0x01 +#define BC_CONNECT_STATE_DISCONNECTED 0x02 + +/* For SPI_CMD_GET_EUI64 */ +#define BC_EUI64_NODE 0x00 +#define BC_EUI64_PARENT 0x01 +#define BC_EUI64_COORDINATOR 0x02 + +/* For SPI_CMD_SEND_PRODUCT_ANNOUNCE */ +#define BC_HOST_UNKNOWN 0x0000 +#define BC_HOST_ARDUINO 0x1000 +#define BC_HOST_MBED 0x2000 +#define BC_HOST_LINUX 0x3000 + +/* For SPI_CMD_GET_CLAIM_STATE */ +#define BC_CLAIM_STATE_CLAIMED 0x00 +#define BC_CLAIM_STATE_NOT_CLAIMED 0x01 + +/* For SPI_CMD_DISPLAY_STYLE */ +#define BC_DISPLAY_NONE 0x00 +#define BC_DISPLAY_STYLE_ONE_LINE 0x01 +#define BC_DISPLAY_STYLE_TWO_LINES 0x02 +#define BC_DISPLAY_STYLE_FOUR_LINES 0x04 + +#define BC_DISPLAY_CLEAR 0xc0 +/* Clear the display without changing the style */ + +/* For SPI_CMD_SEND_EVENT_ */ +#define SPI_EVENT_HEADER_SIZE_BYTES 4 + +/* SPI data sizes */ +#define SPI_MAX_PACKET_SIZE_BYTES 128 +#define SPI_HEADER_SIZE_BYTES 4 +#define SPI_FOOTER_SIZE_BYTES 2 + +#define SPI_MAX_PAYLOAD_SIZE_BYTES \ +(SPI_MAX_PACKET_SIZE_BYTES - (SPI_HEADER_SIZE_BYTES + SPI_FOOTER_SIZE_BYTES)) + +/* Response status values */ +#define SPI_RSP_SUCCESS 0x00 +#define SPI_RSP_INVALID_COMMAND 0x01 +#define SPI_RSP_BUSY 0x02 +#define SPI_RSP_NO_DATA 0x03 +#define SPI_RSP_SEND_FAILED 0x04 +#define SPI_RSP_NO_FREE_BUFFERS 0x05 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudLogPrint.h Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,51 @@
+/*
+
+Debug logging helpers
+
+Copyright (c) 2013 BERG Cloud 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 BERGCLOUDLOGPRINT_H
+#define BERGCLOUDLOGPRINT_H
+
+#ifdef BERGCLOUD_LOG
+#ifdef ARDUINO
+#include <Arduino.h>
+// Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
+// Credit: http://forum.arduino.cc/index.php/topic,85840.0.html
+#ifdef PROGMEM
+#undef PROGMEM
+#define PROGMEM __attribute__((section(".progmem.data")))
+#endif // #ifdef PROGMEM
+#define _LOG(x) Serial.print(F(x))
+#define _LOG_HEX(x) if ((x) < 0x10) Serial.print(F("0")); Serial.print((x), HEX)
+#else // #ifdef ARDUINO
+#include <stdio.h>
+#define _LOG(x) printf(x)
+#define _LOG_HEX(x) printf("%02X", (x))
+#endif // #ifdef ARDUINO
+#else // #ifdef BERGCLOUD_LOG
+#define _LOG(x)
+#endif // #ifdef BERGCLOUD_LOG
+
+#endif // #ifndef BERGCLOUDLOGPRINT_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudMbed.cpp Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,173 @@
+/*
+
+BERGCloud library for mbed
+
+Copyright (c) 2013 BERG Cloud 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.
+
+*/
+
+#include <cstdint>
+#include <cstddef>
+#include <cstdarg>
+
+#include "BERGCloudMbed.h"
+
+uint16_t BERGCloudMbed::SPITransaction(uint8_t *dataOut, uint8_t *dataIn, uint16_t dataSize, bool finalCS)
+{
+ uint16_t i;
+
+ if ( (dataOut == NULL) || (dataIn == NULL) || (spi == NULL) )
+ {
+ _LOG("Invalid parameter (CBERGCloud::SPITransaction)\r\n");
+ return 0;
+ }
+
+ nSSELPin->write(0);
+
+ for (i = 0; i < dataSize; i++)
+ {
+ *dataIn++ = spi->write(*dataOut++);
+ }
+
+ if (finalCS)
+ {
+ nSSELPin->write(1);
+ }
+
+ return dataSize;
+}
+
+void BERGCloudMbed::timerReset(void)
+{
+ timer->reset();
+}
+
+uint32_t BERGCloudMbed::timerRead_mS(void)
+{
+ return timer->read_ms();
+}
+
+void BERGCloudMbed::begin(PinName _MOSIPin, PinName _MISOPin, PinName _SCLKPin, PinName _nSSELPin)
+{
+ /* Call base class method */
+ BERGCloudBase::begin();
+
+ /* Configure nSSEL control pin */
+ nSSELPin = new DigitalOut(_nSSELPin);
+
+ if (nSSELPin == NULL)
+ {
+ _LOG("nSSELPin is NULL (CBERGCloud::begin)\r\n");
+ return;
+ }
+
+ nSSELPin->write(1);
+
+ /* Configure SPI */
+ spi = new SPI(_MOSIPin, _MISOPin, _SCLKPin);
+
+ if (spi == NULL)
+ {
+ _LOG("spi is NULL (CBERGCloud::begin)\r\n");
+ delete nSSELPin;
+ return;
+ }
+
+ spi->format(8, 0); /* 8-bits; SPI MODE 0 */
+ spi->frequency(4000000); /* 4MHz */
+
+ /* Configure timer */
+ timer = new Timer();
+
+ if (timer == NULL)
+ {
+ _LOG("timer is NULL (CBERGCloud::begin)\r\n");
+ delete nSSELPin;
+ delete spi;
+ return;
+ }
+
+ timer->start();
+}
+
+void BERGCloudMbed::end()
+{
+ if (nSSELPin != NULL)
+ {
+ delete nSSELPin;
+ }
+
+ if (spi != NULL)
+ {
+ delete spi;
+ }
+
+ if (timer != NULL)
+ {
+ delete timer;
+ }
+
+ /* Call base class method */
+ BERGCloudBase::end();
+}
+
+bool BERGCloudMbed::display(std::string& s)
+{
+ return display(s.c_str());
+}
+
+uint16_t BERGCloudMbed::getHostType(void)
+{
+ return BC_HOST_MBED;
+}
+
+#ifdef BERGCLOUD_PACK_UNPACK
+
+bool BERGCloudMessage::pack(std::string& s)
+{
+ return pack(s.c_str());
+}
+
+bool BERGCloudMessage::unpack(std::string& s)
+{
+ uint16_t sizeInBytes;
+
+ if (!unpack_raw_header(&sizeInBytes))
+ {
+ return false;
+ }
+
+ if (!remaining(sizeInBytes))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ std::string tmp(buffer[bytesRead], sizeInBytes);
+ bytesRead += sizeInBytes;
+
+ s = tmp;
+
+ return true;
+}
+
+#endif // #ifdef BERGCLOUD_PACK_UNPACK
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudMbed.h Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,71 @@
+/*
+
+BERGCloud library for mbed
+
+Copyright (c) 2013 BERG Cloud 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 BERGCLOUDMBED_H
+#define BERGCLOUDMBED_H
+
+#include "mbed.h"
+#include <string>
+#include "BERGCloudBase.h"
+
+#ifdef BERGCLOUD_PACK_UNPACK
+#include "BERGCloudMessageBase.h"
+#endif
+
+class BERGCloudMbed : public BERGCloudBase
+{
+public:
+ void begin(PinName _MOSIPin, PinName _MISOPin, PinName _SCLKPin, PinName _nSSELPin);
+ void end();
+ using BERGCloudBase::display;
+ /* Methods using std::string class */
+ bool display(std::string& s);
+private:
+ uint16_t SPITransaction(uint8_t *dataOut, uint8_t *dataIn, uint16_t dataSize, bool finalCS);
+ void timerReset(void);
+ uint32_t timerRead_mS(void);
+ uint16_t getHostType(void);
+ SPI *spi;
+ DigitalOut *nSSELPin;
+ Timer *timer;
+};
+
+#ifdef BERGCLOUD_PACK_UNPACK
+
+class BERGCloudMessage : public BERGCloudMessageBase
+{
+public:
+ using BERGCloudMessageBase::pack;
+ using BERGCloudMessageBase::unpack;
+ /* Methods using std::string class */
+ bool pack(std::string& s);
+ bool unpack(std::string& s);
+};
+
+#endif // #ifdef BERGCLOUD_PACK_UNPACK
+
+#endif // #ifndef BERGCLOUDMBED_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudMessageBase.cpp Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,1361 @@
+/*
+
+BERGCloud message pack/unpack
+
+Based on MessagePack http://msgpack.org/
+
+Copyright (c) 2013 BERG Cloud 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.
+
+*/
+
+#include <stddef.h> /* For NULL */
+#include <string.h> /* For memcpy() */
+#include "BERGCloudMessageBase.h"
+
+BERGCloudMessageBase::BERGCloudMessageBase(void)
+{
+}
+
+BERGCloudMessageBase::~BERGCloudMessageBase(void)
+{
+}
+
+#define _MP_FIXNUM_POS_MIN 0x00
+#define _MP_FIXNUM_POS_MAX 0x7f
+#define _MP_FIXMAP_MIN 0x80
+#define _MP_FIXMAP_MAX 0x8f
+#define _MP_FIXARRAY_MIN 0x90
+#define _MP_FIXARRAY_MAX 0x9f
+#define _MP_FIXRAW_MIN 0xa0
+#define _MP_FIXRAW_MAX 0xbf
+#define _MP_NIL 0xc0
+#define _MP_BOOL_FALSE 0xc2
+#define _MP_BOOL_TRUE 0xc3
+#define _MP_FLOAT 0xca
+#define _MP_DOUBLE 0xcb
+#define _MP_UINT8 0xcc
+#define _MP_UINT16 0xcd
+#define _MP_UINT32 0xce
+#define _MP_UINT64 0xcf
+#define _MP_INT8 0xd0
+#define _MP_INT16 0xd1
+#define _MP_INT32 0xd2
+#define _MP_INT64 0xd3
+#define _MP_RAW16 0xda
+#define _MP_RAW32 0xdb
+#define _MP_ARRAY16 0xdc
+#define _MP_ARRAY32 0xdd
+#define _MP_MAP16 0xde
+#define _MP_MAP32 0xdf
+#define _MP_FIXNUM_NEG_MIN 0xe0
+#define _MP_FIXNUM_NEG_MAX 0xff
+
+#define _MAX_FIXRAW (_MP_FIXRAW_MAX - _MP_FIXRAW_MIN)
+#define _MAX_FIXARRAY (_MP_FIXARRAY_MAX - _MP_FIXARRAY_MIN)
+#define _MAX_FIXMAP (_MP_FIXMAP_MAX - _MP_FIXMAP_MIN)
+
+uint16_t BERGCloudMessageBase::strlen(const char *string)
+{
+ uint16_t strLen = 0;
+
+ /* Find string length */
+ if (string != NULL)
+ {
+ while ((strLen < UINT16_MAX) && (*string != '\0'))
+ {
+ string++;
+ strLen++;
+ }
+ }
+
+ return strLen;
+}
+
+bool BERGCloudMessageBase::strcompare(const char *s1, const char *s2)
+{
+ uint16_t count = 0;
+
+ if ((s1 == NULL) || (s2==NULL))
+ {
+ return false;
+ }
+
+ while ((*s1 != '\0') && (*s2 != '\0'))
+ {
+ if (*s1++ != *s2++)
+ {
+ return false;
+ }
+
+ if (count++ == UINT16_MAX)
+ {
+ return false;
+ }
+ }
+
+ /* identical */
+ return true;
+}
+
+
+/*
+ Pack methods
+*/
+
+bool BERGCloudMessageBase::pack(uint8_t n)
+{
+ if (!available(sizeof(n) + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_UINT8);
+ add(n);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(uint16_t n)
+{
+ if (!available(sizeof(n) + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_UINT16);
+ add((uint8_t)(n >> 8));
+ add((uint8_t)n);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(uint32_t n)
+{
+ if (!available(sizeof(n) + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_UINT32);
+ add((uint8_t)(n >> 24));
+ add((uint8_t)(n >> 16));
+ add((uint8_t)(n >> 8));
+ add((uint8_t)n);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(int8_t n)
+{
+ if (!available(sizeof(n) + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_INT8);
+ add((uint8_t)n);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(int16_t n)
+{
+ if (!available(sizeof(n) + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_INT16);
+ add((uint8_t)(n >> 8));
+ add((uint8_t)n);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(int32_t n)
+{
+ if (!available(sizeof(n) + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_INT32);
+ add((uint8_t)(n >> 24));
+ add((uint8_t)(n >> 16));
+ add((uint8_t)(n >> 8));
+ add((uint8_t)n);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(float n)
+{
+ uint32_t data;
+
+ if (!available(sizeof(n) + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ /* Convert to data */
+ memcpy(&data, &n, sizeof(float));
+
+ add(_MP_FLOAT);
+ add((uint8_t)(data >> 24));
+ add((uint8_t)(data >> 16));
+ add((uint8_t)(data >> 8));
+ add((uint8_t)data);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(bool n)
+{
+ /*
+ Note that Arduino redefines 'true' and 'false' in Arduino.h.
+ You can undefine them in your code to make them type 'bool' again:
+ #undef true
+ #undef false
+ */
+
+ if (!available(1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(n ? _MP_BOOL_TRUE : _MP_BOOL_FALSE);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack_nil(void)
+{
+ if (!available(1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_NIL);
+ return true;
+}
+
+bool BERGCloudMessageBase::pack_array(uint16_t items)
+{
+ if (items <= _MAX_FIXARRAY)
+ {
+ /* Use fix array */
+ if (!available(items + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_FIXARRAY_MIN + items);
+ }
+ else
+ {
+ /* Use array 16 */
+ if (!available(items + 1 + sizeof(uint16_t)))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_ARRAY16);
+ add((uint8_t)(items >> 8));
+ add((uint8_t)items);
+ }
+
+ return true;
+}
+
+bool BERGCloudMessageBase::pack_map(uint16_t items)
+{
+ if (items <= _MAX_FIXMAP)
+ {
+ /* Use fix map */
+ if (!available(items + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_FIXMAP_MIN + items);
+ }
+ else
+ {
+ /* Use map 16 */
+ if (!available(items + 1 + sizeof(uint16_t)))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_MAP16);
+ add((uint8_t)(items >> 8));
+ add((uint8_t)items);
+ }
+
+ return true;
+}
+
+bool BERGCloudMessageBase::pack(uint8_t *data, uint16_t sizeInBytes)
+{
+ /* Pack data */
+ if (!pack_raw_header(sizeInBytes))
+ {
+ return false;
+ }
+
+ return pack_raw_data(data, sizeInBytes);
+}
+
+bool BERGCloudMessageBase::pack(const char *string)
+{
+ /* Pack a null-terminated C string */
+ uint16_t strLen;
+
+ strLen = BERGCloudMessageBase::strlen(string);
+
+ return pack((uint8_t *)string, strLen);
+}
+
+/* Separate header and data methods are provided for raw data*/
+/* so that Arduino strings may be packed without having to create */
+/* a temporary buffer first. */
+
+bool BERGCloudMessageBase::pack_raw_header(uint16_t sizeInBytes)
+{
+ if (sizeInBytes <= _MAX_FIXRAW)
+ {
+ /* Use fix raw */
+ if (!available(sizeInBytes + 1))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_FIXRAW_MIN + sizeInBytes);
+ }
+ else
+ {
+ /* Use raw 16 */
+ if (!available(sizeInBytes + 1 + sizeof(uint16_t)))
+ {
+ _LOG_PACK_ERROR_NO_SPACE;
+ return false;
+ }
+
+ add(_MP_RAW16);
+ add((uint8_t)(sizeInBytes >> 8));
+ add((uint8_t)sizeInBytes);
+ }
+
+ return true;
+}
+
+bool BERGCloudMessageBase::pack_raw_data(uint8_t *data, uint16_t sizeInBytes)
+{
+ /* Add data */
+ while (sizeInBytes-- > 0)
+ {
+ add(*data++);
+ }
+
+ return true;
+}
+
+/*
+ Unpack methods
+*/
+
+bool BERGCloudMessageBase::unpack_peek(uint8_t& messagePackType)
+{
+ return peek(&messagePackType);
+}
+
+#ifdef BERGCLOUD_LOG
+bool BERGCloudMessageBase::unpack_peek(void)
+{
+ uint8_t type;
+
+ if (!peek(&type))
+ {
+ return false;
+ }
+
+ if (type <= _MP_FIXNUM_POS_MAX)
+ {
+ _LOG("Positive integer\r\n");
+ return true;
+ }
+
+ if (IN_RANGE(type, _MP_FIXNUM_NEG_MIN, _MP_FIXNUM_NEG_MAX))
+ {
+ _LOG("Negative integer\r\n");
+ return true;
+ }
+
+ if ((type == _MP_MAP16) || (type == _MP_MAP32) || IN_RANGE(type, _MP_FIXMAP_MIN, _MP_FIXMAP_MAX))
+ {
+ _LOG("Map\r\n");
+ return true;
+ }
+
+ if ((type == _MP_ARRAY16) || (type == _MP_ARRAY32) || IN_RANGE(type, _MP_FIXARRAY_MIN, _MP_FIXARRAY_MAX))
+ {
+ _LOG("Array\r\n");
+ return true;
+ }
+
+ if ((type == _MP_RAW16) || (type == _MP_RAW32) || IN_RANGE(type, _MP_FIXRAW_MIN, _MP_FIXRAW_MAX))
+ {
+ _LOG("Raw\r\n");
+ return true;
+ }
+
+ if ((type ==_MP_UINT8) || (type == _MP_UINT16) || (type == _MP_UINT32) || (type == _MP_UINT64))
+ {
+ _LOG("Unsigned integer\r\n");
+ return true;
+ }
+
+ if ((type ==_MP_INT8) || (type == _MP_INT16) || (type == _MP_INT32) || (type == _MP_INT64))
+ {
+ _LOG("Signed integer\r\n");
+ return true;
+ }
+
+ if (type == _MP_NIL)
+ {
+ _LOG("Nil\r\n");
+ return true;
+ }
+
+ if (type == _MP_BOOL_FALSE)
+ {
+ _LOG("Boolean false\r\n");
+ return true;
+ }
+
+ if (type == _MP_BOOL_TRUE)
+ {
+ _LOG("Boolean true\r\n");
+ return true;
+ }
+
+ if (type == _MP_FLOAT)
+ {
+ _LOG("Float\r\n");
+ return true;
+ }
+
+ if (type == _MP_DOUBLE)
+ {
+ _LOG("Double\r\n");
+ return true;
+ }
+
+ _LOG("Unknown\r\n");
+ return false;
+}
+
+void BERGCloudMessageBase::print(void)
+{
+ uint16_t last_read;
+
+ /* Remember the current read position in the raw data */
+ last_read = bytesRead;
+
+ /* Start reading from the beginning of the data */
+ restart();
+
+ /* Print all items */
+ while(unpack_peek())
+ {
+ unpack_skip();
+ }
+
+ /* Return to the last position */
+ bytesRead = last_read;
+}
+
+void BERGCloudMessageBase::print_bytes(void)
+{
+ uint16_t size = used();
+ uint8_t *data = ptr();
+
+ while (size-- > 0)
+ {
+ _LOG_HEX(*data);
+ _LOG(" ");
+ data++;
+ }
+ _LOG("\r\n");
+}
+#endif
+
+bool BERGCloudMessageBase::getUnsignedInteger(uint32_t *value, uint8_t maxBytes)
+{
+ /* Try to decode the next messagePack item as an unsigned integer */
+ /* of less than or equal to 'maxBytes' size in bytes. */
+
+ uint8_t type;
+
+ if (maxBytes == 0)
+ {
+ /* Invalid */
+ return false;
+ }
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (type <= _MP_FIXNUM_POS_MAX)
+ {
+ /* Read fix num value */
+ *value = read();
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_UINT8)
+ {
+ if (!remaining(sizeof(uint8_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 8-bit unsigned integer */
+ *value = read();
+
+ /* Success */
+ return true;
+ }
+
+ if ((type == _MP_UINT16) && (maxBytes >= sizeof(uint16_t)))
+ {
+ if (!remaining(sizeof(uint16_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 16-bit unsigned integer */
+ *value = read();
+ *value = *value << 8;
+ *value |= read();
+
+ /* Success */
+ return true;
+ }
+
+ if ((type == _MP_UINT32) && (maxBytes >= sizeof(uint32_t)))
+ {
+ if (!remaining(sizeof(uint32_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 32-bit unsigned integer */
+ *value = read();
+ *value = *value << 8;
+ *value |= read();
+ *value = *value << 8;
+ *value |= read();
+ *value = *value << 8;
+ *value |= read();
+
+ /* Success */
+ return true;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+bool BERGCloudMessageBase::getSignedInteger(int32_t *value, uint8_t maxBytes)
+{
+ /* Try to decode the next messagePack item as an signed integer */
+ /* of less than or equal to 'maxBytes' size in bytes. */
+
+ uint8_t type;
+
+ if (maxBytes == 0)
+ {
+ /* Invalid */
+ return false;
+ }
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (type <= _MP_FIXNUM_POS_MAX)
+ {
+ /* Read fix num value */
+ *value = (int32_t)read();
+
+ /* Success */
+ return true;
+ }
+
+ if (IN_RANGE(type, _MP_FIXNUM_NEG_MIN, _MP_FIXNUM_NEG_MAX))
+ {
+ /* Read fix num value */
+ *value = (int32_t)read();
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_INT8)
+ {
+ if (!remaining(sizeof(int8_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 8-bit signed integer */
+ *value = (int32_t)read();
+ return true;
+ }
+
+ if ((type == _MP_INT16) && (maxBytes >= sizeof(int16_t)))
+ {
+ if (!remaining(sizeof(int16_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 16-bit signed integer */
+ *value = read();
+ *value = *value << 8;
+ *value |= read();
+
+ /* Success */
+ return true;
+ }
+
+ if ((type == _MP_INT32) && (maxBytes >= sizeof(int32_t)))
+ {
+ if (!remaining(sizeof(int32_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 32-bit signed integer */
+ *value = read();
+ *value = *value << 8;
+ *value |= read();
+ *value = *value << 8;
+ *value |= read();
+ *value = *value << 8;
+ *value |= read();
+
+ /* Success */
+ return true;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+bool BERGCloudMessageBase::unpack_skip(void)
+{
+ /* Skip next item */
+
+ uint8_t type;
+ uint32_t bytesToSkip = 0;
+
+ /* Must be at least one byte of data */
+ if (!remaining(sizeof(uint8_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ type = read();
+
+ if ((type == _MP_UINT8) || (type == _MP_INT8))
+ {
+ bytesToSkip = 1;
+ }
+ else if ((type == _MP_UINT16) || (type == _MP_INT16))
+ {
+ bytesToSkip = 2;
+ }
+ else if ((type == _MP_UINT32) || (type == _MP_INT32) || (type == _MP_FLOAT))
+ {
+ bytesToSkip = 4;
+ }
+ else if ((type == _MP_UINT64) || (type == _MP_INT64) || (type == _MP_DOUBLE))
+ {
+ bytesToSkip = 8;
+ }
+ else if ((type == _MP_ARRAY16) || (type == _MP_MAP16))
+ {
+ /* TODO: This could skip all of the array/map elements too. */
+ bytesToSkip = 2;
+ }
+ else if ((type == _MP_ARRAY32) || (type == _MP_MAP32))
+ {
+ /* TODO: This could skip all of the array/map elements too. */
+ bytesToSkip = 4;
+ }
+ else if (type == _MP_RAW16)
+ {
+ if (!remaining(sizeof(uint16_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read 16-bit unsigned integer, data size */
+ bytesToSkip = read();
+ bytesToSkip = bytesToSkip << 8;
+ bytesToSkip |= read();
+ }
+ else if (type == _MP_RAW32)
+ {
+ if (!remaining(sizeof(uint32_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* read 32-bit unsigned integer, data size */
+ bytesToSkip = read();
+ bytesToSkip = bytesToSkip << 8;
+ bytesToSkip |= read();
+ bytesToSkip = bytesToSkip << 8;
+ bytesToSkip |= read();
+ bytesToSkip = bytesToSkip << 8;
+ bytesToSkip |= read();
+ }
+ else if (IN_RANGE(type, _MP_FIXRAW_MIN, _MP_FIXRAW_MAX))
+ {
+ bytesToSkip = type - _MP_FIXRAW_MIN;
+ }
+
+ if (!remaining(bytesToSkip))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ while (bytesToSkip-- > 0)
+ {
+ /* Discard data */
+ read();
+ }
+
+ /* Success */
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(uint8_t& n)
+{
+ uint32_t temp;
+
+ if (!getUnsignedInteger(&temp, sizeof(uint8_t)))
+ {
+ return false;
+ }
+
+ n = (uint8_t)temp;
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(uint16_t& n)
+{
+ uint32_t temp;
+
+ if (!getUnsignedInteger(&temp, sizeof(uint16_t)))
+ {
+ return false;
+ }
+
+ n = (uint16_t)temp;
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(uint32_t& n)
+{
+ uint32_t temp;
+
+ if (!getUnsignedInteger(&temp, sizeof(uint32_t)))
+ {
+ return false;
+ }
+
+ n = temp;
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(int8_t& n)
+{
+ int32_t temp;
+
+ if (!getSignedInteger(&temp, sizeof(int8_t)))
+ {
+ return false;
+ }
+
+ n = (int8_t)temp;
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(int16_t& n)
+{
+ int32_t temp;
+
+ if (!getSignedInteger(&temp, sizeof(int16_t)))
+ {
+ return false;
+ }
+
+ n = (uint16_t)temp;
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(int32_t& n)
+{
+ int32_t temp;
+
+ if (!getSignedInteger(&temp, sizeof(int32_t)))
+ {
+ return false;
+ }
+
+ n = temp;
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(float& n)
+{
+ /* Try to decode the next messagePack item as an 4-byte float */
+ uint32_t data;
+ uint8_t type;
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (type == _MP_FLOAT)
+ {
+ if (!remaining(sizeof(float)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 32-bit float */
+ data = read();
+ data = data << 8;
+ data |= read();
+ data = data << 8;
+ data |= read();
+ data = data << 8;
+ data |= read();
+
+ /* Convert to float */
+ memcpy(&n, &data, sizeof(float));
+
+ /* Success */
+ return true;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+bool BERGCloudMessageBase::unpack(bool& n)
+{
+ /* Try to decode the next messagePack item as boolean */
+ uint8_t type;
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if ((type == _MP_BOOL_FALSE) || (type == _MP_BOOL_TRUE))
+ {
+ n = (read() == _MP_BOOL_TRUE);
+
+ /* Success */
+ return true;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+bool BERGCloudMessageBase::unpack_nil(void)
+{
+ /* Try to decode the next messagePack item as nil */
+ uint8_t type;
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (type == _MP_NIL)
+ {
+ /* Read type */
+ read();
+
+ /* Success */
+ return true;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+bool BERGCloudMessageBase::unpack_array(uint16_t& items)
+{
+ /* Try to decode the next messagePack item as array */
+ uint8_t type;
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (IN_RANGE(type, _MP_FIXARRAY_MIN, _MP_FIXARRAY_MAX))
+ {
+ /* Read fix num value */
+ items = read() - _MP_FIXARRAY_MIN;
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_ARRAY16)
+ {
+ if (!remaining(sizeof(uint16_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 16-bit unsigned integer */
+ items = read();
+ items = items << 8;
+ items |= read();
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_ARRAY32)
+ {
+ /* Not yet supported */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+bool BERGCloudMessageBase::unpack_map(uint16_t& items)
+{
+ /* Try to decode the next messagePack item as array */
+ uint8_t type;
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (IN_RANGE(type, _MP_FIXMAP_MIN, _MP_FIXMAP_MAX))
+ {
+ /* Read fix num value */
+ items = read() - _MP_FIXMAP_MIN;
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_MAP16)
+ {
+ if (!remaining(sizeof(uint16_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 16-bit unsigned integer */
+ items = read();
+ items = items << 8;
+ items |= read();
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_MAP32)
+ {
+ /* Not yet supported */
+ _LOG_UNPACK_ERROR_TYPE;
+ return true;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+/* Separate header and data methods are provided for raw data*/
+/* so that Arduino strings may be unpacked without having to create */
+/* a temporary buffer first. */
+
+bool BERGCloudMessageBase::unpack_raw_header(uint16_t *sizeInBytes)
+{
+ uint8_t type;
+
+ /* Look at next type */
+ if (!peek(&type))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (IN_RANGE(type, _MP_FIXRAW_MIN, _MP_FIXRAW_MAX))
+ {
+ /* Read fix raw value */
+ *sizeInBytes = read() - _MP_FIXRAW_MIN;
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_RAW16)
+ {
+ if (!remaining(sizeof(uint16_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* Read 16-bit unsigned integer */
+ *sizeInBytes = read();
+ *sizeInBytes = *sizeInBytes << 8;
+ *sizeInBytes |= read();
+
+ /* Success */
+ return true;
+ }
+
+ if (type == _MP_RAW32)
+ {
+ if (!remaining(sizeof(uint32_t)))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ /* Read type */
+ read();
+
+ /* read 32-bit unsigned integer */
+ *sizeInBytes = read();
+ *sizeInBytes = *sizeInBytes << 8;
+ *sizeInBytes |= read();
+ *sizeInBytes = *sizeInBytes << 8;
+ *sizeInBytes |= read();
+ *sizeInBytes = *sizeInBytes << 8;
+ *sizeInBytes |= read();
+
+ /* Success */
+ return true;
+ }
+
+ /* Can't convert this type */
+ _LOG_UNPACK_ERROR_TYPE;
+ return false;
+}
+
+bool BERGCloudMessageBase::unpack_raw_data(uint8_t *pData, uint16_t packedSizeInBytes, uint16_t bufferSizeInBytes)
+{
+ uint8_t data;
+
+ /* Unpack all bytes */
+ while (packedSizeInBytes-- > 0)
+ {
+ data = read();
+
+ /* Only write up to the buffer size */
+ if (bufferSizeInBytes-- > 0)
+ {
+ *pData++ = data;
+ }
+ }
+
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(char *pString, uint32_t maxSizeInBytes)
+{
+ /* Try to decode a null-terminated C string */
+ uint16_t sizeInBytes;
+
+ if (!unpack_raw_header(&sizeInBytes))
+ {
+ return false;
+ }
+
+ if (!remaining(sizeInBytes))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (!unpack_raw_data((uint8_t *)pString, sizeInBytes, maxSizeInBytes - 1)) /* -1 to allow space for null terminator */
+ {
+ return false;
+ }
+
+ /* Add null terminator */
+ pString[sizeInBytes] = '\0';
+
+ /* Success */
+ return true;
+}
+
+bool BERGCloudMessageBase::unpack(uint8_t *pData, uint32_t maxSizeInBytes, uint32_t *pSizeInBytes)
+{
+ /* Try to decode a block of raw data */
+ uint16_t sizeInBytes;
+
+ if (!unpack_raw_header(&sizeInBytes))
+ {
+ return false;
+ }
+
+ if (!remaining(sizeInBytes))
+ {
+ _LOG_UNPACK_ERROR_NO_DATA;
+ return false;
+ }
+
+ if (pSizeInBytes != NULL)
+ {
+ *pSizeInBytes = sizeInBytes;
+ }
+
+ return unpack_raw_data(pData, sizeInBytes, maxSizeInBytes);
+}
+
+bool BERGCloudMessageBase::unpack_find(const char *key)
+{
+ /* Search for a string key in a map; in this simple */
+ /* implementation maps cannot contain maps or arrays */
+ uint16_t last_read;
+ uint16_t map_items;
+ uint8_t type;
+ char keyString[MAX_MAP_KEY_STRING_LENGTH+1]; /* +1 for null terminator */
+
+ if (key == NULL)
+ {
+ return false;
+ }
+
+ if (strlen(key) > MAX_MAP_KEY_STRING_LENGTH)
+ {
+ _LOG("Unpack: Key name too long.\r\n");
+ return false;
+ }
+
+ /* Remember the current read position in the raw data */
+ last_read = bytesRead;
+
+ /* Start reading from the beginning of the data */
+ restart();
+
+ while(peek(&type))
+ {
+ if (IN_RANGE(type, _MP_FIXMAP_MIN, _MP_FIXMAP_MAX) || (type == _MP_MAP16)) /* _MP_MAP32 not yet supported */
+ {
+ /* Map found, get number of items */
+ unpack_map(map_items);
+
+ /* Iterate through the key-value pairs */
+ while (map_items-- > 0)
+ {
+ if (unpack(keyString, sizeof(keyString)))
+ {
+ /* String key found */
+ if (strcompare(keyString, key))
+ {
+ /* Match found */
+ return true;
+ }
+ else
+ {
+ /* No match, skip this value */
+ unpack_skip();
+ }
+ }
+ else
+ {
+ /* Not a suitable string key; skip this key and value */
+ unpack_skip();
+ unpack_skip();
+ }
+ }
+ }
+ else
+ {
+ /* Not a map */
+ unpack_skip();
+ }
+ }
+
+ /* Not found; return to last position */
+ bytesRead = last_read;
+ return false;
+}
+
+bool BERGCloudMessageBase::unpack_find(uint16_t i)
+{
+ /* Search for an index in an array; in this simple */
+ /* implementation arrays cannot contain maps or arrays */
+ uint16_t last_read;
+ uint16_t array_items;
+ uint16_t item;
+ uint8_t type;
+
+ /* Remember the current read position in the raw data */
+ last_read = bytesRead;
+
+ /* Start reading from the beginning of the data */
+ restart();
+
+ while(peek(&type))
+ {
+ if (IN_RANGE(type, _MP_FIXARRAY_MIN, _MP_FIXARRAY_MAX) || (type == _MP_ARRAY16)) /* _MP_ARRAY32 not yet supported */
+ {
+ /* Array found, get number of items */
+ unpack_array(array_items);
+
+ /* Assume items are numbered starting from one */
+ item = 1;
+
+ if (i == 0)
+ {
+ _LOG("Unpack: Array indexes start from 1.\r\n");
+ return false;
+ }
+
+ /* Iterate through the values in the array */
+ while (array_items-- > 0)
+ {
+ if (item++ == i)
+ {
+ /* Found it */
+ return true;
+ }
+ else
+ {
+ /* Skip this item */
+ unpack_skip();
+ }
+ }
+ }
+ else
+ {
+ /* Not an array */
+ unpack_skip();
+ }
+ }
+
+ /* Not found; return to last position */
+ bytesRead = last_read;
+ return false;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudMessageBase.h Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,148 @@
+/*
+
+BERGCloud message pack/unpack
+
+Based on MessagePack http://msgpack.org/
+
+Copyright (c) 2013 BERG Cloud 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 BERGCLOUDMESSAGEBASE_H
+#define BERGCLOUDMESSAGEBASE_H
+
+#include "BERGCloudConfig.h"
+#include "BERGCloudMessageBuffer.h"
+#include "BERGCloudLogPrint.h"
+
+#define _LOG_PACK_ERROR_NO_SPACE _LOG("Pack: Out of space.\r\n")
+#define _LOG_UNPACK_ERROR_TYPE _LOG("Unpack: Can't convert to this variable type.\r\n")
+#define _LOG_UNPACK_ERROR_NO_DATA _LOG("Unpack: No more data.\r\n")
+
+#define IN_RANGE(value, min, max) ((value >= min) && (value <= max))
+
+#define MAX_MAP_KEY_STRING_LENGTH (16)
+
+class BERGCloudMessageBase : public BERGCloudMessageBuffer
+{
+public:
+ BERGCloudMessageBase(void);
+ ~BERGCloudMessageBase(void);
+
+ /* Remove all items */
+ void clear(void);
+
+ /*
+ * Pack methods
+ */
+
+ /* Pack an unsigned integer */
+ bool pack(uint8_t n);
+ bool pack(uint16_t n);
+ bool pack(uint32_t n);
+ /* Pack a signed integer */
+ bool pack(int8_t n);
+ bool pack(int16_t n);
+ bool pack(int32_t n);
+ /* Pack a float */
+ bool pack(float n);
+ /* Pack a boolean */
+ bool pack(bool n);
+
+ /* Pack a nil type */
+ bool pack_nil(void);
+ /* Pack an array header, giving the number of items that will follow */
+ bool pack_array(uint16_t items);
+ /* Pack a map header, giving the number of key-value pairs that will follow */
+ bool pack_map(uint16_t items);
+
+ /* Pack an array of data */
+ bool pack(uint8_t *data, uint16_t sizeInBytes);
+ /* Pack a null-terminated C string */
+ bool pack(const char *string);
+
+ /*
+ * Unpack methods
+ */
+
+ /* Unpack an unsigned integer */
+ bool unpack(uint8_t& n);
+ bool unpack(uint16_t& n);
+ bool unpack(uint32_t& n);
+ /* Unpack a signed integer */
+ bool unpack(int8_t& n);
+ bool unpack(int16_t& n);
+ bool unpack(int32_t& n);
+ /* Unpack a float */
+ bool unpack(float& n);
+ /* Unpack a boolean */
+ bool unpack(bool& n);
+
+ /* Unpack a nil type */
+ bool unpack_nil(void);
+
+ /* Unpack an array header, this gives the number of items that follow */
+ bool unpack_array(uint16_t& items);
+ /* Unpack a map header, this gives the number of key-value pairs that follow */
+ bool unpack_map(uint16_t& items);
+
+ /* Get the messagePack type of the next item without unpacking it, */
+ /* returns false if there are no more items */
+ bool unpack_peek(uint8_t& messagePackType);
+
+#ifdef BERGCLOUD_LOG
+ /* Prints the type of the next item without unpacking it, */
+ /* returns false if there are no more items */
+ bool unpack_peek(void);
+ /* Prints the type of all items without unpacking them */
+ void print(void);
+ /* Print the raw MessagePack bytes of a message */
+ void print_bytes(void);
+#endif
+
+ /* Skip the next item */
+ bool unpack_skip(void);
+ /* Restart unpacking from the beginning */
+ bool unpack_restart();
+ /* Moves to the value associated with the map key 'key' */
+ bool unpack_find(const char *key);
+ /* Moves to the value associated with array index 'i' */
+ bool unpack_find(uint16_t i);
+
+ /* Unpack a null-terminated C string */
+ bool unpack(char *string, uint32_t maxSizeInBytes);
+ /* Unpack an array of data */
+ bool unpack(uint8_t *data, uint32_t maxSizeInBytes, uint32_t *sizeInBytes = NULL);
+
+protected:
+ /* Internal methods */
+ uint16_t strlen(const char *string);
+ bool strcompare(const char *s1, const char *s2);
+ bool pack_raw_header(uint16_t sizeInBytes);
+ bool pack_raw_data(uint8_t *data, uint16_t sizeInBytes);
+ bool unpack_raw_header(uint16_t *sizeInBytes);
+ bool unpack_raw_data(uint8_t *data, uint16_t packedSizeInBytes, uint16_t bufferSizeInBytes);
+ bool getUnsignedInteger(uint32_t *value, uint8_t maxBytes);
+ bool getSignedInteger(int32_t *value, uint8_t maxBytes);
+};
+
+#endif // #ifndef BERGCLOUDMESSAGEBASE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudMessageBuffer.cpp Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,118 @@
+/*
+
+Simple message buffer
+
+Copyright (c) 2013 BERG Cloud 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.
+
+*/
+
+#include "BERGCloudMessageBuffer.h"
+
+BERGCloudMessageBuffer::BERGCloudMessageBuffer(void)
+{
+ clear();
+}
+
+void BERGCloudMessageBuffer::clear(void)
+{
+ bytesWritten = 0; /* Number of bytes written */
+ bytesRead = 0; /* Number of bytes read */
+}
+
+void BERGCloudMessageBuffer::restart(void)
+{
+ /* Restart reading from the beginning */
+ bytesRead = 0;
+}
+
+uint16_t BERGCloudMessageBuffer::size(void)
+{
+ /* Get total size of the buffer */
+ return BUFFER_SIZE_BYTES;
+}
+
+uint16_t BERGCloudMessageBuffer::used(void)
+{
+ /* Get mumber of bytes used in the buffer */
+ return bytesWritten;
+}
+
+void BERGCloudMessageBuffer::used(uint16_t used)
+{
+ /* Set number of bytes used in the buffer */
+ bytesWritten = used;
+}
+
+uint16_t BERGCloudMessageBuffer::available(void)
+{
+ /* Get space available in the buffer */
+ return BUFFER_SIZE_BYTES - bytesWritten;
+}
+
+bool BERGCloudMessageBuffer::available(uint16_t required)
+{
+ /* Test if space is available for the number of bytes required */
+ return (BUFFER_SIZE_BYTES - bytesWritten) >= required;
+}
+
+void BERGCloudMessageBuffer::add(uint8_t data)
+{
+ /* Write a byte to the buffer; no checks */
+ buffer[bytesWritten++] = data;
+}
+
+bool BERGCloudMessageBuffer::peek(uint8_t *data)
+{
+ /* Peek at the next byte in the buffer */
+ if (bytesRead >= bytesWritten)
+ {
+ /* No more data */
+ return false;
+ }
+
+
+ *data = buffer[bytesRead]; /* No increment */
+ return true;
+}
+
+uint8_t BERGCloudMessageBuffer::read(void)
+{
+ /* Read the next byte from the buffer; no checks */
+ return buffer[bytesRead++];
+}
+
+uint16_t BERGCloudMessageBuffer::remaining(void)
+{
+ /* Returns the number of bytes that have been written but not read */
+ return bytesWritten - bytesRead;
+}
+
+bool BERGCloudMessageBuffer::remaining(uint16_t required)
+{
+ /* Test if data is remaining for the number of bytes required */
+ return (bytesWritten - bytesRead) >= required;
+}
+
+uint8_t *BERGCloudMessageBuffer::ptr(void)
+{
+ return buffer;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BERGCloudMessageBuffer.h Tue Nov 12 14:38:30 2013 +0000
@@ -0,0 +1,67 @@
+/*
+
+Simple message buffer
+
+Copyright (c) 2013 BERG Cloud 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 BERGCLOUDMESSAGEBUFFER_H
+#define BERGCLOUDMESSAGEBUFFER_H
+
+#define __STDC_LIMIT_MACROS /* Include C99 stdint defines in C++ code */
+#include <stdint.h>
+
+/* Default buffer size */
+#ifndef BUFFER_SIZE_BYTES
+#define BUFFER_SIZE_BYTES 64
+#endif
+
+class BERGCloudMessageBuffer
+{
+public:
+ BERGCloudMessageBuffer();
+ uint16_t size(void);
+ uint8_t *ptr(void);
+ void clear(void);
+
+ /* Methods for writing to the buffer */
+ uint16_t used(void);
+ void used(uint16_t used);
+ uint16_t available(void);
+ bool available(uint16_t required);
+ void add(uint8_t data);
+
+ /* Methods for reading from the buffer */
+ bool peek(uint8_t *data);
+ uint8_t read(void);
+ uint16_t remaining(void);
+ bool remaining(uint16_t required);
+ void restart(void);
+
+protected:
+ uint8_t buffer[BUFFER_SIZE_BYTES];
+ uint16_t bytesWritten;
+ uint16_t bytesRead;
+};
+
+#endif // #ifndef BERGCLOUDMESSAGEBUFFER_H
+

