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

Files at this revision

API Documentation at this revision

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

BERGCloud.h Show annotated file Show diff for this revision Revisions of this file
BERGCloudBase.cpp Show annotated file Show diff for this revision Revisions of this file
BERGCloudBase.h Show annotated file Show diff for this revision Revisions of this file
BERGCloudConst.h Show annotated file Show diff for this revision Revisions of this file
BERGCloudMbed.cpp Show annotated file Show diff for this revision Revisions of this file
BERGCloudMbed.h Show annotated file Show diff for this revision Revisions of this file
--- /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);