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
Diff: BERGCloudBase.cpp
- Revision:
- 0:b4ccb530b9eb
- Child:
- 4:5a04c00b5b6f
--- /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)
+{
+}
+

