
Fork of my original MQTTGateway
Revision 0:a1734fe1ec4b, committed 2017-04-08
- Comitter:
- vpcola
- Date:
- Sat Apr 08 14:43:14 2017 +0000
- Commit message:
- Initial commit
Changed in this revision
diff -r 000000000000 -r a1734fe1ec4b DownloadFile.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DownloadFile.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,149 @@ +#include "DownloadFile.h" +#include "https_request.h" + +void dump_response(HttpResponse* res) +{ + mbedtls_printf("\r\nStatus: %d - %s\r\n", res->get_status_code(), res->get_status_message().c_str()); + + mbedtls_printf("Headers:\r\n"); + for (size_t ix = 0; ix < res->get_headers_length(); ix++) { + mbedtls_printf("\t%s: %s\r\n", res->get_headers_fields()[ix]->c_str(), res->get_headers_values()[ix]->c_str()); + } + mbedtls_printf("\nBody (%d bytes):\r\n\r\n%s\r\n", res->get_body_length(), res->get_body_as_string().c_str()); +} + +static unsigned int base64enc_len(const char *str) +{ + return (((strlen(str)-1)/3)+1)<<2; +} + +static void base64enc(const char *input, unsigned int length, char *output) +{ + static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned int c, c1, c2, c3; + for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) { + c1 = ((((unsigned char)*((unsigned char *)&input[i])))); + c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0; + c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0; + + c = ((c1 & 0xFC) >> 2); + output[j+0] = base64[c]; + c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4); + output[j+1] = base64[c]; + c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6); + output[j+2] = (length>i+1)?base64[c]:'='; + c = (c3 & 0x3F); + output[j+3] = (length>i+2)?base64[c]:'='; + } + output[(((length-1)/3)+1)<<2] = '\0'; +} + +static string encode(const string& str) +{ + char* out = new char[ base64enc_len(str.c_str()) ]; + base64enc(str.c_str(), str.length(), out); + string res(out); + delete[] out; + return res; +} + +void DownloadFile::basic_auth(const char * user, const char * password) +{ + authstr = user; + authstr += ":"; + authstr += password; + printf("Auth Str : %s\r\n", authstr.c_str()); + + std::string base64str = encode(authstr); + printf("Base64 conversion : %s\r\n", base64str.c_str()); + + authstr = "Basic " + base64str; + printf("Authorization: %s\r\n", authstr.c_str()); +} + +HttpResponse* DownloadFile::get_file(const char * url) +{ + if (url == NULL) + return NULL; + + if(get_req != NULL) + delete get_req; + + HttpResponse* get_res; + Callback<void(const char *at, size_t length)> aBodyCallback = NULL; + + if (fp != NULL) + aBodyCallback = mbed::callback(this, &DownloadFile::body_callback); + + if (useSSL) + { + get_req_ssl = new HttpsRequest(network, + pem, HTTP_GET, + url, + aBodyCallback); + + if (!authstr.empty()) + get_req_ssl->set_header("Authorization", authstr.c_str()); + + get_req_ssl->set_debug(true); + + get_res = get_req_ssl->send(); + + } + else + { + get_req = new HttpRequest(network, + HTTP_GET, + url, + aBodyCallback); + + if (!authstr.empty()) + get_req->set_header("Authorization", authstr.c_str()); + + get_res = get_req->send(); + } + + if (!get_res) { + printf("HttpRequest failed (error code %d)\r\n", get_req->get_error()); + return NULL; + } + + //dump_response(get_res); + + return get_res; +} + +std::string DownloadFile::get_file_content() +{ + size_t numread; + + if (fp == NULL) + return ""; + + // plain old c .. + // Determine file size + fseek(fp, 0, SEEK_END); + size_t size = ftell(fp); + + char* dummy = new char[(sizeof(char) * size) + 1]; + + rewind(fp); + numread = fread(dummy, sizeof(char), size, fp); + // Make sure its NULL terminanted + dummy[numread] = 0; + + // create a return string + std::string retstr = std::string((const char *) dummy); + + delete[] dummy; + + return retstr; +} + +void DownloadFile::body_callback(const char* data, size_t data_len) +{ + // do something with the data + if (fp != NULL) { + size_written += fwrite((const void *) data, sizeof(char), data_len, fp); + } +}
diff -r 000000000000 -r a1734fe1ec4b DownloadFile.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DownloadFile.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,80 @@ +#ifndef _DOWNLOAD_FILE_H_ +#define _DOWNLOAD_FILE_H_ + +#include <stdio.h> +#include <string> +#include "mbed.h" +#include "rtos.h" +#include "NetworkInterface.h" +#include "https_request.h" +#include "http_request.h" + +class DownloadFile +{ + public: + DownloadFile(NetworkInterface* nw, const char * file = NULL, const char * capem = NULL) + :network(nw), + filename(file), + pem(capem), + useSSL(capem != NULL), + fp(NULL), + size_written(0), + get_req_ssl(NULL), + get_req(NULL) + { + if (filename) + { + fp = fopen(file, "w+"); + if (fp != NULL) + printf("File open successfull!\r\n"); + } + } + + virtual ~DownloadFile() + { + if (fp != NULL) + fclose(fp); + + // HttpsRequest destructor also free's up + // the HttpsResult ... so it must be consumed + // before this class goes out of scope + if(get_req) + delete get_req; + if(get_req_ssl) + delete get_req_ssl; + } + + HttpResponse* get_file(const char * url); + + std::string get_file_content(); + + const char * get_filename() + { + return filename; + } + + size_t get_written_size() { + return size_written; + } + + void basic_auth(const char * user, const char * password); + + + protected: + void body_callback(const char* data, size_t data_len); + + private: + NetworkInterface* network; + const char * filename; + const char * pem; + bool useSSL; + FILE * fp; + size_t size_written; + std::string authstr; + + HttpsRequest* get_req_ssl; + HttpRequest* get_req; +}; + +#endif +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/FP/FP.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/FP/FP.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,212 @@ +/** + * @file FP.h + * @brief Core Utility - Templated Function Pointer Class + * @author sam grove + * @version 1.1 + * @see http://mbed.org/users/sam_grove/code/FP/ + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FP_H +#define FP_H + +/** Example using the FP Class with global functions + * @code + * #include "mbed.h" + * #include "FP.h" + * + * FP<void,bool>fp; + * DigitalOut myled(LED1); + * + * void handler(bool value) + * { + * myled = value; + * return; + * } + * + * int main() + * { + * fp.attach(&handler); + * + * while(1) + * { + * fp(1); + * wait(0.2); + * fp(0); + * wait(0.2); + * } + * } + * @endcode + */ + +/** Example using the FP Class with different class member functions + * @code + * #include "mbed.h" + * #include "FP.h" + * + * FP<void,bool>fp; + * DigitalOut myled(LED4); + * + * class Wrapper + * { + * public: + * Wrapper(){} + * + * void handler(bool value) + * { + * myled = value; + * return; + * } + * }; + * + * int main() + * { + * Wrapper wrapped; + * fp.attach(&wrapped, &Wrapper::handler); + * + * while(1) + * { + * fp(1); + * wait(0.2); + * fp(0); + * wait(0.2); + * } + * } + * @endcode + */ + +/** Example using the FP Class with member FP and member function +* @code +* #include "mbed.h" +* #include "FP.h" +* +* DigitalOut myled(LED2); +* +* class Wrapper +* { +* public: +* Wrapper() +* { +* fp.attach(this, &Wrapper::handler); +* } +* +* void handler(bool value) +* { +* myled = value; +* return; +* } +* +* FP<void,bool>fp; +* }; +* +* int main() +* { +* Wrapper wrapped; +* +* while(1) +* { +* wrapped.fp(1); +* wait(0.2); +* wrapped.fp(0); +* wait(0.2); +* } +* } +* @endcode +*/ + +/** + * @class FP + * @brief API for managing Function Pointers + */ +template<class retT, class argT> +class FP +{ +public: + /** Create the FP object - only one callback can be attached to the object, that is + * a member function or a global function, not both at the same time + */ + FP() + { + obj_callback = 0; + c_callback = 0; + } + + /** Add a callback function to the object + * @param item - Address of the initialized object + * @param member - Address of the member function (dont forget the scope that the function is defined in) + */ + template<class T> + void attach(T *item, retT (T::*method)(argT)) + { + obj_callback = (FPtrDummy *)(item); + method_callback = (retT (FPtrDummy::*)(argT))(method); + return; + } + + /** Add a callback function to the object + * @param function - The address of a globally defined function + */ + void attach(retT (*function)(argT)) + { + c_callback = function; + } + + /** Invoke the function attached to the class + * @param arg - An argument that is passed into the function handler that is called + * @return The return from the function hanlder called by this class + */ + retT operator()(argT arg) const + { + if( 0 != c_callback ) { + return obj_callback ? (obj_callback->*method_callback)(arg) : (*c_callback)(arg); + } + return (retT)0; + } + + /** Determine if an callback is currently hooked + * @return 1 if a method is hooked, 0 otherwise + */ + bool attached() + { + return obj_callback || c_callback; + } + + /** Release a function from the callback hook + */ + void detach() + { + obj_callback = 0; + c_callback = 0; + } + +private: + + // empty type used for casting + class FPtrDummy; + + FPtrDummy *obj_callback; + + /** + * @union Funciton + * @brief Member or global callback function + */ + union { + retT (*c_callback)(argT); /*!< Footprint for a global function */ + retT (FPtrDummy::*method_callback)(argT); /*!< Footprint for a member function */ + }; +}; + +#endif
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTConnect.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTConnect.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Ian Craggs - add connack return code definitions + *******************************************************************************/ + +#ifndef MQTTCONNECT_H_ +#define MQTTCONNECT_H_ + +enum connack_return_codes +{ + MQTT_CONNECTION_ACCEPTED = 0, + MQTT_UNNACCEPTABLE_PROTOCOL = 1, + MQTT_CLIENTID_REJECTED = 2, + MQTT_SERVER_UNAVAILABLE = 3, + MQTT_BAD_USERNAME_OR_PASSWORD = 4, + MQTT_NOT_AUTHORIZED = 5, +}; + + +typedef union +{ + unsigned char all; /**< all connect flags */ +#if defined(REVERSED) + struct + { + unsigned int username : 1; /**< 3.1 user name */ + unsigned int password : 1; /**< 3.1 password */ + unsigned int willRetain : 1; /**< will retain setting */ + unsigned int willQoS : 2; /**< will QoS value */ + unsigned int will : 1; /**< will flag */ + unsigned int cleansession : 1; /**< clean session flag */ + unsigned int : 1; /**< unused */ + } bits; +#else + struct + { + unsigned int : 1; /**< unused */ + unsigned int cleansession : 1; /**< cleansession flag */ + unsigned int will : 1; /**< will flag */ + unsigned int willQoS : 2; /**< will QoS value */ + unsigned int willRetain : 1; /**< will retain setting */ + unsigned int password : 1; /**< 3.1 password */ + unsigned int username : 1; /**< 3.1 user name */ + } bits; +#endif +} MQTTConnectFlags; /**< connect flags byte */ + + + +/** + * Defines the MQTT "Last Will and Testament" (LWT) settings for + * the connect packet. + */ +typedef struct +{ + /** The eyecatcher for this structure. must be MQTW. */ + char struct_id[4]; + /** The version number of this structure. Must be 0 */ + int struct_version; + /** The LWT topic to which the LWT message will be published. */ + MQTTString topicName; + /** The LWT payload. */ + MQTTString message; + /** + * The retained flag for the LWT message (see MQTTAsync_message.retained). + */ + unsigned char retained; + /** + * The quality of service setting for the LWT message (see + * MQTTAsync_message.qos and @ref qos). + */ + char qos; +} MQTTPacket_willOptions; + + +#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 } + + +typedef struct +{ + /** The eyecatcher for this structure. must be MQTC. */ + char struct_id[4]; + /** The version number of this structure. Must be 0 */ + int struct_version; + /** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1 + */ + unsigned char MQTTVersion; + MQTTString clientID; + unsigned short keepAliveInterval; + unsigned char cleansession; + unsigned char willFlag; + MQTTPacket_willOptions will; + MQTTString username; + MQTTString password; +} MQTTPacket_connectData; + +typedef union +{ + unsigned char all; /**< all connack flags */ +#if defined(REVERSED) + struct + { + unsigned int sessionpresent : 1; /**< session present flag */ + unsigned int : y; /**< unused */ + } bits; +#else + struct + { + unsigned int : 7; /**< unused */ + unsigned int sessionpresent : 1; /**< session present flag */ + } bits; +#endif +} MQTTConnackFlags; /**< connack flags byte */ + +#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}} } + +int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options); +int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len); + +int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent); +int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen); + +int MQTTSerialize_disconnect(unsigned char* buf, int buflen); +int MQTTSerialize_pingreq(unsigned char* buf, int buflen); + +#endif /* MQTTCONNECT_H_ */
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTConnectClient.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTConnectClient.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "MQTTPacket.h" +#include "StackTrace.h" + +#include <string.h> + +/** + * Determines the length of the MQTT connect packet that would be produced using the supplied connect options. + * @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 + */ +int MQTTSerialize_connectLength(MQTTPacket_connectData* options) +{ + int len = 0; + + FUNC_ENTRY; + + if (options->MQTTVersion == 3) + len = 12; /* variable depending on MQTT or MQIsdp */ + else if (options->MQTTVersion == 4) + len = 10; + + len += MQTTstrlen(options->clientID)+2; + if (options->willFlag) + len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2; + if (options->username.cstring || options->username.lenstring.data) + len += MQTTstrlen(options->username)+2; + if (options->password.cstring || options->password.lenstring.data) + len += MQTTstrlen(options->password)+2; + + FUNC_EXIT_RC(len); + return len; +} + + +/** + * Serializes the connect options into the buffer. + * @param buf the buffer into which the packet will be serialized + * @param len the length in bytes of the supplied buffer + * @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, int buflen, MQTTPacket_connectData* options) +{ + unsigned char *ptr = buf; + MQTTHeader header = {0}; + MQTTConnectFlags flags = {0}; + int len = 0; + int rc = -1; + + FUNC_ENTRY; + if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + header.byte = 0; + header.bits.type = CONNECT; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, len); /* write remaining length */ + + if (options->MQTTVersion == 4) + { + writeCString(&ptr, "MQTT"); + writeChar(&ptr, (char) 4); + } + else + { + writeCString(&ptr, "MQIsdp"); + writeChar(&ptr, (char) 3); + } + + flags.all = 0; + flags.bits.cleansession = options->cleansession; + flags.bits.will = (options->willFlag) ? 1 : 0; + if (flags.bits.will) + { + flags.bits.willQoS = options->will.qos; + flags.bits.willRetain = options->will.retained; + } + + if (options->username.cstring || options->username.lenstring.data) + flags.bits.username = 1; + if (options->password.cstring || options->password.lenstring.data) + flags.bits.password = 1; + + writeChar(&ptr, flags.all); + writeInt(&ptr, options->keepAliveInterval); + writeMQTTString(&ptr, options->clientID); + if (options->willFlag) + { + writeMQTTString(&ptr, options->will.topicName); + writeMQTTString(&ptr, options->will.message); + } + if (flags.bits.username) + writeMQTTString(&ptr, options->username); + if (flags.bits.password) + writeMQTTString(&ptr, options->password); + + rc = ptr - buf; + + exit: FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Deserializes the supplied (wire) buffer into connack data - return code + * @param sessionPresent the session present flag returned (only for MQTT 3.1.1) + * @param connack_rc returned integer value of the connack return code + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @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, int buflen) +{ + MQTTHeader header = {0}; + unsigned char* curdata = buf; + unsigned char* enddata = NULL; + int rc = 0; + int mylen; + MQTTConnackFlags flags = {0}; + + FUNC_ENTRY; + header.byte = readChar(&curdata); + if (header.bits.type != CONNACK) + goto exit; + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + if (enddata - curdata < 2) + goto exit; + + flags.all = readChar(&curdata); + *sessionPresent = flags.bits.sessionpresent; + *connack_rc = readChar(&curdata); + + rc = 1; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + + +/** + * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer, to avoid overruns + * @param packettype the message type + * @return serialized length, or error if 0 + */ +int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype) +{ + MQTTHeader header = {0}; + int rc = -1; + unsigned char *ptr = buf; + + FUNC_ENTRY; + if (buflen < 2) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + header.byte = 0; + header.bits.type = packettype; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */ + rc = ptr - buf; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket + * @param buf the buffer into which the packet will be serialized + * @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, int buflen) +{ + return MQTTSerialize_zero(buf, buflen, DISCONNECT); +} + + +/** + * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket + * @param buf the buffer into which the packet will be serialized + * @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, int buflen) +{ + return MQTTSerialize_zero(buf, buflen, PINGREQ); +}
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTConnectServer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTConnectServer.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "StackTrace.h" +#include "MQTTPacket.h" +#include <string.h> + +#define min(a, b) ((a < b) ? a : b) + + +/** + * Validates MQTT protocol name and version combinations + * @param protocol the MQTT protocol name as an MQTTString + * @param version the MQTT protocol version number, as in the connect packet + * @return correct MQTT combination? 1 is true, 0 is false + */ +int MQTTPacket_checkVersion(MQTTString* protocol, int version) +{ + int rc = 0; + + if (version == 3 && memcmp(protocol->lenstring.data, "MQIdsp", + min(6, protocol->lenstring.len)) == 0) + rc = 1; + else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT", + min(4, protocol->lenstring.len)) == 0) + rc = 1; + return rc; +} + + +/** + * Deserializes the supplied (wire) buffer into connect data structure + * @param data the connect data structure to be filled out + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param len the length in bytes of the data in the supplied buffer + * @return error code. 1 is success, 0 is failure + */ +int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len) +{ + MQTTHeader header = {0}; + MQTTConnectFlags flags = {0}; + unsigned char* curdata = buf; + unsigned char* enddata = &buf[len]; + int rc = 0; + MQTTString Protocol; + int version; + int mylen = 0; + + FUNC_ENTRY; + header.byte = readChar(&curdata); + if (header.bits.type != CONNECT) + goto exit; + + curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */ + + if (!readMQTTLenString(&Protocol, &curdata, enddata) || + enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */ + goto exit; + + version = (int)readChar(&curdata); /* Protocol version */ + /* If we don't recognize the protocol version, we don't parse the connect packet on the + * basis that we don't know what the format will be. + */ + if (MQTTPacket_checkVersion(&Protocol, version)) + { + flags.all = readChar(&curdata); + data->cleansession = flags.bits.cleansession; + data->keepAliveInterval = readInt(&curdata); + if (!readMQTTLenString(&data->clientID, &curdata, enddata)) + goto exit; + if (flags.bits.will) + { + data->willFlag = 1; + data->will.qos = flags.bits.willQoS; + data->will.retained = flags.bits.willRetain; + if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) || + !readMQTTLenString(&data->will.message, &curdata, enddata)) + goto exit; + } + if (flags.bits.username) + { + if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata)) + goto exit; /* username flag set, but no username supplied - invalid */ + if (flags.bits.password && + (enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata))) + goto exit; /* password flag set, but no password supplied - invalid */ + } + else if (flags.bits.password) + goto exit; /* password flag set without username - invalid */ + rc = 1; + } +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Serializes the connack packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param connack_rc the integer connack return code to be used + * @param sessionPresent the MQTT 3.1.1 sessionPresent flag + * @return serialized length, or error if 0 + */ +int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent) +{ + MQTTHeader header = {0}; + int rc = 0; + unsigned char *ptr = buf; + MQTTConnackFlags flags = {0}; + + FUNC_ENTRY; + if (buflen < 2) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + header.byte = 0; + header.bits.type = CONNACK; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */ + + flags.all = 0; + flags.bits.sessionpresent = sessionPresent; + writeChar(&ptr, flags.all); + writeChar(&ptr, connack_rc); + + rc = ptr - buf; +exit: + FUNC_EXIT_RC(rc); + return rc; +} +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTDeserializePublish.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTDeserializePublish.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "StackTrace.h" +#include "MQTTPacket.h" +#include <string.h> + +#define min(a, b) ((a < b) ? 1 : 0) + +/** + * Deserializes the supplied (wire) buffer into publish data + * @param dup returned integer - the MQTT dup flag + * @param qos returned integer - the MQTT QoS value + * @param retained returned integer - the MQTT retained flag + * @param packetid returned integer - the MQTT packet identifier + * @param topicName returned MQTTString - the MQTT topic in the publish + * @param payload returned byte buffer - the MQTT publish payload + * @param payloadlen returned integer - the length of the MQTT payload + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @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, int* payloadlen, unsigned char* buf, int buflen) +{ + MQTTHeader header = {0}; + unsigned char* curdata = buf; + unsigned char* enddata = NULL; + int rc = 0; + int mylen = 0; + + FUNC_ENTRY; + header.byte = readChar(&curdata); + if (header.bits.type != PUBLISH) + goto exit; + *dup = header.bits.dup; + *qos = header.bits.qos; + *retained = header.bits.retain; + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + + if (!readMQTTLenString(topicName, &curdata, enddata) || + enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */ + goto exit; + + if (*qos > 0) + *packetid = readInt(&curdata); + + *payloadlen = enddata - curdata; + *payload = curdata; + rc = 1; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + + +/** + * Deserializes the supplied (wire) buffer into an ack + * @param packettype returned integer - the MQTT packet type + * @param dup returned integer - the MQTT dup flag + * @param packetid returned integer - the MQTT packet identifier + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @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, int buflen) +{ + MQTTHeader header = {0}; + unsigned char* curdata = buf; + unsigned char* enddata = NULL; + int rc = 0; + int mylen; + + FUNC_ENTRY; + header.byte = readChar(&curdata); + *dup = header.bits.dup; + *packettype = header.bits.type; + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + + if (enddata - curdata < 2) + goto exit; + *packetid = readInt(&curdata); + + rc = 1; +exit: + FUNC_EXIT_RC(rc); + return rc; +} +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTPacket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTPacket.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,453 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "StackTrace.h" +#include "MQTTPacket.h" + +#include <string.h> + +/** + * Encodes the message length according to the MQTT algorithm + * @param buf the buffer into which the encoded data is written + * @param length the length to be encoded + * @return the number of bytes written to buffer + */ +int MQTTPacket_encode(unsigned char* buf, int length) +{ + int rc = 0; + + FUNC_ENTRY; + do + { + char d = length % 128; + length /= 128; + /* if there are more digits to encode, set the top bit of this digit */ + if (length > 0) + d |= 0x80; + buf[rc++] = d; + } while (length > 0); + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Decodes the message length according to the MQTT algorithm + * @param getcharfn pointer to function to read the next character from the data source + * @param value the decoded length returned + * @return the number of bytes read from the socket + */ +int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value) +{ + unsigned char c; + int multiplier = 1; + int len = 0; +#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4 + + FUNC_ENTRY; + *value = 0; + do + { + int rc = MQTTPACKET_READ_ERROR; + + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) + { + rc = MQTTPACKET_READ_ERROR; /* bad data */ + goto exit; + } + rc = (*getcharfn)(&c, 1); + if (rc != 1) + goto exit; + *value += (c & 127) * multiplier; + multiplier *= 128; + } while ((c & 128) != 0); +exit: + FUNC_EXIT_RC(len); + return len; +} + + +int MQTTPacket_len(int rem_len) +{ + rem_len += 1; /* header byte */ + + /* now remaining_length field */ + if (rem_len < 128) + rem_len += 1; + else if (rem_len < 16384) + rem_len += 2; + else if (rem_len < 2097151) + rem_len += 3; + else + rem_len += 4; + return rem_len; +} + + +static unsigned char* bufptr; + +int bufchar(unsigned char* c, int count) +{ + int i; + + for (i = 0; i < count; ++i) + *c = *bufptr++; + return count; +} + + +int MQTTPacket_decodeBuf(unsigned char* buf, int* value) +{ + bufptr = buf; + return MQTTPacket_decode(bufchar, value); +} + + +/** + * Calculates an integer from two bytes read from the input buffer + * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned + * @return the integer value calculated + */ +int readInt(unsigned char** pptr) +{ + unsigned char* ptr = *pptr; + int len = 256*(*ptr) + (*(ptr+1)); + *pptr += 2; + return len; +} + + +/** + * Reads one character from the input buffer. + * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned + * @return the character read + */ +char readChar(unsigned char** pptr) +{ + char c = **pptr; + (*pptr)++; + return c; +} + + +/** + * Writes one character to an output buffer. + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param c the character to write + */ +void writeChar(unsigned char** pptr, char c) +{ + **pptr = c; + (*pptr)++; +} + + +/** + * Writes an integer as 2 bytes to an output buffer. + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param anInt the integer to write + */ +void writeInt(unsigned char** pptr, int anInt) +{ + **pptr = (unsigned char)(anInt / 256); + (*pptr)++; + **pptr = (unsigned char)(anInt % 256); + (*pptr)++; +} + + +/** + * Writes a "UTF" string to an output buffer. Converts C string to length-delimited. + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param string the C string to write + */ +void writeCString(unsigned char** pptr, const char* string) +{ + int len = strlen(string); + writeInt(pptr, len); + memcpy(*pptr, string, len); + *pptr += len; +} + + +int getLenStringLen(char* ptr) +{ + int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1)); + return len; +} + + +void writeMQTTString(unsigned char** pptr, MQTTString mqttstring) +{ + if (mqttstring.lenstring.len > 0) + { + writeInt(pptr, mqttstring.lenstring.len); + memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len); + *pptr += mqttstring.lenstring.len; + } + else if (mqttstring.cstring) + writeCString(pptr, mqttstring.cstring); + else + writeInt(pptr, 0); +} + + +/** + * @param mqttstring the MQTTString structure into which the data is to be read + * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned + * @param enddata pointer to the end of the data: do not read beyond + * @return 1 if successful, 0 if not + */ +int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata) +{ + int rc = 0; + + FUNC_ENTRY; + /* the first two bytes are the length of the string */ + if (enddata - (*pptr) > 1) /* enough length to read the integer? */ + { + mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */ + if (&(*pptr)[mqttstring->lenstring.len] <= enddata) + { + mqttstring->lenstring.data = (char*)*pptr; + *pptr += mqttstring->lenstring.len; + rc = 1; + } + } + mqttstring->cstring = NULL; + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string + * @param mqttstring the string to return the length of + * @return the length of the string + */ +int MQTTstrlen(MQTTString mqttstring) +{ + int rc = 0; + + if (mqttstring.cstring) + rc = strlen(mqttstring.cstring); + else + rc = mqttstring.lenstring.len; + return rc; +} + + +/** + * Compares an MQTTString to a C string + * @param a the MQTTString to compare + * @param bptr the C string to compare + * @return boolean - equal or not + */ +int MQTTPacket_equals(MQTTString* a, char* bptr) +{ + int alen = 0, + blen = 0; + char *aptr; + + if (a->cstring) + { + aptr = a->cstring; + alen = strlen(a->cstring); + } + else + { + aptr = a->lenstring.data; + alen = a->lenstring.len; + } + blen = strlen(bptr); + + return (alen == blen) && (strncmp(aptr, bptr, alen) == 0); +} + + +/** + * Helper function to read packet data from some source into a buffer + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param getfn pointer to a function which will read any number of bytes from the needed source + * @return integer MQTT packet type, or -1 on error + */ +int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int)) +{ + int rc = -1; + MQTTHeader header = {0}; + int len = 0; + int rem_len = 0; + + /* 1. read the header byte. This has the packet type in it */ + if ((*getfn)(buf, 1) != 1) + goto exit; + + len = 1; + /* 2. read the remaining length. This is variable in itself */ + MQTTPacket_decode(getfn, &rem_len); + len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */ + + /* 3. read the rest of the buffer using a callback to supply the rest of the data */ + if ((*getfn)(buf + len, rem_len) != rem_len) + goto exit; + + header.byte = buf[0]; + rc = header.bits.type; +exit: + return rc; +} + + +const char* MQTTPacket_names[] = +{ + "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", + "PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", + "PINGREQ", "PINGRESP", "DISCONNECT" +}; + + +char* MQTTPacket_toString(char* strbuf, int strbuflen, unsigned char* buf, int buflen) +{ + int index = 0; + int rem_length = 0; + MQTTHeader header = {0}; + int strindex = 0; + + header.byte = buf[index++]; + index += MQTTPacket_decodeBuf(&buf[index], &rem_length); + + switch (header.bits.type) + { + case CONNECT: + { + MQTTPacket_connectData data; + if (MQTTDeserialize_connect(&data, buf, buflen) == 1) + { + strindex = snprintf(strbuf, strbuflen, + "CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %hd", + (int)data.MQTTVersion, data.clientID.lenstring.len, data.clientID.lenstring.data, + (int)data.cleansession, data.keepAliveInterval); + if (data.willFlag) + strindex += snprintf(&strbuf[strindex], strbuflen - strindex, + ", will QoS %d, will retain %d, will topic %.*s, will message %.*s", + data.will.qos, data.will.retained, + data.will.topicName.lenstring.len, data.will.topicName.lenstring.data, + data.will.message.lenstring.len, data.will.message.lenstring.data); + if (data.username.lenstring.data && data.username.lenstring.len > 0) + { + printf("user name\n"); + strindex += snprintf(&strbuf[strindex], strbuflen - strindex, + ", user name %.*s", data.username.lenstring.len, data.username.lenstring.data); + } + if (data.password.lenstring.data && data.password.lenstring.len > 0) + strindex += snprintf(&strbuf[strindex], strbuflen - strindex, + ", password %.*s", data.password.lenstring.len, data.password.lenstring.data); + } + } + break; + case CONNACK: + { + unsigned char sessionPresent, connack_rc; + if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1) + strindex = snprintf(strbuf, strbuflen, + "CONNACK session present %d, rc %d", sessionPresent, connack_rc); + } + break; + case PUBLISH: + { + unsigned char dup, retained, *payload; + unsigned short packetid; + int qos, payloadlen; + MQTTString topicName = MQTTString_initializer; + if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName, + &payload, &payloadlen, buf, buflen) == 1) + strindex = snprintf(strbuf, strbuflen, + "PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s", + dup, qos, retained, packetid, + (topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data, + payloadlen, (payloadlen < 20) ? payloadlen : 20, payload); + } + break; + case PUBACK: + case PUBREC: + case PUBREL: + case PUBCOMP: + { + unsigned char packettype, dup; + unsigned short packetid; + if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1) + strindex = snprintf(strbuf, strbuflen, + "%s dup %d, packet id %d", + MQTTPacket_names[packettype], dup, packetid); + } + break; + case SUBSCRIBE: + { + unsigned char dup; + unsigned short packetid; + int maxcount = 1, count = 0; + MQTTString topicFilters[1]; + int requestedQoSs[1]; + if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count, + topicFilters, requestedQoSs, buf, buflen) == 1) + strindex = snprintf(strbuf, strbuflen, + "SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d", + dup, packetid, count, + topicFilters[0].lenstring.len, topicFilters[0].lenstring.data, + requestedQoSs[0]); + } + break; + case SUBACK: + { + unsigned short packetid; + int maxcount = 1, count = 0; + int grantedQoSs[1]; + if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1) + strindex = snprintf(strbuf, strbuflen, + "SUBACK packet id %d count %d granted qos %d", + packetid, count, grantedQoSs[0]); + } + break; + case UNSUBSCRIBE: + { + unsigned char dup; + unsigned short packetid; + int maxcount = 1, count = 0; + MQTTString topicFilters[1]; + if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1) + strindex = snprintf(strbuf, strbuflen, + "UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s", + dup, packetid, count, + topicFilters[0].lenstring.len, topicFilters[0].lenstring.data); + } + break; + case UNSUBACK: + { + unsigned short packetid; + if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1) + strindex = snprintf(strbuf, strbuflen, + "UNSUBACK packet id %d", packetid); + } + break; + case PINGREQ: + case PINGRESP: + case DISCONNECT: + strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]); + break; + } + return strbuf; +}
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTPacket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTPacket.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef MQTTPACKET_H_ +#define MQTTPACKET_H_ + +#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +enum errors +{ + MQTTPACKET_BUFFER_TOO_SHORT = -2, + MQTTPACKET_READ_ERROR = -1, + MQTTPACKET_READ_COMPLETE, +}; + +enum msgTypes +{ + CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, + PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, + PINGREQ, PINGRESP, DISCONNECT +}; + +/** + * Bitfields for the MQTT header byte. + */ +typedef union +{ + unsigned char byte; /**< the whole byte */ +#if defined(REVERSED) + struct + { + unsigned int type : 4; /**< message type nibble */ + unsigned int dup : 1; /**< DUP flag bit */ + unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */ + unsigned int retain : 1; /**< retained flag bit */ + } bits; +#else + struct + { + unsigned int retain : 1; /**< retained flag bit */ + unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */ + unsigned int dup : 1; /**< DUP flag bit */ + unsigned int type : 4; /**< message type nibble */ + } bits; +#endif +} MQTTHeader; + +typedef struct +{ + int len; + char* data; +} MQTTLenString; + +typedef struct +{ + char* cstring; + MQTTLenString lenstring; +} MQTTString; + +#define MQTTString_initializer {NULL, {0, NULL}} + +int MQTTstrlen(MQTTString mqttstring); + +#include "MQTTConnect.h" +#include "MQTTPublish.h" +#include "MQTTSubscribe.h" +#include "MQTTUnsubscribe.h" + +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); + +int MQTTPacket_len(int rem_len); +int MQTTPacket_equals(MQTTString* a, char* b); + +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); + +int readInt(unsigned char** pptr); +char readChar(unsigned char** pptr); +void writeChar(unsigned char** pptr, char c); +void writeInt(unsigned char** pptr, int anInt); +int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata); +void writeCString(unsigned char** pptr, const char* string); +void writeMQTTString(unsigned char** pptr, MQTTString mqttstring); + +int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int)); + +char* MQTTPacket_toString(char* strbuf, int strbuflen, unsigned char* buf, int buflen); + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +} +#endif + + +#endif /* MQTTPACKET_H_ */
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTPublish.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTPublish.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef MQTTPUBLISH_H_ +#define MQTTPUBLISH_H_ + +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); + +int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName, + unsigned char** payload, int* payloadlen, unsigned char* buf, int len); + +int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid); +int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid); +int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid); + +#endif /* MQTTPUBLISH_H_ */
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTSerializePublish.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTSerializePublish.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "MQTTPacket.h" +#include "StackTrace.h" + +#include <string.h> + + +/** + * Determines the length of the MQTT publish packet that would be produced using the supplied parameters + * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0) + * @param topicName the topic name to be used in the publish + * @param payloadlen the length of the payload to be sent + * @return the length of buffer needed to contain the serialized version of the packet + */ +int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen) +{ + int len = 0; + + len += 2 + MQTTstrlen(topicName) + payloadlen; + if (qos > 0) + len += 2; /* packetid */ + return len; +} + + +/** + * Serializes the supplied publish data into the supplied buffer, ready for sending + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param dup integer - the MQTT dup flag + * @param qos integer - the MQTT QoS value + * @param retained integer - the MQTT retained flag + * @param packetid integer - the MQTT packet identifier + * @param topicName MQTTString - the MQTT topic in the publish + * @param payload byte buffer - the MQTT publish 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, 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}; + int rem_len = 0; + int rc = 0; + + FUNC_ENTRY; + if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + header.bits.type = PUBLISH; + header.bits.dup = dup; + header.bits.qos = qos; + header.bits.retain = retained; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */; + + writeMQTTString(&ptr, topicName); + + if (qos > 0) + writeInt(&ptr, packetid); + + memcpy(ptr, payload, payloadlen); + ptr += payloadlen; + + rc = ptr - buf; + +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + + +/** + * Serializes the ack packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param type the MQTT packet type + * @param dup the MQTT dup flag + * @param packetid the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid) +{ + MQTTHeader header = {0}; + int rc = 0; + unsigned char *ptr = buf; + + FUNC_ENTRY; + if (buflen < 4) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + header.bits.type = packettype; + header.bits.dup = dup; + header.bits.qos = 0; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */ + writeInt(&ptr, packetid); + rc = ptr - buf; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Serializes a puback packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param packetid integer - the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid) +{ + return MQTTSerialize_ack(buf, buflen, PUBACK, packetid, 0); +} + + +/** + * Serializes a pubrel packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param dup integer - the MQTT dup flag + * @param packetid integer - the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid) +{ + return MQTTSerialize_ack(buf, buflen, PUBREL, packetid, dup); +} + + +/** + * Serializes a pubrel packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param packetid integer - the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid) +{ + return MQTTSerialize_ack(buf, buflen, PUBCOMP, packetid, 0); +} + +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTSubscribe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTSubscribe.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef MQTTSUBSCRIBE_H_ +#define MQTTSUBSCRIBE_H_ + +int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, + int count, MQTTString topicFilters[], int requestedQoSs[]); + +int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, + int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len); + +int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs); + +int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len); + + +#endif /* MQTTSUBSCRIBE_H_ */
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTSubscribeClient.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTSubscribeClient.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "MQTTPacket.h" +#include "StackTrace.h" + +#include <string.h> + +/** + * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters + * @param count the number of topic filter strings in topicFilters + * @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 + */ +int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[]) +{ + int i; + int len = 2; /* packetid */ + + for (i = 0; i < count; ++i) + len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */ + return len; +} + + +/** + * Serializes the supplied subscribe data into the supplied buffer, ready for sending + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied bufferr + * @param dup integer - the MQTT dup flag + * @param packetid integer - the MQTT packet identifier + * @param count - number of members in the topicFilters and reqQos arrays + * @param topicFilters - array of topic filter names + * @param requestedQoSs - array of requested QoS + * @return the length of the serialized data. <= 0 indicates error + */ +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}; + int rem_len = 0; + int rc = 0; + int i = 0; + + FUNC_ENTRY; + if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + header.byte = 0; + header.bits.type = SUBSCRIBE; + header.bits.dup = dup; + header.bits.qos = 1; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */; + + writeInt(&ptr, packetid); + + for (i = 0; i < count; ++i) + { + writeMQTTString(&ptr, topicFilters[i]); + writeChar(&ptr, requestedQoSs[i]); + } + + rc = ptr - buf; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + + +/** + * Deserializes the supplied (wire) buffer into suback data + * @param packetid returned integer - the MQTT packet identifier + * @param maxcount - the maximum number of members allowed in the grantedQoSs array + * @param count returned integer - number of members in the grantedQoSs array + * @param grantedQoSs returned array of integers - the granted qualities of service + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @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, int buflen) +{ + MQTTHeader header = {0}; + unsigned char* curdata = buf; + unsigned char* enddata = NULL; + int rc = 0; + int mylen; + + FUNC_ENTRY; + header.byte = readChar(&curdata); + if (header.bits.type != SUBACK) + goto exit; + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + if (enddata - curdata < 2) + goto exit; + + *packetid = readInt(&curdata); + + *count = 0; + while (curdata < enddata) + { + if (*count > maxcount) + { + rc = -1; + goto exit; + } + grantedQoSs[(*count)++] = readChar(&curdata); + } + + rc = 1; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTSubscribeServer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTSubscribeServer.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "MQTTPacket.h" +#include "StackTrace.h" + +#include <string.h> + + +/** + * Deserializes the supplied (wire) buffer into subscribe data + * @param dup integer returned - the MQTT dup flag + * @param packetid integer returned - the MQTT packet identifier + * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays + * @param count - number of members in the topicFilters and requestedQoSs arrays + * @param topicFilters - array of topic filter names + * @param requestedQoSs - array of requested QoS + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @return the length of the serialized data. <= 0 indicates error + */ +int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[], + int requestedQoSs[], unsigned char* buf, int buflen) +{ + MQTTHeader header = {0}; + unsigned char* curdata = buf; + unsigned char* enddata = NULL; + int rc = -1; + int mylen = 0; + + FUNC_ENTRY; + header.byte = readChar(&curdata); + if (header.bits.type != SUBSCRIBE) + goto exit; + *dup = header.bits.dup; + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + + *packetid = readInt(&curdata); + + *count = 0; + while (curdata < enddata) + { + if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata)) + goto exit; + if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */ + goto exit; + requestedQoSs[*count] = readChar(&curdata); + (*count)++; + } + + rc = 1; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Serializes the supplied suback data into the supplied buffer, ready for sending + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param packetid integer - the MQTT packet identifier + * @param count - number of members in the grantedQoSs array + * @param grantedQoSs - array of granted QoS + * @return the length of the serialized data. <= 0 indicates error + */ +int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs) +{ + MQTTHeader header = {0}; + int rc = -1; + unsigned char *ptr = buf; + int i; + + FUNC_ENTRY; + if (buflen < 2 + count) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + header.byte = 0; + header.bits.type = SUBACK; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */ + + writeInt(&ptr, packetid); + + for (i = 0; i < count; ++i) + writeChar(&ptr, grantedQoSs[i]); + + rc = ptr - buf; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTUnsubscribe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTUnsubscribe.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifndef MQTTUNSUBSCRIBE_H_ +#define MQTTUNSUBSCRIBE_H_ + +int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, + int count, MQTTString topicFilters[]); + +int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[], + unsigned char* buf, int len); + +int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid); + +int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len); + +#endif /* MQTTUNSUBSCRIBE_H_ */
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTUnsubscribeClient.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTUnsubscribeClient.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "MQTTPacket.h" +#include "StackTrace.h" + +#include <string.h> + +/** + * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters + * @param count the number of topic filter strings in topicFilters + * @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 + */ +int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[]) +{ + int i; + int len = 2; /* packetid */ + + for (i = 0; i < count; ++i) + len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/ + return len; +} + + +/** + * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @param dup integer - the MQTT dup flag + * @param packetid integer - the MQTT packet identifier + * @param count - number of members in the topicFilters array + * @param topicFilters - array of topic filter names + * @return the length of the serialized data. <= 0 indicates error + */ +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}; + int rem_len = 0; + int rc = -1; + int i = 0; + + FUNC_ENTRY; + if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + + header.byte = 0; + header.bits.type = UNSUBSCRIBE; + header.bits.dup = dup; + header.bits.qos = 1; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */; + + writeInt(&ptr, packetid); + + for (i = 0; i < count; ++i) + writeMQTTString(&ptr, topicFilters[i]); + + rc = ptr - buf; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Deserializes the supplied (wire) buffer into unsuback data + * @param packetid returned integer - the MQTT packet identifier + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @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, int buflen) +{ + unsigned char type = 0; + unsigned char dup = 0; + int rc = 0; + + FUNC_ENTRY; + rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen); + if (type == UNSUBACK) + rc = 1; + FUNC_EXIT_RC(rc); + return rc; +} + +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/MQTTUnsubscribeServer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/MQTTUnsubscribeServer.c Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "MQTTPacket.h" +#include "StackTrace.h" + +#include <string.h> + + +/** + * Deserializes the supplied (wire) buffer into unsubscribe data + * @param dup integer returned - the MQTT dup flag + * @param packetid integer returned - the MQTT packet identifier + * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays + * @param count - number of members in the topicFilters and requestedQoSs arrays + * @param topicFilters - array of topic filter names + * @param buf the raw buffer data, of the correct length determined by the remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @return the length of the serialized data. <= 0 indicates error + */ +int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[], + unsigned char* buf, int len) +{ + MQTTHeader header = {0}; + unsigned char* curdata = buf; + unsigned char* enddata = NULL; + int rc = 0; + int mylen = 0; + + FUNC_ENTRY; + header.byte = readChar(&curdata); + if (header.bits.type != UNSUBSCRIBE) + goto exit; + *dup = header.bits.dup; + + curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */ + enddata = curdata + mylen; + + *packetid = readInt(&curdata); + + *count = 0; + while (curdata < enddata) + { + if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata)) + goto exit; + (*count)++; + } + + rc = 1; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + + +/** + * Serializes the supplied unsuback data into the supplied buffer, ready for sending + * @param buf the buffer into which the packet will be serialized + * @param buflen the length in bytes of the supplied buffer + * @param packetid integer - the MQTT packet identifier + * @return the length of the serialized data. <= 0 indicates error + */ +int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid) +{ + MQTTHeader header = {0}; + int rc = 0; + unsigned char *ptr = buf; + + FUNC_ENTRY; + if (buflen < 2) + { + rc = MQTTPACKET_BUFFER_TOO_SHORT; + goto exit; + } + header.byte = 0; + header.bits.type = UNSUBACK; + writeChar(&ptr, header.byte); /* write header */ + + ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */ + + writeInt(&ptr, packetid); + + rc = ptr - buf; +exit: + FUNC_EXIT_RC(rc); + return rc; +} + +
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/StackTrace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/StackTrace.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Ian Craggs - fix for bug #434081 + *******************************************************************************/ + +#ifndef STACKTRACE_H_ +#define STACKTRACE_H_ + +#include <stdio.h> +#define NOSTACKTRACE 1 + +#if defined(NOSTACKTRACE) +#define FUNC_ENTRY +#define FUNC_ENTRY_NOLOG +#define FUNC_ENTRY_MED +#define FUNC_ENTRY_MAX +#define FUNC_EXIT +#define FUNC_EXIT_NOLOG +#define FUNC_EXIT_MED +#define FUNC_EXIT_MAX +#define FUNC_EXIT_RC(x) +#define FUNC_EXIT_MED_RC(x) +#define FUNC_EXIT_MAX_RC(x) + +#else + +#if defined(WIN32) +#define inline __inline +#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM) +#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1) +#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM) +#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM) +#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM) +#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1) +#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM) +#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM) +#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM) +#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM) +#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM) +#else +#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM) +#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1) +#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM) +#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM) +#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM) +#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1) +#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM) +#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM) +#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM) +#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM) +#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM) + +void StackTrace_entry(const char* name, int line, int trace); +void StackTrace_exit(const char* name, int line, void* return_value, int trace); + +void StackTrace_printStack(FILE* dest); +char* StackTrace_get(unsigned long); + +#endif + +#endif + + + + +#endif /* STACKTRACE_H_ */
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/samples/publish-subscribe.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/samples/publish-subscribe.txt Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,115 @@ +#include "MQTTPacket.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "EthernetInterface.h" + + +TCPSocketConnection mysock; + +int getdata(char* buf, int count) +{ + return mysock.receive(buf, (size_t)count); +} + +int toStop = 0; + + +int main() +{ + MQTTPacket_connectData data = MQTTPacket_connectData_initializer; + int rc = 0; + char buf[200]; + int buflen = sizeof(buf); + int msgid = 1; + MQTTString topicString = MQTTString_initializer; + int req_qos = 0; + char* payload = "mypayload"; + int payloadlen = strlen(payload); + int len = 0; + EthernetInterface eth; + + eth.init(); //Use DHCP + eth.connect(); + + rc = mysock.connect("m2m.eclipse.org", 1883); + + data.clientID.cstring = "SendReceive mbed MQTT "; + data.keepAliveInterval = 20; + data.cleansession = 1; + + mysock.set_blocking(true, 1000); /* 1 second Timeout */ + + len = MQTTSerialize_connect(buf, buflen, &data); + rc = mysock.send(buf, len); + + /* wait for connack */ + if (MQTTPacket_read(buf, buflen, getdata) == CONNACK) + { + int connack_rc; + + if (MQTTDeserialize_connack(&connack_rc, buf, buflen) != 1 || connack_rc != 0) + { + printf("Unable to connect, return code %d\n", connack_rc); + goto exit; + } + } + else + goto exit; + + /* subscribe */ + topicString.cstring = "substopic"; + len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos); + + rc = mysock.send(buf, len); + if (MQTTPacket_read(buf, buflen, getdata) == SUBACK) /* wait for suback */ + { + int submsgid; + int subcount; + int granted_qos; + + rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen); + if (granted_qos != 0) + { + printf("granted qos != 0, %d\n", granted_qos); + goto exit; + } + } + else + goto exit; + + topicString.cstring = "pubtopic"; + while (!toStop) + { + if (MQTTPacket_read(buf, buflen, getdata) == PUBLISH) + { + int dup; + int qos; + int retained; + int msgid; + int payloadlen_in; + char* payload_in; + int rc; + MQTTString receivedTopic; + + rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic, + &payload_in, &payloadlen_in, buf, buflen); + printf("message arrived %.*s\n", payloadlen_in, payload_in); + } + + printf("publishing reading\n"); + len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, payload, payloadlen); + rc = mysock.send(buf, len); + } + + printf("disconnecting\n"); + len = MQTTSerialize_disconnect(buf, buflen); + rc = mysock.send(buf, len); + +exit: + eth.disconnect(); + + return 0; +}
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/samples/simple-publish.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/samples/simple-publish.txt Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include "mbed.h" +#include "EthernetInterface.h" +#include "C12832_lcd.h" + +#include "MQTTPacket.h" + +DigitalOut myled(LED2); +C12832_LCD lcd; + +int publish() +{ + MQTTPacket_connectData data = MQTTPacket_connectData_initializer; + int rc = 0; + char buf[200]; + int buflen = sizeof(buf); + TCPSocketConnection mysock; + MQTTString topicString = MQTTString_initializer; + char* payload = "I'm alive!"; + int payloadlen = strlen(payload); + int len = 0; + + mysock.connect("m2m.eclipse.org", 1883); + + data.clientID.cstring = "mbed test client - Ian Craggs"; + data.keepAliveInterval = 20; + data.cleansession = 1; + data.MQTTVersion = 3; + + len = MQTTSerialize_connect(buf, buflen, &data); + + topicString.cstring = "mbed NXP LPC1768"; + len += MQTTSerialize_publish(buf + len, buflen - len, 0, 0, 0, 0, topicString, payload, payloadlen); + + len += MQTTSerialize_disconnect(buf + len, buflen - len); + + rc = 0; + while (rc < len) + { + int rc1 = mysock.send(buf, len); + if (rc1 == -1) + { + lcd.printf("Send failed\n"); + break; + } + else + rc += rc1; + } + if (rc == len) + lcd.printf("Send succeeded\n"); + wait(0.2); + + return 0; +} + +int main() +{ + EthernetInterface eth; + eth.init(); //Use DHCP + eth.connect(); + lcd.printf("IP Address is %s\n", eth.getIPAddress()); + + while(1) + { + myled = 1; + publish(); + wait(0.2); + myled = 0; + publish(); + wait(0.2); + } + + eth.disconnect(); +} \ No newline at end of file
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTPacket/test/test1.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTPacket/test/test1.txt Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,631 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + + +#include "MQTTPacket.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#if !defined(_WINDOWS) + #include <sys/time.h> + #include <sys/socket.h> + #include <unistd.h> + #include <errno.h> +#else +#include <winsock2.h> +#include <ws2tcpip.h> +#define MAXHOSTNAMELEN 256 +#define EAGAIN WSAEWOULDBLOCK +#define EINTR WSAEINTR +#define EINPROGRESS WSAEINPROGRESS +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ENOTCONN WSAENOTCONN +#define ECONNRESET WSAECONNRESET +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +struct Options +{ + char* connection; /**< connection to system under test. */ + char** haconnections; + int hacount; + int verbose; + int test_no; +} options = +{ + "tcp://m2m.eclipse.org:1883", + NULL, + 0, + 0, + 0, +}; + +void usage() +{ + +} + +void getopts(int argc, char** argv) +{ + int count = 1; + + while (count < argc) + { + if (strcmp(argv[count], "--test_no") == 0) + { + if (++count < argc) + options.test_no = atoi(argv[count]); + else + usage(); + } + else if (strcmp(argv[count], "--connection") == 0) + { + if (++count < argc) + { + options.connection = argv[count]; + printf("\nSetting connection to %s\n", options.connection); + } + else + usage(); + } + else if (strcmp(argv[count], "--haconnections") == 0) + { + if (++count < argc) + { + char* tok = strtok(argv[count], " "); + options.hacount = 0; + options.haconnections = malloc(sizeof(char*) * 5); + while (tok) + { + options.haconnections[options.hacount] = malloc(strlen(tok) + 1); + strcpy(options.haconnections[options.hacount], tok); + options.hacount++; + tok = strtok(NULL, " "); + } + } + else + usage(); + } + else if (strcmp(argv[count], "--verbose") == 0) + { + options.verbose = 1; + printf("\nSetting verbose on\n"); + } + count++; + } +} + + +#define LOGA_DEBUG 0 +#define LOGA_INFO 1 +#include <stdarg.h> +#include <time.h> +#include <sys/timeb.h> +void MyLog(int LOGA_level, char* format, ...) +{ + static char msg_buf[256]; + va_list args; + struct timeb ts; + + struct tm *timeinfo; + + if (LOGA_level == LOGA_DEBUG && options.verbose == 0) + return; + + ftime(&ts); + timeinfo = localtime(&ts.time); + strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo); + + sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm); + + va_start(args, format); + vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args); + va_end(args); + + printf("%s\n", msg_buf); + fflush(stdout); +} + + +#if defined(WIN32) || defined(_WINDOWS) +#define mqsleep(A) Sleep(1000*A) +#define START_TIME_TYPE DWORD +static DWORD start_time = 0; +START_TIME_TYPE start_clock(void) +{ + return GetTickCount(); +} +#elif defined(AIX) +#define mqsleep sleep +#define START_TIME_TYPE struct timespec +START_TIME_TYPE start_clock(void) +{ + static struct timespec start; + clock_gettime(CLOCK_REALTIME, &start); + return start; +} +#else +#define mqsleep sleep +#define START_TIME_TYPE struct timeval +/* TODO - unused - remove? static struct timeval start_time; */ +START_TIME_TYPE start_clock(void) +{ + struct timeval start_time; + gettimeofday(&start_time, NULL); + return start_time; +} +#endif + + +#if defined(WIN32) +long elapsed(START_TIME_TYPE start_time) +{ + return GetTickCount() - start_time; +} +#elif defined(AIX) +#define assert(a) +long elapsed(struct timespec start) +{ + struct timespec now, res; + + clock_gettime(CLOCK_REALTIME, &now); + ntimersub(now, start, res); + return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L; +} +#else +long elapsed(START_TIME_TYPE start_time) +{ + struct timeval now, res; + + gettimeofday(&now, NULL); + timersub(&now, &start_time, &res); + return (res.tv_sec)*1000 + (res.tv_usec)/1000; +} +#endif + + +#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d) +#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e) + +int tests = 0; +int failures = 0; +FILE* xml; +START_TIME_TYPE global_start_time; +char output[3000]; +char* cur_output = output; + + +void write_test_result() +{ + long duration = elapsed(global_start_time); + + fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000); + if (cur_output != output) + { + fprintf(xml, "%s", output); + cur_output = output; + } + fprintf(xml, "</testcase>\n"); +} + + +void myassert(char* filename, int lineno, char* description, int value, char* format, ...) +{ + ++tests; + if (!value) + { + va_list args; + + ++failures; + printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description); + + va_start(args, format); + vprintf(format, args); + va_end(args); + + cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n", + description, filename, lineno); + } + else + MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description); +} + +#define min(a, b) ((a < b) ? a : b) + +int checkMQTTStrings(MQTTString a, MQTTString b) +{ + if (!a.lenstring.data) + { + a.lenstring.data = a.cstring; + if (a.cstring) + a.lenstring.len = strlen(a.cstring); + } + if (!b.lenstring.data) + { + b.lenstring.data = b.cstring; + if (b.cstring) + b.lenstring.len = strlen(b.cstring); + } + return memcmp(a.lenstring.data, b.lenstring.data, min(a.lenstring.len, b.lenstring.len)) == 0; +} + + +int checkConnectPackets(MQTTPacket_connectData* before, MQTTPacket_connectData* after) +{ + int rc = 0; + int start_failures = failures; + + assert("struct_ids should be the same", + memcmp(before->struct_id, after->struct_id, 4) == 0, "struct_ids were different %.4s\n", after->struct_id); + + assert("struct_versions should be the same", + before->struct_version == after->struct_version, "struct_versions were different\n", rc); + + assert("MQTT versions should be the same", + before->MQTTVersion == after->MQTTVersion, "MQTT versions were different\n", rc); + + assert("ClientIDs should be the same", + checkMQTTStrings(before->clientID, after->clientID), "ClientIDs were different\n", rc); + + assert("keepAliveIntervals should be the same", + before->keepAliveInterval == after->keepAliveInterval, "keepAliveIntervals were different %d\n", after->keepAliveInterval); + + assert("cleansessions should be the same", + before->cleansession == after->cleansession, "cleansessions were different\n", rc); + + assert("willFlags should be the same", + before->willFlag == after->willFlag, "willFlags were different\n", rc); + + if (before->willFlag) + { + assert("will struct_ids should be the same", + memcmp(before->will.struct_id, after->will.struct_id, 4) == 0, "will struct_ids were different %.4s\n", after->struct_id); + + assert("will struct_versions should be the same", + before->will.struct_version == after->will.struct_version, "will struct_versions were different\n", rc); + + assert("topic names should be the same", + checkMQTTStrings(before->will.topicName, after->will.topicName), "topic names were different\n", rc); + + assert("messages should be the same", + checkMQTTStrings(before->will.message, after->will.message), "messages were different\n", rc); + + assert("retained flags should be the same", + before->will.retained == after->will.retained, "retained flags were different\n", rc); + + assert("will qos should be the same", + before->will.qos == after->will.qos, "will qos were different\n", rc); + } + + assert("usernames should be the same", + checkMQTTStrings(before->clientID, after->clientID), "usernames were different\n", rc); + assert("passwords should be the same", + checkMQTTStrings(before->password, after->password), "passwords were different\n", rc); + return failures == start_failures; +} + +int test1(struct Options options) +{ + MQTTPacket_connectData data = MQTTPacket_connectData_initializer; + MQTTPacket_connectData data_after = MQTTPacket_connectData_initializer; + int rc = 0; + char buf[100]; + int buflen = sizeof(buf); + + fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\""); + global_start_time = start_clock(); + failures = 0; + MyLog(LOGA_INFO, "Starting test 1 - serialization of connect and back"); + + data.clientID.cstring = "me"; + + data.keepAliveInterval = 20; + data.cleansession = 1; + data.username.cstring = "testuser"; + data.password.cstring = "testpassword"; + + data.willFlag = 1; + data.will.message.cstring = "will message"; + data.will.qos = 1; + data.will.retained = 0; + data.will.topicName.cstring = "will topic"; + + rc = MQTTSerialize_connect(buf, buflen, &data); + assert("good rc from serialize connect", rc > 0, "rc was %d\n", rc); + + rc = MQTTDeserialize_connect(&data_after, buf, buflen); + assert("good rc from deserialize connect", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + rc = checkConnectPackets(&data, &data_after); + assert("packets should be the same", rc == 1, "packets were different\n", rc); + +/* exit: */ + MyLog(LOGA_INFO, "TEST1: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + write_test_result(); + return failures; +} + + +int test2(struct Options options) +{ + int rc = 0; + char buf[100]; + int buflen = sizeof(buf); + + unsigned char dup = 0; + int qos = 2; + unsigned char retained = 0; + int msgid = 23; + MQTTString topicString = MQTTString_initializer; + char *payload = "kkhkhkjkj jkjjk jk jk "; + int payloadlen = strlen(payload); + + unsigned char dup2 = 1; + int qos2 = 1; + unsigned char retained2 = 1; + int msgid2 = 3243; + MQTTString topicString2 = MQTTString_initializer; + char *payload2 = NULL; + int payloadlen2 = 0; + + fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\""); + global_start_time = start_clock(); + failures = 0; + MyLog(LOGA_INFO, "Starting test 2 - serialization of publish and back"); + + topicString.cstring = "mytopic"; + rc = MQTTSerialize_publish(buf, buflen, dup, qos, retained, msgid, topicString, + payload, payloadlen); + assert("good rc from serialize publish", rc > 0, "rc was %d\n", rc); + + rc = MQTTDeserialize_publish(&dup2, &qos2, &retained2, &msgid2, &topicString2, + &payload2, &payloadlen2, buf, buflen); + assert("good rc from deserialize publish", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2); + assert("qoss should be the same", qos == qos2, "qoss were different %d\n", qos2); + assert("retaineds should be the same", retained == retained2, "retaineds were different %d\n", retained2); + assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2); + + assert("topics should be the same", + checkMQTTStrings(topicString, topicString2), "topics were different %s\n", ""); //topicString2); + + assert("payload lengths should be the same", + payloadlen == payloadlen2, "payload lengths were different %d\n", payloadlen2); + + assert("payloads should be the same", + memcmp(payload, payload2, payloadlen) == 0, "payloads were different %s\n", ""); + +/*exit:*/ + MyLog(LOGA_INFO, "TEST2: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + write_test_result(); + return failures; +} + + + +int test3(struct Options options) +{ + int i = 0; + int rc = 0; + char buf[100]; + int buflen = sizeof(buf); +#define TOPIC_COUNT 2 + + int dup = 0; + int msgid = 23; + int count = TOPIC_COUNT; + MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer }; + int req_qoss[TOPIC_COUNT] = {2, 1}; + + int dup2 = 1; + int msgid2 = 2223; + int count2 = 0; + MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer }; + int req_qoss2[TOPIC_COUNT] = {0, 0}; + + fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\""); + global_start_time = start_clock(); + failures = 0; + MyLog(LOGA_INFO, "Starting test 2 - serialization of subscribe and back"); + + topicStrings[0].cstring = "mytopic"; + topicStrings[1].cstring = "mytopic2"; + rc = MQTTSerialize_subscribe(buf, buflen, dup, msgid, count, topicStrings, req_qoss); + assert("good rc from serialize subscribe", rc > 0, "rc was %d\n", rc); + + rc = MQTTDeserialize_subscribe(&dup2, &msgid2, 2, &count2, topicStrings2, req_qoss2, buf, buflen); + assert("good rc from deserialize subscribe", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2); + assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2); + + assert("count should be the same", count == count2, "counts were different %d\n", count2); + + for (i = 0; i < count2; ++i) + { + assert("topics should be the same", + checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", ""); + + assert("qoss should be the same", req_qoss[i] == req_qoss2[i], "qoss were different %d\n", req_qoss2[i]); + } + +/*exit:*/ + MyLog(LOGA_INFO, "TEST3: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + write_test_result(); + return failures; +} + + +int test4(struct Options options) +{ + int i = 0; + int rc = 0; + char buf[100]; + int buflen = sizeof(buf); +#define TOPIC_COUNT 2 + + int msgid = 23; + int count = TOPIC_COUNT; + int granted_qoss[TOPIC_COUNT] = {2, 1}; +; + int msgid2 = 2223; + int count2 = 0; + int granted_qoss2[TOPIC_COUNT] = {0, 0}; + + fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\""); + global_start_time = start_clock(); + failures = 0; + MyLog(LOGA_INFO, "Starting test 4 - serialization of suback and back"); + + rc = MQTTSerialize_suback(buf, buflen, msgid, count, granted_qoss); + assert("good rc from serialize suback", rc > 0, "rc was %d\n", rc); + + rc = MQTTDeserialize_suback(&msgid2, 2, &count2, granted_qoss2, buf, buflen); + assert("good rc from deserialize suback", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2); + + assert("count should be the same", count == count2, "counts were different %d\n", count2); + + for (i = 0; i < count2; ++i) + assert("qoss should be the same", granted_qoss[i] == granted_qoss2[i], "qoss were different %d\n", granted_qoss2[i]); + +/* exit: */ + MyLog(LOGA_INFO, "TEST4: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + write_test_result(); + return failures; +} + + +int test5(struct Options options) +{ + int i = 0; + int rc = 0; + char buf[100]; + int buflen = sizeof(buf); +#define TOPIC_COUNT 2 + + int dup = 0; + int msgid = 23; + int count = TOPIC_COUNT; + MQTTString topicStrings[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer }; + + int dup2 = 1; + int msgid2 = 2223; + int count2 = 0; + MQTTString topicStrings2[TOPIC_COUNT] = { MQTTString_initializer, MQTTString_initializer }; + + fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\""); + global_start_time = start_clock(); + failures = 0; + MyLog(LOGA_INFO, "Starting test 2 - serialization of unsubscribe and back"); + + topicStrings[0].cstring = "mytopic"; + topicStrings[1].cstring = "mytopic2"; + rc = MQTTSerialize_unsubscribe(buf, buflen, dup, msgid, count, topicStrings); + assert("good rc from serialize unsubscribe", rc > 0, "rc was %d\n", rc); + + rc = MQTTDeserialize_unsubscribe(&dup2, &msgid2, 2, &count2, topicStrings2, buf, buflen); + assert("good rc from deserialize unsubscribe", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("dups should be the same", dup == dup2, "dups were different %d\n", dup2); + assert("msgids should be the same", msgid == msgid2, "msgids were different %d\n", msgid2); + + assert("count should be the same", count == count2, "counts were different %d\n", count2); + + for (i = 0; i < count2; ++i) + assert("topics should be the same", + checkMQTTStrings(topicStrings[i], topicStrings2[i]), "topics were different %s\n", ""); + +/* exit: */ + MyLog(LOGA_INFO, "TEST5: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + write_test_result(); + return failures; +} + + +int test6(struct Options options) +{ + int rc = 0; + char buf[100]; + int buflen = sizeof(buf); + + int connack_rc = 77; + + int connack_rc2 = 0; + + fprintf(xml, "<testcase classname=\"test1\" name=\"de/serialization\""); + global_start_time = start_clock(); + failures = 0; + MyLog(LOGA_INFO, "Starting test 2 - serialization of connack and back"); + + rc = MQTTSerialize_connack(buf, buflen, connack_rc); + assert("good rc from serialize connack", rc > 0, "rc was %d\n", rc); + + rc = MQTTDeserialize_connack(&connack_rc2, buf, buflen); + assert("good rc from deserialize connack", rc == 1, "rc was %d\n", rc); + + /* data after should be the same as data before */ + assert("dups should be the same", connack_rc == connack_rc2, "dups were different %d\n", connack_rc2); + +/* exit: */ + MyLog(LOGA_INFO, "TEST6: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", tests, failures); + write_test_result(); + return failures; +} + + +int main(int argc, char** argv) +{ + int rc = 0; + int (*tests[])() = {NULL, test1, test2, test3, test4, test5, test6}; + + xml = fopen("TEST-test1.xml", "w"); + fprintf(xml, "<testsuite name=\"test1\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests) - 1)); + + getopts(argc, argv); + + if (options.test_no == 0) + { /* run all the tests */ + for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no) + rc += tests[options.test_no](options); /* return number of failures. 0 = test succeeded */ + } + else + rc = tests[options.test_no](options); /* run just the selected test */ + + if (rc == 0) + MyLog(LOGA_INFO, "verdict pass"); + else + MyLog(LOGA_INFO, "verdict fail"); + + fprintf(xml, "</testsuite>\n"); + fclose(xml); + return rc; +}
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTSManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTSManager.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,133 @@ +#include "MQTTSManager.h" +#include "XbeeMonitor.h" +#include "Utils.h" +#include "jsmn.h" +#include <string> + +using namespace MQTT; + +#define MQTTS_PORT 8883 + +static const char * topic_update = "garden_update"; +static const char * topic_listen = "garden_status"; +static const char * hostname = "mqtt.mbedhacks.com"; +static const char * clientID = "mbed-sample"; +static const char * username = "mbedhacks"; +static const char * password = "qwer123"; + +static MQTTThreadedClient * pmqtt = NULL; +Thread mqttThd(osPriorityNormal, DEFAULT_STACK_SIZE * 2); +RadioControlData postdata; +static char tempbuff[100]; + +static int jsoneq(const char * json, jsmntok_t * tok, const char * s) +{ + if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start && + strncmp(json + tok->start, s, tok->end - tok->start) == 0) { + return 0; + } + return -1; +} + +void messageArrived(MessageData& md) +{ + int i, r; + + jsmn_parser p; + jsmntok_t t[100]; + + Message &message = md.message; + printf("Arrived Callback 1 : qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id); + printf("Payload [%.*s]\r\n", message.payloadlen, (char*)message.payload); + + // handle payload + const char * jsonstring = std::string((const char *) message.payload, message.payloadlen).c_str(); + + jsmn_init(&p); + r = jsmn_parse(&p, jsonstring, strlen(jsonstring), t, sizeof(t)/sizeof(t[0])); + + uint64_t radio_id = 0; + int sprinkler_pin = 1; // 0 - turn on sprinkler, 1 - off + + /* Top level element is an object */ + if ((r > 0) && (t[0].type == JSMN_OBJECT)) + { + /* Loop over all tokens */ + for (i = 1; i < r; i++) + { + if (jsoneq(jsonstring, &t[i], "radioid") == 0) + { + memset(tempbuff, 0, sizeof(tempbuff)); + strncpy(tempbuff, jsonstring + t[i+1].start, t[i+1].end - t[i+1].start); + radio_id = strtoull(&tempbuff[0], NULL, 0); + i++; + } + else if (jsoneq(jsonstring, &t[i], "sprinkler") == 0) + { + memset(tempbuff, 0, sizeof(tempbuff)); + strncpy(tempbuff, jsonstring + t[i+1].start, t[i+1].end - t[i+1].start); + sprinkler_pin = strtoul(&tempbuff[0], NULL, 0); + i++; + } + else + { + + } + } + } + + // TODO: Send the values to the XBeeMonitor thread + printf("Radio ID: %llu\r\n", radio_id); + printf("Sprinkler Pin : %d\r\n", sprinkler_pin); + postdata.radioID = radio_id; + postdata.sprinkler_pin = sprinkler_pin; + postRadioControl(postdata); +} + +int mqttsInit(NetworkInterface * net, const char * pem) +{ + pmqtt = new MQTTThreadedClient(net, pem); + if (pmqtt == NULL) + return -1; + + MQTTPacket_connectData logindata = MQTTPacket_connectData_initializer; + logindata.MQTTVersion = 3; + logindata.clientID.cstring = (char *) clientID; + logindata.username.cstring = (char *) username; + logindata.password.cstring = (char *) password; + + pmqtt->setConnectionParameters(hostname, MQTTS_PORT, logindata); + pmqtt->addTopicHandler(topic_listen, messageArrived); + + return 0; +} + +void postMQTTUpdate(SensorData &msg) +{ + // Serialize data to json string ... + if (pmqtt) + { + PubMessage message; + message.qos = QOS0; + message.id = 123; + + strcpy(&message.topic[0], topic_update); + size_t numbytes = snprintf(&message.payload[0], MAX_MQTT_PAYLOAD_SIZE, + "{\"radio\":%llu,\"status\":{\"sprinkler\":%d,\"humidity\":%d,\"temperature\":%.2f,\"luminance\":%d}}", + msg.deviceaddr, + msg.sprinkler, + msg.humidity, + msg.temperature, + msg.luminance); + printf("[%s]\r\n", &message.payload[0]); + message.payloadlen = numbytes; + pmqtt->publish(message); + } +} + +int runMQTTS() +{ + if ( pmqtt && (mqttThd.start(mbed::callback(pmqtt, &MQTTThreadedClient::startListener)) != osOK ) ) + return -1; + return 0; +} \ No newline at end of file
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTSManager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTSManager.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,13 @@ +#ifndef _MQTTS_MANAGER_H_ +#define _MQTTS_MANAGER_H_ + + +#include "MQTTThreadedClient.h" +#include "Sensor.h" + + +int mqttsInit(NetworkInterface * net, const char * pem); +void postMQTTUpdate(SensorData &msg); +int runMQTTS(); + +#endif
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTThreadedClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTThreadedClient.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,941 @@ +#include "mbed.h" +#include "rtos.h" +#include "MQTTThreadedClient.h" +#include "mbedtls/platform.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" + +#ifdef DEBUG +#define DBG(fmt, args...) printf(fmt, ## args) +#else +#define DBG(fmt, args...) /* Don't do anything in release builds */ +#endif + +static MemoryPool<MQTT::PubMessage, 4> mpool; +static Queue<MQTT::PubMessage, 4> mqueue; + +// SSL/TLS variables +mbedtls_entropy_context _entropy; +mbedtls_ctr_drbg_context _ctr_drbg; +mbedtls_x509_crt _cacert; +mbedtls_ssl_context _ssl; +mbedtls_ssl_config _ssl_conf; +mbedtls_ssl_session saved_session; + +namespace MQTT { + +/** + * Receive callback for mbed TLS + */ +static int ssl_recv(void *ctx, unsigned char *buf, size_t len) +{ + int recv = -1; + TCPSocket *socket = static_cast<TCPSocket *>(ctx); + socket->set_timeout(DEFAULT_SOCKET_TIMEOUT); + recv = socket->recv(buf, len); + + if (NSAPI_ERROR_WOULD_BLOCK == recv) { + return MBEDTLS_ERR_SSL_WANT_READ; + } else if (recv < 0) { + return -1; + } else { + return recv; + } +} + +/** + * Send callback for mbed TLS + */ +static int ssl_send(void *ctx, const unsigned char *buf, size_t len) +{ + int sent = -1; + TCPSocket *socket = static_cast<TCPSocket *>(ctx); + socket->set_timeout(DEFAULT_SOCKET_TIMEOUT); + sent = socket->send(buf, len); + + if(NSAPI_ERROR_WOULD_BLOCK == sent) { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } else if (sent < 0) { + return -1; + } else { + return sent; + } +} + +#if DEBUG_LEVEL > 0 +/** + * Debug callback for mbed TLS + * Just prints on the USB serial port + */ +static void my_debug(void *ctx, int level, const char *file, int line, + const char *str) +{ + const char *p, *basename; + (void) ctx; + + /* Extract basename from file */ + for(p = basename = file; *p != '\0'; p++) { + if(*p == '/' || *p == '\\') { + basename = p + 1; + } + } + + if (_debug) { + mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); + } +} + +/** + * Certificate verification callback for mbed TLS + * Here we only use it to display information on each cert in the chain + */ +static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) +{ + const uint32_t buf_size = 1024; + char *buf = new char[buf_size]; + (void) data; + + if (_debug) mbedtls_printf("\nVerifying certificate at depth %d:\r\n", depth); + mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); + if (_debug) mbedtls_printf("%s", buf); + + if (*flags == 0) + if (_debug) mbedtls_printf("No verification issue for this certificate\r\n"); + else { + mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); + if (_debug) mbedtls_printf("%s\n", buf); + } + + delete[] buf; + return 0; +} +#endif + + +void MQTTThreadedClient::setupTLS() +{ + if (useTLS) + { + mbedtls_entropy_init(&_entropy); + mbedtls_ctr_drbg_init(&_ctr_drbg); + mbedtls_x509_crt_init(&_cacert); + mbedtls_ssl_init(&_ssl); + mbedtls_ssl_config_init(&_ssl_conf); + memset( &saved_session, 0, sizeof( mbedtls_ssl_session ) ); + } +} + +void MQTTThreadedClient::freeTLS() +{ + if (useTLS) + { + mbedtls_entropy_free(&_entropy); + mbedtls_ctr_drbg_free(&_ctr_drbg); + mbedtls_x509_crt_free(&_cacert); + mbedtls_ssl_free(&_ssl); + mbedtls_ssl_config_free(&_ssl_conf); + } +} + +int MQTTThreadedClient::initTLS() +{ + int ret; + + DBG("Initializing TLS ...\r\n"); + DBG("mbedtls_ctr_drdbg_seed ...\r\n"); + if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy, + (const unsigned char *) DRBG_PERS, + sizeof (DRBG_PERS))) != 0) { + mbedtls_printf("mbedtls_crt_drbg_init returned [%x]\r\n", ret); + _error = ret; + return -1; + } + DBG("mbedtls_x509_crt_parse ...\r\n"); + if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *) ssl_ca_pem, + strlen(ssl_ca_pem) + 1)) != 0) { + mbedtls_printf("mbedtls_x509_crt_parse returned [%x]\r\n", ret); + _error = ret; + return -1; + } + + DBG("mbedtls_ssl_config_defaults ...\r\n"); + if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + mbedtls_printf("mbedtls_ssl_config_defaults returned [%x]\r\n", ret); + _error = ret; + return -1; + } + + DBG("mbedtls_ssl_config_ca_chain ...\r\n"); + mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL); + DBG("mbedtls_ssl_conf_rng ...\r\n"); + mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg); + + /* It is possible to disable authentication by passing + * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode() + */ + DBG("mbedtls_ssl_conf_authmode ...\r\n"); + mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); + +#if DEBUG_LEVEL > 0 + mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL); + mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL); + mbedtls_debug_set_threshold(DEBUG_LEVEL); +#endif + + DBG("mbedtls_ssl_setup ...\r\n"); + if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) { + mbedtls_printf("mbedtls_ssl_setup returned [%x]\r\n", ret); + _error = ret; + return -1; + } + + return 0; +} + +int MQTTThreadedClient::doTLSHandshake() +{ + int ret; + + /* Start the handshake, the rest will be done in onReceive() */ + DBG("Starting the TLS handshake...\r\n"); + ret = mbedtls_ssl_handshake(&_ssl); + if (ret < 0) + { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE) + mbedtls_printf("mbedtls_ssl_handshake returned [%x]\r\n", ret); + else + { + // do not close the socket if timed out + ret = TIMEOUT; + } + return ret; + } + + /* Handshake done, time to print info */ + DBG("TLS connection to %s:%d established\r\n", + host.c_str(), port); + + const uint32_t buf_size = 1024; + char *buf = new char[buf_size]; + mbedtls_x509_crt_info(buf, buf_size, "\r ", + mbedtls_ssl_get_peer_cert(&_ssl)); + + DBG("Server certificate:\r\n%s\r", buf); + // Verify server cert ... + uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl); + if( flags != 0 ) + { + mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags); + DBG("Certificate verification failed:\r\n%s\r\r\n", buf); + // free server cert ... before error return + delete [] buf; + return -1; + } + + DBG("Certificate verification passed\r\n\r\n"); + // delete server cert after verification + delete [] buf; + +#if defined(MBEDTLS_SSL_CLI_C) + // TODO: Save the session here for reconnect. + if( ( ret = mbedtls_ssl_get_session( &_ssl, &saved_session ) ) != 0 ) + { + mbedtls_printf( "mbedtls_ssl_get_session returned -0x%x\n\n", -ret ); + hasSavedSession = false; + return -1; + } +#endif + DBG("Session saved for reconnect ...\r\n"); + hasSavedSession = true; + + return 0; +} + +int MQTTThreadedClient::readBytesToBuffer(char * buffer, size_t size, int timeout) +{ + int rc; + + if (tcpSocket == NULL) + return -1; + + if (useTLS) + { + // Do SSL/TLS read + rc = mbedtls_ssl_read(&_ssl, (unsigned char *) buffer, size); + if (MBEDTLS_ERR_SSL_WANT_READ == rc) + return TIMEOUT; + else + return rc; + } else { + // non-blocking socket ... + tcpSocket->set_timeout(timeout); + rc = tcpSocket->recv( (void *) buffer, size); + + // return 0 bytes if timeout ... + if (NSAPI_ERROR_WOULD_BLOCK == rc) + return TIMEOUT; + else + return rc; // return the number of bytes received or error + } +} + +int MQTTThreadedClient::sendBytesFromBuffer(char * buffer, size_t size, int timeout) +{ + int rc; + + if (tcpSocket == NULL) + return -1; + + if (useTLS) { + // Do SSL/TLS write + rc = mbedtls_ssl_write(&_ssl, (const unsigned char *) buffer, size); + if (MBEDTLS_ERR_SSL_WANT_WRITE == rc) + return TIMEOUT; + else + return rc; + } else { + + // set the write timeout + tcpSocket->set_timeout(timeout); + rc = tcpSocket->send(buffer, size); + + if ( NSAPI_ERROR_WOULD_BLOCK == rc) + return TIMEOUT; + else + return rc; + } +} + +int MQTTThreadedClient::readPacketLength(int* value) +{ + int rc = MQTTPACKET_READ_ERROR; + unsigned char c; + int multiplier = 1; + int len = 0; + const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4; + + *value = 0; + do + { + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) + { + rc = MQTTPACKET_READ_ERROR; /* bad data */ + goto exit; + } + + rc = readBytesToBuffer((char *) &c, 1, DEFAULT_SOCKET_TIMEOUT); + if (rc != 1) + { + rc = MQTTPACKET_READ_ERROR; + goto exit; + } + + *value += (c & 127) * multiplier; + multiplier *= 128; + } while ((c & 128) != 0); + + rc = MQTTPACKET_READ_COMPLETE; + +exit: + if (rc == MQTTPACKET_READ_ERROR ) + len = -1; + + return len; +} + +int MQTTThreadedClient::sendPacket(size_t length) +{ + int rc = FAILURE; + int sent = 0; + + while (sent < length) + { + rc = sendBytesFromBuffer((char *) &sendbuf[sent], length - sent, DEFAULT_SOCKET_TIMEOUT); + if (rc < 0) // there was an error writing the data + break; + sent += rc; + } + + if (sent == length) + rc = SUCCESS; + else + rc = FAILURE; + + return rc; +} +/** + * Reads the entire packet to readbuf and returns + * the type of packet when successful, otherwise + * a negative error code is returned. + **/ +int MQTTThreadedClient::readPacket() +{ + int rc = FAILURE; + MQTTHeader header = {0}; + int len = 0; + int rem_len = 0; + + /* 1. read the header byte. This has the packet type in it */ + if ( (rc = readBytesToBuffer((char *) &readbuf[0], 1, DEFAULT_SOCKET_TIMEOUT)) != 1) + goto exit; + + len = 1; + /* 2. read the remaining length. This is variable in itself */ + if ( readPacketLength(&rem_len) < 0 ) + goto exit; + + len += MQTTPacket_encode(readbuf + 1, rem_len); /* put the original remaining length into the buffer */ + + if (rem_len > (MAX_MQTT_PACKET_SIZE - len)) + { + rc = BUFFER_OVERFLOW; + goto exit; + } + + /* 3. read the rest of the buffer using a callback to supply the rest of the data */ + if (rem_len > 0 && (readBytesToBuffer((char *) (readbuf + len), rem_len, DEFAULT_SOCKET_TIMEOUT) != rem_len)) + goto exit; + + // Convert the header to type + // and update rc + header.byte = readbuf[0]; + rc = header.bits.type; + +exit: + + return rc; +} + +/** + * Read until a specified packet type is received, or untill the specified + * timeout dropping packets along the way. + **/ +int MQTTThreadedClient::readUntil(int packetType, int timeout) +{ + int pType = FAILURE; + Timer timer; + + timer.start(); + do { + pType = readPacket(); + if (pType < 0) + break; + + if (timer.read_ms() > timeout) + { + pType = FAILURE; + break; + } + }while(pType != packetType); + + return pType; +} + + +int MQTTThreadedClient::login() +{ + int rc = FAILURE; + int len = 0; + + if (!isConnected) + { + DBG("Session not connected! \r\n"); + return rc; + } + + // Copy the keepAliveInterval value to local + // MQTT specifies in seconds, we have to multiply that + // amount for our 32 bit timers which accepts ms. + keepAliveInterval = (connect_options.keepAliveInterval * 1000); + + DBG("Login with: \r\n"); + DBG("\tUsername: [%s]\r\n", connect_options.username.cstring); + DBG("\tPassword: [%s]\r\n", connect_options.password.cstring); + + if ((len = MQTTSerialize_connect(sendbuf, MAX_MQTT_PACKET_SIZE, &connect_options)) <= 0) + { + DBG("Error serializing connect packet ...\r\n"); + return rc; + } + if ((rc = sendPacket((size_t) len)) != SUCCESS) // send the connect packet + { + DBG("Error sending the connect request packet ...\r\n"); + return rc; + } + + // Wait for the CONNACK + if (readUntil(CONNACK, COMMAND_TIMEOUT) == CONNACK) + { + unsigned char connack_rc = 255; + bool sessionPresent = false; + DBG("Connection acknowledgement received ... deserializing respones ...\r\n"); + if (MQTTDeserialize_connack((unsigned char*)&sessionPresent, &connack_rc, readbuf, MAX_MQTT_PACKET_SIZE) == 1) + rc = connack_rc; + else + rc = FAILURE; + } + else + rc = FAILURE; + + if (rc == SUCCESS) + { + DBG("Connected!!! ... starting connection timers ...\r\n"); + resetConnectionTimer(); + } + + DBG("Returning with rc = %d\r\n", rc); + + return rc; +} + + +void MQTTThreadedClient::disconnect() +{ + if (isConnected) + { + if( useTLS + && ( mbedtls_ssl_session_reset( &_ssl ) != 0 ) + ) + { + DBG( "Session reset returned an error \r\n"); + } + + isConnected = false; + tcpSocket->close(); + } +} + +int MQTTThreadedClient::connect() +{ + int ret = FAILURE; + + if ((network == NULL) || (tcpSocket == NULL) + || host.empty()) + { + DBG("Network settings not set! \r\n"); + return ret; + } + + if (useTLS) + { + if( ( ret = mbedtls_ssl_session_reset( &_ssl ) ) != 0 ) { + mbedtls_printf( " failed\n ! mbedtls_ssl_session_reset returned -0x%x\n\n", -ret ); + return ret; + } +#if defined(MBEDTLS_SSL_CLI_C) + if ( hasSavedSession && (( ret = mbedtls_ssl_set_session( &_ssl, &saved_session ) ) != 0 )) { + mbedtls_printf( " failed\n ! mbedtls_ssl_conf_session returned %d\n\n", ret ); + return ret; + } +#endif + } + + tcpSocket->open(network); + if (useTLS) + { + DBG("mbedtls_ssl_set_hostname ...\r\n"); + mbedtls_ssl_set_hostname(&_ssl, host.c_str()); + DBG("mbedtls_ssl_set_bio ...\r\n"); + mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(tcpSocket), + ssl_send, ssl_recv, NULL ); + } + + if (( ret = tcpSocket->connect(host.c_str(), port)) < 0 ) + { + DBG("Error connecting to %s:%d with %d\r\n", host.c_str(), port, ret); + return ret; + }else + isConnected = true; + + if (useTLS) + { + + if (doTLSHandshake() < 0) + { + DBG("TLS Handshake failed! \r\n"); + return FAILURE; + }else + DBG("TLS Handshake complete!! \r\n"); + } + + return login(); +} + +void MQTTThreadedClient::setConnectionParameters(const char * chost, uint16_t cport, MQTTPacket_connectData & options) +{ + // Copy the settings for reconnection + host = chost; + port = cport; + connect_options = options; +} + +int MQTTThreadedClient::publish(PubMessage& msg) +{ +#if 0 + int id = queue.call(mbed::callback(this, &MQTTThreadedClient::sendPublish), topic, message); + // TODO: handle id values when the function is called later + if (id == 0) + return FAILURE; + else + return SUCCESS; +#endif + PubMessage *message = mpool.alloc(); + // Simple copy + *message = msg; + + // Push the data to the thread + DBG("[Thread:%d] Pushing data to consumer thread ...\r\n", Thread::gettid()); + mqueue.put(message); + + return SUCCESS; +} + +int MQTTThreadedClient::sendPublish(PubMessage& message) +{ + MQTTString topicString = MQTTString_initializer; + + if (!isConnected) + { + DBG("[Thread:%d] Not connected!!! ...\r\n", Thread::gettid()); + return FAILURE; + } + + topicString.cstring = (char*) &message.topic[0]; + int len = MQTTSerialize_publish(sendbuf, MAX_MQTT_PACKET_SIZE, 0, message.qos, false, message.id, + topicString, (unsigned char*) &message.payload[0], (int) message.payloadlen); + if (len <= 0) + { + DBG("[Thread:%d]Failed serializing message ...\r\n", Thread::gettid()); + return FAILURE; + } + + if (sendPacket(len) == SUCCESS) + { + DBG("[Thread:%d]Successfully sent publish packet to server ...\r\n", Thread::gettid()); + return SUCCESS; + } + + DBG("[Thread:%d]Failed to send publish packet to server ...\r\n", Thread::gettid()); + return FAILURE; +} + +void MQTTThreadedClient::addTopicHandler(const char * topicstr, void (*function)(MessageData &)) +{ + // Push the subscription into the map ... + FP<void,MessageData &> fp; + fp.attach(function); + + topicCBMap.insert(std::pair<std::string, FP<void,MessageData &> >(std::string(topicstr),fp)); +} + +int MQTTThreadedClient::processSubscriptions() +{ + int numsubscribed = 0; + + if (!isConnected) + { + DBG("Session not connected!!\r\n"); + return 0; + } + + DBG("Processing subscribed topics ....\r\n"); + + std::map<std::string, FP<void, MessageData &> >::iterator it; + for(it = topicCBMap.begin(); it != topicCBMap.end(); it++) + { + int rc = FAILURE; + int len = 0; + //TODO: We only subscribe to QoS = 0 for now + QoS qos = QOS0; + + MQTTString topic = {(char*)it->first.c_str(), {0, 0}}; + DBG("Subscribing to topic [%s]\r\n", topic.cstring); + + + len = MQTTSerialize_subscribe(sendbuf, MAX_MQTT_PACKET_SIZE, 0, packetid.getNext(), 1, &topic, (int*)&qos); + if (len <= 0) { + DBG("Error serializing subscribe packet ...\r\n"); + continue; + } + + if ((rc = sendPacket(len)) != SUCCESS) { + DBG("Error sending subscribe packet [%d]\r\n", rc); + continue; + } + + DBG("Waiting for subscription ack ...\r\n"); + // Wait for SUBACK, dropping packets read along the way ... + if (readUntil(SUBACK, COMMAND_TIMEOUT) == SUBACK) { // wait for suback + int count = 0, grantedQoS = -1; + unsigned short mypacketid; + if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, readbuf, MAX_MQTT_PACKET_SIZE) == 1) + rc = grantedQoS; // 0, 1, 2 or 0x80 + // For as long as we do not get 0x80 .. + if (rc != 0x80) + { + // Reset connection timers here ... + resetConnectionTimer(); + DBG("Successfully subscribed to %s ...\r\n", it->first.c_str()); + numsubscribed++; + } else { + DBG("Failed to subscribe to topic %s ... (not authorized?)\r\n", it->first.c_str()); + } + } else + DBG("Failed to subscribe to topic %s (ack not received) ...\r\n", it->first.c_str()); + } // end for loop + + return numsubscribed; +} + +bool MQTTThreadedClient::isTopicMatched(char* topicFilter, MQTTString& topicName) +{ + char* curf = topicFilter; + char* curn = topicName.lenstring.data; + char* curn_end = curn + topicName.lenstring.len; + + while (*curf && curn < curn_end) + { + if (*curn == '/' && *curf != '/') + break; + if (*curf != '+' && *curf != '#' && *curf != *curn) + break; + if (*curf == '+') + { // skip until we meet the next separator, or end of string + char* nextpos = curn + 1; + while (nextpos < curn_end && *nextpos != '/') + nextpos = ++curn + 1; + } + else if (*curf == '#') + curn = curn_end - 1; // skip until end of string + curf++; + curn++; + }; + + return (curn == curn_end) && (*curf == '\0'); +} + +int MQTTThreadedClient::handlePublishMsg() +{ + MQTTString topicName = MQTTString_initializer; + Message msg; + int intQoS; + DBG("[Thread:%d]Deserializing publish message ...\r\n", Thread::gettid()); + if (MQTTDeserialize_publish((unsigned char*)&msg.dup, + &intQoS, + (unsigned char*)&msg.retained, + (unsigned short*)&msg.id, + &topicName, + (unsigned char**)&msg.payload, + (int*)&msg.payloadlen, readbuf, MAX_MQTT_PACKET_SIZE) != 1) + { + DBG("[Thread:%d]Error deserializing published message ...\r\n", Thread::gettid()); + return -1; + } + + std::string topic; + if (topicName.lenstring.len > 0) + { + topic = std::string((const char *) topicName.lenstring.data, (size_t) topicName.lenstring.len); + }else + topic = (const char *) topicName.cstring; + + DBG("[Thread:%d]Got message for topic [%s], QoS [%d] ...\r\n", Thread::gettid(), topic.c_str(), intQoS); + + msg.qos = (QoS) intQoS; + + + // Call the handlers for each topic + if (topicCBMap.find(topic) != topicCBMap.end()) + { + // Call the callback function + if (topicCBMap[topic].attached()) + { + DBG("[Thread:%d]Invoking function handler for topic ...\r\n", Thread::gettid()); + MessageData md(topicName, msg); + topicCBMap[topic](md); + + return 1; + } + } + + // TODO: depending on the QoS + // we send data to the server = PUBACK or PUBREC + switch(intQoS) + { + case QOS0: + // We send back nothing ... + break; + case QOS1: + // TODO: implement + break; + case QOS2: + // TODO: implement + break; + default: + break; + } + + return 0; +} + +void MQTTThreadedClient::resetConnectionTimer() +{ + if (keepAliveInterval > 0) + { + comTimer.reset(); + comTimer.start(); + } +} + +bool MQTTThreadedClient::hasConnectionTimedOut() +{ + if (keepAliveInterval > 0 ) { + // Check connection timer + if (comTimer.read_ms() > keepAliveInterval) + return true; + else + return false; + } + + return false; +} + +void MQTTThreadedClient::sendPingRequest() +{ + int len = MQTTSerialize_pingreq(sendbuf, MAX_MQTT_PACKET_SIZE); + if (len > 0 && (sendPacket(len) == SUCCESS)) // send the ping packet + { + printf("MQTT Ping request sent successfully ...\r\n"); + } +} + +void MQTTThreadedClient::startListener() +{ + int pType; + int numsubs; + // Continuesly listens for packets and dispatch + // message handlers ... + if (useTLS) + { + initTLS(); + } + + while(true) + { + + // Attempt to reconnect and login + if ( connect() < 0 ) + { + disconnect(); + // Wait for a few secs and reconnect ... + Thread::wait(6000); + continue; + } + + numsubs = processSubscriptions(); + DBG("Subscribed %d topics ...\r\n", numsubs); + + // loop read + while(true) + { + pType = readPacket(); + switch(pType) + { + case TIMEOUT: + // No data available from the network ... + break; + case FAILURE: + { + DBG("readPacket returned failure \r\n"); + goto reconnect; + } + case BUFFER_OVERFLOW: + { + // TODO: Network error, do we disconnect and reconnect? + DBG("[Thread:%d]Failure or buffer overflow problem ... \r\n", Thread::gettid()); + MBED_ASSERT(false); + } + break; + /** + * The rest of the return codes below (all positive) is about MQTT + * response codes + **/ + case CONNACK: + case PUBACK: + case SUBACK: + break; + case PUBLISH: + { + DBG("[Thread:%d]Publish received!....\r\n", Thread::gettid()); + // We receive data from the MQTT server .. + if (handlePublishMsg() < 0) { + DBG("[Thread:%d]Error handling PUBLISH message ... \r\n", Thread::gettid()); + break; + } + } + break; + case PINGRESP: + { + printf("MQTT Got ping response ...\r\n"); + resetConnectionTimer(); + } + break; + default: + DBG("[Thread:%d]Unknown/Not handled message from server pType[%d]\r\n", Thread::gettid(), pType); + } + + // Check if its time to send a keepAlive packet + if (hasConnectionTimedOut()) { + // Queue the ping request so that other + // pending operations queued above will go first + queue.call(this, &MQTTThreadedClient::sendPingRequest); + } + + // Check if we have messages on the message queue + osEvent evt = mqueue.get(10); + if (evt.status == osEventMessage) { + + DBG("[Thread:%d]Got message to publish! ... \r\n", Thread::gettid()); + + // Unpack the message + PubMessage * message = (PubMessage *)evt.value.p; + + // Send the packet, do not queue the call + // like the ping above .. + if ( sendPublish(*message) == SUCCESS) { + // Reset timers if we have been able to send successfully + resetConnectionTimer(); + } else { + // Disconnected? + goto reconnect; + } + + // Free the message from mempool after using + mpool.free(message); + } + + // Dispatch any queued events ... + queue.dispatch(100); + } // end while loop + +reconnect: + // reconnect? + DBG("Client disconnected!! ... retrying ...\r\n"); + disconnect(); + + }; +} + +void MQTTThreadedClient::stopListener() +{ + // TODO: Set a signal/flag that the running thread + // will check if its ok to stop ... +} + +} \ No newline at end of file
diff -r 000000000000 -r a1734fe1ec4b MQTTSManager/MQTTThreadedClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MQTTSManager/MQTTThreadedClient.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,197 @@ +#ifndef _MQTT_THREADED_CLIENT_H_ +#define _MQTT_THREADED_CLIENT_H_ + +#include "mbed.h" +#include "rtos.h" +#include "MQTTPacket.h" +#include "NetworkInterface.h" +#include "FP.h" +#include "config.h" + +#include <cstdio> +#include <string> +#include <map> + +//#define MQTT_DEBUG 1 + + +#define COMMAND_TIMEOUT 5000 +#define DEFAULT_SOCKET_TIMEOUT 1000 +#define MAX_MQTT_PACKET_SIZE 500 +#define MAX_MQTT_PAYLOAD_SIZE 300 + +namespace MQTT +{ + +typedef enum { QOS0, QOS1, QOS2 } QoS; + +// all failure return codes must be negative +typedef enum { BUFFER_OVERFLOW = -3, TIMEOUT = -2, FAILURE = -1, SUCCESS = 0 } returnCode; + + +typedef struct +{ + QoS qos; + bool retained; + bool dup; + unsigned short id; + void *payload; + size_t payloadlen; +}Message, *pMessage; + +// TODO: +// Merge this struct with the one above, in order to use the same +// data structure for sending and receiving. I need to simplify +// the PubMessage to not contain pointers like the one above. +typedef struct +{ + char topic[100]; + QoS qos; + unsigned short id; + size_t payloadlen; + char payload[MAX_MQTT_PAYLOAD_SIZE]; +}PubMessage, *pPubMessage; + +struct MessageData +{ + MessageData(MQTTString &aTopicName, Message &aMessage) : message(aMessage), topicName(aTopicName) + { } + Message &message; + MQTTString &topicName; +}; + +class PacketId +{ +public: + PacketId() + { + next = 0; + } + + int getNext() + { + return next = (next == MAX_PACKET_ID) ? 1 : ++next; + } + +private: + static const int MAX_PACKET_ID = 65535; + int next; +}; + + + +class MQTTThreadedClient +{ +public: + MQTTThreadedClient(NetworkInterface * aNetwork, const char * pem = NULL) + : network(aNetwork), + ssl_ca_pem(pem), + port((pem != NULL) ? 8883 : 1883), + queue(32 * EVENTS_EVENT_SIZE), + isConnected(false), + hasSavedSession(false), + useTLS(pem != NULL) + { + DRBG_PERS = "mbed TLS MQTT client"; + tcpSocket = new TCPSocket(); + setupTLS(); + } + + ~MQTTThreadedClient() + { + // TODO: signal the thread to shutdown + freeTLS(); + + if (isConnected) + disconnect(); + + } + /** + * Sets the connection parameters. Must be called before running the startListener as a thread. + * + * @param host - pointer to the host where the MQTT server is running + * @param port - the port number to connect, 1883 for non secure connections, 8883 for + * secure connections + * @param options - the connect data used for logging into the MQTT server. + */ + void setConnectionParameters(const char * host, uint16_t port, MQTTPacket_connectData & options); + int publish(PubMessage& message); + + void addTopicHandler(const char * topic, void (*function)(MessageData &)); + template<typename T> + void addTopicHandler(const char * topic, T *object, void (T::*member)(MessageData &)) + { + FP<void,MessageData &> fp; + fp.attach(object, member); + + topicCBMap.insert(std::pair<std::string, FP<void,MessageData &> >(std::string(topic),fp)); + } + + // TODO: Add unsubscribe functionality. + + // Start the listener thread and start polling + // MQTT server. + void startListener(); + // Stop the listerner thread and closes connection + void stopListener(); + +protected: + + int handlePublishMsg(); + void disconnect(); + int connect(); + + +private: + NetworkInterface * network; + const char * ssl_ca_pem; + TCPSocket * tcpSocket; + PacketId packetid; + const char *DRBG_PERS; + nsapi_error_t _error; + // Connection options + std::string host; + uint16_t port; + MQTTPacket_connectData connect_options; + // Event queue + EventQueue queue; + bool isConnected; + bool hasSavedSession; + + // TODO: Because I'm using a map, I can only have one handler + // for each topic (one that's mapped to the topic string). + // Attaching another handler on the same topic is not possible. + // In the future, use a vector instead of maps to allow multiple + // handlers for the same topic. + std::map<std::string, FP<void, MessageData &> > topicCBMap; + + unsigned char sendbuf[MAX_MQTT_PACKET_SIZE]; + unsigned char readbuf[MAX_MQTT_PACKET_SIZE]; + + unsigned int keepAliveInterval; + Timer comTimer; + + // SSL/TLS functions + bool useTLS; + void setupTLS(); + int initTLS(); + void freeTLS(); + int doTLSHandshake(); + + int processSubscriptions(); + int readPacket(); + int sendPacket(size_t length); + int readPacketLength(int* value); + int readUntil(int packetType, int timeout); + int readBytesToBuffer(char * buffer, size_t size, int timeout); + int sendBytesFromBuffer(char * buffer, size_t size, int timeout); + bool isTopicMatched(char* topic, MQTTString& topicName); + int sendPublish(PubMessage& message); + void resetConnectionTimer(); + void sendPingRequest(); + bool hasConnectionTimedOut(); + int login(); +}; + +} +#endif
diff -r 000000000000 -r a1734fe1ec4b NTPClient/NTPClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NTPClient/NTPClient.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,185 @@ +/* NTPClient.cpp */ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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. + */ + +//Debug is disabled by default +#if 0 +//Enable debug +#define __DEBUG__ +#include <cstdio> +#define DBG(x, ...) std::printf("[NTPClient : DBG]"x"\r\n", ##__VA_ARGS__); +#define WARN(x, ...) std::printf("[NTPClient : WARN]"x"\r\n", ##__VA_ARGS__); +#define ERR(x, ...) std::printf("[NTPClient : ERR]"x"\r\n", ##__VA_ARGS__); + +#else +//Disable debug +#define DBG(x, ...) +#define WARN(x, ...) +#define ERR(x, ...) + +#endif +#include "NetworkInterface.h" +#include "NTPClient.h" + +#include "UDPSocket.h" + +#include "mbed.h" //time() and set_time() + +#define NTP_PORT 123 +#define NTP_CLIENT_PORT 0 //Random port +#define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) + +/*NTPClient::NTPClient() : m_sock() +{ + +}*/ + +NTPClient::NTPClient(NetworkInterface * _m_intf, int utcOffset) + : m_intf(_m_intf), + utc_offset(utcOffset) +{ +} + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + + +#if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) + +#define htons(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define ntohs(x) htons(x) +#define htonl(x) ((((x) & 0xff) << 24) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff0000UL) >> 8) | \ + (((x) & 0xff000000UL) >> 24)) +#define ntohl(x) htonl(x) + +#else + +#define htons(x) (x) +#define htonl(x) (x) +#define ntohl(x) (x) +#define ntohs(x) (x) + +#endif + + +NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout) +{ +#ifdef __DEBUG__ + time_t ctTime; + ctTime = time(NULL); + set_time(ctTime); + DBG("Time is set to (UTC): %s", ctime(&ctTime)); +#endif + + + SocketAddress address(0, port); + int r = m_intf->gethostbyname(host, &address); + if (r) { + printf("error: 'gethostbyname(\"%s\")' failed with code %d\r\n", host, r); + } else if (!address) { + printf("error: 'gethostbyname(\"%s\")' returned null IP address\r\n", host); + } + //printf ("address: %s\n\r",address.get_ip_address()); + + //Create & bind socket + if (m_sock.open(m_intf) < 0) printf ("ERROR sock open \n\r"); + m_sock.set_timeout(timeout); + + struct NTPPacket pkt; + memset (&pkt, 0, sizeof(NTPPacket)); + + //Now ping the server and wait for response + DBG("Ping"); + //Prepare NTP Packet: + pkt.li = 0; //Leap Indicator : No warning + pkt.vn = 4; //Version Number : 4 + pkt.mode = 3; //Client mode + pkt.stratum = 0; //Not relevant here + pkt.poll = 0; //Not significant as well + pkt.precision = 0; //Neither this one is + + int ret = m_sock.sendto(address, (char*)&pkt, sizeof(NTPPacket) ); + if (ret < 0 ) + { + ERR("Could not send packet %d", ret); + m_sock.close(); + return NTP_CONN; + } + + //Read response + DBG("Pong"); + + ret = m_sock.recvfrom(&address, (char*)&pkt, sizeof(NTPPacket) ); // LICIO + if(ret < 0) + { + ERR("Could not receive packet %d", ret); + m_sock.close(); + return NTP_CONN; + } + + if(ret < sizeof(NTPPacket)) //TODO: Accept chunks + { + ERR("Receive packet size does not match"); + m_sock.close(); + return NTP_PRTCL; + } + + if( pkt.stratum == 0) //Kiss of death message : Not good ! + { + ERR("Kissed to death!"); + m_sock.close(); + return NTP_PRTCL; + } + + //Correct Endianness + pkt.refTm_s = ntohl( pkt.refTm_s ); + pkt.refTm_f = ntohl( pkt.refTm_f ); + pkt.origTm_s = ntohl( pkt.origTm_s ); + pkt.origTm_f = ntohl( pkt.origTm_f ); + pkt.rxTm_s = ntohl( pkt.rxTm_s ); + pkt.rxTm_f = ntohl( pkt.rxTm_f ); + pkt.txTm_s = ntohl( pkt.txTm_s ); + pkt.txTm_f = ntohl( pkt.txTm_f ); + + // see RFC 4330 p.13 + int timeoffset = utc_offset * 60 * 60; + time_t txTm = (time_t)((pkt.txTm_s - NTP_TIMESTAMP_DELTA) + timeoffset); + + set_time(txTm); + +#ifdef __DEBUG__ + ctTime = time(NULL); + DBG("Time is now (UTC): %s", ctime(&ctTime)); +#endif + m_sock.close(); + + return NTP_OK; +} +
diff -r 000000000000 -r a1734fe1ec4b NTPClient/NTPClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NTPClient/NTPClient.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,98 @@ +/* NTPClient.h */ +/* Copyright (C) 2012 mbed.org, MIT License + * + * 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. + */ + +/** \file +NTP Client header file +*/ + +#ifndef NTPCLIENT_H_ +#define NTPCLIENT_H_ + +#include <stdint.h> +#include "UDPSocket.h" + +#define NTP_DEFAULT_PORT 123 +#define NTP_DEFAULT_TIMEOUT 4000 + +///NTP client results +enum NTPResult +{ + NTP_DNS, ///<Could not resolve name + NTP_PRTCL, ///<Protocol error + NTP_TIMEOUT, ///<Connection timeout + NTP_CONN, ///<Connection error + NTP_OK = 0, ///<Success +}; + +/** NTP Client to update the mbed's RTC using a remote time server +* +*/ +class NTPClient +{ +public: + /** + Instantiate the NTP client + */ + // NTPClient(); + NTPClient(NetworkInterface * _m_intf, int utcOffset = 0); + /**Get current time (blocking) + Update the time using the server host + Blocks until completion + @param host NTP server IPv4 address or hostname (will be resolved via DNS) + @param port port to use; defaults to 123 + @param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended) + @return 0 on success, NTP error code (<0) on failure + */ + NTPResult setTime(const char* host, uint16_t port = NTP_DEFAULT_PORT, uint32_t timeout = NTP_DEFAULT_TIMEOUT); + +private: + struct NTPPacket //See RFC 4330 for Simple NTP + { + //WARN: We are in LE! Network is BE! + //LSb first + unsigned mode : 3; + unsigned vn : 3; + unsigned li : 2; + + uint8_t stratum; + uint8_t poll; + uint8_t precision; + //32 bits header + + uint32_t rootDelay; + uint32_t rootDispersion; + uint32_t refId; + + uint32_t refTm_s; + uint32_t refTm_f; + uint32_t origTm_s; + uint32_t origTm_f; + uint32_t rxTm_s; + uint32_t rxTm_f; + uint32_t txTm_s; + uint32_t txTm_f; + } __attribute__ ((packed)); + + NetworkInterface * m_intf; // WiFi interface + int utc_offset; + UDPSocket m_sock; +}; + + +#endif /* NTPCLIENT_H_ */
diff -r 000000000000 -r a1734fe1ec4b README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,1 @@ +# MQTTGateway
diff -r 000000000000 -r a1734fe1ec4b Sensor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sensor.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,41 @@ +#ifndef _SENSOR_H_ +#define _SENSOR_H_ + + +#include <stdio.h> +#include <stdint.h> +#include <string> +#include "Utils.h" + +// Keep SensorData a POD type +typedef struct _SensorData +{ + uint64_t deviceaddr; + + uint16_t humidity; + float temperature; + uint16_t luminance; + // Relay value (negative logic) + // true = off + // false = on + bool sprinkler; + + + void debug() + { + printf("Channel id (lo): [%lX]\r\n", UINT64_HI32(deviceaddr)); + printf("Channel id (hi): [%lX]\r\n", UINT64_LO32(deviceaddr)); + printf("Humidity : [%d]\r\n", humidity); + printf("Temperature : [%.2f]\r\n", temperature); + printf("Luminance : [%d]\r\n", luminance); + } +} SensorData; + +typedef struct _SensorInfo +{ + int id; + std::string name; +} SensorInfo; + + +#endif \ No newline at end of file
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/DigiLogger/DigiLogger.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/DigiLogger/DigiLogger.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "DigiLogger.h" + +#include <stdarg.h> + +using namespace DigiLog; + +LogLevel DigiLogger::_log_level; + +DigiLogger* DigiLogger::current_logger; + +/* Base Class constructor */ +DigiLogger::DigiLogger() +{ + _log_level = LogLevelNone; + + current_logger = NULL; +} + +/* Class destructor */ +DigiLogger::~DigiLogger() +{ + current_logger = NULL; +} + +void DigiLogger::set_level(LogLevel log_level) +{ + _log_level = log_level; +} + +LogLevel DigiLogger::get_level() +{ + return _log_level; +} + +void DigiLogger::log_format(LogLevel log_level, const char *format, ...) +{ + static char buffer[DEBUG_BUFFER_LEN]; + va_list argp; + + if (current_logger == NULL) { + return; + } + + if (_log_level < log_level) { + return; + } + + va_start(argp, format); + vsnprintf(buffer, DEBUG_BUFFER_LEN, format, argp); + va_end(argp); + + current_logger->log_buffer(buffer); +} + +void DigiLogger::log_buffer(char const * const buffer) +{ + (void)(buffer); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/DigiLogger/DigiLogger.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/DigiLogger/DigiLogger.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__DIGI_LOGGER_H_) +#define __DIGI_LOGGER_H_ + +#include <cstdlib> +#include <stdio.h> + +/** + * @defgroup LogLevel + * @{ + */ +/** + * Library Logging level. + */ +enum LogLevel { + LogLevelNone, /** Level None */ + LogLevelError, /** Level Error */ + LogLevelWarning, /** Level Warning */ + LogLevelInfo, /** Level Info */ + LogLevelDebug, /** Level Debug */ + LogLevelFrameData, /** Level Frame Data */ + LogLevelAll /** Level All */ +}; +/** + * @} + */ + +#define DEBUG_BUFFER_LEN 200 + +namespace DigiLog { + +class DigiLogger +{ + protected: + + /** module log level */ + static LogLevel _log_level; + + static DigiLogger* current_logger; + + /* Not implemented for base class */ + virtual void log_buffer(char const * const buffer); + + public: + + /** Class constructor */ + DigiLogger(); + + /** Class destructor */ + virtual ~DigiLogger(); + + /** set_level - set logging level. + * + * @param log_level desired overall logging level + */ + static void set_level(LogLevel log_level); + + /** get_level - get logging level. + * + * @returns current overall logging level + */ + static LogLevel get_level(); + + /** log_format - logs a printf-like message. + * + * @param log_level logging level + * @param format ... printf-like message + */ + static void log_format(LogLevel log_level, const char *format, ...); + +}; + +} /* namespace DigiLog */ + +#endif /* defined(__DIGI_LOGGER_H_) */ + + +
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/DigiLogger/DigiLoggerMbedSerial.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/DigiLogger/DigiLoggerMbedSerial.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "DigiLoggerMbedSerial.h" + +using namespace DigiLog; + +Serial *DigiLoggerMbedSerial::_log_serial; + +/* Class constructor when using a serial port as logging channel */ +DigiLoggerMbedSerial::DigiLoggerMbedSerial(Serial * log_serial, LogLevel log_level) +{ + _log_serial = log_serial; + + _log_level = log_level; + + DigiLogger::current_logger = this; +} + +/* Class destructor */ +DigiLoggerMbedSerial::~DigiLoggerMbedSerial() +{ + _log_serial = NULL; + DigiLogger::current_logger = NULL; +} + +void DigiLoggerMbedSerial::log_buffer(char const * const buffer) +{ + if (_log_serial == NULL) { + return; + } + + _log_serial->printf("%s", buffer); + fflush(*_log_serial); +} + + +
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/DigiLogger/DigiLoggerMbedSerial.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/DigiLogger/DigiLoggerMbedSerial.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__DIGI_LOGGER_MBED_SERIAL_H_) +#define __DIGI_LOGGER_MBED_SERIAL_H_ + +#include "mbed.h" +#include "DigiLogger.h" + +namespace DigiLog { + +class DigiLoggerMbedSerial : public DigiLogger +{ + protected: + + /** serial port for debugging */ + static Serial *_log_serial; + + /** log_buffer - logs a buffer through the configured serial port. + * + * @param buffer ... buffer to log + */ + virtual void log_buffer(char const * const buffer); + + public: + + /** Class constructor */ + DigiLoggerMbedSerial(Serial * log_serial, LogLevel log_level = LogLevelInfo); + + /** Class destructor */ + virtual ~DigiLoggerMbedSerial(); +}; + +} /* namespace DigiLog */ + +#endif /* defined(__DIGI_LOGGER_MBED_SERIAL_H_) */ + + +
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameBuffer/FrameBuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameBuffer/FrameBuffer.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "FrameBuffer.h" +#include "Utils/Debug.h" + +#if !(defined AVOID_DISABLE_IRQS) +#define disable_irq() __disable_irq() +#define enable_irq() __enable_irq() +#else +#define disable_irq() +#define enable_irq() +#endif + +FrameBuffer::FrameBuffer(uint8_t size, uint16_t max_payload_len) : _size(size), _head(0), _tail(0), _dropped_frames(0) +{ + _frm_buf = new buf_element_t[_size]; + + assert(_frm_buf != NULL); + + for (int i = 0; i < _size; i++) { + _frm_buf[i].frame = new ApiFrame(max_payload_len - 1); + _frm_buf[i].status = FrameStatusFree; + } +} + +FrameBuffer::~FrameBuffer() +{ + for (int i = 0; i < _size; i++) { + delete _frm_buf[i].frame; + } + + delete _frm_buf; +} + +ApiFrame *FrameBuffer::get_next_free_frame(void) +{ + uint8_t i = _head; + ApiFrame *ret = NULL; + + do { + if (_frm_buf[i].status == FrameStatusFree || _frm_buf[i].status == FrameStatusComplete) { + if (_frm_buf[i].status == FrameStatusComplete) { + _dropped_frames++; + } + _frm_buf[i].status = FrameStatusAssigned; + ret = _frm_buf[i].frame; + _head = ++i % _size; + break; + } + i++; + i = i % _size; + } while (i != _head); + + return ret; +} + +bool FrameBuffer::complete_frame(ApiFrame *frame) +{ + bool ret = false; + + for (int i = 0; i < _size; i++) { + if (_frm_buf[i].frame == frame) { + _frm_buf[i].status = FrameStatusComplete; + ret = true; + break; + } + } + + return ret; +} + +ApiFrame *FrameBuffer::get_next_complete_frame(void) +{ + uint8_t i = _tail; + ApiFrame *ret = NULL; + + do { + disable_irq(); + if (_frm_buf[i].status == FrameStatusComplete) { + _frm_buf[i].status = FrameStatusAssigned; + enable_irq(); + ret = _frm_buf[i].frame; + _tail = ++i % _size; + break; + } + enable_irq(); + i++; + i = i % _size; + } while (i != _tail); + + return ret; +} + +bool FrameBuffer::free_frame(ApiFrame *frame) +{ + bool ret = false; + + for (int i = 0; i < _size; i++) { + if (_frm_buf[i].frame == frame) { + _frm_buf[i].status = FrameStatusFree; + ret = true; + break; + } + } + + return ret; +} + +uint32_t FrameBuffer::get_dropped_frames_count(void) +{ + const uint32_t dropped_frames = _dropped_frames; + + _dropped_frames = 0; + + return dropped_frames; +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameBuffer/FrameBuffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameBuffer/FrameBuffer.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FRAME_BUFFER_H_) +#define __FRAME_BUFFER_H_ + +#include "config.h" +#include "mbed.h" +#include "Frames/ApiFrame.h" + +#if FRAME_BUFFER_SIZE > 255 +# error "FRAME_BUFFER_SIZE must be lower than 256" +#endif + +typedef struct element { + ApiFrame *frame; + uint8_t status; +} buf_element_t; + +/** + * @class FrameBuffer + * @brief storage class for incoming frames + */ +class FrameBuffer +{ + public: + /** Constructor */ + FrameBuffer(uint8_t size, uint16_t max_payload_len); + + FrameBuffer(const FrameBuffer& other); /* Intentionally not implemented */ + /** Destructor */ + ~FrameBuffer(); + + /** get_next_free_frame returns the next free frame + * + * @returns a pointer to the next free frame */ + ApiFrame *get_next_free_frame(); + + /** complete_frame sets the status of the frame to complete once the + * data has been set in the buffer. + * + * @param pointer to the buffer we want to set as complete + * @returns true on success, false otherwise + */ + bool complete_frame(ApiFrame *frame); + + /** free_frame makes the frame available to be reused in future + * + * @param frame to release */ + bool free_frame(ApiFrame *frame); + + /** get_next_complete_frame returns the pointer to the next complete frame + * + * @returns the pointer to the selected buffer + */ + ApiFrame *get_next_complete_frame(); + + /** get_dropped_frames_count returns the number of dropped frames since latest call to this method + * + * @returns the number of dropped frames since latest call to this method + */ + uint32_t get_dropped_frames_count(); + +protected: + + /** frame status */ + enum FrameStatus { + FrameStatusFree = 0, /**< Free */ + FrameStatusAssigned, /**< Assigned */ + FrameStatusComplete /**< Complete */ + }; + + /** buffer array */ + buf_element_t * _frm_buf; + + uint8_t _size; + + + /** head frame index */ + uint8_t _head; + + /** tail frame index for application */ + uint8_t _tail; + + /** dropped frames */ + uint32_t _dropped_frames; +}; + +#endif /* __FRAME_BUFFER_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_AtCmdResp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_AtCmdResp.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,208 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "FrameHandlers/FH_AtCmdResp.h" +#include "Frames/ApiFrame.h" + +using namespace XBeeLib; + +/** Class constructor */ +FH_AtCmdResp::FH_AtCmdResp() : + FrameHandler(ApiFrame::AtCmdResp), at_cmd_resp_cb(NULL) +{ +} + +FH_AtCmdResp::FH_AtCmdResp(ApiFrame::ApiFrameType type) : + FrameHandler(type), at_cmd_resp_cb(NULL) +{ +} + +/** Class destructor */ +FH_AtCmdResp::~FH_AtCmdResp() +{ +} + +void FH_AtCmdResp::register_at_cmd_resp_cb(at_cmd_resp_cb_t function) +{ + at_cmd_resp_cb = function; +} + +void FH_AtCmdResp::unregister_at_cmd_resp_cb() +{ + at_cmd_resp_cb = NULL; +} + +void FH_AtCmdResp::process_frame_data(const ApiFrame * const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (at_cmd_resp_cb == NULL) { + return; + } + + at_cmd_resp_cb(frame->get_data(), frame->get_data_len()); +} + + +/** Class constructor */ +FH_NodeDiscoveryZB::FH_NodeDiscoveryZB() : + FH_AtCmdResp(ApiFrame::AtCmdResp), node_discovery_cb(NULL) +{ +} + +/** Class destructor */ +FH_NodeDiscoveryZB::~FH_NodeDiscoveryZB() +{ +} + +void FH_NodeDiscoveryZB::register_node_discovery_cb(node_discovery_zb_cb_t function) +{ + node_discovery_cb = function; +} + +void FH_NodeDiscoveryZB::unregister_node_discovery_cb() +{ + node_discovery_cb = NULL; +} + + +void FH_NodeDiscoveryZB::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (node_discovery_cb == NULL) { + return; + } + + if (frame->get_data_at(ATCMD_RESP_CMD_LOW_OFFSET) != 'N' || + frame->get_data_at(ATCMD_RESP_CMD_HIGH_OFFSET) != 'D') { + return; + } + + if (frame->get_data_at(ATCMD_RESP_STATUS_OFFSET) != AtCmdFrame::AtCmdRespOk) { + return; + } + + const uint8_t * const data = frame->get_data(); /* The data payload we get here is the full AT command response payload, excluding the frameid. Keep that in mind for the offsets */ + const uint16_t addr16 = UINT16(data[ATCMD_RESP_NW_ADDR_H_OFFSET], data[ATCMD_RESP_NW_ADDR_L_OFFSET]); + const uint64_t addr64 = addr64_from_uint8_t(&data[ATCMD_RESP_SH_ADDR_L_OFFSET]); + const char * const node_id = (const char *)&data[ATCMD_RESP_NI_OFFSET]; + RemoteXBeeZB remote = RemoteXBeeZB(addr64, addr16); + + node_discovery_cb(remote, node_id); +} + + + +/** Class constructor */ +FH_NodeDiscovery802::FH_NodeDiscovery802() : + FH_AtCmdResp(ApiFrame::AtCmdResp), node_discovery_cb(NULL) +{ +} + +/** Class destructor */ +FH_NodeDiscovery802::~FH_NodeDiscovery802() +{ +} + +void FH_NodeDiscovery802::register_node_discovery_cb(node_discovery_802_cb_t function) +{ + node_discovery_cb = function; +} + +void FH_NodeDiscovery802::unregister_node_discovery_cb() +{ + node_discovery_cb = NULL; +} + + +void FH_NodeDiscovery802::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (node_discovery_cb == NULL) { + return; + } + + if (frame->get_data_at(ATCMD_RESP_CMD_LOW_OFFSET) != 'N' || + frame->get_data_at(ATCMD_RESP_CMD_HIGH_OFFSET) != 'D') { + return; + } + + if (frame->get_data_at(ATCMD_RESP_STATUS_OFFSET) != AtCmdFrame::AtCmdRespOk) { + return; + } + + const uint16_t min_atnd_response_with_data = sizeof (uint16_t) + sizeof(uint64_t); + if (frame->get_data_len() < min_atnd_response_with_data) { + /* Do not process the ATND "OK" response */ + return; + } + + const uint8_t * const data = frame->get_data(); + const uint16_t addr16 = UINT16(data[ATCMD_RESP_NW_ADDR_H_OFFSET], data[ATCMD_RESP_NW_ADDR_L_OFFSET]); + const uint64_t addr64 = addr64_from_uint8_t(&data[ATCMD_RESP_SH_ADDR_L_OFFSET]); +#if 0 + const uint8_t signal_strength = data[ATCMD_802_RESP_SIGN_STR_OFFSET]; +#endif + const RemoteXBee802 remote = RemoteXBee802(addr64, addr16); + const char * const nodeid = (const char *)(&data[ATCMD_802_RESP_NI_OFFSET]); + + node_discovery_cb(remote, nodeid); +} + +/** Class constructor */ +FH_NodeDiscoveryDM::FH_NodeDiscoveryDM() : + FH_AtCmdResp(ApiFrame::AtCmdResp), node_discovery_cb(NULL) +{ +} + +/** Class destructor */ +FH_NodeDiscoveryDM::~FH_NodeDiscoveryDM() +{ +} + +void FH_NodeDiscoveryDM::register_node_discovery_cb(node_discovery_dm_cb_t function) +{ + node_discovery_cb = function; +} + +void FH_NodeDiscoveryDM::unregister_node_discovery_cb() +{ + node_discovery_cb = NULL; +} + + +void FH_NodeDiscoveryDM::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (node_discovery_cb == NULL) { + return; + } + + if (frame->get_data_at(ATCMD_RESP_CMD_LOW_OFFSET) != 'N' || + frame->get_data_at(ATCMD_RESP_CMD_HIGH_OFFSET) != 'D') { + return; + } + + if (frame->get_data_at(ATCMD_RESP_STATUS_OFFSET) != AtCmdFrame::AtCmdRespOk) { + return; + } + + const uint8_t * const data = frame->get_data(); /* The data payload we get here is the full AT command response payload, excluding the frameid. Keep that in mind for the offsets */ + const uint64_t addr64 = addr64_from_uint8_t(&data[ATCMD_RESP_SH_ADDR_L_OFFSET]); + const char * const node_id = (const char *)&data[ATCMD_RESP_NI_OFFSET]; + RemoteXBeeDM remote = RemoteXBeeDM(addr64); + + node_discovery_cb(remote, node_id); +} \ No newline at end of file
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_AtCmdResp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_AtCmdResp.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_AT_CMD_RESP_H_) +#define __FH_AT_CMD_RESP_H_ + +#include "FrameHandler.h" +#include "XBee/XBee.h" + +namespace XBeeLib { +typedef void (*at_cmd_resp_cb_t)(const uint8_t * data, uint16_t len); + +class FH_AtCmdResp : public FrameHandler +{ + private: + /** Callback function, invoked (if registered) when an at command response packet is received */ + at_cmd_resp_cb_t at_cmd_resp_cb; + + public: + + /** Class constructor */ + FH_AtCmdResp(); + + /** Class constructor */ + FH_AtCmdResp(ApiFrame::ApiFrameType type); + + + /** Class destructor */ + virtual ~FH_AtCmdResp(); + + virtual void process_frame_data(const ApiFrame *const frame); + + virtual void register_at_cmd_resp_cb(at_cmd_resp_cb_t function); + + virtual void unregister_at_cmd_resp_cb(); +}; + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** Node Discovery Response callback type declaration for ZigBee + * @param remote discovered remote node. + * @param node_id Node Identifier (NI parameter) of remote. + */ +typedef void (*node_discovery_zb_cb_t)(const RemoteXBeeZB& remote, char const * const node_id); +/** + * @} + */ + +class FH_NodeDiscoveryZB : public FH_AtCmdResp +{ + private: + /** Callback function, invoked (if registered) when an at command response packet is received */ + node_discovery_zb_cb_t node_discovery_cb; + + public: + + /** Class constructor */ + FH_NodeDiscoveryZB(); + + /** Class destructor */ + virtual ~FH_NodeDiscoveryZB(); + + virtual void process_frame_data(const ApiFrame *const frame); + + virtual void register_node_discovery_cb(node_discovery_zb_cb_t function); + + virtual void unregister_node_discovery_cb(); +}; + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** Node Discovery Response callback type declaration for ZigBee + * @param remote discovered remote node. + * @param node_id Node Identifier (NI parameter) of remote. + */ +typedef void (*node_discovery_dm_cb_t)(const RemoteXBeeDM& remote, char const * const node_id); +/** + * @} + */ + +class FH_NodeDiscoveryDM : public FH_AtCmdResp +{ + private: + /** Callback function, invoked (if registered) when an at command response packet is received */ + node_discovery_dm_cb_t node_discovery_cb; + + public: + + /** Class constructor */ + FH_NodeDiscoveryDM(); + + /** Class destructor */ + virtual ~FH_NodeDiscoveryDM(); + + virtual void process_frame_data(const ApiFrame *const frame); + + virtual void register_node_discovery_cb(node_discovery_dm_cb_t function); + + virtual void unregister_node_discovery_cb(); +}; + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** Node Discovery Response callback type declaration for 802.15.4 + * @param remote discovered remote node. + * @param node_id Node Identifier (NI parameter) of remote. + */ +typedef void (*node_discovery_802_cb_t)(const RemoteXBee802& remote, char const * const node_id); +/** + * @} + */ + +class FH_NodeDiscovery802 : public FH_AtCmdResp +{ + private: + /** Callback function, invoked (if registered) when an at command response packet is received */ + node_discovery_802_cb_t node_discovery_cb; + + public: + + /** Class constructor */ + FH_NodeDiscovery802(); + + /** Class destructor */ + virtual ~FH_NodeDiscovery802(); + + virtual void process_frame_data(const ApiFrame *const frame); + + virtual void register_node_discovery_cb(node_discovery_802_cb_t function); + + virtual void unregister_node_discovery_cb(); +}; + +} /* namespace XBeeLib */ + +#endif /* __FH_AT_CMD_RESP_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSample802.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSample802.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" + +using namespace XBeeLib; + +/** Class constructor */ +FH_IoDataSampe64b802::FH_IoDataSampe64b802() : FrameHandler(ApiFrame::Io64Bit), + io_data_cb(NULL) +{ +} + +/** Class destructor */ +FH_IoDataSampe64b802::~FH_IoDataSampe64b802() +{ + +} + +void FH_IoDataSampe64b802::register_io_data_cb(io_data_cb_802_t function) +{ + io_data_cb = function; +} + +void FH_IoDataSampe64b802::unregister_io_data_cb() +{ + io_data_cb = NULL; +} + +#define IO_SAMPLE_64_802_DATA_OFFSET 10 + +void FH_IoDataSampe64b802::process_frame_data(const ApiFrame *const frame) +{ + const uint8_t * const datap = frame->get_data(); + + /* The caller checks that the type matches, so no need to check it here again */ + if (io_data_cb == NULL) { + return; + } + + /* We got an IO packet, decode it... */ + const uint64_t sender64 = addr64_from_uint8_t(datap); + const RemoteXBee802 sender = RemoteXBee802(sender64); + const IOSample802 ioSample = IOSample802(&datap[IO_SAMPLE_64_802_DATA_OFFSET], frame->get_data_len() - IO_SAMPLE_64_802_DATA_OFFSET); + + io_data_cb(sender, ioSample); +} + +/** Class constructor */ +FH_IoDataSampe16b802::FH_IoDataSampe16b802() : FrameHandler(ApiFrame::Io16Bit), + io_data_cb(NULL) +{ +} + +/** Class destructor */ +FH_IoDataSampe16b802::~FH_IoDataSampe16b802() +{ +} + +void FH_IoDataSampe16b802::register_io_data_cb(io_data_cb_802_t function) +{ + io_data_cb = function; +} + +void FH_IoDataSampe16b802::unregister_io_data_cb() +{ + io_data_cb = NULL; +} + +#define IO_SAMPLE_16_802_ADDR16_MSB_OFFSET 0 +#define IO_SAMPLE_16_802_ADDR16_LSB_OFFSET 1 +#define IO_SAMPLE_16_802_DATA_OFFSET 4 + +void FH_IoDataSampe16b802::process_frame_data(const ApiFrame *const frame) +{ + const uint8_t * const datap = frame->get_data();; + + /* The caller checks that the type matches, so no need to check it here again */ + if (io_data_cb == NULL) { + return; + } + + /* We got an IO packet, decode it... */ + const uint16_t sender16 = ADDR16(datap[IO_SAMPLE_16_802_ADDR16_MSB_OFFSET], datap[IO_SAMPLE_16_802_ADDR16_LSB_OFFSET]); + const RemoteXBee802 sender = RemoteXBee802(sender16); + + const IOSample802 ioSample = IOSample802(&datap[IO_SAMPLE_16_802_DATA_OFFSET], frame->get_data_len() - IO_SAMPLE_16_802_DATA_OFFSET); + + io_data_cb(sender, ioSample); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSample802.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSample802.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_IO_DATA_SAMPLE_802_H_) +#define __FH_IO_DATA_SAMPLE_802_H_ + +#include "FrameHandler.h" +#include "RemoteXBee/RemoteXBee.h" + +namespace XBeeLib { + +class IOSample802; + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** IO Data Sample reception (802.15.4 modules) callback type declaration + * @param remote the remote module that sent the data + * @param sample_data a referece to an @ref IOSample802 that can be queried for the IoLines' values + */ +typedef void (*io_data_cb_802_t)(const RemoteXBee802& remote, const IOSample802& sample_data); +/** + * @} + */ + + +class FH_IoDataSampe64b802 : public FrameHandler +{ + public: + /** Class constructor */ + FH_IoDataSampe64b802(); + + /** Class destructor */ + virtual ~FH_IoDataSampe64b802(); + + virtual void process_frame_data(const ApiFrame *const frame); + + void register_io_data_cb(io_data_cb_802_t function); + void unregister_io_data_cb(); + + private: + /** Callback function, invoked if registered */ + io_data_cb_802_t io_data_cb; + +}; + +class FH_IoDataSampe16b802 : public FrameHandler +{ + public: + /** Class constructor */ + FH_IoDataSampe16b802(); + + /** Class destructor */ + virtual ~FH_IoDataSampe16b802(); + + virtual void process_frame_data(const ApiFrame *const frame); + + void register_io_data_cb(io_data_cb_802_t function); + + void unregister_io_data_cb(); + + private: + /** Callback function, invoked if registered */ + io_data_cb_802_t io_data_cb; +}; + +} /* namespace XBeeLib */ + +#endif /* __FH_IO_DATA_SAMPLE_802_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleDM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleDM.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" + +using namespace XBeeLib; + +/** Class constructor */ +FH_IoDataSampeDM::FH_IoDataSampeDM() : FrameHandler(ApiFrame::IoSampleRxZBDM), + io_data_cb(NULL) +{ +} + +/** Class destructor */ +FH_IoDataSampeDM::~FH_IoDataSampeDM() +{ +} + +void FH_IoDataSampeDM::register_io_data_cb(io_data_cb_dm_t function) +{ + io_data_cb = function; +} + +void FH_IoDataSampeDM::unregister_io_data_cb() +{ + io_data_cb = NULL; +} + +/* DM RX packet offsets */ +#define DM_IO_SAMPLE_DATA_OFFSET 11 + +void FH_IoDataSampeDM::process_frame_data(const ApiFrame *const frame) +{ + const uint8_t * const datap = frame->get_data();; + + /* The caller checks that the type matches, so no need to check it here again */ + if (io_data_cb == NULL) { + return; + } + + /* We got an IO packet, decode it... */ + const uint64_t sender64 = addr64_from_uint8_t(datap); + const RemoteXBeeDM sender = RemoteXBeeDM(sender64); + const IOSampleDM ioSample = IOSampleDM(&datap[DM_IO_SAMPLE_DATA_OFFSET], frame->get_data_len() - DM_IO_SAMPLE_DATA_OFFSET); + + io_data_cb(sender, ioSample); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleDM.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleDM.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_IO_DATA_SAMPLE_DM_H_) +#define __FH_IO_DATA_SAMPLE_DM_H_ + +#include "FrameHandler.h" +#include "RemoteXBee/RemoteXBee.h" + +namespace XBeeLib { + +class IOSampleDM; + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** IO Data Sample reception (ZigBee modules) callback type declaration + * @param remote the remote module that sent the data + * @param sample_data a referece to an @ref IOSampleDM that can be queried for the IoLines' values + */ +typedef void (*io_data_cb_dm_t)(const RemoteXBeeDM& remote, const IOSampleDM& sample_data); +/** + * @} + */ + +class FH_IoDataSampeDM : public FrameHandler +{ + public: + /** Class constructor */ + FH_IoDataSampeDM(); + + /** Class destructor */ + virtual ~FH_IoDataSampeDM(); + + virtual void process_frame_data(const ApiFrame *const frame); + + void register_io_data_cb(io_data_cb_dm_t function); + + void unregister_io_data_cb(); + + private: + /** Callback function, invoked if registered */ + io_data_cb_dm_t io_data_cb; +}; + +} /* namespace XBeeLib */ + +#endif /* __FH_IO_DATA_SAMPLE_DM_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleZB.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleZB.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" + +using namespace XBeeLib; + +/** Class constructor */ +FH_IoDataSampeZB::FH_IoDataSampeZB() : FrameHandler(ApiFrame::IoSampleRxZBDM), + io_data_cb(NULL) +{ +} + +/** Class destructor */ +FH_IoDataSampeZB::~FH_IoDataSampeZB() +{ +} + +void FH_IoDataSampeZB::register_io_data_cb(io_data_cb_zb_t function) +{ + io_data_cb = function; +} + +void FH_IoDataSampeZB::unregister_io_data_cb() +{ + io_data_cb = NULL; +} + +/* ZB RX packet offsets */ +#define ZB_IO_SAMPLE_ADDR16_MSB_OFFSET 8 +#define ZB_IO_SAMPLE_ADDR16_LSB_OFFSET 9 +#define ZB_IO_SAMPLE_DATA_OFFSET 11 + +void FH_IoDataSampeZB::process_frame_data(const ApiFrame *const frame) +{ + const uint8_t * const datap = frame->get_data();; + + /* The caller checks that the type matches, so no need to check it here again */ + if (io_data_cb == NULL) { + return; + } + + /* We got an IO packet, decode it... */ + const uint64_t sender64 = addr64_from_uint8_t(datap); + const uint16_t sender16 = ADDR16(datap[ZB_IO_SAMPLE_ADDR16_MSB_OFFSET], datap[ZB_IO_SAMPLE_ADDR16_LSB_OFFSET]); + const RemoteXBeeZB sender = RemoteXBeeZB(sender64, sender16); + const IOSampleZB ioSample = IOSampleZB(&datap[ZB_IO_SAMPLE_DATA_OFFSET], frame->get_data_len() - ZB_IO_SAMPLE_DATA_OFFSET); + + io_data_cb(sender, ioSample); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleZB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_IoDataSampleZB.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_IO_DATA_SAMPLE_ZB_H_) +#define __FH_IO_DATA_SAMPLE_ZB_H_ + +#include "FrameHandler.h" +#include "RemoteXBee/RemoteXBee.h" + +namespace XBeeLib { + +class IOSampleZB; + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** IO Data Sample reception (ZigBee modules) callback type declaration + * @param remote the remote module that sent the data + * @param sample_data a referece to an @ref IOSampleZB that can be queried for the IoLines' values + */ +typedef void (*io_data_cb_zb_t)(const RemoteXBeeZB& remote, const IOSampleZB& sample_data); +/** + * @} + */ + +class FH_IoDataSampeZB : public FrameHandler +{ + public: + /** Class constructor */ + FH_IoDataSampeZB(); + + /** Class destructor */ + virtual ~FH_IoDataSampeZB(); + + virtual void process_frame_data(const ApiFrame *const frame); + + void register_io_data_cb(io_data_cb_zb_t function); + + void unregister_io_data_cb(); + + private: + /** Callback function, invoked if registered */ + io_data_cb_zb_t io_data_cb; +}; + +} /* namespace XBeeLib */ + +#endif /* __FH_IO_DATA_SAMPLE_ZB_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_ModemStatus.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_ModemStatus.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "FH_ModemStatus.h" + +/** Class constructor */ +FH_ModemStatus::FH_ModemStatus() : FrameHandler(ApiFrame::AtModemStatus), modem_status_cb(NULL) +{ +} + +/** Class destructor */ +FH_ModemStatus::~FH_ModemStatus() +{ +} + +void FH_ModemStatus::register_modem_status_cb(modem_status_cb_t function) +{ + modem_status_cb = function; +} + +void FH_ModemStatus::unregister_modem_status_cb(void) +{ + modem_status_cb = NULL; +} + +void FH_ModemStatus::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (modem_status_cb == NULL) { + return; + } + + modem_status_cb((AtCmdFrame::ModemStatus)frame->get_data_at(0)); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_ModemStatus.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_ModemStatus.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_MODEM_STATUS_H_) +#define __FH_MODEM_STATUS_H_ + +#include "Frames/AtCmdFrame.h" +#include "FrameHandler.h" + +typedef void (*modem_status_cb_t)(AtCmdFrame::ModemStatus status); + +class FH_ModemStatus : public FrameHandler +{ + private: + /** Callback function, invoked (if registered) when a modem status packet is received */ + modem_status_cb_t modem_status_cb; + + public: + /** Class constructor */ + FH_ModemStatus(); + + /** Class destructor */ + virtual ~FH_ModemStatus(); + + /** Method called by the stack to process the modem status frame data + + \param frame pointer pointing to api frame that must be processed */ + virtual void process_frame_data(const ApiFrame *const frame); + + virtual void register_modem_status_cb(modem_status_cb_t function); + + virtual void unregister_modem_status_cb(void); +}; + +#endif /* __FH_MODEM_STATUS_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacket802.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacket802.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "FH_RxPacket802.h" + +using namespace XBeeLib; + +/** Class constructor */ +FH_RxPacket64b802::FH_RxPacket64b802() : FrameHandler(ApiFrame::RxPacket64Bit), + receive_cb(NULL) +{ +} + +/** Class destructor */ +FH_RxPacket64b802::~FH_RxPacket64b802() +{ +} + +void FH_RxPacket64b802::register_receive_cb(receive_802_cb_t function) +{ + receive_cb = function; +} + +void FH_RxPacket64b802::unregister_receive_cb(void) +{ + receive_cb = NULL; +} + +/* 802.15.4 RX packet offsets */ +#define RX_802_RSSI_OFFSET 8 +#define RX_802_OPTIONS_OFFSET 9 +#define RX_802_DATA_OFFSET 10 +#define RX_802_OVERHEAD (8+1+1) + +#define BROADCAST_PACKET 0x02 + +void FH_RxPacket64b802::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (receive_cb == NULL) { + return; + } + + /* We got a rx packet, decode it... */ + const uint8_t *datap = frame->get_data(); + const uint64_t sender64 = addr64_from_uint8_t(datap); + const uint8_t rx_options = datap[RX_802_OPTIONS_OFFSET]; + const RemoteXBee802 sender = RemoteXBee802(sender64); + + receive_cb(sender, rx_options & BROADCAST_PACKET, &datap[RX_802_DATA_OFFSET], frame->get_data_len() - RX_802_OVERHEAD); +} + + +/** Class constructor */ +FH_RxPacket16b802::FH_RxPacket16b802() : FrameHandler(ApiFrame::RxPacket16Bit), + receive_cb(NULL) +{ +} + +/** Class destructor */ +FH_RxPacket16b802::~FH_RxPacket16b802() +{ +} + +void FH_RxPacket16b802::register_receive_cb(receive_802_cb_t function) +{ + receive_cb = function; +} + +void FH_RxPacket16b802::unregister_receive_cb(void) +{ + receive_cb = NULL; +} + +/* 802.15.4 RX packet offsets */ +#define RX_802_ADDR16_MSB_OFFSET 0 +#define RX_802_ADDR16_LSB_OFFSET 1 +#define RX_802_RSSI_OFFSET2 2 +#define RX_802_OPTIONS_OFFSET2 3 +#define RX_802_DATA_OFFSET2 4 +#define RX_802_OVERHEAD2 (2+1+1) + +void FH_RxPacket16b802::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (receive_cb == NULL) { + return; + } + + /* We got a rx packet, decode it... */ + const uint8_t *datap = frame->get_data(); + const uint16_t sender16 = ADDR16(datap[RX_802_ADDR16_MSB_OFFSET], datap[RX_802_ADDR16_LSB_OFFSET]); + const uint8_t rx_options = datap[RX_802_OPTIONS_OFFSET2]; + const RemoteXBee802 sender = RemoteXBee802(sender16); + + receive_cb(sender, rx_options & BROADCAST_PACKET, &datap[RX_802_DATA_OFFSET2], frame->get_data_len() - RX_802_OVERHEAD2); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacket802.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacket802.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_RX_PACKET_802_H_) +#define __FH_RX_PACKET_802_H_ + +#include "FrameHandler.h" +#include "RemoteXBee/RemoteXBee.h" + +namespace XBeeLib { + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** receive callback type declaration + * @param remote the remote module that sent the data + * @param broadcast a boolean to tell if the message was broadcast (true) or unicast (false) + * @param data a pointer to data sent by @b remote. + * @param len length (in bytes) of @b data buffer + */ +typedef void (*receive_802_cb_t)(const RemoteXBee802& remote, bool broadcast, const uint8_t *const data, uint16_t len); +/** + * @} + */ + +class FH_RxPacket64b802 : public FrameHandler +{ + private: + /** Callback function, invoked if registered */ + receive_802_cb_t receive_cb; + + public: + /** Class constructor */ + FH_RxPacket64b802(); + + /** Class destructor */ + virtual ~FH_RxPacket64b802(); + + virtual void process_frame_data(const ApiFrame* const frame); + + virtual void register_receive_cb(receive_802_cb_t function); + + virtual void unregister_receive_cb(); +}; + +class FH_RxPacket16b802 : public FrameHandler +{ + private: + /** Callback function, invoked if registered */ + receive_802_cb_t receive_cb; + + public: + /** Class constructor */ + FH_RxPacket16b802(); + + /** Class destructor */ + virtual ~FH_RxPacket16b802(); + + virtual void process_frame_data(const ApiFrame *const frame); + + virtual void register_receive_cb(receive_802_cb_t function); + + virtual void unregister_receive_cb(); +}; + +} /* namespace XBeeLib */ + +#endif /* __FH_RX_PACKET_802_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketDM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketDM.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "FH_RxPacketDM.h" + +using namespace XBeeLib; + +/** Class constructor */ +FH_RxPacketDM::FH_RxPacketDM() : FrameHandler(ApiFrame::RxPacketAO0), receive_cb(NULL) +{ +} + +/** Class destructor */ +FH_RxPacketDM::~FH_RxPacketDM() +{ +} + +void FH_RxPacketDM::register_receive_cb(receive_dm_cb_t function) +{ + receive_cb = function; +} + +void FH_RxPacketDM::unregister_receive_cb(void) +{ + receive_cb = NULL; +} + +/* DM RX packet offsets */ +#define DM_RX_OPTIONS_OFFSET 10 +#define DM_RX_DATA_OFFSET 11 +#define DM_RX_OVERHEAD (8+2+1) + +#define BROADCAST_PACKET 0x02 + +void FH_RxPacketDM::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (receive_cb == NULL) { + return; + } + + /* We got a rx packet, decode it... */ + const uint8_t *datap = frame->get_data(); + const uint64_t sender64 = addr64_from_uint8_t(datap); + const uint8_t rx_options = datap[DM_RX_OPTIONS_OFFSET]; + const RemoteXBeeDM sender = RemoteXBeeDM(sender64); + + receive_cb(sender, rx_options & BROADCAST_PACKET, &datap[DM_RX_DATA_OFFSET], frame->get_data_len() - DM_RX_OVERHEAD); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketDM.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketDM.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_RX_PACKET_DM_H_) +#define __FH_RX_PACKET_DM_H_ + +#include "FrameHandler.h" +#include "RemoteXBee/RemoteXBee.h" + +namespace XBeeLib { + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** receive callback type declaration + * @param remote the remote module that sent the data + * @param broadcast a boolean to tell if the message was broadcast (true) or unicast (false) + * @param data a pointer to data sent by @b remote. + * @param len length (in bytes) of @b data buffer + */ +typedef void (*receive_dm_cb_t)(const RemoteXBeeDM& remote, bool broadcast, const uint8_t *const data, uint16_t len); +/** + * @} + */ + +class FH_RxPacketDM : public FrameHandler +{ + private: + /** Callback function, invoked if registered */ + receive_dm_cb_t receive_cb; + + public: + /** Class constructor */ + FH_RxPacketDM(); + + /** Class destructor */ + virtual ~FH_RxPacketDM(); + + /** Method called by the stack to process the modem status frame data + + \param frame pointer pointing to api frame that must be processed */ + virtual void process_frame_data(const ApiFrame* const frame); + + void register_receive_cb(receive_dm_cb_t function); + + void unregister_receive_cb(); +}; + +} /* namespace XBeeLib */ + +#endif /* __FH_RX_PACKET_DM_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketZB.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketZB.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "FH_RxPacketZB.h" + +using namespace XBeeLib; + +/** Class constructor */ +FH_RxPacketZB::FH_RxPacketZB() : FrameHandler(ApiFrame::RxPacketAO0), receive_cb(NULL) +{ +} + +/** Class destructor */ +FH_RxPacketZB::~FH_RxPacketZB() +{ +} + +void FH_RxPacketZB::register_receive_cb(receive_zb_cb_t function) +{ + receive_cb = function; +} + +void FH_RxPacketZB::unregister_receive_cb(void) +{ + receive_cb = NULL; +} + +/* ZB RX packet offsets */ +#define ZB_RX_ADDR16_MSB_OFFSET 8 +#define ZB_RX_ADDR16_LSB_OFFSET 9 +#define ZB_RX_OPTIONS_OFFSET 10 +#define ZB_RX_DATA_OFFSET 11 +#define ZB_RX_OVERHEAD (8+2+1) + +#define BROADCAST_PACKET 0x02 + +void FH_RxPacketZB::process_frame_data(const ApiFrame *const frame) +{ + /* The caller checks that the type matches, so no need to check it here again */ + + if (receive_cb == NULL) { + return; + } + + /* We got a rx packet, decode it... */ + const uint8_t *datap = frame->get_data(); + const uint64_t sender64 = addr64_from_uint8_t(datap); + const uint16_t sender16 = ADDR16(datap[ZB_RX_ADDR16_MSB_OFFSET], datap[ZB_RX_ADDR16_LSB_OFFSET]); + const uint8_t rx_options = datap[ZB_RX_OPTIONS_OFFSET]; + const RemoteXBeeZB sender = RemoteXBeeZB(sender64, sender16); + + receive_cb(sender, rx_options & BROADCAST_PACKET, &datap[ZB_RX_DATA_OFFSET], frame->get_data_len() - ZB_RX_OVERHEAD); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketZB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FH_RxPacketZB.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FH_RX_PACKET_ZB_H_) +#define __FH_RX_PACKET_ZB_H_ + +#include "FrameHandler.h" +#include "RemoteXBee/RemoteXBee.h" + +namespace XBeeLib { + +/** + * @defgroup callback_types "Callback types declaration" + * @{ + */ +/** receive callback type declaration + * @param remote the remote module that sent the data + * @param broadcast a boolean to tell if the message was broadcast (true) or unicast (false) + * @param data a pointer to data sent by @b remote. + * @param len length (in bytes) of @b data buffer + */ +typedef void (*receive_zb_cb_t)(const RemoteXBeeZB& remote, bool broadcast, const uint8_t *const data, uint16_t len); +/** + * @} + */ + +class FH_RxPacketZB : public FrameHandler +{ + private: + /** Callback function, invoked if registered */ + receive_zb_cb_t receive_cb; + + public: + /** Class constructor */ + FH_RxPacketZB(); + + /** Class destructor */ + virtual ~FH_RxPacketZB(); + + /** Method called by the stack to process the modem status frame data + + \param frame pointer pointing to api frame that must be processed */ + virtual void process_frame_data(const ApiFrame* const frame); + + void register_receive_cb(receive_zb_cb_t function); + + void unregister_receive_cb(); +}; + +} /* namespace XBeeLib */ + +#endif /* __FH_RX_PACKET_ZB_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FrameHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FrameHandler.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "FrameHandler.h" + +FrameHandler::FrameHandler(ApiFrame::ApiFrameType t) : _type(t) +{ +} + +FrameHandler::~FrameHandler() +{ +} + +ApiFrame::ApiFrameType FrameHandler::get_type() const +{ + return _type; +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/FrameHandlers/FrameHandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/FrameHandlers/FrameHandler.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__FRAME_HANDLER_H_) +#define __FRAME_HANDLER_H_ + +#include "Frames/ApiFrame.h" + +/** Class for the frame handlers */ +class FrameHandler +{ + friend class ApiFrame; + + public: + /** Class constructor + * + * @param type frame type handled by this frame handler + */ + FrameHandler(ApiFrame::ApiFrameType type); + + FrameHandler(const FrameHandler& other); /* Intentionally not implemented */ + /** Class destructor */ + virtual ~FrameHandler(); + + /** get_type returns the type of frames handled by this handler + * + * @returns the frame type handled by the handler + */ + ApiFrame::ApiFrameType get_type() const; + + /** process_frame_data method called by the library to process the + * the incoming frames if the type matches. + * + * @param frame pointer pointing to the api frame that must be processed + */ + virtual void process_frame_data(const ApiFrame *const frame) = 0; + + protected: + /** frame type handled by this handler */ + ApiFrame::ApiFrameType _type; +}; + +#endif /* defined(__FRAME_HANDLER_H_) */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/802_Frames.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/802_Frames.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "802_Frames.h" + +#define FRAME_ID_LEN 1 +#define ADDR64_LEN 8 +#define ADDR16_LEN 2 +#define OPTIONS_LEN 1 +#define TX_REQUEST_OVERHEAD (FRAME_ID_LEN + ADDR64_LEN + OPTIONS_LEN) +#define TX_REQUEST_OVERHEAD2 (FRAME_ID_LEN + ADDR16_LEN + OPTIONS_LEN) + +/** Class constructor */ +TxFrame802::TxFrame802(uint64_t addr, uint8_t tx_options, + const uint8_t *const data, uint16_t len) +{ + uint8_t frame_data[TX_REQUEST_OVERHEAD + len]; + + _frame_id = get_next_frame_id(); + + /* copy the frame id, the 64bit remote address, the tx options byte + * and the frame data */ + + frame_data[0] = _frame_id; + rmemcpy(&frame_data[1], (const uint8_t *)&addr, sizeof addr); + frame_data[9] = tx_options; + + if (len) { + memcpy(&frame_data[10], data, len); + } + + set_api_frame(TxReq64Bit, frame_data, TX_REQUEST_OVERHEAD + len); +} + +/** Class constructor */ +TxFrame802::TxFrame802(uint16_t addr16, uint8_t tx_options, + const uint8_t *const data, uint16_t len) +{ + uint8_t frame_data[TX_REQUEST_OVERHEAD2 + len]; + + _frame_id = get_next_frame_id(); + + /* copy the frame id, the 16bit remote address, the tx options byte + * and the frame data */ + + frame_data[0] = _frame_id; + frame_data[1] = (uint8_t)(addr16 >> 8); + frame_data[2] = (uint8_t)addr16; + frame_data[3] = tx_options; + + if (len) { + memcpy(&frame_data[4], data, len); + } + + set_api_frame(TxReq16Bit, frame_data, TX_REQUEST_OVERHEAD2 + len); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/802_Frames.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/802_Frames.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__802_FRAMES_H_) +#define __802_FRAMES_H_ + +#include "ApiFrame.h" + +class TxFrame802 : public ApiFrame +{ + public: + /** Class constructor */ + TxFrame802(uint64_t addr, uint8_t tx_options, const uint8_t *const data, uint16_t len); + TxFrame802(uint16_t addr16, uint8_t tx_options, const uint8_t *const data, uint16_t len); + + protected: +}; + +#endif /* __802_FRAMES_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/ApiFrame.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/ApiFrame.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,132 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "mbed.h" +#include "XBee/XBee.h" +#include "ApiFrame.h" + +using namespace XBeeLib; + +uint8_t ApiFrame::last_frame_id = 0; + +ApiFrame::ApiFrame(void) +{ + this->_type = Invalid; + this->_data = NULL; + this->_data_frame_len = 0; + this->_alloc_data = false; + _frame_id = get_next_frame_id(); +} + +ApiFrame::ApiFrame(uint16_t len) +{ + this->_type = Invalid; + this->_data = new uint8_t[len]; + this->_alloc_data = true; + this->_data_frame_len = len; + this->_frame_id = get_next_frame_id(); +} + +uint8_t ApiFrame::get_next_frame_id(void) +{ + last_frame_id++; + if (last_frame_id == 0) { + last_frame_id++; + } + + return last_frame_id; +} + +ApiFrame::ApiFrame(ApiFrameType type, const uint8_t *data, uint16_t len) +{ + this->_data = NULL; + set_api_frame(type, data, len); +} + +void ApiFrame::set_api_frame(ApiFrameType type, const uint8_t *data, uint16_t len) +{ + this->_type = type; + this->_data_frame_len = len; + if (this->_data) { + delete _data; + } + this->_data = new uint8_t[len]; + this->_alloc_data = true; + assert(this->_data != NULL); + memcpy((void *)this->_data, data, len); +} + +ApiFrame::~ApiFrame() +{ + if (this->_data != NULL && this->_alloc_data) { + delete[] this->_data; + } +} + +void ApiFrame::dump(void) const +{ +#if defined(ENABLE_LOGGING) + digi_log(LogLevelFrameData, "API frame: type %02x, len %d\r\n", this->_type, this->_data_frame_len); + for (int i = 0; i < this->_data_frame_len; i++) + digi_log(LogLevelFrameData, "%02x ", this->_data[i]); + digi_log(LogLevelFrameData, "\r\n"); +#endif +} + +void ApiFrame::dump_if(ApiFrameType type) +{ + if (_type != type) { + return; + } + dump(); +} + +ApiFrame::ApiFrameType ApiFrame::get_frame_type() const +{ + return _type; +} + +void ApiFrame::set_frame_type(ApiFrameType type) +{ + _type = type; +} + +uint16_t ApiFrame::get_data_len() const +{ + return _data_frame_len; +} + +void ApiFrame::set_data_len(uint16_t len) +{ + _data_frame_len = len; +} + +const uint8_t *ApiFrame::get_data() const +{ + return _data; +} + +uint8_t ApiFrame::get_data_at(uint16_t index) const +{ + return *(_data + index); +} + +void ApiFrame::set_data(uint8_t d, uint16_t index) +{ + *(_data + index) = d; +} + +/* Returns the frame_id of this frame */ +uint8_t ApiFrame::get_frame_id() const +{ + return _frame_id; +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/ApiFrame.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/ApiFrame.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__API_FRAME_H_) +#define __API_FRAME_H_ + +#include "XBee/Addresses.h" + +/** Class for XBee API frames */ +class ApiFrame +{ + /** Static variable that contains the last frame ID value assigned */ + static uint8_t last_frame_id; + + public: + /** List of API frames. Note that not all frames are supported by all radios */ + enum ApiFrameType { + + TxReq64Bit = 0x00, /**< TxReq64Bit: Only for 802.15.4 modules */ + TxReq16Bit = 0x01, /**< TxReq16Bit: Only for 802.15.4 modules */ + AtCmd = 0x08, /**< AtCmd */ + AtCmdQueuePV = 0x09, /**< AtCmdQueuePV */ + TxReqZBDM = 0x10, /**< TxReqZBDM: Only for ZigBee and DigiMesh modules */ + ExpAddrCmd = 0x11, /**< ExpAddrCmd: Only for ZigBee modules and DigiMesh */ + RemoteCmdReq = 0x17, /**< RemoteCmdReq */ + CreateSrcRoute = 0x21, /**< CreateSrcRoute */ + RxPacket64Bit = 0x80, /**< RxPacket64Bit: Only for 802.15.4 modules */ + RxPacket16Bit = 0x81, /**< RxPacket16Bit: Only for 802.15.4 modules */ + Io64Bit = 0x82, /**< Io64Bit: Only for 802.15.4 modules */ + Io16Bit = 0x83, /**< Io16Bit */ + AtCmdResp = 0x88, /**< AtCmdResp */ + TxStatus = 0x89, /**< TxStatus */ + AtModemStatus = 0x8A, /**< AtModemStatus */ + TxStatusZBDM = 0x8B, /**< TxStatusZBDM: Only for ZigBee and DigiMesh modules */ + RouteInfo = 0x8D, /**< RouteInfo: Only for DigiMesh modules */ + AggregateAddr = 0x8E, /**< AggregateAddr: Only for DigiMesh modules */ + RxPacketAO0 = 0x90, /**< RxPacketAO0: Only for ZigBee and DigiMesh modules */ + RxPacketAO1 = 0x91, /**< RxPacketAO1: Only for ZigBee and DigiMesh modules */ + IoSampleRxZBDM = 0x92, /**< IoSampleRxZBDM: Only for ZigBee and DigiMesh modules */ + SensorRxIndAO0 = 0x94, /**< SensorRxIndAO0: Only for ZigBee modules */ + NodeIdentIndAO0 = 0x95, /**< NodeIdentIndAO0: Only for ZigBee and DigiMesh modules */ + RemoteCmdResp = 0x97, /**< RemoteCmdResp */ + OtaFwUpStatus = 0xA0, /**< OtaFwUpStatus */ + RouteRecInd = 0xA1, /**< RouteRecInd */ + Many2OneRRInd = 0xA3, /**< Many2OneRRInd */ + Invalid = ~0, /**< Invalid */ + }; + + /** Default constructor */ + ApiFrame(); + + /** Constructor + * + * @param len length of the API frame (will allocate len bytes). + */ + ApiFrame(uint16_t len); + + /** Constructor + * + * @param type frame type of this api frame. + * @param data pointer to frame data payload. + * @param len length of the payload. + */ + ApiFrame(ApiFrameType type, const uint8_t *data, uint16_t len); + + /** Destructor */ + ~ApiFrame(); + + ApiFrame(const ApiFrame& other); /* Intentionally not implemented */ + + /** get_frame_type gets the type of the frame + * + * @returns the type of this frame. + */ + ApiFrameType get_frame_type() const; + + /** dump dumps the information of this frame */ + void dump() const; + + /** dump_if dumps the information of the frame if the frame type matches + * with the parameter. + * + * @param type dump the frame info/data if the frame type matches with type. + */ + void dump_if(ApiFrameType type); + + + /** set_frame_type sets the type of the frame to type. + * + * @param type the type we want to set on the frame. + */ + void set_frame_type(ApiFrameType type); + + /** get_data_len gets the length of the frame data payload. + * + * @returns the length of the data payload. + */ + uint16_t get_data_len() const; + + /** set_data_len sets the length of the frame data payload. + * + * @param len the length of the data payload will be set on this frame. + */ + void set_data_len(uint16_t len); + + /** get_data returns a pointer to the frame data payload. + * + * @returns a pointer to the frame data payload. + */ + const uint8_t *get_data() const; + + /** get_data_at returns the byte at index offset. + * + * @param index offset of the byte we want to get. + * @returns the byte at index offset. + */ + uint8_t get_data_at(uint16_t index) const; + + /** set_data sets data byte at the specified index or offset. + * + * @param data byte that will be set at index position. + * @param index offset of the byte we want to set. + */ + void set_data(uint8_t data, uint16_t index); + + /** get_frame_id returns the frame id of this frame. + * + * @returns the frame id of this frame. + */ + uint8_t get_frame_id() const; + + static uint8_t get_current_frame_id() + { + return last_frame_id; + } + + protected: + /** Type of this frame */ + ApiFrameType _type; + + /** length of the payload, excluding the frame type */ + uint16_t _data_frame_len; + + /** pointer to the frame data */ + uint8_t *_data; + + /** True if the constructor allocates the data. Needed to delete it on the destructor */ + bool _alloc_data; + + /** Frame ID of this frame */ + uint8_t _frame_id; + + /** get_next_frame_id - returns the next frame ID secuentially, skipping the value 0 + * + * @returns the next frame ID that should be assigned to a frame + */ + uint8_t get_next_frame_id(); + + /** set_api_frame sets several members + * + * @param type frame type of this api frame. + * @param data pointer to frame data payload. + * @param len length of the payload. + */ + void set_api_frame(ApiFrameType type, const uint8_t *data, uint16_t len); +}; + +#endif /* __API_FRAME_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/AtCmdFrame.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/AtCmdFrame.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,147 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "mbed.h" +#include "Utils/Debug.h" +#include "AtCmdFrame.h" + +#define AT_CMD_LEN 2 +#define AT_CMD_ID_LEN 1 + +void AtCmdFrame::build_at_cmd_frame(const char *cmd, const uint8_t *cmd_params, uint8_t payload_len, bool reverse) +{ + uint8_t frame_data[AT_CMD_LEN + AT_CMD_ID_LEN + payload_len]; + + frame_data[0] = _frame_id; + frame_data[1] = cmd[0]; + frame_data[2] = cmd[1]; + if (payload_len) { + if (reverse) { + rmemcpy(&frame_data[3], cmd_params, payload_len); + } else { + memcpy(&frame_data[3], cmd_params, payload_len); + } + } + + set_api_frame(AtCmd, frame_data, AT_CMD_LEN + AT_CMD_ID_LEN + payload_len); +} + +AtCmdFrame::AtCmdFrame(const char * const cmd, uint32_t cmd_param) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + uint8_t len; + if (cmd_param <= 0xFF) { + len = 1; + } else if (cmd_param <= 0xFFFF) { + len = 2; + } else if (cmd_param <= 0xFFFFFF) { + len = 3; + } else { + len = 4; + } + build_at_cmd_frame(cmd, (uint8_t *)&cmd_param, len); +} + +AtCmdFrame::AtCmdFrame(const char * const cmd, const uint8_t * cmd_param, uint16_t param_len) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + build_at_cmd_frame(cmd, cmd_param, param_len, false); +} + +AtCmdFrame::AtCmdFrame(uint64_t remote, const char * const cmd, uint32_t cmd_param) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + build_at_cmd_remote_frame(remote, ADDR16_UNKNOWN, cmd, (uint8_t *)&cmd_param, 4); +} + +AtCmdFrame::AtCmdFrame(uint64_t remote, const char * const cmd, const uint8_t * cmd_param, uint16_t param_len) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + build_at_cmd_remote_frame(remote, ADDR16_UNKNOWN, cmd, cmd_param, param_len, false); +} + +AtCmdFrame::AtCmdFrame(uint16_t remote, const char * const cmd, uint32_t cmd_param) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + build_at_cmd_remote_frame(ADDR64_UNASSIGNED, remote, cmd, (uint8_t *)&cmd_param, 4); +} + +AtCmdFrame::AtCmdFrame(uint16_t remote, const char * const cmd, const uint8_t * cmd_param, uint16_t param_len) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + build_at_cmd_remote_frame(ADDR64_UNASSIGNED, remote, cmd, cmd_param, param_len, false); +} + +AtCmdFrame::AtCmdFrame(uint64_t remote64, uint16_t remote16, const char * const cmd, uint32_t cmd_param) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + build_at_cmd_remote_frame(remote64, remote16, cmd, (uint8_t *)&cmd_param, 4); +} + +AtCmdFrame::AtCmdFrame(uint64_t remote64, uint16_t remote16, const char * const cmd, + const uint8_t * cmd_param, uint16_t param_len) +{ + assert(cmd != NULL); + assert(strlen(cmd) == AT_CMD_LEN); + + build_at_cmd_remote_frame(remote64, remote16, cmd, cmd_param, param_len, false); +} + +#define FRAME_ID_LEN 1 +#define ADDR64_LEN 8 +#define ADDR16_LEN 2 +#define OPTIONS_LEN 1 +#define AT_CMD_LEN 2 +#define REM_AT_CMD_OVERHEAD (FRAME_ID_LEN + ADDR64_LEN + \ + ADDR16_LEN + OPTIONS_LEN + \ + AT_CMD_LEN) + +void AtCmdFrame::build_at_cmd_remote_frame(uint64_t remote64, uint16_t remote16, + const char *const cmd, const uint8_t *const cmd_params, uint8_t params_len, bool reverse) +{ + uint8_t frame_data[REM_AT_CMD_OVERHEAD + params_len]; + + /* copy the frame id, the 64bit remote address, the 16bit network address, + * the options byte, the command and the command params */ + + frame_data[0] = _frame_id; + rmemcpy(&frame_data[1], (const uint8_t *)&remote64, sizeof remote64); + frame_data[9] = (uint8_t)(remote16 >> 8); + frame_data[10] = (uint8_t)remote16; + frame_data[11] = 0x02; /* TODO Options */ + frame_data[12] = cmd[0]; + frame_data[13] = cmd[1]; + + if (params_len) { + if (reverse) { + rmemcpy(&frame_data[14], cmd_params, params_len); + } else { + memcpy(&frame_data[14], cmd_params, params_len); + } + } + + set_api_frame(RemoteCmdReq, frame_data, REM_AT_CMD_OVERHEAD + params_len); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/AtCmdFrame.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/AtCmdFrame.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__AT_CMD_FRAME_H_) +#define __AT_CMD_FRAME_H_ + +#include "ApiFrame.h" + +#define REM_AT_CMD_RESP_FRM_ID_OFFSET 0 +#define REM_AT_CMD_RESP_STATUS_OFFSET 13 +#define REM_AT_CMD_RESP_CMD_DATA_OFFSET 14 +#define REM_AT_CMD_RESP_OVERHEAD 14 /* ID + ADDR64 + ADDR16 + CMD + status */ + +#define ATCMD_RESP_FRAME_ID_OFFSET 0 +#define ATCMD_RESP_CMD_LOW_OFFSET 1 +#define ATCMD_RESP_CMD_HIGH_OFFSET 2 +#define ATCMD_RESP_STATUS_OFFSET 3 +#define ATCMD_RESP_DATA_OFFSET 4 +#define ATCMD_RESP_NW_ADDR_H_OFFSET 4 +#define ATCMD_RESP_NW_ADDR_L_OFFSET 5 +#define ATCMD_RESP_SH_ADDR_L_OFFSET 6 +#define ATCMD_RESP_SH_ADDR_H_OFFSET 10 +#define ATCMD_RESP_NI_OFFSET 14 + +#define ATCMD_RESP_OVERHEAD 4 /* ID + CMD + status */ + +#define ATCMD_802_RESP_SIGN_STR_OFFSET 14 +#define ATCMD_802_RESP_NI_OFFSET 15 + +#define MAX_NI_PARAM_LEN 20 + +/** Class for the AT command api frames. Derived from ApiFrame */ +class AtCmdFrame : public ApiFrame +{ + public: + + /** + * AtCmdResp + */ + enum AtCmdResp { + AtCmdRespOk = 0, /**< Ok */ + AtCmdRespError = 1, /**< Error */ + AtCmdRespInvalidCmd = 2, /**< Invalid Command */ + AtCmdRespInvalidParam = 3, /**< Invalid Parameter */ + AtCmdRespTxFailure = 4, /**< Tx Failure */ + AtCmdRespLenMismatch = 0xfd, /**< Length Mismatch (Error generated by the library) */ + AtCmdRespInvalidAddr = 0xfe, /**< Invalid Address (Error generated by the library) */ + AtCmdRespTimeout = 0xff, /**< Timeout (Error generated by the library) */ + }; + + /** + * ModemStatus + */ + enum ModemStatus { + HwReset = 0, /**< Hardware reset */ + WdReset = 1, /**< Watchdog timer reset */ + JoinedNW = 2, /**< Joined network (routers and end devices) */ + Disassociated = 3, /**< Disassociated */ + SyncLost = 4, /**< Synchronization Lost */ + CoordRealign = 5, /**< Coordinator realignment */ + CoordStarted = 6, /**< Coordinator started */ + NwSecKeyUpdated = 7, /**< Network security key was updated */ + NwWokeUp = 0x0B, /**< NwWokeUp */ + NwToSleep = 0x0C, /**< NwToSleep */ + VccExceeded = 0x0D, /**< VccExceeded: PRO S2B only? */ + ModConfChangeJoinInProg = 0x11, /**< Modem configuration changed while join in progress */ + }; + + /** Class constructor + * + * @param cmd at command of the frame + * @param cmd_param command parameter + * @param param_len length of the command param + */ + AtCmdFrame(const char * const cmd, const uint32_t cmd_param); + + /** Class constructor + * + * @param cmd at command of the frame + * @param cmd_param pointer to command parameter + * @param param_len length of the command param + */ + AtCmdFrame(const char * const cmd, const uint8_t * cmd_param = NULL, uint16_t param_len = 0); + + /** Class constructor + * + * @param remote 64 bit address of the remote device where we want to run the command + * @param cmd at command of the frame + * @param cmd_param command parameter + */ + AtCmdFrame(uint64_t remote, const char * const cmd, uint32_t cmd_param); + + /** Class constructor + * + * @param remote 64 bit address of the remote device where we want to run the command + * @param cmd at command of the frame + * @param cmd_param pointer to command parameter + * @param param_len length of the command param + */ + AtCmdFrame(uint64_t remote, const char * const cmd, const uint8_t * cmd_param = NULL, uint16_t param_len = 0); + + /** Class constructor + * + * @param remote 16 bit address of the remote device where we want to run the command + * @param cmd at command of the frame + * @param cmd_param command parameter + */ + AtCmdFrame(uint16_t remote, const char * const cmd, uint32_t cmd_param); + + /** Class constructor + * + * @param remote 16 bit address of the remote device where we want to run the command + * @param cmd at command of the frame + * @param cmd_param pointer to command parameter + * @param param_len length of the command param + */ + AtCmdFrame(uint16_t remote, const char * const cmd, const uint8_t * cmd_param = NULL, uint16_t param_len = 0); + + /** Class constructor + * + * @param remote 64 bit address of the remote device where we want to run the command + * @param remote 16 bit address of the remote device where we want to run the command + * @param cmd at command of the frame + * @param cmd_param command parameter + */ + AtCmdFrame(uint64_t remote64, uint16_t remote16, const char * const cmd, uint32_t cmd_param); + + /** Class constructor + * + * @param remote 64 bit address of the remote device where we want to run the command + * @param remote 16 bit address of the remote device where we want to run the command + * @param cmd at command of the frame + * @param cmd_param pointer to command parameter + * @param param_len length of the command param + */ + AtCmdFrame(uint64_t remote64, uint16_t remote16, const char * const cmd, const uint8_t * cmd_param = NULL, uint16_t param_len = 0); + + protected: + /** build_at_cmd_frame method used by the constructors to create the at command frame + * + * @param cmd at command of the frame + * @param cmd_params pointer to command parameter + * @param param_len length of the command param + */ + void build_at_cmd_frame(const char *cmd, const uint8_t *cmd_params, uint8_t payload_len, bool reverse = true); + + /** build_at_cmd_remote_frame method used by the constructors to create the at command frame + * + * @param remote64 64 bit address of the remote device where we want to run the command + * @param remote16 16 bit address of the remote device where we want to run the command + * @param cmd at command of the frame + * @param cmd_params pointer to command parameter + * @param param_len length of the command param + */ + void build_at_cmd_remote_frame(uint64_t remote64, uint16_t remote16, + const char *const cmd, const uint8_t *const cmd_params, uint8_t payload_len, bool reverse = true); +}; + +#endif /* __AT_CMD_FRAME_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/DigiMeshFrames.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/DigiMeshFrames.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "DigiMeshFrames.h" + +#define FRAME_ID_LEN 1 +#define ADDR64_LEN 8 +#define ADDR16_LEN 2 +#define BROADCAST_RADIOUS_LEN 1 +#define OPTIONS_LEN 1 +#define TX_REQUEST_OVERHEAD (FRAME_ID_LEN + ADDR64_LEN + \ + ADDR16_LEN + BROADCAST_RADIOUS_LEN + \ + OPTIONS_LEN) +#define SOURCE_EP_LEN 1 +#define DEST_EP_LEN 1 +#define CLUSTER_ID_LEN 2 +#define PROFILE_ID_LEN 2 + +#define EXP_ADDR_OVERHEAD (TX_REQUEST_OVERHEAD + SOURCE_EP_LEN + \ + DEST_EP_LEN + CLUSTER_ID_LEN + \ + PROFILE_ID_LEN) + +/** Class constructor */ +TxFrameDM::TxFrameDM(uint64_t addr, uint16_t addr16, uint8_t broadcast_rad, uint8_t tx_opt, + const uint8_t *const data, uint16_t len) +{ + uint8_t frame_data[TX_REQUEST_OVERHEAD + len]; + + _frame_id = get_next_frame_id(); + + /* copy the frame id, the 64bit remote address, the 16bit network address, + * the broad cast radious, the options byte and the frame data */ + + frame_data[0] = _frame_id; + rmemcpy(&frame_data[1], (const uint8_t *)&addr, sizeof addr); + frame_data[9] = (uint8_t)(addr16 >> 8); + frame_data[10] = (uint8_t)addr16; + frame_data[11] = broadcast_rad; + frame_data[12] = tx_opt; + + if (len) { + memcpy(&frame_data[13], data, len); + } + + set_api_frame(TxReqZBDM, frame_data, TX_REQUEST_OVERHEAD + len); +} + +/** Class constructor */ +TxFrameDM::TxFrameDM(uint64_t addr, uint16_t addr16, uint8_t source_ep, uint8_t dest_ep, + uint16_t cluster_id, uint16_t profile_id, uint8_t broadcast_rad, + uint8_t tx_opt, const uint8_t *const data, uint16_t len) +{ + uint8_t frame_data[EXP_ADDR_OVERHEAD + len]; + + _frame_id = get_next_frame_id(); + + /* copy the frame id, the 64bit remote address, the 16bit network address, + * the end point source and destination addresses, the cluster and profile IDs, + * the broad cast radious, the options byte and the frame data */ + + frame_data[0] = _frame_id; + rmemcpy(&frame_data[1], (const uint8_t *)&addr, sizeof addr); + frame_data[9] = (uint8_t)(addr16 >> 8); + frame_data[10] = (uint8_t)addr16; + frame_data[11] = source_ep; + frame_data[12] = dest_ep; + frame_data[13] = (uint8_t)(cluster_id >> 8); + frame_data[14] = (uint8_t)cluster_id; + frame_data[15] = (uint8_t)(profile_id >> 8); + frame_data[16] = (uint8_t)profile_id; + frame_data[17] = broadcast_rad; + frame_data[18] = tx_opt; + + if (len) { + memcpy(&frame_data[19], data, len); + } + + set_api_frame(ExpAddrCmd, frame_data, EXP_ADDR_OVERHEAD + len); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/DigiMeshFrames.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/DigiMeshFrames.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__DIGIMESH_FRAME_H_) +#define __DIGIMESH_FRAME_H_ + +#include "ApiFrame.h" + +class TxFrameDM : public ApiFrame +{ + public: + /** Class constructor */ + TxFrameDM(uint64_t addr, uint16_t addr16, uint8_t broadcast_rad, + uint8_t tx_opt, const uint8_t *const data, uint16_t len); + + /** Class constructor */ + TxFrameDM(uint64_t addr, uint16_t addr16, uint8_t source_ep, uint8_t dest_ep, + uint16_t cluster_id, uint16_t profile_id, uint8_t broadcast_rad, + uint8_t tx_opt, const uint8_t *const data, uint16_t len); +}; + +#endif /* __DIGIMESH_FRAME_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/ZigbeeFrames.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/ZigbeeFrames.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "ZigbeeFrames.h" + +#define FRAME_ID_LEN 1 +#define ADDR64_LEN 8 +#define ADDR16_LEN 2 +#define BROADCAST_RADIOUS_LEN 1 +#define OPTIONS_LEN 1 +#define TX_REQUEST_OVERHEAD (FRAME_ID_LEN + ADDR64_LEN + \ + ADDR16_LEN + BROADCAST_RADIOUS_LEN + \ + OPTIONS_LEN) +#define SOURCE_EP_LEN 1 +#define DEST_EP_LEN 1 +#define CLUSTER_ID_LEN 2 +#define PROFILE_ID_LEN 2 + +#define EXP_ADDR_OVERHEAD (TX_REQUEST_OVERHEAD + SOURCE_EP_LEN + \ + DEST_EP_LEN + CLUSTER_ID_LEN + \ + PROFILE_ID_LEN) + +/** Class constructor */ +TxFrameZB::TxFrameZB(uint64_t addr, uint16_t addr16, uint8_t broadcast_rad, uint8_t tx_opt, + const uint8_t *const data, uint16_t len) +{ + uint8_t frame_data[TX_REQUEST_OVERHEAD + len]; + + _frame_id = get_next_frame_id(); + + /* copy the frame id, the 64bit remote address, the 16bit network address, + * the broad cast radious, the options byte and the frame data */ + + frame_data[0] = _frame_id; + rmemcpy(&frame_data[1], (const uint8_t *)&addr, sizeof addr); + frame_data[9] = (uint8_t)(addr16 >> 8); + frame_data[10] = (uint8_t)addr16; + frame_data[11] = broadcast_rad; + frame_data[12] = tx_opt; + + if (len) { + memcpy(&frame_data[13], data, len); + } + + set_api_frame(TxReqZBDM, frame_data, TX_REQUEST_OVERHEAD + len); +} + +/** Class constructor */ +TxFrameZB::TxFrameZB(uint64_t addr, uint16_t addr16, uint8_t source_ep, uint8_t dest_ep, + uint16_t cluster_id, uint16_t profile_id, uint8_t broadcast_rad, + uint8_t tx_opt, const uint8_t *const data, uint16_t len) +{ + uint8_t frame_data[EXP_ADDR_OVERHEAD + len]; + + _frame_id = get_next_frame_id(); + + /* copy the frame id, the 64bit remote address, the 16bit network address, + * the end point source and destination addresses, the cluster and profile IDs, + * the broad cast radious, the options byte and the frame data */ + + frame_data[0] = _frame_id; + rmemcpy(&frame_data[1], (const uint8_t *)&addr, sizeof addr); + frame_data[9] = (uint8_t)(addr16 >> 8); + frame_data[10] = (uint8_t)addr16; + frame_data[11] = source_ep; + frame_data[12] = dest_ep; + frame_data[13] = (uint8_t)(cluster_id >> 8); + frame_data[14] = (uint8_t)cluster_id; + frame_data[15] = (uint8_t)(profile_id >> 8); + frame_data[16] = (uint8_t)profile_id; + frame_data[17] = broadcast_rad; + frame_data[18] = tx_opt; + + if (len) { + memcpy(&frame_data[19], data, len); + } + + set_api_frame(ExpAddrCmd, frame_data, EXP_ADDR_OVERHEAD + len); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Frames/ZigbeeFrames.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Frames/ZigbeeFrames.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__ZIGBEE_FRAME_H_) +#define __ZIGBEE_FRAME_H_ + +#include "ApiFrame.h" + +class TxFrameZB : public ApiFrame +{ + public: + /** Class constructor */ + TxFrameZB(uint64_t addr, uint16_t addr16, uint8_t broadcast_rad, + uint8_t tx_opt, const uint8_t *const data, uint16_t len); + + /** Class constructor */ + TxFrameZB(uint64_t addr, uint16_t addr16, uint8_t source_ep, uint8_t dest_ep, + uint16_t cluster_id, uint16_t profile_id, uint8_t broadcast_rad, + uint8_t tx_opt, const uint8_t *const data, uint16_t len); +}; + +#endif /* __ZIGBEE_FRAME_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/IO/IO.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/IO/IO.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#ifndef __IO_H_ +#define __IO_H_ + +#define DR_PWM_MAX_VAL 0x3FF + +namespace XBeeLib { + +/** + * @defgroup IoMode + * @{ + */ +/** + * IoMode + */ +enum IoMode { + Disabled = 0, /**< Disabled */ + SpecialFunc = 1, /**< Special Function */ + Adc = 2, /**< Adc */ + Pwm = 2, /**< Pwm */ + DigitalInput = 3, /**< Digital Input */ + DigitalOutLow = 4, /**< Digital Out Low */ + DigitalOutHigh = 5, /**< Digital Out High */ +}; +/** + * @} + */ + +/** + * @defgroup DioVal + * @{ + */ +/** + * DioVal + */ +enum DioVal { + Low = 0, /**< Low Value */ + High = 1, /**< High Value */ +}; +/** + * @} + */ + +} /* namespace XBeeLib */ + + +#endif /* __IO_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/IO/IOSample802.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/IO/IOSample802.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" +#include "IO/IOSample802.h" +#include "Utils/Debug.h" + +#define IO_SAMPLE_802_DIGITAL_INPUTS_MASK 0x01FF +#define IO_SAMPLE_802_DIGITAL_INPUTS_COUNT 9 +#define IO_SAMPLE_802_MIN_SIZE (2 + 2) + +using namespace XBeeLib; + +IOSample802::IOSample802(const uint8_t* const raw_data, size_t size) +{ + if (raw_data == NULL || size == 0) { + _channel_mask = 0; + return; + } + assert(size >= IO_SAMPLE_802_MIN_SIZE); + assert(size <= sizeof _sampled_data); + + _channel_mask = UINT16(raw_data[1], raw_data[2]); + _sampled_data_size = size - 3; + memcpy(&_sampled_data[0], &raw_data[3], _sampled_data_size); +} + +IOSample802::~IOSample802() +{ + +} + +RadioStatus IOSample802::get_dio(XBee802::IoLine line, DioVal* const dio_value) const +{ + if (line > XBee802::DI8) { + digi_log(LogLevelError, "get_dio: Pin %d not supported as IO\r\n", line); + return Failure; + } + + const uint16_t mask = 1 << line; + if (mask & _channel_mask) { + const uint8_t digital_channels = get_dio_channels(); + + *dio_value = digital_channels & mask ? High : Low; + return Success; + } + return Failure; +} + +RadioStatus IOSample802::get_adc(XBee802::IoLine line, uint16_t* const val) const +{ + if (line > XBee802::DIO5_AD5) { + digi_log(LogLevelError, "get_adc: Pin %d not supported as ADC\r\n", line); + return Failure; + } + const uint8_t analog_mask = _channel_mask >> IO_SAMPLE_802_DIGITAL_INPUTS_COUNT; + const uint8_t line_mask = 1 << line; + const bool adc_present = line_mask & analog_mask; + if (!adc_present) { + return Failure; + } + + uint8_t analog_data_idx = dio_channels_present() == 0 ? 0 : 2; + uint8_t line_sample = 0; + + while (analog_data_idx < _sampled_data_size) { + if (analog_mask & (1 << line_sample)) { + if (line_sample == line) { + /* Write the analog value */ + *val = UINT16(_sampled_data[analog_data_idx], _sampled_data[analog_data_idx + 1]); + break; + } + analog_data_idx += 2; + } + line_sample++; + } + + return Success; +} + +inline bool IOSample802::dio_channels_present(void) const +{ + return _channel_mask & IO_SAMPLE_802_DIGITAL_INPUTS_MASK; +} + +inline uint8_t IOSample802::get_dio_channels(void) const +{ + if (dio_channels_present()) { + return UINT16(_sampled_data[0], _sampled_data[1]); + } else { + return 0; + } +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/IO/IOSample802.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/IO/IOSample802.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#ifndef _IO_IOSAMPLE802_H_ +#define _IO_IOSAMPLE802_H_ + +#define MAX_IO_SAMPLE_802_LEN 100 //(2 + 2 * 20) + +namespace XBeeLib { + +/** Class to handle the incoming IO Data Samples in 802.15.4 modules */ +class IOSample802 { + public: + /** Class constructor + * @param raw_data The IO Sample data, as returned by an "IS" command response or in the Io16Bit (0x83) or Io64Bit (0x82) frames + * @param size size (in bytes) of raw_data + */ + IOSample802(const uint8_t* const raw_data = NULL, size_t size = 0); + + /** Class destructor */ + ~IOSample802(); + + /** get_dio - read the value of a DIO configured as digital input + * + * @param line DIO line being read + * @param val pointer where the DIO value read will be stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_dio(XBee802::IoLine line, DioVal* const dio_value) const; + + /** get_adc - read the value of the espcified ADC line + * + * @param line ADC line being read + * @param val pointer where the value read from the ADC will be stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_adc(XBee802::IoLine line, uint16_t* const val) const; + + /** is_valid - checks if the IOSample802 object has at least one DIO or ADC sample. + * @returns true if valid, false otherwise + */ + inline bool is_valid() + { + return _channel_mask != 0; + } + + protected: + uint16_t _channel_mask; + uint8_t _sampled_data[MAX_IO_SAMPLE_802_LEN]; + uint8_t _sampled_data_size; + + inline bool dio_channels_present(void) const; + inline uint8_t get_dio_channels(void) const; +}; + +} /* namespace XBeeLib */ + +#endif /* _IO_IOSAMPLE802_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/IO/IOSampleDM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/IO/IOSampleDM.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" +#include "IO/IOSampleDM.h" + +#define IO_SAMPLE_DM_MIN_SIZE (2 + 1 + 2) + +using namespace XBeeLib; + +IOSampleDM::IOSampleDM(const uint8_t* const raw_data, size_t size) +{ + if (raw_data == NULL || size == 0) { + _digital_mask = 0; + _analog_mask = 0; + return; + } + assert(size >= IO_SAMPLE_DM_MIN_SIZE); + assert(size <= sizeof _sampled_data); + + _digital_mask = UINT16(raw_data[1], raw_data[2]); + _analog_mask = raw_data[3]; + _sampled_data_size = size - 4; + memcpy(&_sampled_data[0], &raw_data[4], _sampled_data_size); +} + +IOSampleDM::~IOSampleDM() +{ + +} + +RadioStatus IOSampleDM::get_dio(XBeeDM::IoLine line, DioVal* const dio_value) const +{ + const uint16_t mask = 1 << line; + if (mask & _digital_mask) { + const uint16_t digital_channels = get_digital_channels(); + + *dio_value = digital_channels & mask ? High : Low; + return Success; + } + return Failure; +} + +RadioStatus IOSampleDM::get_adc(XBeeDM::IoLine line, uint16_t* const val) const +{ + const uint8_t line_mask = 1 << line; + const bool adc_present = line_mask & _analog_mask; + if (!adc_present) { + return Failure; + } + + uint8_t analog_data_idx = _digital_mask == 0 ? 0 : 2; + uint8_t line_sample = 0; + + while (analog_data_idx < _sampled_data_size) { + if (_analog_mask & (1 << line_sample)) { + if (line_sample == line) { + /* Write the analog value */ + *val = UINT16(_sampled_data[analog_data_idx], _sampled_data[analog_data_idx + 1]); + break; + } + analog_data_idx += 2; + } + line_sample++; + } + + return Success; +} + +inline uint16_t IOSampleDM::get_digital_channels(void) const +{ + if (_digital_mask == 0) { + return 0; + } + return UINT16(_sampled_data[0], _sampled_data[1]); +} +
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/IO/IOSampleDM.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/IO/IOSampleDM.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#ifndef _IO_IOSAMPLEDM_H_ +#define _IO_IOSAMPLEDM_H_ + +#define MAX_IO_SAMPLE_DM_LEN (2 + 2 * 5) + +namespace XBeeLib { + +/** Class to handle the incoming IO Data Samples in ZigBee modules */ +class IOSampleDM { + public: + /** Class constructor + * @param raw_data The IO Sample data, as returned by an "IS" command response or in the IoSampleRxZBDM (0x92) frames + * @param size size (in bytes) of raw_data. + */ + IOSampleDM(const uint8_t* const raw_data = NULL, size_t size = 0); + + /** Class destructor */ + ~IOSampleDM(); + + /** get_dio - read the value of a DIO configured as digital input + * + * @param line DIO line being read + * @param val pointer where the DIO value read will be stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_dio(XBeeDM::IoLine line, DioVal* const dio_value) const; + + /** get_adc - read the value of the espcified ADC line + * + * @param line ADC line being read + * @param val pointer where the value read from the ADC will be stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_adc(XBeeDM::IoLine line, uint16_t* const val) const; + + /** is_valid - checks if the IOSampleDM object has at least one DIO or ADC sample. + * @returns true if valid, false otherwise + */ + inline bool is_valid() + { + return _digital_mask != 0 || _analog_mask != 0; + } + + protected: + uint16_t _digital_mask; + uint8_t _analog_mask; + uint8_t _sampled_data[MAX_IO_SAMPLE_DM_LEN]; + uint8_t _sampled_data_size; + + inline uint16_t get_digital_channels(void) const; +}; + +} /* namespace XBeeLib */ + +#endif /* _IO_IOSAMPLEDM_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/IO/IOSampleZB.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/IO/IOSampleZB.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" +#include "IO/IOSampleZB.h" + +#define IO_SAMPLE_ZB_MIN_SIZE (2 + 1 + 2) + +using namespace XBeeLib; + +IOSampleZB::IOSampleZB(const uint8_t* const raw_data, size_t size) +{ + if (raw_data == NULL || size == 0) { + _digital_mask = 0; + _analog_mask = 0; + return; + } + assert(size >= IO_SAMPLE_ZB_MIN_SIZE); + assert(size <= sizeof _sampled_data); + + _digital_mask = UINT16(raw_data[1], raw_data[2]); + _analog_mask = raw_data[3]; + _sampled_data_size = size - 4; + memcpy(&_sampled_data[0], &raw_data[4], _sampled_data_size); +} + +IOSampleZB::~IOSampleZB() +{ + +} + +RadioStatus IOSampleZB::get_dio(XBeeZB::IoLine line, DioVal* const dio_value) const +{ + const uint16_t mask = 1 << line; + if (mask & _digital_mask) { + const uint16_t digital_channels = get_digital_channels(); + + *dio_value = digital_channels & mask ? High : Low; + return Success; + } + return Failure; +} + +RadioStatus IOSampleZB::get_adc(XBeeZB::IoLine line, uint16_t* const val) const +{ + const uint8_t line_mask = 1 << line; + const bool adc_present = line_mask & _analog_mask; + if (!adc_present) { + return Failure; + } + + uint8_t analog_data_idx = _digital_mask == 0 ? 0 : 2; + uint8_t line_sample = 0; + + while (analog_data_idx < _sampled_data_size) { + if (_analog_mask & (1 << line_sample)) { + if (line_sample == line) { + /* Write the analog value */ + *val = UINT16(_sampled_data[analog_data_idx], _sampled_data[analog_data_idx + 1]); + break; + } + analog_data_idx += 2; + } + line_sample++; + } + + return Success; +} + +inline uint16_t IOSampleZB::get_digital_channels(void) const +{ + if (_digital_mask == 0) { + return 0; + } + return UINT16(_sampled_data[0], _sampled_data[1]); +} +
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/IO/IOSampleZB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/IO/IOSampleZB.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#ifndef _IO_IOSAMPLEZB_H_ +#define _IO_IOSAMPLEZB_H_ + +#define MAX_IO_SAMPLE_ZB_LEN (2 + 2 * 5) + +namespace XBeeLib { + +/** Class to handle the incoming IO Data Samples in ZigBee modules */ +class IOSampleZB { + public: + /** Class constructor + * @param raw_data The IO Sample data, as returned by an "IS" command response or in the IoSampleRxZBDM (0x92) frames + * @param size size (in bytes) of raw_data. + */ + IOSampleZB(const uint8_t* const raw_data = NULL, size_t size = 0); + + /** Class destructor */ + ~IOSampleZB(); + + /** get_dio - read the value of a DIO configured as digital input + * + * @param line DIO line being read + * @param val pointer where the DIO value read will be stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_dio(XBeeZB::IoLine line, DioVal* const dio_value) const; + + /** get_adc - read the value of the espcified ADC line + * + * @param line ADC line being read + * @param val pointer where the value read from the ADC will be stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_adc(XBeeZB::IoLine line, uint16_t* const val) const; + + /** is_valid - checks if the IOSampleZB object has at least one DIO or ADC sample. + * @returns true if valid, false otherwise + */ + inline bool is_valid() + { + return _digital_mask != 0 || _analog_mask != 0; + } + + protected: + uint16_t _digital_mask; + uint8_t _analog_mask; + uint8_t _sampled_data[MAX_IO_SAMPLE_ZB_LEN]; + uint8_t _sampled_data_size; + + inline uint16_t get_digital_channels(void) const; +}; + +} /* namespace XBeeLib */ + +#endif /* _IO_IOSAMPLEZB_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/RemoteXBee/RemoteXBee.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/RemoteXBee/RemoteXBee.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "RemoteXBee.h" + +using namespace XBeeLib; + +RemoteXBee::RemoteXBee() +{ + _dev_addr64 = ADDR64_UNASSIGNED; + _dev_addr16 = ADDR16_UNKNOWN; +} + +RemoteXBee::RemoteXBee(uint64_t remote64) : _dev_addr64(remote64) +{ + _dev_addr16 = ADDR16_UNKNOWN; +} + +RemoteXBee::~RemoteXBee() +{ +} + +uint64_t RemoteXBee::get_addr64() const +{ + return _dev_addr64; +} + +uint16_t RemoteXBee::get_addr16() const +{ + return _dev_addr16; +} + +RemoteXBee802::RemoteXBee802() : RemoteXBee() +{ +} + +RemoteXBee802::RemoteXBee802(uint64_t remote64) : RemoteXBee(remote64) +{ +} + +RemoteXBee802::RemoteXBee802(uint16_t remote16) : RemoteXBee() +{ + _dev_addr16 = remote16; +} + +RemoteXBee802::RemoteXBee802(uint64_t remote64, uint16_t remote16) : RemoteXBee(remote64) +{ + _dev_addr16 = remote16; +} + +RemoteXBee802::~RemoteXBee802() +{ +} + +RemoteXBeeZB::RemoteXBeeZB() : RemoteXBee() +{ +} + +RemoteXBeeZB::RemoteXBeeZB(uint64_t remote64) : RemoteXBee(remote64) +{ +} + +RemoteXBeeZB::RemoteXBeeZB(uint64_t remote64, uint16_t remote16) : RemoteXBee(remote64) +{ + _dev_addr16 = remote16; +} + +RemoteXBeeZB::~RemoteXBeeZB() +{ +} + +RemoteXBeeDM::RemoteXBeeDM() : RemoteXBee() +{ +} + +RemoteXBeeDM::RemoteXBeeDM(uint64_t remote64) : RemoteXBee(remote64) +{ +} + +RemoteXBeeDM::~RemoteXBeeDM() +{ +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/RemoteXBee/RemoteXBee.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/RemoteXBee/RemoteXBee.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,182 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__XBEE_REMOTE_H_) +#define __XBEE_REMOTE_H_ + +#include "XBee/Addresses.h" + +namespace XBeeLib { + +/** Class for Remote XBee modules. Not to be used directly. */ +class RemoteXBee +{ + public: + + /** Default Class constructor for a remote device (connected wirelessly). No address set. + */ + RemoteXBee(); + + /** Class constructor for a remote device (connected wirelessly) using 64bit addressing + * @param remote64 the 64-bit address (ATSH and ATSL parameters) of the remote XBee module + */ + RemoteXBee(uint64_t remote64); + + /** Class destructor */ + ~RemoteXBee(); + + /** get_addr64 - returns the 64bit address of the remote device + * + * @returns the 64bit address of the remote device + */ + uint64_t get_addr64() const; + + /** get_addr16 - returns the 16bit address of the remote device + * + * @returns the 16bit address of the remote device + */ + uint16_t get_addr16() const; + + /** operator == overload so the object can be compared to equal */ + inline bool operator == (const RemoteXBee &b) const + { + return ((b._dev_addr16 == _dev_addr16) && + (b._dev_addr64 == _dev_addr64)); + } + + /** operator != overload so the object can be compared to not equal */ + inline bool operator != (const RemoteXBee &b) const + { + return !(this == &b); + } + + /** is_valid_addr16b - checks if the RemoteXBee object has a valid 16b address + * @returns true if valid, false otherwise + */ + inline bool is_valid_addr16b() const + { + return (_dev_addr16 != ADDR16_UNKNOWN); + } + + /** is_valid_addr64b - checks if the RemoteXBee object has a valid 64b address + * @returns true if valid, false otherwise + */ + inline bool is_valid_addr64b() const + { + return !(_dev_addr64 == ADDR64_UNASSIGNED); + } + + + protected: + /** Remote Device 64 bit address */ + uint64_t _dev_addr64; + + /** Remote Device 16 bit address */ + uint16_t _dev_addr16; +}; + +class FH_NodeDiscovery802; +/** Class for 802.15.4 Remote XBee modules */ +class RemoteXBee802 : public RemoteXBee +{ + public: + + /** Default Class constructor for a 802.15.4 remote device (connected wirelessly). No address set. + */ + RemoteXBee802(); + + /** Class constructor for a 802.15.4 remote device (connected wirelessly) using 64bit addressing + * @param remote64 the 64-bit address (ATSH and ATSL parameters) of the remote XBee module + */ + RemoteXBee802(uint64_t remote64); + + /** Class constructor for a 802.15.4 remote device (connected wirelessly) using 16bit addressing + * @param remote16 the 16-bit address (ATMY parameter) of the remote XBee module + */ + RemoteXBee802(uint16_t remote16); + + /** Class destructor */ + ~RemoteXBee802(); + + inline bool is_valid(void) + { + return is_valid_addr64b() || is_valid_addr16b(); + } + + protected: + + friend FH_NodeDiscovery802; + friend class XBee802; + + /** Class constructor for a 802.15.4 remote device (connected wirelessly) for which both the 64-bit and 16-bit addresses are known. + * This constructor is only used by FH_NodeDiscovery802 class. + * @param remote64 the 64-bit address (ATSH and ATSL parameters) of the remote XBee module + * @param remote16 the 16-bit address (ATMY parameter) of the remote XBee module + */ + RemoteXBee802(uint64_t remote64, uint16_t remote16); +}; + +/** Class for ZigBee Remote XBee modules */ +class RemoteXBeeZB : public RemoteXBee +{ + public: + + /** Default Class constructor for a ZigBee remote device (connected wirelessly). No address set. + */ + RemoteXBeeZB(); + + /** Class constructor for a ZigBee remote device (connected wirelessly) using 64bit addressing + * @param remote64 the 64-bit address (ATSH and ATSL parameters) of the remote XBee module + */ + RemoteXBeeZB(uint64_t remote64); + + /** Class constructor for a ZigBee remote device (connected wirelessly) using 64bit and 16b addressing + * @param remote64 the 64-bit address (ATSH and ATSL parameters) of the remote XBee module + * @param remote16 the 16-bit address (ATMY parameter) of the remote XBee module + */ + RemoteXBeeZB(uint64_t remote64, uint16_t remote16); + + /** Class destructor */ + ~RemoteXBeeZB(); + + inline bool is_valid(void) + { + return is_valid_addr64b(); + } +}; + +/** Class for DigiMesh Remote XBee modules */ +class RemoteXBeeDM : public RemoteXBee +{ + public: + + /** Default Class constructor for a DigiMesh remote device (connected wirelessly). No address set. + */ + RemoteXBeeDM(); + + /** Class constructor for a DigiMesh remote device (connected wirelessly) using 64bit addressing + * @param remote64 the 64-bit address (ATSH and ATSL parameters) of the remote XBee module + */ + RemoteXBeeDM(uint64_t remote64); + + /** Class destructor */ + ~RemoteXBeeDM(); + + inline bool is_valid(void) + { + return is_valid_addr64b(); + } +}; + +} /* namespace XBeeLib */ + +#endif /* defined(__XBEE_REMOTE_H_) */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Utils/Debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Utils/Debug.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__DEBUG_H_) +#define __DEBUG_H_ + +#include "config.h" + +#if defined(ENABLE_LOGGING) + +#include "DigiLogger.h" + +#define digi_log(...) DigiLog::DigiLogger::log_format(__VA_ARGS__); +#else +#define digi_log(...) do {} while(0) +#endif + +#if defined(ENABLE_ASSERTIONS) +#include "mbed.h" +#if !(defined assert) +#define assert(expr) if (!(expr)) { \ + digi_log(LogLevelNone, "Assertion failed: %s, file %s, line %d\n", \ + #expr, __FILE__, __LINE__); \ + mbed_die(); \ + } +#endif +#else +#define assert(expr) +#endif + +#endif /* __DEBUG_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Utils/Utils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Utils/Utils.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "Utils.h" +#include <string.h> + +void rmemcpy(uint8_t * const dest, const uint8_t * const src, uint16_t bytes) +{ + uint8_t *destp = dest + bytes - 1; + uint8_t *srcp = (uint8_t *)src; + + while (destp >= dest) + *destp-- = *srcp++; +} + +uint64_t addr64_from_uint8_t(const uint8_t * const data, bool big_endian = true) +{ + int64_t addr64; + if (big_endian) { + rmemcpy((uint8_t *)&addr64, data, 8); + } else { + memcpy((uint8_t *)&addr64, data, 8); + } + return addr64; +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/Utils/Utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/Utils/Utils.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__XB_UTILS_H_) +#define __XB_UTILS_H_ + +#include <stdint.h> + +/** Buils an uint16_t out of 2 single bytes */ +#define UINT16(msb,lsb) (uint16_t)(((msb) << 8) | (lsb)) +/** Buils an uint64_t out of 2 uint32_t */ +#define UINT64(msb,lsb) (uint64_t)(((uint64_t)(msb) << 32) | (lsb)) + +#define UINT64_HI32(u64) (uint32_t)((u64) >> 32) +#define UINT64_LO32(u64) (uint32_t)((u64) & 0xFFFFFFFF) + +#define UNUSED_PARAMETER(a) ((void)(a)) + +/** rmemcpy - like memcpy but copies the bytes in reverse order + * + * @param dest pointer with the destination address + * @param src pointer with the source address + * @param bytes number of bytes that will be copied + */ +void rmemcpy(uint8_t * const dest, const uint8_t * const src, uint16_t bytes); + +#endif /* __XB_UTILS_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/XBee/Addresses.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/XBee/Addresses.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#ifndef __ADDRESSES_H_ +#define __ADDRESSES_H_ + +#include <stdint.h> +#include <string.h> + +#include "Utils/Utils.h" + +/* Some commonly used addresses */ +#define ADDR64_BROADCAST ((uint64_t)0x000000000000FFFF) +#define ADDR64_COORDINATOR ((uint64_t)0x0000000000000000) +#define ADDR64_UNASSIGNED ((uint64_t)0xFFFFFFFFFFFFFFFF) + +#define ADDR16_UNKNOWN ((uint16_t)0xFFFE) +#define ADDR16_BROADCAST ((uint16_t)0xFFFF) + +/** Macro used to create a 16bit data type from 2 bytes */ +#define ADDR16(msb,lsb) UINT16(msb,lsb) + +uint64_t addr64_from_uint8_t(const uint8_t * const data, bool big_endian = true); + +#endif /* __ADDRESSES_H_ */
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/XBee/AtCommands.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/XBee/AtCommands.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" + +#define GET_CMD_RESP(fr, radio_location) (radio_location == RadioRemote ? fr->get_data_at(REM_AT_CMD_RESP_STATUS_OFFSET) \ + : fr->get_data_at(ATCMD_RESP_STATUS_OFFSET)) + +#define GET_DATA_LEN(fr, radio_location) (radio_location == RadioRemote ? (fr->get_data_len() - REM_AT_CMD_RESP_OVERHEAD) \ + : (fr->get_data_len() - ATCMD_RESP_OVERHEAD)) + +#define GET_DATA_OFF(radio_location) (radio_location == RadioRemote ? REM_AT_CMD_RESP_CMD_DATA_OFFSET \ + : ATCMD_RESP_DATA_OFFSET) + +using namespace XBeeLib; + +/** Method that sends an AT command to the module and waits for the command response. + * @returns the AT command response */ +AtCmdFrame::AtCmdResp XBee::send_at_cmd(AtCmdFrame *frame, + uint8_t *const buf, uint16_t *const len, RadioLocation radio_location, bool reverse) +{ + AtCmdFrame::AtCmdResp resp = AtCmdFrame::AtCmdRespTimeout; + ApiFrame *resp_frame; + ApiFrame::ApiFrameType expected_type = + (frame->get_frame_type() == ApiFrame::AtCmd) ? + ApiFrame::AtCmdResp : ApiFrame::RemoteCmdResp; + + send_api_frame(frame); + + /* Wait for the AT command response packet */ + resp_frame = get_this_api_frame(frame->get_frame_id(), expected_type); + if (resp_frame == NULL) { + return resp; + } + + resp = (AtCmdFrame::AtCmdResp)GET_CMD_RESP(resp_frame, radio_location); + if (resp == AtCmdFrame::AtCmdRespOk) { + if (buf != NULL && len != NULL) { + + /* Copy the command response data */ + uint16_t new_len = GET_DATA_LEN(resp_frame, radio_location); + + *len = (*len < new_len) ? *len : new_len; + + /* rmemcpy makes the endian change */ + if (reverse) { + rmemcpy(buf, resp_frame->get_data() + GET_DATA_OFF(radio_location), *len); + } else { + memcpy(buf, resp_frame->get_data() + GET_DATA_OFF(radio_location), *len); + } + } + } else { + digi_log(LogLevelWarning, "send_at_cmd bad response: 0x%x\r\n", resp); + } + + /* Once processed, remove the frame from the buffer */ + _framebuf_syncr.free_frame(resp_frame); + return resp; +} + +/** Method that sends an AT command to the module and waits for the command response. + * @returns the AT command response */ +AtCmdFrame::AtCmdResp XBee::send_at_cmd(AtCmdFrame *frame) +{ + return send_at_cmd(frame, NULL, NULL); +} + +AtCmdFrame::AtCmdResp XBee::send_at_cmd(AtCmdFrame *frame, uint8_t *data) +{ + uint16_t len = sizeof *data; + AtCmdFrame::AtCmdResp atCmdResponse = send_at_cmd(frame, data, &len); + + if (atCmdResponse == AtCmdFrame::AtCmdRespOk && len != sizeof *data) { + atCmdResponse = AtCmdFrame::AtCmdRespLenMismatch; + } + + return atCmdResponse; +} + +AtCmdFrame::AtCmdResp XBee::send_at_cmd(AtCmdFrame *frame, uint16_t *data) +{ + uint16_t len = sizeof *data; + AtCmdFrame::AtCmdResp atCmdResponse = send_at_cmd(frame, (uint8_t *)data, &len); + + if (atCmdResponse == AtCmdFrame::AtCmdRespOk && len != sizeof *data) { + atCmdResponse = AtCmdFrame::AtCmdRespLenMismatch; + } + + return atCmdResponse; +} + +AtCmdFrame::AtCmdResp XBee::send_at_cmd(AtCmdFrame *frame, uint32_t *data) +{ + uint16_t len = sizeof *data; + AtCmdFrame::AtCmdResp atCmdResponse = send_at_cmd(frame, (uint8_t *)data, &len); + + if (atCmdResponse == AtCmdFrame::AtCmdRespOk && len != sizeof *data) { + atCmdResponse = AtCmdFrame::AtCmdRespLenMismatch; + } + + return atCmdResponse; +} + +AtCmdFrame::AtCmdResp XBee::get_param(const char * const param, uint32_t * const data) +{ + uint16_t len = sizeof *data; + AtCmdFrame cmd_frame = AtCmdFrame(param); + + *data = 0; /* Set to zero, send_at_cmd() only writes the necessary bytes, so if only 1 is written all the remaining 3 should be 0. */ + AtCmdFrame::AtCmdResp atCmdResponse = send_at_cmd(&cmd_frame, (uint8_t *)data, &len); + + if (atCmdResponse == AtCmdFrame::AtCmdRespOk && len > sizeof *data) { + atCmdResponse = AtCmdFrame::AtCmdRespLenMismatch; + } + + return atCmdResponse; +} + +AtCmdFrame::AtCmdResp XBee::set_param(const char * const param, uint32_t data) +{ + AtCmdFrame cmd_frame = AtCmdFrame(param, data); + return send_at_cmd(&cmd_frame, NULL, NULL); +} + +AtCmdFrame::AtCmdResp XBee::set_param(const char * const param, const uint8_t * data, uint16_t len) +{ + AtCmdFrame cmd_frame = AtCmdFrame(param, data, len); + return send_at_cmd(&cmd_frame, NULL, NULL); +} + +AtCmdFrame::AtCmdResp XBee::get_param(const char * const param, uint8_t * const data, uint16_t * const len) +{ + AtCmdFrame cmd_frame = AtCmdFrame(param); + return send_at_cmd(&cmd_frame, data, len, RadioLocal, false); +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/XBee/RadioConfig.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/XBee/RadioConfig.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,366 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" +#include "Frames/ApiFrame.h" + +using namespace XBeeLib; + +RadioStatus XBee::write_config(void) +{ + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param("WR"); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + return Success; +} + +RadioStatus XBee::set_power_level(uint8_t level) +{ + AtCmdFrame::AtCmdResp cmdresp; + + if (level > 4) { + return Failure; + } + + cmdresp = set_param("PL", level); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + + return Success; +} + +RadioStatus XBee::get_power_level(uint8_t * const level) +{ + if (level == NULL) { + return Failure; + } + AtCmdFrame::AtCmdResp cmdresp; + + uint32_t var32; + cmdresp = get_param("PL", &var32); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + *level = var32; + return Success; +} + +RadioStatus XBee::software_reset(void) +{ + volatile uint16_t * const rst_cnt_p = &_wd_reset_cnt; + const uint16_t init_rst_cnt = *rst_cnt_p; + + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param("FR"); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "software_reset failed!\r\n"); + return Failure; + } + + return wait_for_module_to_reset(rst_cnt_p, init_rst_cnt); +} + +RadioStatus XBee::set_node_identifier(const char * const node_id) +{ + if (node_id == NULL) { + return Failure; + } + + AtCmdFrame::AtCmdResp cmdresp; + const size_t str_len = strlen(node_id); + + if(str_len > 20 || str_len < 1) { + return Failure; + } + + cmdresp = set_param("NI", (const uint8_t *)node_id, str_len); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + return Success; +} + +RadioStatus XBee::get_node_identifier(char * const node_id) +{ + if (node_id == NULL) { + return Failure; + } + + uint16_t max_ni_length = 20; + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = get_param("NI", (uint8_t *)node_id, &max_ni_length); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + node_id[max_ni_length] = '\0'; + return Success; +} + +RadioStatus XBee::enable_network_encryption(bool enable) +{ + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param("EE", enable); + return cmdresp == AtCmdFrame::AtCmdRespOk ? Success : Failure; +} + +RadioStatus XBee::set_network_encryption_key(const uint8_t * const key, const uint16_t length) +{ + if (key == NULL || length == 0 || length > 16) { + return Failure; + } + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param("KY", key, length); + return cmdresp == AtCmdFrame::AtCmdRespOk ? Success : Failure; +} + +uint16_t XBee::get_hw_version() const +{ + return _hw_version; +} + +uint16_t XBee::get_fw_version() const +{ + return _fw_version; +} + +void XBee::set_tx_options(uint8_t options) +{ + _tx_options = options; +} + +uint8_t XBee::get_tx_options() const +{ + return _tx_options; +} + +RadioStatus XBee::start_node_discovery() +{ + RadioStatus status; + uint16_t nd_timeout; + + status = get_node_discovery_timeout(&nd_timeout); + if (status != Success) { + return status; + } + + _nd_timeout = nd_timeout; + + _nd_timer.start(); + + AtCmdFrame cmd_frame = AtCmdFrame("ND"); + send_api_frame(&cmd_frame); + + return Success; +} + +bool XBee::is_node_discovery_in_progress() +{ + const int nd_timer = _nd_timer.read_ms(); + + if (nd_timer == 0) + return false; + + if (nd_timer > _nd_timeout) { + _nd_timer.stop(); + _nd_timer.reset(); + } + + return true; +} + +void XBee::_get_remote_node_by_id(const char * const node_id, uint64_t * const addr64, uint16_t * const addr16) +{ + *addr64 = ADDR64_UNASSIGNED; + *addr16 = ADDR16_UNKNOWN; + if (node_id == NULL) { + return; + } + const size_t node_id_len = strlen(node_id); + if (node_id_len == 0 || node_id_len > MAX_NI_PARAM_LEN) { + return; + } + + const uint16_t old_timeout = _timeout_ms; + + RadioStatus status; + uint16_t nd_timeout; + bool wait_for_complete_timeout; + + status = get_node_discovery_timeout(&nd_timeout, &wait_for_complete_timeout); + if (status != Success) { + return; + } + _timeout_ms = nd_timeout; + + Timer nd_timer = Timer(); + + nd_timer.start(); + + AtCmdFrame atnd_frame = AtCmdFrame("ND", (const uint8_t *)node_id, strlen(node_id)); + const uint8_t frame_id = atnd_frame.get_frame_id(); + _node_by_ni_frame_id = frame_id; + send_api_frame(&atnd_frame); + + ApiFrame * const resp_frame = get_this_api_frame(frame_id, ApiFrame::AtCmdResp); + _timeout_ms = old_timeout; + + _node_by_ni_frame_id = 0; + + if (resp_frame == NULL) { + digi_log(LogLevelWarning, "_get_remote_node_by_id: timeout when waiting for ATND response"); + return; + } + + if (resp_frame->get_data_len() < sizeof (uint16_t) + sizeof (uint64_t)) { + /* In 802.15.4 this might be the OK or Timeout message with no information */ + digi_log(LogLevelInfo, "_get_remote_node_by_id: node not found\r\n", __FUNCTION__, node_id); + _framebuf_syncr.free_frame(resp_frame); + return; + } + + const AtCmdFrame::AtCmdResp resp = (AtCmdFrame::AtCmdResp)resp_frame->get_data_at(ATCMD_RESP_STATUS_OFFSET); + if (resp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelWarning, "_get_remote_node_by_id: send_at_cmd bad response: 0x%x\r\n", resp); + _framebuf_syncr.free_frame(resp_frame); + return; + } + + rmemcpy((uint8_t *)addr16, resp_frame->get_data() + ATCMD_RESP_DATA_OFFSET, sizeof *addr16); + rmemcpy((uint8_t *)addr64, resp_frame->get_data() + ATCMD_RESP_DATA_OFFSET + sizeof *addr16, sizeof *addr64); + _framebuf_syncr.free_frame(resp_frame); + + if (wait_for_complete_timeout) { + while (nd_timer.read_ms() < nd_timeout) { + wait_ms(10); + } + } + + return; +} + +RadioStatus XBee::config_node_discovery(uint16_t backoff_ms, uint8_t options) +{ + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param("NT", (uint8_t)(backoff_ms / 100)); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + + cmdresp = set_param("NO", (uint8_t)options); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + cmdresp = set_param("AC"); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + + return Success; +} + +RadioStatus XBee::get_config_node_discovery(uint16_t * const backoff_ms, uint8_t * const options) +{ + AtCmdFrame::AtCmdResp cmdresp; + uint32_t var32; + + cmdresp = get_param("NT", &var32); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + *backoff_ms = var32; + + cmdresp = get_param("NO", &var32); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + *options = var32; + return Success; +} + +RadioStatus XBee::_get_iosample(const RemoteXBee& remote, uint8_t * const io_sample, uint16_t * const len) +{ + AtCmdFrame::AtCmdResp cmdresp; + + /* Force a sample read */ + cmdresp = get_param(remote, "IS", io_sample, len); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "_get_iosample error %d:\r\n", cmdresp); + return Failure; + } + + return Success; +} + +RadioStatus XBee::config_io_sample_destination(const RemoteXBee& remote, const RemoteXBee& destination) +{ + uint32_t dh; + uint32_t dl; + + if (destination.is_valid_addr64b()) { + const uint64_t dest64 = destination.get_addr64(); + dh = (uint32_t)((dest64 >> 32) & 0xFFFFFFFF); + dl = (uint32_t)((dest64 & 0xFFFFFFFF)); + } else if (destination.is_valid_addr16b()) { + const uint16_t destAddr16 = destination.get_addr16(); + dh = 0; + dl = destAddr16; + } else { + digi_log(LogLevelError, "send_io_sample_to: Invalid destination"); + return Failure; + } + + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param(remote, "DH", dh); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "send_io_sample_to error %d:\r\n", cmdresp); + return Failure; + } + + cmdresp = set_param(remote, "DL", dl); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "send_io_sample_to error %d:\r\n", cmdresp); + return Failure; + } + + return Success; +} + +RadioStatus XBee::set_io_sample_rate(const RemoteXBee& remote, const float seconds) +{ + const float max_seconds = 65.535; + + if (seconds > max_seconds) { + digi_log(LogLevelError, "XBee::set_io_sample_rate error seconds rate exceeds maximum %d:\r\n", max_seconds); + return Failure; + } + + AtCmdFrame::AtCmdResp cmdresp; + const uint16_t milliseconds = seconds * 1000; + + cmdresp = set_param(remote, "IR", milliseconds); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "XBee::set_io_sample_rate error %d:\r\n", cmdresp); + return Failure; + } + + return Success; +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/XBee/XBee.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/XBee/XBee.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,880 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#include "XBeeLib.h" +#include "FrameHandlers/FH_ModemStatus.h" + +/* States for the state machine that processes incoming data on the serial port */ +#define WAITING_FOR_START_FRAME (0) +#define WAITING_FOR_LENGTH_MSB (1) +#define WAITING_FOR_LENGTH_LSB (2) +#define WAITING_FOR_PAYLOAD (3) +#define WAITING_FOR_CHECKSUM (4) + +#define IS_API2() (_mode == ModeAPI2) +#define IS_API_MODE() (_mode == ModeAPI1 || _mode == ModeAPI2) + +using namespace XBeeLib; + +#if defined(FRAME_BUFFER_SIZE_SYNCR) +#if FRAME_BUFFER_SIZE_SYNCR < 2 +#error "FRAME_BUFFER_SIZE_SYNCR must be at least 2" +#endif +#else +#define FRAME_BUFFER_SIZE_SYNCR 1 +#endif + +#define MAX_FRAME_PAYLOAD_LEN_SYNCR (1 /* type */ + 1 /* id */ + 2 /* at cmd*/ + 1 /* status */ + 2 /* MY sender */ + \ + 8 /* 64b sender */ + 20 /* max id */ + 1 /* null ter */ + 2 /* MY parent */ + 1 /* dev type */ + \ + 1 /* source event */ + 2 /* prof. id */ + 2 /* man. id */) + +FrameBuffer XBee::_framebuf_app(FRAME_BUFFER_SIZE, MAX_FRAME_PAYLOAD_LEN); +FrameBuffer XBee::_framebuf_syncr(FRAME_BUFFER_SIZE_SYNCR, MAX_FRAME_PAYLOAD_LEN_SYNCR); + +#if defined(DEVICE_SERIAL_FC) +bool XBee::check_radio_flow_control() +{ + AtCmdFrame::AtCmdResp cmdresp; + uint32_t value; + + if (_serial_flow_type == SerialBase::RTSCTS || _serial_flow_type == SerialBase::CTS) { + cmdresp = get_param("D7", &value); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "Could not read CTS configuration. Error %d\r\n", cmdresp); + return false; + } else if (value != 1) { + digi_log(LogLevelError, "Bad CTS configuration. Radio 'D7' param is %d and should be 1\r\n", value); + return false; + } + } + + if (_serial_flow_type == SerialBase::RTSCTS || _serial_flow_type == SerialBase::RTS) { + cmdresp = get_param("D6", &value); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "Could not read RTS configuration. Error %d\r\n", cmdresp); + return false; + } else if (value != 1) { + digi_log(LogLevelError, "Bad RTS configuration. Radio 'D6' param is %d and should be 1\r\n", value); + return false; + } + } + + return true; +} +#endif + +/* Class constructor */ +XBee::XBee(PinName tx, PinName rx, PinName reset, PinName rts, PinName cts, int baud) : + _mode(ModeUnknown), _hw_version(0), _fw_version(0), _timeout_ms(SYNC_OPS_TIMEOUT_MS), _dev_addr64(ADDR64_UNASSIGNED), + _reset(NULL), _tx_options(0), _hw_reset_cnt(0), _wd_reset_cnt(0), _modem_status_handler(NULL), _modem_status(AtCmdFrame::HwReset), _initializing(true), _node_by_ni_frame_id(0) +{ + + if (reset != NC) { + _reset = new DigitalOut(reset, 1); + } + + _uart = new RawSerial(tx, rx); + _uart->baud(baud); + + _serial_flow_type = SerialBase::Disabled; +#if defined(DEVICE_SERIAL_FC) + if (rts != NC && cts != NC) { + _serial_flow_type = SerialBase::RTSCTS; + _uart->set_flow_control(_serial_flow_type, rts, cts); + } else if (rts != NC && cts == NC) { + _serial_flow_type = SerialBase::RTS; + _uart->set_flow_control(_serial_flow_type, rts); + } else if (rts == NC && cts != NC) { + _serial_flow_type = SerialBase::CTS; + _uart->set_flow_control(_serial_flow_type, cts); + } +#endif + /* Enable the reception of bytes on the serial interface by providing a cb */ + _uart->attach(this, &XBee::uart_read_cb, Serial::RxIrq); + + for (int i = 0; i < MAX_FRAME_HANDLERS; i++) { + _fhandlers[i] = NULL; + } +} + +/* Class destructor */ +XBee::~XBee() +{ + unregister_modem_status_cb(); + + if (_uart != NULL) { + delete _uart; + } + if (_reset != NULL) { + delete _reset; + } +} + +#include <inttypes.h> + +RadioStatus XBee::init(void) +{ + AtCmdFrame::AtCmdResp cmd_resp; + uint32_t var32; + + _initializing = true; + + const unsigned int max_reset_retries = 3; + RadioStatus reset_status; + for (unsigned int i = 0; i < max_reset_retries; i++) { + reset_status = device_reset(); + if (reset_status == Success) { + break; + } + } + if (reset_status != Success) { + return reset_status; + } + + /* Check if radio is in API1 or API2 _mode */ + cmd_resp = get_param("AP", &var32); + if (cmd_resp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + _mode = (RadioMode)var32; + + /* Read the device unique 64b address */ + uint32_t serialn_high, serialn_low; + cmd_resp = get_param("SH", &serialn_high); + if (cmd_resp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + + cmd_resp = get_param("SL", &serialn_low); + if (cmd_resp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + + _dev_addr64 = ((uint64_t)serialn_high << 32) | serialn_low; + + /* Read some important parameters */ + cmd_resp = get_param("HV", &var32); + if (cmd_resp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + _hw_version = var32; + + cmd_resp = get_param("VR", &var32); + if (cmd_resp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + _fw_version = var32; + + digi_log(LogLevelInfo, "mode: %02x\r\n", (uint8_t)_mode); + digi_log(LogLevelInfo, "HV: %04x\r\n", _hw_version); + digi_log(LogLevelInfo, "VR: %04x\r\n", _fw_version); + digi_log(LogLevelInfo, "ADDR64: %08x:%08x\r\n", UINT64_HI32(_dev_addr64), UINT64_LO32(_dev_addr64)); + +#if defined(DEVICE_SERIAL_FC) + bool valid_radio_fc = check_radio_flow_control(); + assert(valid_radio_fc == true); +#endif + + _initializing = false; + if (_modem_status_handler != NULL) { + const ApiFrame frame = ApiFrame(ApiFrame::AtModemStatus, (uint8_t *)&_modem_status, sizeof(_modem_status)); + _modem_status_handler->process_frame_data(&frame); + } + + return Success; +} + +uint64_t XBee::get_addr64() const +{ + return _dev_addr64; +} + +RadioStatus XBee::hardware_reset() +{ + if (_reset != NULL) { + volatile uint16_t * const rst_cnt_p = &_hw_reset_cnt; + const uint16_t init_rst_cnt = *rst_cnt_p; + *_reset = 0; + wait_ms(10); + *_reset = 1; + return wait_for_module_to_reset(rst_cnt_p, init_rst_cnt); + } + + return Failure; +} + +RadioStatus XBee::device_reset() +{ + if (hardware_reset() == Success) { + return Success; + } + + return software_reset(); +} + +RadioStatus XBee::wait_for_module_to_reset(volatile uint16_t *rst_cnt_p, uint16_t init_rst_cnt) +{ + Timer timer = Timer(); + timer.start(); + + while (*rst_cnt_p == init_rst_cnt && timer.read_ms() < RESET_TIMEOUT_MS) { + wait_ms(100); + } + + if (*rst_cnt_p == init_rst_cnt) { + digi_log(LogLevelWarning, "Reset Timeout\r\n"); + return Failure; + } + return Success; +} + +/** Callback function called when data is received on the serial port */ +void XBee::uart_read_cb(void) +{ + static uint8_t rxstate = WAITING_FOR_START_FRAME; + static uint16_t framelen = 0; + static uint16_t bytes_read; + static uint8_t chksum; + static ApiFrame *frame = NULL; + static bool last_byte_escaped = false; + static FrameBuffer * framebuf = NULL; + + while (_uart->readable()) { + uint8_t data = _uart->getc(); + + if (IS_API2() && rxstate != WAITING_FOR_START_FRAME) { + if (last_byte_escaped) { + data = data ^ DR_ESCAPE_XOR_BYTE; + last_byte_escaped = false; + } else if (data == DR_ESCAPE_BYTE) { + last_byte_escaped = true; + continue; + } + } + + switch (rxstate) { + case WAITING_FOR_START_FRAME: + if (data == DR_START_OF_FRAME) { + rxstate = WAITING_FOR_LENGTH_MSB; + } + break; + + case WAITING_FOR_LENGTH_MSB: + framelen = data << 8; + rxstate = WAITING_FOR_LENGTH_LSB; + break; + + case WAITING_FOR_LENGTH_LSB: + framelen |= data; + rxstate = WAITING_FOR_PAYLOAD; + bytes_read = 0; + chksum = 0; + /* Sanity check that the frame is smaller than... */ + if (framelen > MAX_FRAME_PAYLOAD_LEN) { + digi_log(LogLevelDebug, "framelen=%d too long\r\n", framelen); + digi_log(LogLevelWarning, "Frame dropped, frame too long. Increase MAX_FRAME_PAYLOAD_LEN define\r\n"); + rxstate = WAITING_FOR_START_FRAME; + } + break; + + case WAITING_FOR_PAYLOAD: + #define CACHED_SIZE 3 + static uint8_t frame_cached[CACHED_SIZE]; + + if (framelen <= CACHED_SIZE) { + if (!bytes_read) { + const ApiFrame::ApiFrameType frame_type = (ApiFrame::ApiFrameType)data; + switch (frame_type) + { + case ApiFrame::AtCmdResp: + case ApiFrame::RemoteCmdResp: + case ApiFrame::TxStatusZBDM: + case ApiFrame::TxStatus: + framebuf = &_framebuf_syncr; + break; + + case ApiFrame::RxPacket64Bit: + case ApiFrame::RxPacket16Bit: + case ApiFrame::Io64Bit: + case ApiFrame::Io16Bit: + case ApiFrame::AtModemStatus: + case ApiFrame::RxPacketAO0: + case ApiFrame::IoSampleRxZBDM: + framebuf = &_framebuf_app; + break; + + case ApiFrame::RxPacketAO1: + case ApiFrame::SensorRxIndAO0: + case ApiFrame::NodeIdentIndAO0: + case ApiFrame::OtaFwUpStatus: + case ApiFrame::RouteRecInd: + case ApiFrame::Many2OneRRInd: + case ApiFrame::TxReq64Bit: + case ApiFrame::TxReq16Bit: + case ApiFrame::AtCmd: + case ApiFrame::AtCmdQueuePV: + case ApiFrame::TxReqZBDM: + case ApiFrame::ExpAddrCmd: + case ApiFrame::RemoteCmdReq: + case ApiFrame::CreateSrcRoute: + case ApiFrame::Invalid: + case ApiFrame::RouteInfo: + case ApiFrame::AggregateAddr: + framebuf = NULL; + break; + } + + if (framebuf == NULL) { + digi_log(LogLevelWarning, "Discarding not supported frame type %02x\r\n", frame_type); + rxstate = WAITING_FOR_START_FRAME; + } else { + frame = framebuf->get_next_free_frame(); + if (frame == NULL) { + /* It's not possible to achive this condition as we discard older frames and only one frame can be used by syncr. commands */ + assert(frame != NULL); + rxstate = WAITING_FOR_START_FRAME; + } else { + frame->set_data_len(framelen - 1); + } + + frame->set_frame_type(frame_type); + } + } else { + frame->set_data(data, bytes_read - 1); + } + chksum += data; + bytes_read++; + if (bytes_read == framelen) { + rxstate = WAITING_FOR_CHECKSUM; + } + break; + } + + + if (bytes_read < CACHED_SIZE) { + frame_cached[bytes_read] = data; + } + else if (bytes_read == CACHED_SIZE) { + const ApiFrame::ApiFrameType frame_type = (ApiFrame::ApiFrameType)frame_cached[0]; + switch (frame_type) + { + case ApiFrame::RemoteCmdResp: + case ApiFrame::TxStatusZBDM: + case ApiFrame::TxStatus: + framebuf = &_framebuf_syncr; + break; + + case ApiFrame::AtCmdResp: + if ((frame_cached[1] != _node_by_ni_frame_id ) && (frame_cached[2] == 'N') && (data == 'D')) + { + framebuf = &_framebuf_app; + } else { + framebuf = &_framebuf_syncr; + } + break; + + case ApiFrame::RxPacket64Bit: + case ApiFrame::RxPacket16Bit: + case ApiFrame::Io64Bit: + case ApiFrame::Io16Bit: + case ApiFrame::AtModemStatus: + case ApiFrame::RxPacketAO0: + case ApiFrame::IoSampleRxZBDM: + framebuf = &_framebuf_app; + break; + + case ApiFrame::RxPacketAO1: + case ApiFrame::SensorRxIndAO0: + case ApiFrame::NodeIdentIndAO0: + case ApiFrame::OtaFwUpStatus: + case ApiFrame::RouteRecInd: + case ApiFrame::Many2OneRRInd: + case ApiFrame::TxReq64Bit: + case ApiFrame::TxReq16Bit: + case ApiFrame::AtCmd: + case ApiFrame::AtCmdQueuePV: + case ApiFrame::TxReqZBDM: + case ApiFrame::ExpAddrCmd: + case ApiFrame::RemoteCmdReq: + case ApiFrame::CreateSrcRoute: + case ApiFrame::Invalid: + case ApiFrame::RouteInfo: + case ApiFrame::AggregateAddr: + framebuf = NULL; + break; + } + + if (framebuf == NULL) { + digi_log(LogLevelWarning, "Discarding not supported frame type %02x\r\n", frame_type); + rxstate = WAITING_FOR_START_FRAME; + } else { + frame = framebuf->get_next_free_frame(); + if (frame == NULL) { + /* It's not possible to achive this condition as we discard older frames and only one frame can be used by syncr. commands */ + assert(frame != NULL); + rxstate = WAITING_FOR_START_FRAME; + } else { + frame->set_data_len(framelen - 1); + } + + frame->set_frame_type(frame_type); + frame->set_data(frame_cached[1], 0); + frame->set_data(frame_cached[2], 1); + frame->set_data(data, 2); + } + } else { + frame->set_data(data, bytes_read - 1); + } + chksum += data; + bytes_read++; + if (bytes_read == framelen) { + rxstate = WAITING_FOR_CHECKSUM; + } + break; + + case WAITING_FOR_CHECKSUM: + chksum += data; + if (chksum == 0xFF) { + /* We got a valid frame!! */ + frame->dump(); + + /* If its a _modem status frame, process it to update the status info of the library. + * The frame is also queued to allow processing it other handlers registered. + * Note that radio_status_update() has to be fast to minimize the impact of processing + * the funcion here */ + if (frame->get_frame_type() == ApiFrame::AtModemStatus) { + radio_status_update((AtCmdFrame::ModemStatus)frame->get_data_at(0)); + if (_initializing) { + framebuf->free_frame(frame); + } else { + framebuf->complete_frame(frame); + } + } else { + framebuf->complete_frame(frame); + /* Note, the frame will be released elsewhere, once it has been processed */ + } + } else { + framebuf->free_frame(frame); + digi_log(LogLevelWarning, "Checksum error, got %02x, %02x\r\n", data, chksum); + } + /* Intentional fall-through */ + default: + rxstate = WAITING_FOR_START_FRAME; + break; + } + } + /* TODO, signal the thread processing incoming frames */ +} + +/* This is a pure virtual function, but exists here because its called from this class to + * to update the status of the object, and can be called before the construction of the + * object has been completed and the virtual functions filled */ +void XBee::radio_status_update(AtCmdFrame::ModemStatus modem_status) +{ + UNUSED_PARAMETER(modem_status); +} + +void XBee::set_timeout(uint16_t timeout_ms) +{ + this->_timeout_ms = timeout_ms; +} + +uint16_t XBee::get_timeout(void) const +{ + return _timeout_ms; +} + +ApiFrame * XBee::get_this_api_frame(uint8_t id, ApiFrame::ApiFrameType type, + ApiFrame::ApiFrameType type2) +{ + Timer timer = Timer(); + timer.start(); + + while (timer.read_ms() < _timeout_ms) { + ApiFrame * frame = _framebuf_syncr.get_next_complete_frame(); + if (frame == NULL) { + wait_ms(10); + continue; + } + + if ((frame->get_frame_type() != type) && + (frame->get_frame_type() != type2)) { + _framebuf_syncr.complete_frame(frame); + wait_ms(1); + continue; + } + + if (frame->get_data_at(ATCMD_RESP_FRAME_ID_OFFSET) != id) { + _framebuf_syncr.complete_frame(frame); + wait_ms(1); + continue; + } + + /* frame found */ + return frame; + } + + digi_log(LogLevelWarning, "Frame type: %02x, id: %02x, timeout\r\n", (uint8_t)type, id); + + return NULL; +} + +void XBee::send_byte_escaping_if(uint8_t data) +{ + if (IS_API2()) { + switch (data) { + case DR_START_OF_FRAME: + case DR_ESCAPE_BYTE: + case DR_XON_BYTE: + case DR_XOFF_BYTE: + _uart->putc(DR_ESCAPE_BYTE); + _uart->putc(data ^ DR_ESCAPE_XOR_BYTE); + break; + default: + _uart->putc(data); + } + } else { + _uart->putc(data); + } +} + +void XBee::send_api_frame(ApiFrame *frame) +{ + uint8_t chksum; + const uint8_t *data; + uint16_t bytes_sent = 0, frame_len; + + frame->dump(); + + frame_len = 1 + frame->get_data_len(); /* frame type + frame payload */ + data = frame->get_data(); + + /* Send the start of frame delimiter */ + _uart->putc(DR_START_OF_FRAME); + + /* Now the length */ + send_byte_escaping_if((uint8_t)(frame_len >> 8)); + send_byte_escaping_if((uint8_t)frame_len); + + /* Send the Frame type and then the payload */ + chksum = (uint8_t)frame->get_frame_type(); + send_byte_escaping_if(chksum); + bytes_sent++; + + /* And now, send the packet payload */ + while (bytes_sent++ < frame_len) { + chksum += *data; + send_byte_escaping_if(*data++); + } + + /* And finally send the checksum */ + send_byte_escaping_if(~chksum); +} + +RadioStatus XBee::register_frame_handler(FrameHandler *const handler) +{ + if (handler != NULL) { + for (int i = 0; i < MAX_FRAME_HANDLERS; i++) { + if (_fhandlers[i] != NULL) { + continue; + } + _fhandlers[i] = handler; + return Success; + } + } + + digi_log(LogLevelError, "No more Frame Handlers available. Increase MAX_FRAME_HANDLERS define\r\n"); + + return Failure; +} + +RadioStatus XBee::unregister_frame_handler(FrameHandler *const handler) +{ + int i; + + if (handler != NULL) { + for (i = 0; i < MAX_FRAME_HANDLERS; i++) { + if (_fhandlers[i] == handler) { + break; + } + } + + if (i == MAX_FRAME_HANDLERS) { + return Failure; + } + + do { + if (i == MAX_FRAME_HANDLERS - 1) { + _fhandlers[i] = NULL; + } else { + _fhandlers[i] = _fhandlers[i + 1]; + } + } while (++i < MAX_FRAME_HANDLERS); + } + + return Success; +} + +XBee::RadioProtocol XBee::get_radio_protocol(void) const +{ + enum HardwareVersion { +#ifdef EXTRA_XBEE_PROTOCOLS + X09_009 = 0x01, + X09_019 = 0x02, + XH9_009 = 0x03, + XH9_019 = 0x04, + X24_009 = 0x05, + X24_019 = 0x06, + X09_001 = 0x07, + XH9_001 = 0x08, + X08_004 = 0x09, + XC09_009 = 0x0A, + XC09_038 = 0x0B, + X24_038 = 0x0C, + X09_009_TX = 0x0D, + X09_019_TX = 0x0E, + XH9_009_TX = 0x0F, + XH9_019_TX = 0x10, + X09_001_TX = 0x11, + XH9_001_TX = 0x12, + XT09B_XXX = 0x13, + XT09_XXX = 0x14, + XC08_009 = 0x15, + XC08_038 = 0x16, +#endif + XB24_AXX_XX = 0x17, + XBP24_AXX_XX = 0x18, + XB24_BXIX_XXX = 0x19, + XBP24_BXIX_XXX = 0x1A, +#ifdef EXTRA_XBEE_PROTOCOLS + XBP09_DXIX_XXX = 0x1B, + XBP09_XCXX_XXX = 0x1C, + XBP08_DXXX_XXX = 0x1D, +#endif + XBP24B = 0x1E, +#ifdef EXTRA_XBEE_PROTOCOLS + XB24_WF = 0x1F, + AMBER_MBUS = 0x20, +#endif + XBP24C = 0x21, + XB24C = 0x22, +#ifdef EXTRA_XBEE_PROTOCOLS + XSC_GEN3 = 0x23, + SRD_868_GEN3 = 0x24, + ABANDONATED = 0x25, + SMT_900LP = 0x26, + WIFI_ATHEROS = 0x27, + SMT_WIFI_ATHEROS = 0x28, + SMT_475LP = 0x29, + XBEE_CELL_TH = 0x2A, + XLR_MODULE = 0x2B, + XB900HP_NZ = 0x2C, + XBP24C_TH_DIP = 0x2D, + XB24C_TH_DIP = 0x2E, + XLR_BASEBOARD = 0x2F, + XBP24C_S2C_SMT = 0x30 +#endif + }; + const bool fw_4_bytes_len = _fw_version > 0x0FFF && _fw_version < 0xFFFF; + const uint8_t fw_nibble_3 = (_fw_version >> (4 * 3)) & 0x000F; + const uint8_t fw_nibble_1 = (_fw_version >> (4 * 1)) & 0x000F; + const uint8_t fw_nibble_0 = (_fw_version >> (4 * 0)) & 0x000F; + const uint8_t hw_version_msb = _hw_version >> 8; + + if (hw_version_msb == XB24_AXX_XX || hw_version_msb == XBP24_AXX_XX) { +#ifdef EXTRA_XBEE_PROTOCOLS + if (fw_4_bytes_len && fw_nibble_3 == 8) { + return DigiMesh; + } + return Raw_802_15_4; +#else + if (!(fw_4_bytes_len && fw_nibble_3 == 8)) { + return Raw_802_15_4; + } +#endif + } else if (hw_version_msb == XB24_BXIX_XXX || hw_version_msb == XBP24_BXIX_XXX) { + if (fw_4_bytes_len && ((fw_nibble_3 == 1 && fw_nibble_1 == 2 && fw_nibble_0 == 0) || fw_nibble_3 == 2)) { + return ZigBee; + } +#ifdef EXTRA_XBEE_PROTOCOLS + if (fw_4_bytes_len && fw_nibble_3 == 3) { + return SmartEnergy; + } + return ZNet; + } else if (hw_version_msb == XBP09_DXIX_XXX) { + if (fw_4_bytes_len && (fw_nibble_3 == 8 || fw_nibble_1 == 8)) { + return DigiMesh; + } + return DigiPoint; + } else if (hw_version_msb == XBP08_DXXX_XXX) { + return DigiPoint; +#endif + } else if (hw_version_msb == XBP24B) { +#ifdef EXTRA_XBEE_PROTOCOLS + if (fw_4_bytes_len && fw_nibble_3 == 3) { + return SmartEnergy; + } + return ZigBee; +#else + if (!(fw_4_bytes_len && fw_nibble_3 == 3)) { + return ZigBee; + } +#endif +#ifdef EXTRA_XBEE_PROTOCOLS + } else if (hw_version_msb == XB24_WF || hw_version_msb == WIFI_ATHEROS || hw_version_msb == SMT_WIFI_ATHEROS) { + return XBeeWiFi; +#endif + } else if (hw_version_msb == XBP24C || hw_version_msb == XB24C) { + if (fw_4_bytes_len && fw_nibble_3 == 2) { + return Raw_802_15_4; + } +#ifdef EXTRA_XBEE_PROTOCOLS + if (fw_4_bytes_len && fw_nibble_3 == 5) { + return SmartEnergy; + } + return ZigBee; +#else + if (!(fw_4_bytes_len && fw_nibble_3 == 5)) { + return ZigBee; + } +#endif +#ifdef EXTRA_XBEE_PROTOCOLS + } else if (hw_version_msb == XSC_GEN3 || hw_version_msb == SRD_868_GEN3) { + if (fw_4_bytes_len && fw_nibble_3 == 8) { + return DigiMesh; + } else if (fw_4_bytes_len && fw_nibble_3 == 1) { + return DigiPoint; + } + return None; + } else if (hw_version_msb == XBEE_CELL_TH) { + return None; + } else if (hw_version_msb == XLR_MODULE) { + return None; + } else if (hw_version_msb == XLR_BASEBOARD) { + return None; + } else if (hw_version_msb == XB900HP_NZ) { + return DigiPoint; + } else if (hw_version_msb == XBP24C_TH_DIP || hw_version_msb == XB24C_TH_DIP || hw_version_msb == XBP24C_S2C_SMT) { + if (fw_4_bytes_len && fw_nibble_3 == 9) { + return DigiMesh; + } + if (fw_4_bytes_len && fw_nibble_3 == 5) { + return SmartEnergy; + } + if (fw_4_bytes_len && fw_nibble_3 == 2) { + return Raw_802_15_4; + } + return ZigBee; + } +#else + } +#endif + + return None; +} + +#define TX_STATUS_OFFSET_ZB 4 +#define TX_STATUS_OFFSET_802 1 + +TxStatus XBee::send_data(ApiFrame *frame) +{ + TxStatus resp = TxStatusTimeout; + ApiFrame *resp_frame; + + send_api_frame(frame); + + /* Wait for the transmit status response packet */ + resp_frame = get_this_api_frame(frame->get_frame_id(), + ApiFrame::TxStatusZBDM, ApiFrame::TxStatus); + if (resp_frame == NULL) { + return resp; + } + + uint8_t index = resp_frame->get_frame_type() == ApiFrame::TxStatusZBDM ? + TX_STATUS_OFFSET_ZB : TX_STATUS_OFFSET_802; + + resp = (TxStatus)resp_frame->get_data_at(index); + + /* Once processed, remove the frame from the buffer */ + _framebuf_syncr.free_frame(resp_frame); + + return resp; +} + +TxStatus XBee::send_data_broadcast(const uint8_t *const data, uint16_t len, bool syncr) +{ + const RemoteXBee remoteDevice = RemoteXBee(ADDR64_BROADCAST); + return send_data(remoteDevice, data, len, syncr); +} + +uint32_t XBee::process_rx_frames() +{ + ApiFrame *frame = NULL; + + while ((frame = _framebuf_app.get_next_complete_frame()) != NULL) { + for (int i = 0; i < MAX_FRAME_HANDLERS; i++) { + + if (_fhandlers[i] == NULL) { + /* No more handlers, break here */ + break; + } + + /* Check if frame and handler match, if not... go for the next one */ + if (frame->get_frame_type() != _fhandlers[i]->get_type()) { + continue; + } + + _fhandlers[i]->process_frame_data(frame); + } + + /* Once processed, remove the frame from the buffer */ + _framebuf_app.free_frame(frame); + } + + const uint32_t dropped_frames = _framebuf_app.get_dropped_frames_count(); + if (dropped_frames != 0) { + digi_log(LogLevelWarning, "process_rx_frames: %d frames dropped!!!\r\n", dropped_frames); + } + + return dropped_frames; +} + +void XBee::register_modem_status_cb(modem_status_cb_t function) +{ + if (_modem_status_handler == NULL) { + _modem_status_handler = new FH_ModemStatus(); + register_frame_handler(_modem_status_handler); + } + _modem_status_handler->register_modem_status_cb(function); +} + +void XBee::unregister_modem_status_cb() +{ + if (_modem_status_handler != NULL) { + _modem_status_handler->unregister_modem_status_cb(); + unregister_frame_handler(_modem_status_handler); + delete _modem_status_handler; + _modem_status_handler = NULL; /* as delete does not set to NULL */ + } +} + +int XBee::get_AI(void) +{ + uint32_t atai; + const AtCmdFrame::AtCmdResp status = get_param("AI", &atai); + + if (status != AtCmdFrame::AtCmdRespOk) { + digi_log(LogLevelError, "get_association_indication() failed with %d\r\n", status); + return -1; + } + return atai; +}
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/XBee/XBee.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/XBee/XBee.h Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,714 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ + +#if !defined(__DIGI_RADIO_H_) +#define __DIGI_RADIO_H_ + +#include <stdint.h> +#include "config.h" +#include "Utils/Debug.h" +#include "Frames/AtCmdFrame.h" +#include "FrameHandlers/FrameHandler.h" +#include "FrameHandlers/FH_ModemStatus.h" +#include "FrameBuffer/FrameBuffer.h" +#include "Addresses.h" +#include "RemoteXBee/RemoteXBee.h" +#include "IO/IO.h" + +#define MAX_FRAME_HANDLERS 4 +#define RESET_TIMEOUT_MS 5000 + +#define DR_API_FRAME_OVERHEAD 4 /* Start of frame + frame len + checksum */ +#define DR_MIN_API_FRAME_LEN 4 +#define DR_START_OF_FRAME 0x7E +#define DR_ESCAPE_BYTE 0x7D +#define DR_XON_BYTE 0x11 +#define DR_XOFF_BYTE 0x13 +#define DR_ESCAPE_XOR_BYTE 0x20 + +/* TODO, verify these flags work in all modules */ +#define DISABLE_RETRIES_AND_ROUTE_REPAIR 0x01 +#define ENABLE_APS_ENCRYPTION 0x20 +#define USE_EXTENDED_TX_TIMEOUT 0x40 + +namespace XBeeLib { + +/** + * @defgroup RadioStatus + * @{ + */ +/** + * RadioStatus + */ +enum RadioStatus { + Success = 0, /**< Success */ + Failure = -1, /**< Failure */ +}; +/** + * @} + */ + +/** + * @defgroup TxStatus + * @{ + */ +/** + * TxStatus + */ +enum TxStatus { + TxStatusSuccess = 0, /**< Success */ + TxStatusAckFail = 1, /**< MAC ACK Failure */ + TxStatusCCAFail = 2, /**< CCA Failure */ + TxStatusInvDestEP = 0x15, /**< Invalid destination endpoint */ + TxStatusNwAckFail = 0x21, /**< Network ACK Failure */ + TxStatusNotJoinNw = 0x22, /**< Not Joined to Network */ + TxStatusSelfAddr = 0x23, /**< Self-addressed */ + TxStatusAddrNotFound = 0x24, /**< Address Not Found */ + TxStatusRouteNotFound = 0x25, /**< Route Not Found */ + TxStatusBroadSrcFail2Heard = 0x26, /**< Broadcast source failed to hear a neighbor relay the message */ + TxStatusInvBindTableIdx = 0x2B, /**< Invalid binding table index */ + TxStatusResourceError = 0x2C, /**< Resource error lack of free buffers, timers, etc. */ + TxStatusAttBroadcWithAPS = 0x2D, /**< Attempted broadcast with APS transmission */ + TxStatusAttUnicWithAPSEE0 = 0x2E, /**< Attempted unicast with APS transmission, but EE=0 */ + TxStatusResourceError2 = 0x31, /**< TxStatusResourceError2 */ + TxStatusInternalError = 0x32, /**< Resource error lack of free buffers, timers, etc. */ + TxStatusPayloadTooLarge = 0x74, /**< Data payload too large */ + TxStatusIndirectMsgUnReq = 0x75, /**< Indirect message unrequested */ + TxStatusInvalidAddr = 0xfe, /**< Invalid Address (Error generated by the library) */ + TxStatusTimeout = 0xff, /**< Timeout (Error generated by the library) */ +}; +/** + * @} + */ + +/** + * @defgroup RadioLocation + * @{ + */ +/** + * RadioLocation + */ +enum RadioLocation { + RadioLocal = 0, /**< Local Radio */ + RadioRemote = 1, /**< Remote Radio */ +}; +/** + * @} + */ + +/** Parent Class for XBee modules, not to be directly used */ +class XBee +{ + private: + /** wait_for_module_to_reset - waits until a Modem Status packet with a reset status + * is received, or the timeout expires. + * + * @returns + * Success if a Modem Status was received, + * Failure otherwise + */ + RadioStatus wait_for_module_to_reset(volatile uint16_t *rst_cnt_p, uint16_t init_rst_cnt); + + protected: + /** buffer to store the received frames */ + static FrameBuffer _framebuf_app; + static FrameBuffer _framebuf_syncr; + + public: + + /** + * RadioMode + */ + enum RadioMode { + ModeUnknown = 0, /**< Unknown */ + ModeAPI1 = 1, /**< API1 */ + ModeAPI2 = 2, /**< API2 */ + ModeTransparent = 3, /**< Transparent */ + ModeBootloader = 4, /**< Bootloader */ + }; + + /** Class constructor + * @param tx the TX pin of the UART that will interface the XBee module + * @param rx the RX pin of the UART that will interface the XBee module + * @param reset the pin to which the XBee's reset line is attached to, use NC if not available + * @param rts the RTS pin for the UART that will interface the XBee module, use NC if not available + * @param cts the CTS pin for the UART that will interface the XBee module, use NC if not available + * @param baud the baudrate for the UART that will interface the XBee module. Note that the module has to be already configured + * to this baud rate (ATBD parameter). By default it is configured to 9600 bps + * */ + XBee(PinName tx, PinName rx, PinName reset = NC, PinName rts = NC, PinName cts = NC, int baud = 9600); + + XBee(const XBee& other); /* Intentionally not implemented */ + /** Class destructor */ + virtual ~XBee(); + + /** init- initializes object + * This function must be called just after creating the object so it initializes internal data. + * @returns + * Success if the module has been properly initialized and is ready to process data. + * Failure otherwise. + */ + RadioStatus init(); + + /** get_addr64 - returns the 64bit address of the local device + * + * @returns the 64bit address of the local device + */ + uint64_t get_addr64() const; + + /** hardware_reset - performs a hardware reset. The reset GPIO must have + * been provided to the constructor + * + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus hardware_reset(); + + /** software_reset - performs a firmware reset + * + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus software_reset(); + + /** device_reset - performs a hardware reset if there is a GPIO connected to the + * reset line of the device. Otherwise, performs a firmware reset. + * + * @returns + * Success if the operation was successful, + * Failure otherwise + */ +#if defined(UNIT_TEST) + virtual +#endif + RadioStatus device_reset(); + + /** set_tx_options - sets the transmit options byte, used with the transmit frames. + * Valid flags are: + * - DISABLE_RETRIES_AND_ROUTE_REPAIR + * - ENABLE_APS_ENCRYPTION + * - USE_EXTENDED_TX_TIMEOUT + * + * @param options variable with the option flags + */ + void set_tx_options(uint8_t options); + + /** get_tx_options - returns the tx options byte configured in the library. + * + * @returns the tx options byte configured in the library. + */ + uint8_t get_tx_options() const; + + /************************ Configuration member methods *************************/ + /** write_config - write settings to non volatile memory + * + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus write_config(); + + /** config_io_sample_destination - configures to which node a remote module will send its IO Samples to. + * @Note: this will modify 'remote' DH and DL parameters, if the remote node is configured in transparent mode this could lead to unwanted behavior. + * Consult the module's reference manual for more information. + * + * @param remote remote device that will be sending the IO Samples + * @param destination remote device that will be receiving the IO Samples sent by 'remote' + * @returns the result of the data transfer + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus config_io_sample_destination(const RemoteXBee& remote, const RemoteXBee& destination); + + /** set_io_sample_rate - configures how often the IO Samples should be sent to the destination (see @ref send_io_sample_to). + * + * @param remote remote device that will be sending the IO Samples + * @param seconds the IO Sample sending rate in seconds (granularity is of 1 millisecond). Maximum is 65.535 seconds. + * @returns the result of the data transfer + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus set_io_sample_rate(const RemoteXBee& remote, float seconds); + + /** set_power_level - sets the power level at which the radio will transmit + * + * @param level power level at which the radio will transmit + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus set_power_level(uint8_t level); + + /** get_power_level - reads the power level configured in the radio + * + * @param level pointer where the read power level will be stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_power_level(uint8_t * const level); + + /** get_hw_version - gets the hardware version of the radio + * + * @returns the hardware version of the radio + */ + uint16_t get_hw_version() const; + + /** get_fw_version - gets the firmware version of the radio + * + * @returns the firmware version of the radio + */ + uint16_t get_fw_version() const; + + /** set_node_identifier - configures the Node Identifier string + * + * @param node_id NULL-terminated string with the Node Identifier that will be set on the module. Up to 20 characters length (21 with NULL-terminator). + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus set_node_identifier(const char * const node_id); + + /** get_node_identifier - reads the configured Node Identifier string + * + * @param node_id Pointer to where to store the read Node Identifier, it must point to a buffer with at least 21-bytes length. + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_node_identifier(char * const node_id); + + /** enable_network_encryption - Enable network encryption. + * + * @param enable whether to enable this feature or not + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus enable_network_encryption(bool enable); + + /** set_network_encryption_key - Sets the 128-bit AES key used for encryption and decryption. Setting it to 0 will cause the coordinator to transmit the network key in the clear to joining devices, and will cause joining devices to acquire the network key in the clear when joining. + * It is not recommended to set the key programmatically, because it could be read through the raw serial port bits. + * @param key pointer to the 128-bit AES key + * @param length size of the buffer pointed by 'key' + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus set_network_encryption_key(const uint8_t * const key, const uint16_t length); + + /** start_node_discovery - starts a node discovery operation. The responses + * have to be processes on the callback function that have to be registered + * for that purpose. + * + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus start_node_discovery(); + + /** is_node_discovery_in_progress - checks if node discovery is in progress. + * @returns true if node discovery is in progress, false otherwise + */ + bool is_node_discovery_in_progress(); + +#define XBEEZB_ND_OPTION_APPEND_DD (1 << 0) +#define XBEEZB_ND_OPTION_SELF_RESPONSE (1 << 1) +#define XBEE802_ND_OPTION_SELF_RESPONSE (1 << 0) +#define XBEEDM_ND_OPTION_APPEND_DD (1 << 0) +#define XBEEDM_ND_OPTION_SELF_RESPONSE (1 << 1) +#define XBEEDM_ND_OPTION_INCLUDE_RSSI (1 << 2) + + /** config_node_discovery - configures the node discovery operation + * + * @param backoff_ms max allowed time for devices in the network to answer + * to the Node Discovery request + * @param options node discovery options (flags) + * XBEE802_ND_OPTION_SELF_RESPONSE - to allow the module self responding (802.15.4 only) + * XBEEZB_ND_OPTION_SELF_RESPONSE - to allow the module self responding (ZigBee only) + * XBEEZB_ND_OPTION_APPEND_DD - to append the DD value to the response (ZigBee only) + * XBEEDM_ND_OPTION_INCLUDE_RSSI - to include RSSI information in response (DigiMesh only) + * XBEEDM_ND_OPTION_SELF_RESPONSE - to allow the module self responding (DigiMesh only) + * XBEEDM_ND_OPTION_APPEND_DD - to append the DD value to the response (DigiMesh only) + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus config_node_discovery(uint16_t backoff_ms, uint8_t options = 0); + + /** get_config_node_discovery - reads the configuration of the node discovery + * settings + * + * @param backoff_ms pointer where the configured node discovery back-off time value will be stored + * @param options pointer whre the node discovery options (flags) will be saved + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus get_config_node_discovery(uint16_t * const backoff_ms, uint8_t * const options); + + /** set_timeout - sets the timeout in ms, used by sync methods + * + * @param timeout_ms new timeout in ms + */ + void set_timeout(uint16_t timeout_ms); + + /** get_timeout - gets the timeout in ms configured in the library. This value + * is used in sync commands + * + * @returns the configured timeout value in ms + */ + uint16_t get_timeout() const; + + /* ... */ + + /*********************** send_data member methods ************************/ + /** send_data - sends data to a remote device + * + * @param remote remote device + * @param data pointer to the data that will be sent + * @param len number of bytes that will be transmitted + * @param syncr if true, method waits for the packet answer with the result of the operation + * @returns the result of the data transfer + * TxStatusSuccess if the operation was successful, + * the error code otherwise + */ + virtual TxStatus send_data(const RemoteXBee& remote, const uint8_t *const data, uint16_t len, bool syncr = true) = 0; + + /** send_data_broadcast - sends data to all devices in the network, using the broadcast address. + * + * @param data pointer to the data that will be sent + * @param len number of bytes that will be transmitted + * @param syncr if true, method waits for the packet answer with the result of the operation + * @returns the result of the data transfer + * TxStatusSuccess if the operation was successful, + * the error code otherwise + */ + TxStatus send_data_broadcast(const uint8_t *const data, uint16_t len, bool syncr = true); + + /** set_param - sets a parameter in the local radio by sending an AT command and waiting for the response. + * + * @param param parameter to be set. + * @param data the parameter value (4 bytes) to be set. + * @returns the command response status. + */ + AtCmdFrame::AtCmdResp set_param(const char * const param, uint32_t data); + + /** set_param - sets a parameter in the local radio by sending an AT command and waiting for the response. + * + * @param param parameter to be set. + * @param data the parameter value byte array (len bytes) to be set. + * @param len number of bytes of the parameter value. + * @returns the command response status. + */ + AtCmdFrame::AtCmdResp set_param(const char * const param, const uint8_t * data = NULL, uint16_t len = 0); + + /** get_param - gets a parameter from the local radio by sending an AT command and waiting for the response. + * + * @param param parameter to be get. + * @param data pointer where the param value (4 bytes) will be stored. + * @returns the command response status. + */ + AtCmdFrame::AtCmdResp get_param(const char * const param, uint32_t * const data); + + /** get_param - gets a parameter from the local radio by sending an AT command and waiting for the response. + * + * @param param parameter to be get. + * @param data pointer where the param value (n bytes) will be stored. + * @param len pointer where the number of bytes of the param value will be stored. + * @returns the command response status. + */ + AtCmdFrame::AtCmdResp get_param(const char * const param, uint8_t * const data, uint16_t * const len); + + /** set_param - sets a parameter in a remote radio by sending an AT command and waiting for the response. + * + * @param remote remote device + * @param param parameter to be set. + * @param data the parameter value (4 bytes) to be set. + * @returns the command response status. + */ + virtual AtCmdFrame::AtCmdResp set_param(const RemoteXBee& remote, const char * const param, uint32_t data) = 0; + + /** set_param - sets a parameter in a remote radio by sending an AT command and waiting for the response. + * + * @param remote remote device + * @param param parameter to be set. + * @param data the parameter value byte array (len bytes) to be set. + * @param len number of bytes of the parameter value. + * @returns the command response status. + */ + virtual AtCmdFrame::AtCmdResp set_param(const RemoteXBee& remote, const char * const param, const uint8_t * data = NULL, uint16_t len = 0) = 0; + + /** get_param - gets a parameter from a remote radio by sending an AT command and waiting for the response. + * + * @param remote remote device + * @param param parameter to be get. + * @param data pointer where the param value (4 bytes) will be stored. + * @returns the command response status. + */ + virtual AtCmdFrame::AtCmdResp get_param(const RemoteXBee& remote, const char * const param, uint32_t * const data) = 0; + + /** get_param - gets a parameter from a remote radio by sending an AT command and waiting for the response. + * + * @param remote remote device + * @param param parameter to be get. + * @param data pointer where the param value (n bytes) will be stored. + * @param len pointer where the number of bytes of the param value will be stored. + * @returns the command response status. + */ + virtual AtCmdFrame::AtCmdResp get_param(const RemoteXBee& remote, const char * const param, uint8_t * const data, uint16_t * const len) = 0; + + /** process_rx_frames - method that processes the frames queued in the reception + * buffer. Calls the process_frame_data method of the frame + * handlers registered + * + * @returns Number of dropped frames since latest call to this method. + */ + uint32_t process_rx_frames(); + + /** register_modem_status_cb - registers the callback function that will be called + * when a Modem Status packet is received + * + * @param function function pointer with the callback function + */ + void register_modem_status_cb(modem_status_cb_t function); + + /** unregister_modem_status_cb - removes the Modem Status reception callback */ + void unregister_modem_status_cb(); + + protected: + +#define EXTRA_XBEE_PROTOCOLS + + enum RadioProtocol { + None, + ZigBee, + Raw_802_15_4, +#ifdef EXTRA_XBEE_PROTOCOLS + XBeeWiFi, + DigiMesh, + SmartEnergy, + DigiPoint, + ZNet, +#endif + }; + /** send_byte_escaping_if - sends a byte, through the serial interface, to + * the radio, escaping the byte if the working mode of the radio is API2. + * + * @param line PWM line being set + * @param data the byte that will be send to radio + */ + void send_byte_escaping_if(uint8_t data); + + /** uart_read_cb - serial interface callback, called when data is received on + * the serial port. The function parses the incoming data and, when a good + * frame is detected, saves it in the frame list + */ + void uart_read_cb(); + + /** get_this_api_frame - searches in the FrameBuffer for an incoming frame + * with frameid equal to id and frame type equal to type + * or type2. If after timeout the frame hast not been found, + * returns. + * + * @param id id of the frame we are looking for. + * @param type tye type we expect the frame to be. + * @param type2 alternative valid type, if provided. + * @returns a pointer to the frame found in the FrameBuffer or a null pointer if + * the frame has not been found and the timeout expired. + */ + ApiFrame * get_this_api_frame(uint8_t id, ApiFrame::ApiFrameType type, + ApiFrame::ApiFrameType type2 = ApiFrame::Invalid); + + /** send_api_frame - method to send, over the serial port, an API frame + * + * @param frame pointer to the frame that will be sent. + */ +#if defined(UNIT_TEST) + virtual +#endif + void send_api_frame(ApiFrame *frame); + + /** update_radio_status - method called when a modem status frame is received + * to update the internal status variables of the library. + * @note This is not a pure virtual function because it can be called while + * the object is being constructed and we need the implementation of the + * base class. + * + * @param status byte with the status received in the modem status frame + */ + virtual void radio_status_update(AtCmdFrame::ModemStatus modem_status); + + /** Method used internaly by the derived classes to transmit data to + * remote nodes, waiting for the answer from the device + * + * @param frame frame that will be sent to the radio (have to be a + * proper transmit frame + * @returns the result of the data transfer + * TxStatusSuccess if the operation was successful, + * the error code otherwise + */ + TxStatus send_data(ApiFrame *frame); + + /** send_at_cmd - sends an AT command to the radio and waits for the response. + * + * @param frame api frame with the command and command params. + * @param buf pointer where the param response (n bytes) will be stored. + * @param len pointer where the number of bytes of the param response will be stored. + * @param radio_location radio location, either RadioLocal or RadioRemote. + * @param reverse reverse the byte ordering of the response saved in buf. + * @returns the command response status. + */ + AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame, + uint8_t *const buf, uint16_t *const len, RadioLocation radio_location = RadioLocal, bool reverse = true); + + /* send_at_cmd - methods used internally by other methods */ + AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame); + AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame, uint8_t *data); + AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame, uint16_t *data); + AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame, uint32_t *data); + + /** register_frame_handler - registers an object to handle incoming frames from + * the radio. + * @note For any type of frame more than one handler can be registered and all + * of them are called, sequentially, when a frame of that type arrives. + * + * @param handler pointer to the frame handler object + * @returns the result of the registration + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus register_frame_handler(FrameHandler *const handler); + + /** unregister_frame_handler - removes a previously registered frame handler + * + * @param handler pointer to the frame handler object + * @returns the result of the unregister operation + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus unregister_frame_handler(FrameHandler *const handler); + + /** get_radio_protocol - returns the RF protocol that the connected module uses + * based on its firmware and hardware versions + * + * @returns a RadioProtocol enum. + */ + RadioProtocol get_radio_protocol(void) const; + + /** _get_iosample - forces an io_sample read (reads all digital and analog inputs) + * + * @param remote remote device + * @param io_sample buffer where the io_sample response is copied + * @param len pointer where the length of the io_sample response is stored + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + RadioStatus _get_iosample(const RemoteXBee& remote, uint8_t * const io_sample, uint16_t * const len); + + void _get_remote_node_by_id(const char * const node_id, uint64_t * addr64, uint16_t * addr16); + + /** check_radio_flow_control - checks that the radio has the CTS "D7" and RTS "D6" pins configured + * according to the serial hardware flow control selected by the user + * + * @returns true if check success. + */ + bool check_radio_flow_control(); + + /** get_AI - reads the AI parameter. + * + * @returns + * -1 if an error occurred when reading AI. + * 0-0xFF the AI value. + */ + int get_AI(void); + + /** get_node_discovery_timeout - gets the node discovery timeout + * + * @param timeout_ms pointer where the node discovery timeout value will be stored + * @param wait_for_complete_timeout pointer where the function will store if the operator + * has to wait for the complete nd timeout after issuing + * a directed nd request + * @returns + * Success if the operation was successful, + * Failure otherwise + */ + virtual RadioStatus get_node_discovery_timeout(uint16_t * const timeout_ms) = 0; + virtual RadioStatus get_node_discovery_timeout(uint16_t * const timeout_ms, bool * const wait_for_complete_timeout) = 0; + + /** serial hardware flow control selected by the user (RTSCTS, RTS,CTS) */ + SerialBase::Flow _serial_flow_type; + + /** Operating mode of the module (API1, API2,...) */ + RadioMode _mode; + + /** Hardware version value of the radio */ + uint16_t _hw_version; + + /** Firmware version value of the radio */ + uint16_t _fw_version; + + /** Timeout in ms for sync operations (when we wait for a response) */ + uint16_t _timeout_ms; + + /** Device 64 bit address (SH, SL) */ + uint64_t _dev_addr64; + + /** Serial Interface, use RawSerial as we dont use the streams */ + RawSerial *_uart; + + /** IO connected to the radio reset line */ + DigitalOut *_reset; + + /** Transmit options byte */ + uint8_t _tx_options; + + /** Array of frame handler pointers. We use an array instead of a vector or other + * data structure to save memory and avoid dynamic memory allocation, to avoid + * memory fragmentation */ + FrameHandler *_fhandlers[MAX_FRAME_HANDLERS]; + + /** Hardware reset counter, automatically updated by the library */ + volatile uint16_t _hw_reset_cnt; + + /** Watchdog reset counter, automatically updated by the library */ + volatile uint16_t _wd_reset_cnt; + + /** Frame handler used for the Modem Status packets. Automatically registered when a callback + * function is registered */ + FH_ModemStatus *_modem_status_handler; + + /** Latest modem status received */ + AtCmdFrame::ModemStatus _modem_status; + + /** Library is initializing */ + bool _initializing; + + /** Timer used for node discovery */ + Timer _nd_timer; + + /** node discovery timeout */ + int _nd_timeout; + + /** If a _get_remote_node_by_id() is in progress, this keeps the expected frame id */ + uint8_t _node_by_ni_frame_id; +}; + +} /* namespace XBeeLib */ + +#endif /* defined(__DIGI_RADIO_H_) */ + + +
diff -r 000000000000 -r a1734fe1ec4b XbeeMonitor/XBeeLib/XBee802/XBee802.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XbeeMonitor/XBeeLib/XBee802/XBee802.cpp Sat Apr 08 14:43:14 2017 +0000 @@ -0,0 +1,615 @@ +/** + * Copyright (c) 2015 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ +#include "XBee802.h" +#include "IO/IOSample802.h" +#include "Frames/802_Frames.h" +#include "FrameHandlers/FH_ModemStatus.h" + +using namespace XBeeLib; + +/* Class constructor */ +XBee802::XBee802(PinName tx, PinName rx, PinName reset, PinName rts, PinName cts, int baud) : + XBee(tx, rx, reset, rts, cts, baud), + _nd_handler(NULL), _rx_64b_handler(NULL), _rx_16b_handler(NULL), + _io_data_64b_handler(NULL), _io_data_16b_handler(NULL) +{ + +} + +/* Class destructor */ +XBee802::~XBee802() +{ + unregister_node_discovery_cb(); + unregister_receive_cb(); + unregister_io_sample_cb(); +} + +RadioStatus XBee802::init() +{ + RadioStatus retval = XBee::init(); + uint16_t addr16; + RadioStatus error = get_network_address(&addr16); + if (error == Success) { + digi_log(LogLevelInfo, "ADDR16: %04x\r\n", addr16); + } else { + digi_log(LogLevelInfo, "ADDR16: UNKNOWN\r\n"); + } + + const RadioProtocol radioProtocol = get_radio_protocol(); + if (radioProtocol != Raw_802_15_4) { + digi_log(LogLevelError, "Radio protocol does not match, needed a %d got a %d\r\n", Raw_802_15_4, radioProtocol); + retval = Failure; + } + assert(radioProtocol == Raw_802_15_4); + + return retval; +} + +RadioStatus XBee802::set_channel(uint8_t channel) +{ + AtCmdFrame::AtCmdResp cmdresp; + + /* Pro and Non-Pro modules have different channels available. The at + command will return an error if the selected channel is not available */ + cmdresp = set_param("CH", channel); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + return Success; +} + +RadioStatus XBee802::get_channel(uint8_t * const channel) +{ + if (channel == NULL) { + return Failure; + } + AtCmdFrame::AtCmdResp cmdresp; + + uint32_t var32; + cmdresp = get_param("CH", &var32); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + *channel = var32; + return Success; +} + +RadioStatus XBee802::set_panid(uint16_t panid) +{ + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param("ID", panid); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + return Success; +} + +RadioStatus XBee802::get_panid(uint16_t * const panid) +{ + if (panid == NULL) { + return Failure; + } + AtCmdFrame::AtCmdResp cmdresp; + + uint32_t var32; + cmdresp = get_param("ID", &var32); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + *panid = var32; + return Success; +} + +RadioStatus XBee802::get_network_address(uint16_t * const addr16) +{ + if (addr16 == NULL) { + return Failure; + } + AtCmdFrame::AtCmdResp cmdresp; + + uint32_t var32; + cmdresp = get_param("MY", &var32); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + *addr16 = var32; + return Success; +} + +RadioStatus XBee802::set_network_address(uint16_t addr16) +{ + AtCmdFrame::AtCmdResp cmdresp; + + cmdresp = set_param("MY", addr16); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + return Success; +} + +RadioStatus XBee802::get_node_discovery_timeout(uint16_t * const timeout_ms) +{ + AtCmdFrame::AtCmdResp cmdresp; + uint32_t var32; + + cmdresp = get_param("NT", &var32); + if (cmdresp != AtCmdFrame::AtCmdRespOk) { + return Failure; + } + *timeout_ms = (uint16_t)var32; + + /* No N? command available for this protocol. Add a fix 1s guard time */ + *timeout_ms += 1000; + + return Success; +} + +RadioStatus XBee802::get_node_discovery_timeout(uint16_t * const timeout_ms, bool * const wait_for_complete_timeout) +{ + const RadioStatus status = get_node_discovery_timeout(timeout_ms); + + /* This protocol requires to wait for the complete timeout before attempting + to execute other commands */ + *wait_for_complete_timeout = true; + + return status; +} + +void XBee802::radio_status_update(AtCmdFrame::ModemStatus modem_status) +{ + /* Update the radio status variables */ + if (modem_status == AtCmdFrame::HwReset) { + _hw_reset_cnt++; + } else if (modem_status == AtCmdFrame::WdReset) { + _wd_reset_cnt++; + } + + _modem_status = modem_status; + + digi_log(LogLevelDebug, "\r\nUpdating radio status: %02x\r\n", modem_status); +} + +TxStatus XBee802::send_data(const RemoteXBee& remote, const uint8_t *const data, uint16_t len, bool syncr) +{ + if (remote.is_valid_addr64b()) { + const uint64_t remote64 = remote.get_addr64(); + + digi_log(LogLevelDebug, "send_data ADDR64: %08x:%08x\r\n", UINT64_HI32(remote64), UINT64_LO32(remote64)); + + TxFrame802 frame = TxFrame802(remote64, _tx_options, data, len); + + if (syncr) { + return send_data(&frame); + } else { + frame.set_data(0, 0); /* Set frame id to 0 so there is no answer */ + send_api_frame(&frame); + return TxStatusSuccess; + } + } + + if (remote.is_valid_addr16b()) { + const uint16_t remote16 = remote.get_addr16(); + + digi_log(LogLevelDebug, "send_data ADDR16: %04x\r\n", remote16); + + TxFrame802 frame = TxFrame802(remote16, _tx_options, data, len); + + if (syncr) { + return send_data(&frame); + } else { + frame.set_data(0, 0); /* Set frame id to 0 so there is no answer */ + send_api_frame(&frame); + return TxStatusSuccess; + } + } + + return TxStatusInvalidAddr; +} + +XBee802::AssocStatus XBee802::get_assoc_status(void) +{ + return (AssocStatus)get_AI(); +} + +RemoteXBee802 XBee802::get_remote_node_by_id(const char * const node_id) +{ + uint64_t addr64; + uint16_t addr16; + + _get_remote_node_by_id(node_id, &addr64, &addr16); + return RemoteXBee802(addr64, addr16); +} + +void XBee802::register_node_discovery_cb(node_discovery_802_cb_t function) +{ + if (_nd_handler == NULL) { + _nd_handler = new FH_NodeDiscovery802(); + register_frame_handler(_nd_handler); + } + _nd_handler->register_node_discovery_cb(function); +} + +void XBee802::unregister_node_discovery_cb() +{ + if (_nd_handler != NULL) { + _nd_handler->unregister_node_discovery_cb(); + unregister_frame_handler(_nd_handler); + delete _nd_handler; + _nd_handler = NULL; /* as delete does not set to NULL */ + } +} + +void XBee802::register_receive_cb(receive_802_cb_t function) +{ + if (_rx_64b_handler == NULL) { + _rx_64b_handler = new FH_RxPacket64b802(); + register_frame_handler(_rx_64b_handler); + } + _rx_64b_handler->register_receive_cb(function); + + if (_rx_16b_handler == NULL) { + _rx_16b_handler = new FH_RxPacket16b802(); + register_frame_handler(_rx_16b_handler); + } + _rx_16b_handler->register_receive_cb(function); +} + +void XBee802::unregister_receive_cb() +{ + if (_rx_64b_handler != NULL) { + _rx_64b_handler->unregister_rec