diff --git a/library.properties b/library.properties index 4d93778..35311a2 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=CayenneMQTT -version=1.0.2-beta +version=1.0.1 author=myDevices maintainer=myDevices sentence=Connect a device to the Cayenne dashboard using MQTT. diff --git a/src/CayenneArduinoMQTTClient.h b/src/CayenneArduinoMQTTClient.h index d18970c..3724a92 100644 --- a/src/CayenneArduinoMQTTClient.h +++ b/src/CayenneArduinoMQTTClient.h @@ -20,7 +20,6 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL #include "CayenneArduinoDefines.h" #include "CayenneMQTTClient/CayenneMQTTClient.h" -#include "CayenneUtils/CayenneDataArray.h" const int MAX_CHANNEL_ARRAY_SIZE = 4; @@ -163,6 +162,30 @@ class CayenneArduinoMQTTClient publishData(DATA_TOPIC, channel, data, type, unit); } + /** + * Sends an array of measurements to a Cayenne channel + * + * @param channel Cayenne channel number + * @param values Array of values to be sent + * @param type Measurement type + */ + void virtualWrite(unsigned int channel, const CayenneDataArray& values, const char* type) + { + publishData(DATA_TOPIC, channel, values.getArray(), values.getCount(), type); + } + + /** + * Sends an array of measurements to a Cayenne channel + * + * @param channel Cayenne channel number + * @param values Array of values to be sent + * @param type Measurement type + */ + void virtualWrite(unsigned int channel, const CayenneDataArray& values, const __FlashStringHelper* type) + { + publishData(DATA_TOPIC, channel, values.getArray(), values.getCount(), type); + } + /** * Sends a response after processing a command * @@ -267,40 +290,6 @@ class CayenneArduinoMQTTClient virtualWrite(channel, value, F(TYPE_DIGITAL_SENSOR), F(UNIT_DIGITAL)); } - /** - * Sends an acceleration value array to a Cayenne channel - * - * @param channel Cayenne channel number - * @param x Acceration on the X-axis - * @param y Acceration on the Y-axis - * @param z Acceration on the Z-axis - */ - void accelWrite(unsigned int channel, float x, float y, float z) - { - CayenneDataArray values; - values.add(x, 1); - values.add(y, 1); - values.add(z, 1); - virtualWrite(channel, values.getString(), F(TYPE_ACCELERATION), F(UNIT_G)); - } - - /** - * Sends a GPS value array to a Cayenne channel - * - * @param channel Cayenne channel number - * @param latitude Latitude in degrees - * @param longitude Longitude in degrees - * @param altitude Altitude in meters - */ - void gpsWrite(unsigned int channel, float latitude, float longitude, float altitude) - { - CayenneDataArray values; - values.add(latitude, 5); - values.add(longitude, 5); - values.add(altitude, 1); - virtualWrite(channel, values.getString(), F(TYPE_GPS), F(UNIT_METER)); - } - /** * Requests Server to re-send current values for all widgets. */ @@ -354,9 +343,9 @@ class CayenneArduinoMQTTClient */ template static void publishData(CayenneTopic topic, unsigned int channel, const T& data, const char* key = NULL, const char* subkey = NULL) { - CayenneDataArray value; - value.add(data); - publishData(topic, channel, value.getString(), key, subkey); + CayenneDataArray values; + values.add(subkey, data); + publishData(topic, channel, values.getArray(), values.getCount(), key); } /** @@ -369,42 +358,39 @@ class CayenneArduinoMQTTClient */ template static void publishData(CayenneTopic topic, unsigned int channel, const T& data, const __FlashStringHelper* key, const __FlashStringHelper* subkey = NULL) { - char keyBuffer[MAX_TYPE_LENGTH + 1] = { 0 }; - char subkeyBuffer[MAX_UNIT_LENGTH + 1] = { 0 }; - CayenneDataArray value; - value.add(data); + char keyBuffer[MAX_TYPE_LENGTH + 1]; + CayenneDataArray values; + values.add(subkey, data); CAYENNE_MEMCPY(keyBuffer, reinterpret_cast(key), CAYENNE_STRLEN(reinterpret_cast(key)) + 1); - if (subkey) - CAYENNE_MEMCPY(subkeyBuffer, reinterpret_cast(subkey), CAYENNE_STRLEN(reinterpret_cast(subkey)) + 1); - publishData(topic, channel, value.getString(), keyBuffer, subkeyBuffer); + publishData(topic, channel, values.getArray(), values.getCount(), keyBuffer); } /** * Publish value array using specified topic suffix * @param topic Cayenne topic * @param channel Cayenne channel number - * @param data Data to send + * @param values Array of values to be sent + * @param valueCount Count of values in array * @param key Optional key to use for a key=data pair - * @param subkey Optional subkey to use for a key,subkey=data pair */ - static void publishData(CayenneTopic topic, unsigned int channel, const char* data, const char* key, const char* subkey) { - CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, key %s, subkey %s, data %s", topic, channel, key, subkey, data); - CayenneMQTTPublishData(&_mqttClient, NULL, topic, channel, key, subkey, data); + static void publishData(CayenneTopic topic, unsigned int channel, const CayenneValuePair values[], size_t valueCount, const char* key) { + CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, value %s, subkey %s, key %s", topic, channel, values[0].value, values[0].unit, key); + CayenneMQTTPublishDataArray(&_mqttClient, NULL, topic, channel, key, values, valueCount); } /** * Publish value array using specified topic suffix * @param topic Cayenne topic * @param channel Cayenne channel number - * @param data Data to send + * @param values Array of values to be sent + * @param valueCount Count of values in array * @param key Optional key to use for a key=data pair - * @param subkey Optional subkey to use for a key,subkey=data pair */ - static void publishData(CayenneTopic topic, unsigned int channel, const char* data, const __FlashStringHelper* key, const char* subkey) { + static void publishData(CayenneTopic topic, unsigned int channel, const CayenneValuePair values[], size_t valueCount, const __FlashStringHelper* key) { char keyBuffer[MAX_TYPE_LENGTH + 1]; CAYENNE_MEMCPY(keyBuffer, reinterpret_cast(key), CAYENNE_STRLEN(reinterpret_cast(key)) + 1); - CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, key %s, subkey %s, data %s", topic, channel, keyBuffer, subkey, data); - CayenneMQTTPublishData(&_mqttClient, NULL, topic, channel, keyBuffer, subkey, data); + CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, value %s, subkey %s, key %s", topic, channel, values[0].value, values[0].unit, keyBuffer); + CayenneMQTTPublishDataArray(&_mqttClient, NULL, topic, channel, keyBuffer, values, valueCount); } /** @@ -482,8 +468,8 @@ void handleMessage(CayenneMessageData* messageData) { Request request = { messageData->channel }; const char* response = NULL; CayenneMessage message(messageData); - if (strlen(messageData->value)) { - CAYENNE_LOG_DEBUG("In: value %s, channel %d", messageData->value, request.channel); + if (strlen(messageData->values[0].value)) { + CAYENNE_LOG_DEBUG("In: value %s, channel %d", messageData->values[0].value, request.channel); InputHandlerFunction handler = GetInputHandler(request.channel); if (handler && handler != InputHandler) { handler(request, message); @@ -497,14 +483,14 @@ void handleMessage(CayenneMessageData* messageData) { } if(response == NULL) { // If there was no error, we send the new channel state, which should be the command value we received. - CayenneArduinoMQTTClient::publishState(DATA_TOPIC, messageData->channel, messageData->value); + CayenneArduinoMQTTClient::publishState(DATA_TOPIC, messageData->channel, messageData->values[0].value); } CayenneArduinoMQTTClient::responseWrite(response, messageData->id); } #ifdef DIGITAL_AND_ANALOG_SUPPORT void handleAnalogMessage(CayenneMessageData* messageData) { - float value = atof(messageData->value); + float value = atof(messageData->values[0].value); char* response = NULL; if (value >= 0 && value <= 1) { double test = value * 255; @@ -515,18 +501,18 @@ void handleAnalogMessage(CayenneMessageData* messageData) { else { response = ERROR_INCORRECT_PARAM; } - CayenneArduinoMQTTClient::responseWrite(response, messageData->id); + CayenneArduinoMQTTClient::responseWrite(messageData->channel, response, messageData->id); } void handleDigitalMessage(CayenneMessageData* messageData) { char* response = NULL; - if (messageData->value && strlen(messageData->value) == 1) { - CAYENNE_LOG_DEBUG("dw %s, channel %d", messageData->value, messageData->channel); - if (messageData->value[0] == '0') { + if (messageData->values[0].value && strlen(messageData->values[0].value) == 1) { + CAYENNE_LOG_DEBUG("dw %s, channel %d", messageData->values[0].value, messageData->channel); + if (messageData->values[0].value[0] == '0') { digitalWrite(messageData->channel, LOW); CayenneArduinoMQTTClient::publishState(DIGITAL_TOPIC, messageData->channel, LOW); } - else if (messageData->value[0] == '1') { + else if (messageData->values[0].value[0] == '1') { digitalWrite(messageData->channel, HIGH); CayenneArduinoMQTTClient::publishState(DIGITAL_TOPIC, messageData->channel, HIGH); } @@ -537,7 +523,7 @@ void handleDigitalMessage(CayenneMessageData* messageData) { else { response = ERROR_INCORRECT_PARAM; } - CayenneArduinoMQTTClient::responseWrite(response, messageData->id); + CayenneArduinoMQTTClient::responseWrite(messageData->channel, response, messageData->id); } #endif @@ -553,13 +539,13 @@ void CayenneMessageArrived(CayenneMessageData* message) { handleDigitalMessage(message); break; case DIGITAL_CONFIG_TOPIC: - configChannel(CayenneArduinoMQTTClient::digitalChannels, message->channel, message->value); + configChannel(CayenneArduinoMQTTClient::digitalChannels, message->channel, message->values[0].value); break; case ANALOG_COMMAND_TOPIC: handleAnalogMessage(message); break; case ANALOG_CONFIG_TOPIC: - configChannel(CayenneArduinoMQTTClient::analogChannels, message->channel, message->value); + configChannel(CayenneArduinoMQTTClient::analogChannels, message->channel, message->values[0].value); break; #endif default: @@ -569,11 +555,14 @@ void CayenneMessageArrived(CayenneMessageData* message) { // CAYENNE_PRINT.print(message->type); // CAYENNE_PRINT.print(", "); // } -// if (message->unit) { -// CAYENNE_PRINT.print(message->unit); -// CAYENNE_PRINT.print("="); +// for (int i = 0; i < message->valueCount; ++i) { +// if (message->values[i].unit) { +// CAYENNE_PRINT.print(message->values[i].unit); +// CAYENNE_PRINT.print("="); +// } +// CAYENNE_PRINT.print(message->values[i].value); +// CAYENNE_PRINT.print(" "); // } -// CAYENNE_PRINT.print(message->value); // CAYENNE_PRINT.println(); //#endif break; diff --git a/src/CayenneMQTTClient/CayenneMQTTClient.c b/src/CayenneMQTTClient/CayenneMQTTClient.c index 7d2930c..478c844 100644 --- a/src/CayenneMQTTClient/CayenneMQTTClient.c +++ b/src/CayenneMQTTClient/CayenneMQTTClient.c @@ -32,7 +32,8 @@ void MQTTMessageArrived(MessageData* md, void* userData) return; //Null terminate the string since that is required by CayenneParsePayload. The readbuf is set to CAYENNE_MAX_MESSAGE_SIZE+1 to allow for appending a null. ((char*)md->message->payload)[md->message->payloadlen] = '\0'; - result = CayenneParsePayload(&message.type, &message.unit, &message.value, &message.id, message.topic, (char*)md->message->payload); + message.valueCount = CAYENNE_MAX_MESSAGE_VALUES; + result = CayenneParsePayload(message.values, &message.valueCount, &message.type, &message.id, message.topic, (char*)md->message->payload); if (result != CAYENNE_SUCCESS) return; @@ -109,24 +110,10 @@ int CayenneMQTTConnect(CayenneMQTTClient* client) */ int CayenneMQTTPublishData(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const char* unit, const char* value) { - char buffer[CAYENNE_MAX_MESSAGE_SIZE + 1] = { 0 }; - int result = CayenneBuildTopic(buffer, sizeof(buffer), client->username, clientID ? clientID : client->clientID, topic, channel); - if (result == CAYENNE_SUCCESS) { - size_t size = strlen(buffer); - char* payload = &buffer[size + 1]; - size = sizeof(buffer) - (size + 1); - result = CayenneBuildDataPayload(payload, &size, type, unit, value); - if (result == CAYENNE_SUCCESS) { - MQTTMessage message; - message.qos = QOS0; - message.retained = (topic != COMMAND_TOPIC) ? 1 : 0; - message.dup = 0; - message.payload = (void*)payload; - message.payloadlen = size; - result = MQTTPublish(&client->mqttClient, buffer, &message); - } - } - return result; + CayenneValuePair valuePair[1]; + valuePair[0].value = value; + valuePair[0].unit = unit; + return CayenneMQTTPublishDataArray(client, clientID, topic, channel, type, valuePair, 1); } @@ -267,6 +254,38 @@ int CayenneMQTTPublishDataFloat(CayenneMQTTClient* client, const char* clientID, return CayenneMQTTPublishData(client, clientID, topic, channel, type, unit, str); } +/** +* Send multiple value data array to Cayenne. +* @param[in] client The client object +* @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with +* @param[in] topic Cayenne topic +* @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none +* @param[in] type Optional type to use for a type=value pair, can be NULL +* @param[in] values Unit/value array +* @param[in] valueCount Number of values +* @return success code +*/ +int CayenneMQTTPublishDataArray(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount) +{ + char buffer[CAYENNE_MAX_MESSAGE_SIZE + 1] = { 0 }; + int result = CayenneBuildTopic(buffer, sizeof(buffer), client->username, clientID ? clientID : client->clientID, topic, channel); + if (result == CAYENNE_SUCCESS) { + size_t size = strlen(buffer); + char* payload = &buffer[size + 1]; + size = sizeof(buffer) - (size + 1); + result = CayenneBuildDataPayload(payload, &size, type, values, valueCount); + if (result == CAYENNE_SUCCESS) { + MQTTMessage message; + message.qos = QOS0; + message.retained = 1; + message.dup = 0; + message.payload = (void*)payload; + message.payloadlen = size; + result = MQTTPublish(&client->mqttClient, buffer, &message); + } + } + return result; +} /** * Send a response to a channel. diff --git a/src/CayenneMQTTClient/CayenneMQTTClient.h b/src/CayenneMQTTClient/CayenneMQTTClient.h index 18365d6..c2054a6 100644 --- a/src/CayenneMQTTClient/CayenneMQTTClient.h +++ b/src/CayenneMQTTClient/CayenneMQTTClient.h @@ -21,6 +21,7 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL #include "MQTTClient.h" #include "../CayenneUtils/CayenneDefines.h" #include "../CayenneUtils/CayenneUtils.h" +#include "../CayenneUtils/CayenneDataArray.h" #if defined(__cplusplus) extern "C" { @@ -47,8 +48,8 @@ extern "C" { unsigned int channel; /**< The channel the message was received on. */ const char* id; /**< The message ID, if it is a command message, otherwise NULL. */ const char* type; /**< The type of data in the message, if it exists, otherwise NULL. */ - const char* unit; /**< The unit in the message, if it exists, otherwise NULL. */ - const char* value; /**< The value in the message, if it exists, otherwise NULL. */ + CayenneValuePair values[CAYENNE_MAX_MESSAGE_VALUES]; /**< The unit/value data pairs in the message. The units and values can be NULL. */ + size_t valueCount; /**< The count of items in the values array. */ } CayenneMessageData; typedef void(*CayenneMessageHandler)(CayenneMessageData*); @@ -188,6 +189,19 @@ extern "C" { */ DLLExport int CayenneMQTTPublishDataFloat(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const char* unit, float value); + /** + * Send multiple value data array to Cayenne. + * @param[in] client The client object + * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with + * @param[in] topic Cayenne topic + * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none + * @param[in] type Optional type to use for a type=value pair, can be NULL + * @param[in] values Unit / value array + * @param[in] valueCount Number of values + * @return success code + */ + DLLExport int CayenneMQTTPublishDataArray(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount); + /** * Send a response to a channel. * @param[in] client The client object diff --git a/src/CayenneMQTTClient/MQTTClient.c b/src/CayenneMQTTClient/MQTTClient.c index 2055e01..abdee98 100644 --- a/src/CayenneMQTTClient/MQTTClient.c +++ b/src/CayenneMQTTClient/MQTTClient.c @@ -273,7 +273,7 @@ int cycle(MQTTClient* c, Timer* timer) MQTTMessage msg; int intQoS; if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName, - (unsigned char**)&msg.payload, &msg.payloadlen, c->readbuf, c->readbuf_size) != 1) + (unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1) goto exit; msg.qos = (enum QoS)intQoS; deliverMessage(c, &topicName, &msg); diff --git a/src/CayenneMQTTClient/MQTTClient.h b/src/CayenneMQTTClient/MQTTClient.h index 0c3526b..27a350a 100644 --- a/src/CayenneMQTTClient/MQTTClient.h +++ b/src/CayenneMQTTClient/MQTTClient.h @@ -33,8 +33,8 @@ #define DLLExport #endif -#include #include "../MQTTCommon/MQTTPacket.h" +#include "stdio.h" #include "PlatformHeader.h" #if defined(MQTTCLIENT_PLATFORM_HEADER) diff --git a/src/CayenneMessage.h b/src/CayenneMessage.h index b82bee9..4843422 100644 --- a/src/CayenneMessage.h +++ b/src/CayenneMessage.h @@ -38,18 +38,18 @@ class CayenneMessage explicit CayenneMessage(CayenneMessageData* data) : _data(data), _error(NULL) { } - const char* asStr() const { return _data->value; } - const char* asString() const { return _data->value; } - int asInt() const { return atoi(_data->value); } - long asLong() const { return atol(_data->value); } + const char* asStr(size_t index = 0) const { return _data->values[index].value; } + const char* asString(size_t index = 0) const { return _data->values[index].value; } + int asInt(size_t index = 0) const { return atoi(_data->values[index].value); } + long asLong(size_t index = 0) const { return atol(_data->values[index].value); } #ifndef NO_FLOAT - double asDouble() const { return atof(_data->value); } + double asDouble(size_t index = 0) const { return atof(_data->values[index].value); } #endif const char* getId() const { return _data->id; } - void* getBuffer() const { return (void*)_data->value; } - size_t getLength() const { return strlen(_data->value); } - const char* getUnit() const { return _data->unit; } + void* getBuffer(size_t index = 0) const { return (void*)_data->values[index].value; } + size_t getLength(size_t index = 0) const { return strlen(_data->values[index].value); } + const char* getUnit(size_t index = 0) const { return _data->values[index].unit; } void setError(char* error) { _error = error; } const char* getError() const { return _error; } diff --git a/src/CayenneUtils/CayenneDataArray.c b/src/CayenneUtils/CayenneDataArray.c new file mode 100644 index 0000000..ea5233d --- /dev/null +++ b/src/CayenneUtils/CayenneDataArray.c @@ -0,0 +1,193 @@ +/* +The MIT License(MIT) + +Cayenne MQTT Client Library +Copyright (c) 2016 myDevices + +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 "CayenneDataArray.h" +#include +#include + + +/** +* Initialize a data array of unit/value pairs. +* @param[out] dataArray The initialized data array +* @param[in] buffer Buffer for storing unit/value pairs. This buffer should be available for as long as the data array is used. +* @param[in] bufferSize Size of the buffer +*/ +void CayenneDataArrayInit(CayenneDataArray* dataArray, char* buffer, unsigned int bufferSize) +{ + dataArray->valueCount = 0; + dataArray->buffer = buffer; + dataArray->bufferSize = bufferSize; + dataArray->bufferIndex = 0; +} + +/** +* Add the specified unit/value pair to the array. +* @param[in] dataArray The data array to add values to +* @param[in] unit The unit to add +* @param[in] value The value to add +* @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise +*/ +int CayenneDataArrayAdd(CayenneDataArray* dataArray, const char* unit, const char* value) +{ + if (dataArray->valueCount >= CAYENNE_MAX_MESSAGE_VALUES) + return CAYENNE_FAILURE; + + size_t unitLength = unit ? strlen(unit) + 1 : 0; + size_t valueLength = value ? strlen(value) + 1 : 0; + if (dataArray->bufferIndex + unitLength + valueLength > dataArray->bufferSize) + return CAYENNE_FAILURE; + + if (unit) { + memcpy(dataArray->buffer + dataArray->bufferIndex, unit, unitLength); + dataArray->values[dataArray->valueCount].unit = dataArray->buffer + dataArray->bufferIndex; + dataArray->bufferIndex += unitLength; + } + else { + dataArray->values[dataArray->valueCount].unit = NULL; + } + + if (value) { + memcpy(dataArray->buffer + dataArray->bufferIndex, value, valueLength); + dataArray->values[dataArray->valueCount].value = dataArray->buffer + dataArray->bufferIndex; + dataArray->bufferIndex += valueLength; + } + else { + dataArray->values[dataArray->valueCount].value = NULL; + } + + dataArray->valueCount++; + return CAYENNE_SUCCESS; +} + +/** +* Add the specified unit/value pair to the array. +* @param[in] dataArray The data array to add values to +* @param[in] unit The unit to add +* @param[in] value The value to add +* @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise +*/ +int CayenneDataArrayAddInt(CayenneDataArray* dataArray, const char* unit, int value) +{ + char str[2 + 8 * sizeof(value)]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + itoa(value, str, 10); +#else + snprintf(str, sizeof(str), "%d", value); +#endif + return CayenneDataArrayAdd(dataArray, unit, str); +} + +/** +* Add the specified unit/value pair to the array. +* @param[in] dataArray The data array to add values to +* @param[in] unit The unit to add +* @param[in] value The value to add +* @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise +*/ +int CayenneDataArrayAddUInt(CayenneDataArray* dataArray, const char* unit, unsigned int value) +{ + char str[1 + 8 * sizeof(value)]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + utoa(value, str, 10); +#else + snprintf(str, sizeof(str), "%u", value); +#endif + return CayenneDataArrayAdd(dataArray, unit, str); +} + +/** +* Add the specified unit/value pair to the array. +* @param[in] dataArray The data array to add values to +* @param[in] unit The unit to add +* @param[in] value The value to add +* @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise +*/ +int CayenneDataArrayAddLong(CayenneDataArray* dataArray, const char* unit, long value) +{ + char str[2 + 8 * sizeof(value)]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + ltoa(value, str, 10); +#else + snprintf(str, sizeof(str), "%ld", value); +#endif + return CayenneDataArrayAdd(dataArray, unit, str); +} + +/** +* Add the specified unit/value pair to the array. +* @param[in] dataArray The data array to add values to +* @param[in] unit The unit to add +* @param[in] value The value to add +* @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise +*/ +int CayenneDataArrayAddULong(CayenneDataArray* dataArray, const char* unit, unsigned long value) +{ + char str[1 + 8 * sizeof(value)]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + ultoa(value, str, 10); +#else + snprintf(str, sizeof(str), "%lu", value); +#endif + return CayenneDataArrayAdd(dataArray, unit, str); +} + +/** +* Add the specified unit/value pair to the array. +* @param[in] dataArray The data array to add values to +* @param[in] unit The unit to add +* @param[in] value The value to add +* @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise +*/ +int CayenneDataArrayAddDouble(CayenneDataArray* dataArray, const char* unit, double value) +{ + char str[33]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + dtostrf(value, 5, 3, str); +#else + snprintf(str, 33, "%2.3f", value); +#endif + return CayenneDataArrayAdd(dataArray, unit, str); +} + +/** +* Add the specified unit/value pair to the array. +* @param[in] dataArray The data array to add values to +* @param[in] unit The unit to add +* @param[in] value The value to add +* @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise +*/ +int CayenneDataArrayAddFloat(CayenneDataArray* dataArray, const char* unit, float value) +{ + char str[33]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + dtostrf(value, 5, 3, str); +#else + snprintf(str, 33, "%2.3f", value); +#endif + return CayenneDataArrayAdd(dataArray, unit, str); +} + +/** +* Clear the data array. +* @param[in] dataArray The data array to clear +*/ +void CayenneDataArrayClear(CayenneDataArray* dataArray) +{ + dataArray->valueCount = 0; + dataArray->bufferIndex = 0; + memset(dataArray->buffer, 0, dataArray->bufferSize); +} diff --git a/src/CayenneUtils/CayenneDataArray.h b/src/CayenneUtils/CayenneDataArray.h index c732842..7c8ef71 100644 --- a/src/CayenneUtils/CayenneDataArray.h +++ b/src/CayenneUtils/CayenneDataArray.h @@ -28,10 +28,11 @@ namespace CayenneMQTT { /** * @class DataArray - * Class for manipulating a data array. + * Class for manipulating a data array of unit/value pairs. * @param BUFFER_SIZE Maximum buffer size to use for data array, in bytes. + * @param MAX_VALUES Maximum number of unit/value pairs in the array. */ - template + template class DataArray { public: @@ -46,174 +47,290 @@ namespace CayenneMQTT * Clear the array. */ void clear() { - _buffer[0] = '['; // Opening bracket for array - _buffer[1] = '\0'; + for (int i = 0; i < CAYENNE_MAX_MESSAGE_VALUES; ++i) { + _values[i].unit = NULL; + _values[i].value = NULL; + } _valueCount = 0; - _index = 1; + _index = 0; } /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. + * @param[in] unitInFlash If true the unit string is in flash memory, otherwise false. * @param[in] valueInFlash If true the value string is in flash memory, otherwise false. */ - void add(const char* value, bool valueInFlash = false) { + void add(const char* unit, const char* value, bool unitInFlash = false, bool valueInFlash = false) { + if (_valueCount >= CAYENNE_MAX_MESSAGE_VALUES) + return; + + size_t unitLength = 0; + if (unit) { + unitLength = (unitInFlash ? CAYENNE_STRLEN(unit) : strlen(unit)) + 1; + } size_t valueLength = 0; if (value) { valueLength = (valueInFlash ? CAYENNE_STRLEN(value) : strlen(value)) + 1; - // Make sure the value string along with comma & array bracket will fit in buffer. - if (_index + valueLength + 2 > BUFFER_SIZE) - return; - if (_valueCount > 0 && _index > 1) { - if (_buffer[--_index - 1] == ']') - --_index; - _buffer[_index++] = ','; - } + } + if (_index + unitLength + valueLength > BUFFER_SIZE) + return; + + if (unit) { + unitInFlash ? CAYENNE_MEMCPY(_buffer + _index, unit, unitLength) : memcpy(_buffer + _index, unit, unitLength); + _values[_valueCount].unit = _buffer + _index; + _index += unitLength; + } + else { + _values[_valueCount].unit = NULL; + } + + if (value) { valueInFlash ? CAYENNE_MEMCPY(_buffer + _index, value, valueLength) : memcpy(_buffer + _index, value, valueLength); + _values[_valueCount].value = _buffer + _index; _index += valueLength; - if (_valueCount > 0 && _index > 1) { - // Only append the closing bracket if multiple items are added. That way the getString() function can be used get - // the string value without a closing bracket if this class is being used to convert single values to strings. - _buffer[_index - 1] = ']'; - _buffer[_index] = '\0'; - } - ++_valueCount; } + else { + _values[_valueCount].value = NULL; + } + + _valueCount++; } /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. */ - inline void add(const int value) { + inline void add(const char* unit, const int value) { char str[2 + 8 * sizeof(value)]; #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) itoa(value, str, 10); #else snprintf(str, sizeof(str), "%d", value); #endif - add(str); + add(unit, str); } /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. */ - inline void add(const unsigned int value) { + inline void add(const char* unit, const unsigned int value) { char str[1 + 8 * sizeof(value)]; #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) utoa(value, str, 10); #else snprintf(str, sizeof(str), "%u", value); #endif - add(str); + add(unit, str); } /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. */ - inline void add(const long value) { + inline void add(const char* unit, const long value) { char str[2 + 8 * sizeof(value)]; #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) ltoa(value, str, 10); #else snprintf(str, sizeof(str), "%ld", value); #endif - add(str); + add(unit, str); } /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. */ - inline void add(const unsigned long value) { + inline void add(const char* unit, const unsigned long value) { char str[1 + 8 * sizeof(value)]; #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) ultoa(value, str, 10); #else snprintf(str, sizeof(str), "%lu", value); #endif - add(str); + add(unit, str); } -#if defined (__AVR__) || defined (ARDUINO_ARCH_ARC32) +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. - * @param[in] precision Number of digits after the decimal. */ - inline void add(const float value, unsigned char precision = 3) { + inline void add(const char* unit, const float value) { char str[33]; - dtostrf(value, 1, precision, str); - add(str); + dtostrf(value, 5, 3, str); + add(unit, str); } /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. - * @param[in] precision Number of digits after the decimal. */ - inline void add(const double value, unsigned char precision = 3) { + inline void add(const char* unit, const double value) { char str[33]; - dtostrf(value, 1, precision, str); - add(str); + dtostrf(value, 5, 3, str); + add(unit, str); } #else /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. - * @param[in] precision Number of digits after the decimal. */ - inline void add(const float value, unsigned char precision = 3) { + inline void add(const char* unit, const float value) { char str[33]; - snprintf(str, 33, "%.*f", precision, value); - add(str); + snprintf(str, 33, "%2.3f", value); + add(unit, str); } /** - * Add the specified value to the array. - * @param[in] precision Number of digits after the decimal. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. */ - inline void add(const double value, unsigned char precision = 3) { + inline void add(const char* unit, const double value) { char str[33]; - snprintf(str, 33, "%.*f", precision, value); - add(str); + snprintf(str, 33, "%2.3f", value); + add(unit, str); } #endif #ifdef CAYENNE_USING_PROGMEM /** - * Add the specified value to the array. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. * @param[in] value The value to add. */ - void add(const __FlashStringHelper* value) { + void add(const char* unit, const __FlashStringHelper* value) { const char* valueString = reinterpret_cast(value); - add(valueString, true); + add(unit, valueString, false, true); + } + + /** + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. + */ + void add(const __FlashStringHelper* unit, const char* value) { + const char* unitString = reinterpret_cast(unit); + add(unitString, value, true, false); + } + + /** + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. + */ + void add(const __FlashStringHelper* unit, const __FlashStringHelper* value) { + const char* unitString = reinterpret_cast(unit); + const char* valueString = reinterpret_cast(value); + add(unitString, valueString, true, true); + } + + /** + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. + */ + inline void add(const __FlashStringHelper* unit, const int value) { + char str[2 + 8 * sizeof(value)]; + itoa(value, str, 10); + add(unit, str); + } + + /** + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. + */ + inline void add(const __FlashStringHelper* unit, const unsigned int value) { + char str[1 + 8 * sizeof(value)]; + utoa(value, str, 10); + add(unit, str); + } + + /** + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. + */ + inline void add(const __FlashStringHelper* unit, const long value) { + char str[2 + 8 * sizeof(value)]; + ltoa(value, str, 10); + add(unit, str); + } + + /** + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. + */ + inline void add(const __FlashStringHelper* unit, const unsigned long value) { + char str[1 + 8 * sizeof(value)]; + ultoa(value, str, 10); + add(unit, str); } + /** + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. + */ + inline void add(const __FlashStringHelper* unit, const float value) { + char str[33]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + dtostrf(value, 5, 3, str); +#else + snprintf(str, 33, "%2.3f", value); #endif + add(unit, str); + } + /** - * Get the value string. - * @return If there are multiple values this will return the full array string with brackets, otherwise just the single value string without brackets. + * Add the specified unit/value pair to the array. + * @param[in] unit The unit to add. + * @param[in] value The value to add. */ - const char* getString() const { - if (_valueCount > 1) - return _buffer; - return &_buffer[1]; + inline void add(const __FlashStringHelper* unit, const double value) { + char str[33]; +#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) + dtostrf(value, 5, 3, str); +#else + snprintf(str, 33, "%2.3f", value); +#endif + add(unit, str); + } + +#endif + /** + * Get the unit/value pair array. + * @return Pointer to the array. + */ + const CayenneValuePair* getArray() const { + return _values; } /** - * Get the number of items in the value array. + * Get the number of items in the unit/value pair array. * @return Count of items. */ - size_t getCount() const { + const size_t getCount() const { return _valueCount; } private: + CayenneValuePair _values[MAX_VALUES]; size_t _valueCount; char _buffer[BUFFER_SIZE]; size_t _index; @@ -222,6 +339,96 @@ namespace CayenneMQTT typedef CayenneMQTT::DataArray<> CayenneDataArray; +#else + + // C version of the data array. Requires source file to be compiled and linked. + + typedef struct CayenneDataArray + { + CayenneValuePair values[CAYENNE_MAX_MESSAGE_VALUES]; + unsigned int valueCount; + char* buffer; + unsigned int bufferSize; + unsigned int bufferIndex; + } CayenneDataArray; + + /** + * Initialize a data array of unit/value pairs. + * @param[out] dataArray The initialized data array + * @param[in] buffer Buffer for storing unit/value pairs. This buffer should be available for as long as the data array is used. + * @param[in] bufferSize Size of the buffer + */ + DLLExport void CayenneDataArrayInit(CayenneDataArray* dataArray, char* buffer, unsigned int bufferSize); + + /** + * Add the specified unit/value pair to the array. + * @param[in] dataArray The data array to add values to + * @param[in] unit The unit to add + * @param[in] value The value to add + * @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise + */ + DLLExport int CayenneDataArrayAdd(CayenneDataArray* dataArray, const char* unit, const char* value); + + /** + * Add the specified unit/value pair to the array. + * @param[in] dataArray The data array to add values to + * @param[in] unit The unit to add + * @param[in] value The value to add + * @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise + */ + DLLExport int CayenneDataArrayAddInt(CayenneDataArray* dataArray, const char* unit, int value); + + /** + * Add the specified unit/value pair to the array. + * @param[in] dataArray The data array to add values to + * @param[in] unit The unit to add + * @param[in] value The value to add + * @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise + */ + DLLExport int CayenneDataArrayAddUInt(CayenneDataArray* dataArray, const char* unit, unsigned int value); + + /** + * Add the specified unit/value pair to the array. + * @param[in] dataArray The data array to add values to + * @param[in] unit The unit to add + * @param[in] value The value to add + * @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise + */ + DLLExport int CayenneDataArrayAddLong(CayenneDataArray* dataArray, const char* unit, long value); + + /** + * Add the specified unit/value pair to the array. + * @param[in] dataArray The data array to add values to + * @param[in] unit The unit to add + * @param[in] value The value to add + * @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise + */ + DLLExport int CayenneDataArrayAddULong(CayenneDataArray* dataArray, const char* unit, unsigned long value); + + /** + * Add the specified unit/value pair to the array. + * @param[in] dataArray The data array to add values to + * @param[in] unit The unit to add + * @param[in] value The value to add + * @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise + */ + DLLExport int CayenneDataArrayAddDouble(CayenneDataArray* dataArray, const char* unit, double value); + + /** + * Add the specified unit/value pair to the array. + * @param[in] dataArray The data array to add values to + * @param[in] unit The unit to add + * @param[in] value The value to add + * @return CAYENNE_SUCCESS if unit/value pair was add, CAYENNE_FAILURE otherwise + */ + DLLExport int CayenneDataArrayAddFloat(CayenneDataArray* dataArray, const char* unit, float value); + + /** + * Clear the data array. + * @param[in] dataArray The data array to clear + */ + DLLExport void CayenneDataArrayClear(CayenneDataArray* dataArray); + #endif #endif \ No newline at end of file diff --git a/src/CayenneUtils/CayenneDefines.h b/src/CayenneUtils/CayenneDefines.h index a061023..8717b38 100644 --- a/src/CayenneUtils/CayenneDefines.h +++ b/src/CayenneUtils/CayenneDefines.h @@ -24,11 +24,11 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL #define CAYENNE_TLS_PORT 8883 #ifndef CAYENNE_MAX_MESSAGE_SIZE -#define CAYENNE_MAX_MESSAGE_SIZE 140 // Redefine this for different message size +#define CAYENNE_MAX_MESSAGE_SIZE 134 // Redefine this for different message size #endif -#ifndef CAYENNE_MAX_PAYLOAD_VALUE_SIZE -#define CAYENNE_MAX_PAYLOAD_VALUE_SIZE 35 // Redefine this for different payload value size +#ifndef CAYENNE_MAX_PAYLOAD_SIZE +#define CAYENNE_MAX_PAYLOAD_SIZE 64 // Redefine this for different payload size #endif #ifndef CAYENNE_MAX_MESSAGE_HANDLERS diff --git a/src/CayenneUtils/CayenneTypes.h b/src/CayenneUtils/CayenneTypes.h index b5e1147..aee57ce 100644 --- a/src/CayenneUtils/CayenneTypes.h +++ b/src/CayenneUtils/CayenneTypes.h @@ -19,73 +19,33 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL #define _CAYENNETYPES_h // Data types -#define TYPE_ACCELERATION "accel" // Acceleration, units: UNIT_G -#define TYPE_ANALOG_ACTUATOR "analog_actuator" // Analog Actuator, units: UNIT_ANALOG -#define TYPE_ANALOG_SENSOR "analog_sensor" // Analog Sensor, units: UNIT_ANALOG -#define TYPE_BAROMETRIC_PRESSURE "bp" // Barometric pressure, units: UNIT_PASCAL, UNIT_HECTOPASCAL -#define TYPE_BATTERY "batt" // Battery, units: UNIT_PERCENT, UNIT_RATIO, UNIT_VOLTS -#define TYPE_CO2 "co2" // Carbon Dioxide, units: UNIT_PPM -#define TYPE_COUNTER "counter" // Counter, units: UNIT_ANALOG -#define TYPE_CURRENT "current" // Current, units: UNIT_AMP, UNIT_MAMP -#define TYPE_DIGITAL_ACTUATOR "digital_actuator" // Digital Actuator, units: UNIT_DIGITAL -#define TYPE_DIGITAL_SENSOR "digital_sensor" // Digital Sensor, units: UNIT_DIGITAL -#define TYPE_ENERGY "energy" // Energy, units: UNIT_KWH -#define TYPE_EXT_WATERLEAK "ext_wleak" // External Waterleak, units: UNIT_ANALOG -#define TYPE_FREQUENCY "freq" // Frequency, units: UNIT_HERTZ -#define TYPE_GPS "gps" // GPS, units: UNIT_GPS -#define TYPE_GYROSCOPE "gyro" // Gyroscope, units: UNIT_ROTATION_PER_MINUTE, UNIT_DEGREE_PER_SEC -#define TYPE_LUMINOSITY "lum" // Luminosity, units: UNIT_LUX, UNIT_VOLTS, UNIT_PERCENT, UNIT_RATIO -#define TYPE_MOTION "motion" // Motion, units: UNIT_DIGITAL -#define TYPE_POWER "pow" // Power, units: UNIT_WATT, UNIT_KILOWATT -#define TYPE_PROXIMITY "prox" // Proximity, units: UNIT_CENTIMETER, UNIT_METER, UNIT_DIGITAL -#define TYPE_RAIN_LEVEL "rain_level" // Rain Level, units: UNIT_CENTIMETER, UNIT_MILLIMETER -#define TYPE_RELATIVE_HUMIDITY "rel_hum" // Relative Humidity, units: UNIT_PERCENT, UNIT_RATIO -#define TYPE_RESISTANCE "res" // Resistance, units: UNIT_OHM -#define TYPE_RSSI "rssi" // Received signal strength indicator, units: UNIT_DBM -#define TYPE_SNR "snr" // Signal Noise Ratio, units: UNIT_DB -#define TYPE_SOIL_MOISTURE "soil_moist" // Soil Moisture, units: UNIT_PERCENT -#define TYPE_SOIL_PH "soil_ph" // Soil pH, units: UNIT_ANALOG -#define TYPE_SOIL_WATER_TENSION "soil_w_ten" // Soil Water Tension, units: UNIT_KILOPASCAL, UNIT_PASCAL -#define TYPE_TANK_LEVEL "tl" // Tank Level, units: UNIT_ANALOG -#define TYPE_TEMPERATURE "temp" // Temperature, units: UNIT_FAHRENHEIT, UNIT_CELSIUS, UNIT_KELVIN -#define TYPE_VOLTAGE "voltage" // Voltage, units: UNIT_VOLTS, UNIT_MILLIVOLTS -#define TYPE_WIND_SPEED "wind_speed" // Wind Speed, units: UNIT_KM_PER_H +#define TYPE_BAROMETRIC_PRESSURE "bp" // Barometric pressure +#define TYPE_BATTERY "batt" // Battery +#define TYPE_LUMINOSITY "lum" // Luminosity +#define TYPE_PROXIMITY "prox" // Proximity +#define TYPE_RELATIVE_HUMIDITY "rel_hum" // Relative Humidity +#define TYPE_TEMPERATURE "temp" // Temperature +#define TYPE_VOLTAGE "voltage" // Voltage +#define TYPE_DIGITAL_SENSOR "digital_sensor" // Voltage -#define MAX_TYPE_LENGTH 16 +#define MAX_TYPE_LENGTH 14 // Unit types -#define UNIT_UNDEFINED "null" // Undefined unit type -#define UNIT_AMP "a" // Ampere -#define UNIT_ANALOG "null" // Analog -#define UNIT_CELSIUS "c" // Celsius +#define UNIT_UNDEFINED "null" +#define UNIT_PASCAL "pa" // Pascal +#define UNIT_HECTOPASCAL "hpa" // Hectopascal +#define UNIT_PERCENT "p" // % (0 to 100) +#define UNIT_RATIO "r" // Ratio +#define UNIT_VOLTS "v" // Volts +#define UNIT_LUX "lux" // Lux +#define UNIT_MILLIMETER "mm" // Millimeter #define UNIT_CENTIMETER "cm" // Centimeter -#define UNIT_DB "db" // Decibels -#define UNIT_DBM "dbm" // dBm -#define UNIT_DEGREE_PER_SEC "dps" // Degree per second +#define UNIT_METER "m" // Meter #define UNIT_DIGITAL "d" // Digital (0/1) #define UNIT_FAHRENHEIT "f" // Fahrenheit -#define UNIT_G "g" // Acceleration -#define UNIT_GPS "m" // GPS -#define UNIT_HECTOPASCAL "hpa" // Hectopascal -#define UNIT_HERTZ "hz" // Hertz +#define UNIT_CELSIUS "c" // Celsius #define UNIT_KELVIN "k" // Kelvin -#define UNIT_KILOPASCAL "kpa" // Kilopascal -#define UNIT_KILOWATT "kw" // Kilowatts -#define UNIT_KM_PER_H "kmh" // Kilometer per hour -#define UNIT_KWH "kwh" // Killowatt Hour -#define UNIT_LUX "lux" // Lux -#define UNIT_MAMP "ma" // Milliampere -#define UNIT_METER "m" // Meter -#define UNIT_MILLIMETER "mm" // Millimeter #define UNIT_MILLIVOLTS "mv" // Millivolts -#define UNIT_OHM "ohm" // Ohm -#define UNIT_PASCAL "pa" // Pascal -#define UNIT_PERCENT "p" // Percent (%) -#define UNIT_PPM "ppm" // Parts per million -#define UNIT_RATIO "r" // Ratio -#define UNIT_ROTATION_PER_MINUTE "rpm" // Rotation per minute -#define UNIT_VOLTS "v" // Volts -#define UNIT_WATT "w" // Watts #define MAX_UNIT_LENGTH 4 diff --git a/src/CayenneUtils/CayenneUtils.c b/src/CayenneUtils/CayenneUtils.c index 49f1706..c9124b3 100644 --- a/src/CayenneUtils/CayenneUtils.c +++ b/src/CayenneUtils/CayenneUtils.c @@ -159,7 +159,7 @@ int buildSuffix(char* suffix, size_t length, const CayenneTopic topic, unsigned * @param[in] topicNameLen CayenneTopic name length * return true if topic matches, false otherwise */ -int topicMatches(char* filter, char* topicName, size_t topicNameLen) +int topicMatches(char* filter, char* topicName, unsigned int topicNameLen) { char* curf = filter; char* curn = topicName; @@ -186,38 +186,117 @@ int topicMatches(char* filter, char* topicName, size_t topicNameLen) return ((curn == curn_end) && (*curf == '\0')); } +/** +* Get the count of values in a message. +* @param[out] count Returned number of values found in message +* @param[in] payload Payload string, must be null terminated +* @param[in] token Character token for splitting "unit=value" payloads, 0 to just parse first comma delimited value +* @return CAYENNE_SUCCESS if value count succeeded, error code otherwise +*/ +int getValueCount(size_t* count, char* payload, char token) { + char* index = payload; + size_t unitCount = 0; + size_t valueCount = 0; + int countingValues = 0; + + if (token == 0) { + //Currently there can only be one value in payload if this isn't a "unit=value" payload. + *count = 1; + return CAYENNE_SUCCESS; + } + + *count = 0; + while (*index && index != '\0') { + if ((*index == ',') || (*index == token)) { + if (*index == ',') { + if (countingValues) { + valueCount++; + } + else { + unitCount++; + } + } + else if (*index == token) { + countingValues = 1; + valueCount++; + } + } + index++; + } + + if (countingValues) { + if ((valueCount != unitCount) && !(unitCount == 0 && valueCount == 1)) { + return CAYENNE_FAILURE; + } + } + else { + valueCount = 1; + } + *count = valueCount; + return CAYENNE_SUCCESS; +} + /** * Parse a null terminated payload string in place. This may modify the payload string. +* @param[out] values Returned payload data unit & value array +* @param[in,out] valuesSize Size of values array, returns the count of values in the array * @param[out] type Returned type, NULL if there is none -* @param[out] unit Returned unit, NULL if there is none -* @param[out] value Returned value, NULL if there is none * @param[in] payload Payload string, must be null terminated * @param[in] token Character token for splitting "unit=value" payloads, 0 to just parse first comma delimited value * @return CAYENNE_SUCCESS if value and id were parsed, error code otherwise */ -int parsePayload(const char** type, const char** unit, const char** value, char* payload, char token) { +int parsePayload(CayenneValuePair* values, size_t* valuesSize, const char** type, char* payload, char token) { char* index = payload; + size_t count = 0; + int parsingValues = 0; + size_t valueIndex = 0; +#ifdef PARSE_INFO_PAYLOADS + int result = getValueCount(&count, payload, token); + if (result != CAYENNE_SUCCESS) { + *valuesSize = 0; + return result; + } +#else + count = 1; +#endif + + if(token == 0) + parsingValues = 1; //Don't need to parse units if there is no unit/value separator + + values[0].value = NULL; + values[0].unit = NULL; *type = NULL; - *unit = NULL; - *value = NULL; while (*index && index != '\0') { if ((*index == ',') || (*index == token)) { if (*index == ',') { *type = payload; - *unit = index + 1; + if (valueIndex < *valuesSize) { + if (parsingValues) { + values[valueIndex].value = index + 1; + } + else { + values[valueIndex].unit = index + 1; + } + } *index = '\0'; + valueIndex++; if (token == 0) break; } - else if (*index == token) { + else if (*index == token && !parsingValues) { + parsingValues = 1; + valueIndex = 0; *type = payload; - *value = index + 1; + values[valueIndex].value = index + 1; *index = '\0'; - break; + valueIndex++; + if (count == valueIndex) + break; } } index++; }; + *valuesSize = count; return CAYENNE_SUCCESS; } @@ -244,20 +323,23 @@ int CayenneBuildTopic(char* topicName, size_t length, const char* username, cons * @param[out] payload Returned payload * @param[in,out] length Payload buffer length * @param[in] type Optional type to use for type,unit=value payload, can be NULL -* @param[in] unit Payload unit -* @param[in] value Payload value +* @param[in] values Unit/value array +* @param[in] valueCount Number of values * @return CAYENNE_SUCCESS if topic string was created, error code otherwise */ -int CayenneBuildDataPayload(char* payload, size_t* length, const char* type, const char* unit, const char* value) { +int CayenneBuildDataPayload(char* payload, size_t* length, const char* type, const CayenneValuePair* values, size_t valueCount) { + int i; size_t payloadLength = 0; - if (unit) { - payloadLength += strlen(unit) + 1; - } - else if (type) { - // If type exists but unit does not, use UNIT_UNDEFINED for the unit. - payloadLength += strlen(UNIT_UNDEFINED) + 1; + for (i = 0; i < valueCount; ++i) { + if (values[i].unit) { + payloadLength += strlen(values[i].unit) + 1; + } + else if (type) { + // If type exists but unit does not, use UNIT_UNDEFINED for the unit. + payloadLength += strlen(UNIT_UNDEFINED) + 1; + } + payloadLength += values[i].value ? strlen(values[i].value) + 1 : 0; } - payloadLength += value ? strlen(value) + 1 : 0; payloadLength += type ? strlen(type) + 1 : 0; //If payload can't fit the payload plus a terminating null byte return. if (payloadLength > *length) { @@ -268,16 +350,21 @@ int CayenneBuildDataPayload(char* payload, size_t* length, const char* type, con if (type) { strcat(payload, type); } - if (payload[0] != '\0') - strcat(payload, ","); - if (unit) - strcat(payload, unit); - else if (type) - strcat(payload, UNIT_UNDEFINED); - if (payload[0] != '\0' && value) + for (i = 0; i < valueCount; ++i) { + if (payload[0] != '\0') + strcat(payload, ","); + if (values[i].unit) + strcat(payload, values[i].unit); + else if (type) + strcat(payload, UNIT_UNDEFINED); + } + if (payload[0] != '\0' && valueCount > 0 && values[0].value) strcat(payload, "="); - if (value) - strcat(payload, value); + for (i = 0; i < valueCount && values[i].value; ++i) { + strcat(payload, values[i].value); + if (i + 1 < valueCount) + strcat(payload, ","); + } *length = --payloadLength; //Subtract terminating null return CAYENNE_SUCCESS; } @@ -291,10 +378,13 @@ int CayenneBuildDataPayload(char* payload, size_t* length, const char* type, con * @return CAYENNE_SUCCESS if payload string was created, error code otherwise */ int CayenneBuildResponsePayload(char* payload, size_t* length, const char* id, const char* error) { + CayenneValuePair values[1]; + values[0].unit = id; + values[0].value = error; if (error) { - return CayenneBuildDataPayload(payload, length, "error", id, error); + return CayenneBuildDataPayload(payload, length, "error", values, 1); } - return CayenneBuildDataPayload(payload, length, "ok", id, error); + return CayenneBuildDataPayload(payload, length, "ok", values, 1); } /** @@ -307,7 +397,7 @@ int CayenneBuildResponsePayload(char* payload, size_t* length, const char* id, c * @param[in] length Topic name string length * @return CAYENNE_SUCCESS if topic was parsed, error code otherwise */ -int CayenneParseTopic(CayenneTopic* topic, unsigned int* channel, const char** clientID, const char* username, char* topicName, size_t length) { +int CayenneParseTopic(CayenneTopic* topic, unsigned int* channel, const char** clientID, const char* username, char* topicName, unsigned int length) { char* index = NULL; int i = 0; TopicChannel parseTopics[PARSE_TOPICS_COUNT] = { { COMMAND_TOPIC, CAYENNE_ALL_CHANNELS }, @@ -385,37 +475,42 @@ int CayenneParseTopic(CayenneTopic* topic, unsigned int* channel, const char** c /** * Parse a null terminated payload in place. This may modify the payload string. +* @param[out] values Returned payload data unit & value array +* @param[in,out] valuesSize Size of values array, returns the count of values in the array * @param[out] type Returned type, NULL if there is none -* @param[out] unit Returned unit, NULL if there is none -* @param[out] value Returned value, NULL if there is none * @param[out] id Returned message id, empty string if there is none * @param[in] topic Cayenne topic * @param[in] payload Payload string, must be null terminated. * @return CAYENNE_SUCCESS if topic string was created, error code otherwise */ -int CayenneParsePayload(const char** type, const char** unit, const char** value, const char** id, CayenneTopic topic, char* payload) { - if (!payload) +int CayenneParsePayload(CayenneValuePair* values, size_t* valuesSize, const char** type, const char** id, CayenneTopic topic, char* payload) { + int i; + if (!payload || !valuesSize || *valuesSize == 0) return CAYENNE_FAILURE; *type = NULL; - *unit = NULL; - *value = NULL; *id = NULL; + for(i = 0; i < *valuesSize; i++) { + values[i].unit = NULL; + values[i].value = NULL; + } switch (topic) { #ifdef PARSE_INFO_PAYLOADS case DATA_TOPIC: - parsePayload(type, unit, value, payload, '='); - if (!*value) + parsePayload(values, valuesSize, type, payload, '='); + if (!values[0].value) return CAYENNE_FAILURE; break; #endif #ifdef DIGITAL_AND_ANALOG_SUPPORT #ifdef PARSE_INFO_PAYLOADS case ANALOG_TOPIC: - //Use unit to store resolution - parsePayload(value, unit, unit, payload, 0); - if (!*value) + parsePayload(values, valuesSize, type, payload, 0); + values[0].unit = values[0].value; //Use unit to store resolution + values[0].value = *type; + *type = NULL; + if (!values[0].value) return CAYENNE_FAILURE; break; #endif @@ -423,19 +518,22 @@ int CayenneParsePayload(const char** type, const char** unit, const char** value case ANALOG_COMMAND_TOPIC: #endif case COMMAND_TOPIC: - parsePayload(id, value, unit, payload, 0); - if (!*value) + parsePayload(values, valuesSize, type, payload, 0); + *id = *type; + *type = NULL; + if (!values[0].value) return CAYENNE_FAILURE; break; default: break; } - if (!*value) { - *value = payload; - *unit = NULL; + if (!values[0].value) { + values[0].value = payload; + values[0].unit = NULL; *type = NULL; *id = NULL; + *valuesSize = 1; } return CAYENNE_SUCCESS; diff --git a/src/CayenneUtils/CayenneUtils.h b/src/CayenneUtils/CayenneUtils.h index 585a613..81ce3f9 100644 --- a/src/CayenneUtils/CayenneUtils.h +++ b/src/CayenneUtils/CayenneUtils.h @@ -39,6 +39,15 @@ extern "C" { enum CayenneReturnCode { CAYENNE_BUFFER_OVERFLOW = -2, CAYENNE_FAILURE = -1, CAYENNE_SUCCESS = 0 }; +/** +* A unit/value pair used in Cayenne payloads. +*/ +typedef struct CayenneValuePair +{ + const char* unit; /**< The data unit. */ + const char* value; /**< The data value. */ +} CayenneValuePair; + /** * Build a specified topic string. * @param[out] topicName Returned topic string @@ -56,11 +65,11 @@ DLLExport int CayenneBuildTopic(char* topicName, size_t length, const char* user * @param[out] payload Returned payload * @param[in,out] length Payload buffer length * @param[in] type Optional type to use for type,unit=value payload, can be NULL -* @param[in] unit Payload unit -* @param[in] value Payload value +* @param[in] values Unit/value array +* @param[in] valueCount Number of values * @return CAYENNE_SUCCESS if topic string was created, error code otherwise */ -DLLExport int CayenneBuildDataPayload(char* payload, size_t* length, const char* type, const char* unit, const char* value); +DLLExport int CayenneBuildDataPayload(char* payload, size_t* length, const char* type, const CayenneValuePair* values, size_t valueCount); /** * Build a specified response payload. @@ -82,19 +91,19 @@ DLLExport int CayenneBuildResponsePayload(char* payload, size_t* length, const c * @param[in] length Topic name string length * @return CAYENNE_SUCCESS if topic was parsed, error code otherwise */ -DLLExport int CayenneParseTopic(CayenneTopic* topic, unsigned int* channel, const char** clientID, const char* username, char* topicName, size_t length); +DLLExport int CayenneParseTopic(CayenneTopic* topic, unsigned int* channel, const char** clientID, const char* username, char* topicName, unsigned int length); /** * Parse a null terminated payload in place. This may modify the payload string. +* @param[out] values Returned payload data unit & value array +* @param[in,out] valuesSize Size of values array, returns the count of values in the array * @param[out] type Returned type, NULL if there is none -* @param[out] unit Returned unit, NULL if there is none -* @param[out] value Returned value, NULL if there is none * @param[out] id Returned message id, empty string if there is none * @param[in] topic Cayenne topic * @param[in] payload Payload string, must be null terminated. * @return CAYENNE_SUCCESS if topic string was created, error code otherwise */ -DLLExport int CayenneParsePayload(const char** type, const char** unit, const char** value, const char** id, CayenneTopic topic, char* payload); +DLLExport int CayenneParsePayload(CayenneValuePair* values, size_t* valuesSize, const char** type, const char** id, CayenneTopic topic, char* payload); #if defined(__cplusplus) } diff --git a/src/MQTTCommon/MQTTConnect.h b/src/MQTTCommon/MQTTConnect.h index 6566a98..db90251 100644 --- a/src/MQTTCommon/MQTTConnect.h +++ b/src/MQTTCommon/MQTTConnect.h @@ -124,13 +124,13 @@ typedef union #define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \ MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} } -DLLExport int MQTTSerialize_connect(unsigned char* buf, size_t buflen, MQTTPacket_connectData* options); -DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, size_t len); +DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options); +DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len); -DLLExport int MQTTSerialize_connack(unsigned char* buf, size_t buflen, unsigned char connack_rc, unsigned char sessionPresent); -DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, size_t buflen); +DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent); +DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen); -DLLExport int MQTTSerialize_disconnect(unsigned char* buf, size_t buflen); -DLLExport int MQTTSerialize_pingreq(unsigned char* buf, size_t buflen); +DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen); +DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen); #endif /* MQTTCONNECT_H_ */ diff --git a/src/MQTTCommon/MQTTConnectClient.c b/src/MQTTCommon/MQTTConnectClient.c index a3e0ad6..0fc906a 100644 --- a/src/MQTTCommon/MQTTConnectClient.c +++ b/src/MQTTCommon/MQTTConnectClient.c @@ -23,9 +23,9 @@ * @param options the options to be used to build the connect packet * @return the length of buffer needed to contain the serialized version of the packet */ -size_t MQTTSerialize_connectLength(MQTTPacket_connectData* options) +int MQTTSerialize_connectLength(MQTTPacket_connectData* options) { - size_t len = 0; + int len = 0; if (options->MQTTVersion == 3) @@ -52,12 +52,12 @@ size_t MQTTSerialize_connectLength(MQTTPacket_connectData* options) * @param options the options to be used to build the connect packet * @return serialized length, or error if 0 */ -int MQTTSerialize_connect(unsigned char* buf, size_t buflen, MQTTPacket_connectData* options) +int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options) { unsigned char *ptr = buf; MQTTHeader header = {0}; MQTTConnectFlags flags = {0}; - size_t len = 0; + int len = 0; int rc = -1; if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen) @@ -110,7 +110,7 @@ int MQTTSerialize_connect(unsigned char* buf, size_t buflen, MQTTPacket_connectD if (flags.bits.password) writeMQTTString(&ptr, options->password); - rc = (int)(ptr - buf); + rc = ptr - buf; exit: return rc; @@ -125,7 +125,7 @@ int MQTTSerialize_connect(unsigned char* buf, size_t buflen, MQTTPacket_connectD * @param len the length in bytes of the data in the supplied buffer * @return error code. 1 is success, 0 is failure */ -int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, size_t buflen) +int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen) { MQTTHeader header = {0}; unsigned char* curdata = buf; @@ -160,7 +160,7 @@ int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connac * @param packettype the message type * @return serialized length, or error if 0 */ -int MQTTSerialize_zero(unsigned char* buf, size_t buflen, unsigned char packettype) +int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype) { MQTTHeader header = {0}; int rc = -1; @@ -176,7 +176,7 @@ int MQTTSerialize_zero(unsigned char* buf, size_t buflen, unsigned char packetty writeChar(&ptr, header.byte); /* write header */ ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */ - rc = (int)(ptr - buf); + rc = ptr - buf; exit: return rc; } @@ -188,7 +188,7 @@ int MQTTSerialize_zero(unsigned char* buf, size_t buflen, unsigned char packetty * @param buflen the length in bytes of the supplied buffer, to avoid overruns * @return serialized length, or error if 0 */ -int MQTTSerialize_disconnect(unsigned char* buf, size_t buflen) +int MQTTSerialize_disconnect(unsigned char* buf, int buflen) { return MQTTSerialize_zero(buf, buflen, DISCONNECT_MSG); } @@ -200,7 +200,7 @@ int MQTTSerialize_disconnect(unsigned char* buf, size_t buflen) * @param buflen the length in bytes of the supplied buffer, to avoid overruns * @return serialized length, or error if 0 */ -int MQTTSerialize_pingreq(unsigned char* buf, size_t buflen) +int MQTTSerialize_pingreq(unsigned char* buf, int buflen) { return MQTTSerialize_zero(buf, buflen, PINGREQ_MSG); } diff --git a/src/MQTTCommon/MQTTDeserializePublish.c b/src/MQTTCommon/MQTTDeserializePublish.c index c0a7d02..ad642db 100644 --- a/src/MQTTCommon/MQTTDeserializePublish.c +++ b/src/MQTTCommon/MQTTDeserializePublish.c @@ -33,7 +33,7 @@ * @return error code. 1 is success */ int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName, - unsigned char** payload, size_t* payloadlen, unsigned char* buf, size_t buflen) + unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen) { MQTTHeader header = {0}; unsigned char* curdata = buf; @@ -76,7 +76,7 @@ int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retaine * @param buflen the length in bytes of the data in the supplied buffer * @return error code. 1 is success, 0 is failure */ -int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, size_t buflen) +int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen) { MQTTHeader header = {0}; unsigned char* curdata = buf; diff --git a/src/MQTTCommon/MQTTPacket.c b/src/MQTTCommon/MQTTPacket.c index 0765ead..2d5c8b7 100644 --- a/src/MQTTCommon/MQTTPacket.c +++ b/src/MQTTCommon/MQTTPacket.c @@ -25,7 +25,7 @@ * @param length the length to be encoded * @return the number of bytes written to buffer */ -int MQTTPacket_encode(unsigned char* buf, size_t length) +int MQTTPacket_encode(unsigned char* buf, int length) { int rc = 0; @@ -76,7 +76,7 @@ int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value) } -size_t MQTTPacket_len(size_t rem_len) +int MQTTPacket_len(int rem_len) { rem_len += 1; /* header byte */ @@ -172,8 +172,8 @@ void writeInt(unsigned char** pptr, int anInt) */ void writeCString(unsigned char** pptr, const char* string) { - size_t len = strlen(string); - writeInt(pptr, (int)len); + int len = strlen(string); + writeInt(pptr, len); memcpy(*pptr, string, len); *pptr += len; } @@ -190,7 +190,7 @@ void writeMQTTString(unsigned char** pptr, MQTTString mqttstring) { if (mqttstring.lenstring.len > 0) { - writeInt(pptr, (int)mqttstring.lenstring.len); + writeInt(pptr, mqttstring.lenstring.len); memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len); *pptr += mqttstring.lenstring.len; } @@ -232,9 +232,9 @@ int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned cha * @param mqttstring the string to return the length of * @return the length of the string */ -size_t MQTTstrlen(MQTTString mqttstring) +int MQTTstrlen(MQTTString mqttstring) { - size_t rc = 0; + int rc = 0; if (mqttstring.cstring) rc = strlen(mqttstring.cstring); @@ -252,7 +252,7 @@ size_t MQTTstrlen(MQTTString mqttstring) */ int MQTTPacket_equals(MQTTString* a, char* bptr) { - size_t alen = 0, + int alen = 0, blen = 0; char *aptr; diff --git a/src/MQTTCommon/MQTTPacket.h b/src/MQTTCommon/MQTTPacket.h index ef969ae..dc4fcdc 100644 --- a/src/MQTTCommon/MQTTPacket.h +++ b/src/MQTTCommon/MQTTPacket.h @@ -18,8 +18,6 @@ #ifndef MQTTPACKET_H_ #define MQTTPACKET_H_ -#include - #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ extern "C" { #endif @@ -76,7 +74,7 @@ typedef union typedef struct { - size_t len; + int len; char* data; } MQTTLenString; @@ -88,20 +86,20 @@ typedef struct #define MQTTString_initializer {NULL, {0, NULL}} -size_t MQTTstrlen(MQTTString mqttstring); +int MQTTstrlen(MQTTString mqttstring); #include "MQTTConnect.h" #include "MQTTPublish.h" #include "MQTTSubscribe.h" #include "MQTTUnsubscribe.h" -int MQTTSerialize_ack(unsigned char* buf, size_t buflen, unsigned char type, unsigned char dup, unsigned short packetid); -int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, size_t buflen); +int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid); +int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen); -size_t MQTTPacket_len(size_t rem_len); +int MQTTPacket_len(int rem_len); int MQTTPacket_equals(MQTTString* a, char* b); -int MQTTPacket_encode(unsigned char* buf, size_t length); +int MQTTPacket_encode(unsigned char* buf, int length); int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value); int MQTTPacket_decodeBuf(unsigned char* buf, int* value); diff --git a/src/MQTTCommon/MQTTPublish.h b/src/MQTTCommon/MQTTPublish.h index 899a674..ebe479d 100644 --- a/src/MQTTCommon/MQTTPublish.h +++ b/src/MQTTCommon/MQTTPublish.h @@ -25,14 +25,14 @@ #define DLLExport #endif -DLLExport int MQTTSerialize_publish(unsigned char* buf, size_t buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid, - MQTTString topicName, unsigned char* payload, size_t payloadlen); +DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid, + MQTTString topicName, unsigned char* payload, int payloadlen); DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName, - unsigned char** payload, size_t* payloadlen, unsigned char* buf, size_t len); + unsigned char** payload, int* payloadlen, unsigned char* buf, int len); -DLLExport int MQTTSerialize_puback(unsigned char* buf, size_t buflen, unsigned short packetid); -DLLExport int MQTTSerialize_pubrel(unsigned char* buf, size_t buflen, unsigned char dup, unsigned short packetid); -DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, size_t buflen, unsigned short packetid); +DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid); +DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid); +DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid); #endif /* MQTTPUBLISH_H_ */ diff --git a/src/MQTTCommon/MQTTSerializePublish.c b/src/MQTTCommon/MQTTSerializePublish.c index 1e00d56..7e6d04f 100644 --- a/src/MQTTCommon/MQTTSerializePublish.c +++ b/src/MQTTCommon/MQTTSerializePublish.c @@ -27,9 +27,9 @@ * @param payloadlen the length of the payload to be sent * @return the length of buffer needed to contain the serialized version of the packet */ -size_t MQTTSerialize_publishLength(int qos, MQTTString topicName, size_t payloadlen) +int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen) { - size_t len = 0; + int len = 0; len += 2 + MQTTstrlen(topicName) + payloadlen; if (qos > 0) @@ -51,12 +51,12 @@ size_t MQTTSerialize_publishLength(int qos, MQTTString topicName, size_t payload * @param payloadlen integer - the length of the MQTT payload * @return the length of the serialized data. <= 0 indicates error */ -int MQTTSerialize_publish(unsigned char* buf, size_t buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid, - MQTTString topicName, unsigned char* payload, size_t payloadlen) +int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid, + MQTTString topicName, unsigned char* payload, int payloadlen) { unsigned char *ptr = buf; MQTTHeader header = {0}; - size_t rem_len = 0; + int rem_len = 0; int rc = 0; if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen) @@ -81,7 +81,7 @@ int MQTTSerialize_publish(unsigned char* buf, size_t buflen, unsigned char dup, memcpy(ptr, payload, payloadlen); ptr += payloadlen; - rc = (int)(ptr - buf); + rc = ptr - buf; exit: return rc; @@ -98,7 +98,7 @@ int MQTTSerialize_publish(unsigned char* buf, size_t buflen, unsigned char dup, * @param packetid the MQTT packet identifier * @return serialized length, or error if 0 */ -int MQTTSerialize_ack(unsigned char* buf, size_t buflen, unsigned char packettype, unsigned char dup, unsigned short packetid) +int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid) { MQTTHeader header = {0}; int rc = 0; @@ -116,7 +116,7 @@ int MQTTSerialize_ack(unsigned char* buf, size_t buflen, unsigned char packettyp ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */ writeInt(&ptr, packetid); - rc = (int)(ptr - buf); + rc = ptr - buf; exit: return rc; } @@ -129,7 +129,7 @@ int MQTTSerialize_ack(unsigned char* buf, size_t buflen, unsigned char packettyp * @param packetid integer - the MQTT packet identifier * @return serialized length, or error if 0 */ -int MQTTSerialize_puback(unsigned char* buf, size_t buflen, unsigned short packetid) +int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid) { return MQTTSerialize_ack(buf, buflen, PUBACK_MSG, 0, packetid); } @@ -143,7 +143,7 @@ int MQTTSerialize_puback(unsigned char* buf, size_t buflen, unsigned short packe * @param packetid integer - the MQTT packet identifier * @return serialized length, or error if 0 */ -int MQTTSerialize_pubrel(unsigned char* buf, size_t buflen, unsigned char dup, unsigned short packetid) +int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid) { return MQTTSerialize_ack(buf, buflen, PUBREL_MSG, dup, packetid); } @@ -156,7 +156,7 @@ int MQTTSerialize_pubrel(unsigned char* buf, size_t buflen, unsigned char dup, u * @param packetid integer - the MQTT packet identifier * @return serialized length, or error if 0 */ -int MQTTSerialize_pubcomp(unsigned char* buf, size_t buflen, unsigned short packetid) +int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid) { return MQTTSerialize_ack(buf, buflen, PUBCOMP_MSG, 0, packetid); } diff --git a/src/MQTTCommon/MQTTSubscribe.h b/src/MQTTCommon/MQTTSubscribe.h index 6629f3a..aa91826 100644 --- a/src/MQTTCommon/MQTTSubscribe.h +++ b/src/MQTTCommon/MQTTSubscribe.h @@ -25,15 +25,15 @@ #define DLLExport #endif -DLLExport int MQTTSerialize_subscribe(unsigned char* buf, size_t buflen, unsigned char dup, unsigned short packetid, +DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count, MQTTString topicFilters[], int requestedQoSs[]); DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, - int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, size_t len); + int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len); -DLLExport int MQTTSerialize_suback(unsigned char* buf, size_t buflen, unsigned short packetid, int count, int* grantedQoSs); +DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs); -DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, size_t len); +DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len); #endif /* MQTTSUBSCRIBE_H_ */ diff --git a/src/MQTTCommon/MQTTSubscribeClient.c b/src/MQTTCommon/MQTTSubscribeClient.c index 5799d3f..597759b 100644 --- a/src/MQTTCommon/MQTTSubscribeClient.c +++ b/src/MQTTCommon/MQTTSubscribeClient.c @@ -24,10 +24,10 @@ * @param topicFilters the array of topic filter strings to be used in the publish * @return the length of buffer needed to contain the serialized version of the packet */ -size_t MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[]) +int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[]) { int i; - size_t len = 2; /* packetid */ + int len = 2; /* packetid */ for (i = 0; i < count; ++i) len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */ @@ -46,12 +46,12 @@ size_t MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[]) * @param requestedQoSs - array of requested QoS * @return the length of the serialized data. <= 0 indicates error */ -int MQTTSerialize_subscribe(unsigned char* buf, size_t buflen, unsigned char dup, unsigned short packetid, int count, +int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count, MQTTString topicFilters[], int requestedQoSs[]) { unsigned char *ptr = buf; MQTTHeader header = {0}; - size_t rem_len = 0; + int rem_len = 0; int rc = 0; int i = 0; @@ -77,7 +77,7 @@ int MQTTSerialize_subscribe(unsigned char* buf, size_t buflen, unsigned char dup writeChar(&ptr, requestedQoSs[i]); } - rc = (int)(ptr - buf); + rc = ptr - buf; exit: return rc; } @@ -94,7 +94,7 @@ int MQTTSerialize_subscribe(unsigned char* buf, size_t buflen, unsigned char dup * @param buflen the length in bytes of the data in the supplied buffer * @return error code. 1 is success, 0 is failure */ -int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, size_t buflen) +int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen) { MQTTHeader header = {0}; unsigned char* curdata = buf; diff --git a/src/MQTTCommon/MQTTUnsubscribe.h b/src/MQTTCommon/MQTTUnsubscribe.h index 5ee7840..355ca9a 100644 --- a/src/MQTTCommon/MQTTUnsubscribe.h +++ b/src/MQTTCommon/MQTTUnsubscribe.h @@ -25,14 +25,14 @@ #define DLLExport #endif -DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen, unsigned char dup, unsigned short packetid, +DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count, MQTTString topicFilters[]); DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[], - unsigned char* buf, int size_t); + unsigned char* buf, int len); -DLLExport int MQTTSerialize_unsuback(unsigned char* buf, size_t buflen, unsigned short packetid); +DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid); -DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, size_t len); +DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len); #endif /* MQTTUNSUBSCRIBE_H_ */ diff --git a/src/MQTTCommon/MQTTUnsubscribeClient.c b/src/MQTTCommon/MQTTUnsubscribeClient.c index 38e58d5..b59f174 100644 --- a/src/MQTTCommon/MQTTUnsubscribeClient.c +++ b/src/MQTTCommon/MQTTUnsubscribeClient.c @@ -24,10 +24,10 @@ * @param topicFilters the array of topic filter strings to be used in the publish * @return the length of buffer needed to contain the serialized version of the packet */ -size_t MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[]) +int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[]) { int i; - size_t len = 2; /* packetid */ + int len = 2; /* packetid */ for (i = 0; i < count; ++i) len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/ @@ -45,12 +45,12 @@ size_t MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[]) * @param topicFilters - array of topic filter names * @return the length of the serialized data. <= 0 indicates error */ -int MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen, unsigned char dup, unsigned short packetid, +int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count, MQTTString topicFilters[]) { unsigned char *ptr = buf; MQTTHeader header = {0}; - size_t rem_len = 0; + int rem_len = 0; int rc = -1; int i = 0; @@ -73,7 +73,7 @@ int MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen, unsigned char d for (i = 0; i < count; ++i) writeMQTTString(&ptr, topicFilters[i]); - rc = (int)(ptr - buf); + rc = ptr - buf; exit: return rc; } @@ -86,7 +86,7 @@ int MQTTSerialize_unsubscribe(unsigned char* buf, size_t buflen, unsigned char d * @param buflen the length in bytes of the data in the supplied buffer * @return error code. 1 is success, 0 is failure */ -int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, size_t buflen) +int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen) { unsigned char type = 0; unsigned char dup = 0;