Repository: ty4tw/MQTT-SN Branch: master Commit: 6f471e225221 Files: 65 Total size: 535.4 KB Directory structure: gitextract_nt1a49t7/ ├── Client/ │ ├── Makefile │ ├── README.md │ └── src/ │ ├── LinuxClientSample.cpp │ ├── SoilMoistureClientSample.ino │ ├── lib/ │ │ ├── MQTTSN_Application.h │ │ ├── Network.h │ │ ├── mqUtil.cpp │ │ ├── mqUtil.h │ │ ├── mqttsn.cpp │ │ ├── mqttsn.h │ │ ├── mqttsnClient.cpp │ │ ├── mqttsnClient.h │ │ ├── mqttsnClientAppFw4Arduino.cpp │ │ ├── mqttsnClientAppFw4Arduino.h │ │ ├── mqttsnClientAppFw4Linux.cpp │ │ ├── mqttsnClientAppFw4Linux.h │ │ ├── mqttsnClientAppFw4mbed.cpp │ │ ├── mqttsnClientAppFw4mbed.h │ │ ├── udpStack.cpp │ │ ├── udpStack.h │ │ ├── zbeeStack.cpp │ │ └── zbeeStack.h │ └── mbedClientSample.cpp ├── Gateway/ │ ├── Makefile │ ├── README.md │ └── src/ │ ├── BrokerRecvTask.cpp │ ├── BrokerRecvTask.h │ ├── BrokerSendTask.cpp │ ├── BrokerSendTask.h │ ├── ClientRecvTask.cpp │ ├── ClientRecvTask.h │ ├── ClientSendTask.cpp │ ├── ClientSendTask.h │ ├── ErrorMessage.h │ ├── GatewayControlTask.cpp │ ├── GatewayControlTask.h │ ├── GatewayDefines.h │ ├── GatewayResourcesProvider.cpp │ ├── GatewayResourcesProvider.h │ ├── TomyGateway.cpp │ └── lib/ │ ├── Defines.h │ ├── Messages.cpp │ ├── Messages.h │ ├── ProcessFramework.cpp │ ├── ProcessFramework.h │ ├── TCPStack.cpp │ ├── TCPStack.h │ ├── TLSStack.cpp │ ├── TLSStack.h │ ├── Topics.cpp │ ├── Topics.h │ ├── UDPStack.cpp │ ├── UDPStack.h │ ├── XXXXXStack.cpp │ ├── XXXXXStack.h │ ├── ZBStack.cpp │ └── ZBStack.h ├── LogMonitor/ │ ├── Makefile │ └── src/ │ ├── LogMonitor.cpp │ ├── LogMonitor.h │ ├── LogMonitorApp.cpp │ └── lib/ │ ├── Defines.h │ ├── ProcessFramework.cpp │ └── ProcessFramework.h └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: Client/Makefile ================================================ PROGNAME := TomyClient SRCDIR := src SUBDIR := src/lib SRCS := $(SRCDIR)/LinuxClientSample.cpp \ $(SUBDIR)/mqttsnClientAppFw4Linux.cpp \ $(SUBDIR)/mqttsn.cpp \ $(SUBDIR)/mqttsnClient.cpp \ $(SUBDIR)/zbeeStack.cpp \ $(SUBDIR)/udpStack.cpp \ $(SUBDIR)/mqUtil.cpp CXX := g++ CPPFLAGS += DEFS := LDFLAGS += LIBS += CXXFLAGS := -Wall -O3 OUTDIR := Build PROG := $(OUTDIR)/$(PROGNAME) OBJS := $(SRCS:%.cpp=$(OUTDIR)/%.o) DEPS := $(SRCS:%.cpp=$(OUTDIR)/%.d) .PHONY: install clean distclean all: $(PROG) -include $(DEPS) $(PROG): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(OUTDIR)/%.o:%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< clean: rm -rf $(OUTDIR) distclean: rm -rf Build install: cp -p $(PROG) ../../ ================================================ FILE: Client/README.md ================================================ MQTT-SN Client ====== MQTT-SN Client over XBee (running on linux, Arduino and mbed) MQTT-SN Client over UDP (running on linux and Arduino) Supported functions ------------------- QOS Level 0 and 1 * SEARCHGW, GWINFO * CONNECT, WILLTOPICREQ, WILLTOPIC, WILLMSGREQ, WILLMSG * PINGREQ, PINGRESP * CONNACK, REGISTER, REGACK, SUBACK, PUBACK, UNSUBACK * SUBSCRIBE, PUBLISH, UNSUBSCRIBE, DISCONNECT Implemented control flows: Application program executes publish() function, Message flow as berrow is conducted automaticaly. Client Gateway Broker | | | PUBLISH() -->| --- SERCHGW ----> | | | <-- GWINFO ----- | | | --- CONNECT ----> | | | <--WILLTOPICREQ-- | | | --- WILLTOPIC --> | | | <-- WILLMSGREQ -- | | | --- WILLMSG ----> | ---- CONNECT ----> |(accepted) | <-- CONNACK ----- | <--- CONNACK ----- | | --- PUBLISH ----> | | | <-- PUBACK ----- | (invalid TopicId) | | --- REGISTER ---> | | | <-- REGACK ----- | | | --- PUBLISH ----> | ---- PUBLISH ----> |(accepted) | <-- PUBACK ----- | <---- PUBACK ----- | | | | // // // | | | SUBSCRIBE() -->| --- SUBSCRIBE --> | ---- SUBSCRIBE --> | [set Callback] | <-- SUBACK ------ | <--- SUBACK ------ | | | | // // // | | | | <-- REGISTER ---- | <--- PUBLISH ----- |<-- PUBLISH [exec Callback] | <-- PUBLISH ---- | | | --- PUBACK ---> | ---- PUBACK ----> |--> PUBACK | | | Usage ------ ####Minimum requirements Over XBee Three XBee S2 devices, a coordinator, a gateway and a client. or two XBee S1 with digimesh firmware, gateway and client. Over UDP Arduino with Ethernet shield or Arduino Ether. or linux client. MQTT Broker TomyGateway ####1) Start Gateway see MQTT-SN/Gateway ####2) Start Client (-d parameter is a device which XBee dongle connected.) 1. XBee client $ TomyClient -i ClientID -d /dev/ttyUSB0 -b 9600 2. UDP Client (Linux only, Arduino is embeded parameters defined by UDP_APP_CONFIG) $ TomyClient -i ClientID -g 225.1.1.1 -p 1883 -c -t WillTopic -m WillMessage -k 300 -g : Multicast address -p : Multicast port -c : Clean session -k : Keep alive ####3) XBee configurations Serial interfacing of Clients and gateway. Coordinator is default setting. XBee Firmware version is 2xA7. [BD] 0-7 Arduino Clients : 3 (9600bps) Linux Clients : 5 (38400bps) [D7] 1 [D6] 0 or 1 [AP] 2 [SP] Coordinator, Router Device : AF0 End device :20 Other values are defaults. Baudrate is used by mqtts.begin(device, _baudrate_) or mqtts.begin(_baudrate_) function. In case of LINUX, if you set D6 to 1, uncomment a line //#define XBEE_FLOWCTL_CRTSCTS in Mqtts_Defines.h How to Build (Requiered source code list) ----------- ####1) Linux Client _copy src/lib/* and src/LinuxClientSample.cpp_ $ make $ make install ####2) Arduino Client _Copy src/lib into Aruino Librally directory._ _Copy SoilMoistureClientSample.ino into Aruino sketch directory._ _in IPAddress.h, change raw_address() tp public from private._ _Add beginMulticast() to EthernetUDP.cpp_ see http://forum.arduino.cc/index.php?topic=150006.0 ####3) mbed Client _copy src/lib/* and src/mbedClientSample.cpp_ Module descriptions ------------------- ####1) MqttsClientApp.cpp Client application sample which is used for debug. ####2) MqttsClientFwApp.ino MqttsClient sample application for Arduino. ###Modules in mqttslib ####1) MqttsClient.cpp MQTT-S Client Engine class. This Class is used by a application. Usages are shown as follows. MqttsClient mqtts = MqttsClient(); // Declare the client object mqtts.begin(argv[1], B9600); // argv[1] is a serial device for XBee. ex) /dev/ttyUSB0 mqtts.init("Node-02"); // Get XBee's address64, short address and set XBee Node ID, mqtts.setWillTopic(willtopic); // set WILLTOPIC. mqtts.setWillMessage(willmsg); // set WILLMSG those are sent automatically. mqtts.setKeepAlive(60000); // PINGREQ interval time mqtts.subscribe(topic, callback,qos); // Execute the callback, when the subscribed topic's data is published. mqtts.publish(topic, payload, payload_length,qos); // publish the data, topic is converted into ID automatically. mqtts.publish(topic, MQString* payload,qos); mqtts.unsubscribe(topic); mqtts.disconnect(); above APIs are primitive one. In the Application, use PUBLISE(), SUBSCRIBE(), UNSUBSCRIBE(), DISCONNECT(). see Sample.cpp ####2) MqttsClientAppFw4Arduino.cpp Application framework for Arduino. Interupt and watch dog timer are supported. set MAC address of your Ethernet sheild to the UDP_APP_CONFIG structure. ####3) MqttsClientAppFw4Linux.cpp Application framework for Linux. watch dog timer are supported. ####4) MqttsClientAppFw4mbed.cpp Application framework for mbed. watch dog timer are supported. UDP is not supported. ####5) MQTTS.cpp MQTT-S messages classes and some classes for client and Gateway. ####6) ZBeeStack.cpp XBee control classes ####7) udpStack.cpp UDP control classes ####8) MQTTSN_Application.h Default setting is Linux and UDP. select the system and uncoment it. //#define LINUX //#define MBED select the NetworkStack and uncomment it. //#define NETWORK_XBEE //#define NETWORK_UDP ================================================ FILE: Client/src/LinuxClientSample.cpp ================================================ /* * LinuxClientSample.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #include "lib/MQTTSN_Application.h" #ifdef LINUX #include "lib/mqttsnClientAppFw4Linux.h" #include #include using namespace std; using namespace tomyClient; /*============================================ * * MQTT-SN Client Application for Linux * *===========================================*/ /*------------------------------------------------------ * Create Topic *------------------------------------------------------*/ MQString* tp1 = new MQString("topic/01"); MQString* tp2 = new MQString("topic/02"); MQString* tp3 = new MQString("topic/03"); MQString* tp4 = new MQString("topic/04"); MQString* tp5 = new MQString("topic/05"); MQString* tp_request_01 = new MQString("topic/req/01"); MQString* tp_response_01 = new MQString("topic/rsp/01"); MQString* tp_request_02 = new MQString("topic/req/02"); MQString* tp_response_02 = new MQString("topic/rsp/02"); /*------------------------------------------------------ * Tasks invoked by Timer *------------------------------------------------------*/ int f_publish_all(){ PUBLISH(tp1,"topic/01", 8,QOS1); PUBLISH(tp2,"topic/02", 8,QOS1); PUBLISH(tp3,"topic/03", 8,QOS1); PUBLISH(tp4,"topic/04", 8,QOS1); PUBLISH(tp5,"topic/05", 8,QOS1); Payload pl = Payload(40); pl.set_uint32( 200); pl.set_uint32( 10); pl.set_uint32( 50000); pl.set_uint32( 70000); pl.set_int32( -300); pl.set_int32(-70000); pl.set_float((float)1000.01); pl.set_str("abcdef"); PUBLISH(tp_request_01,&pl,1); return 0; } /*--------------- List of task invoked by Timer ------------*/ TASK_LIST = { //{ MQString* topic, executing duration in second}, {f_publish_all, 10}, END_OF_TASK_LIST }; /*------------------------------------------------------ * Tasks invoked by PUBLISH command Packet *------------------------------------------------------*/ /*----- Topic list used in callback functions -----*/ TOPICS_IN_CALLBACK = { tp_response_01, tp_response_02, END_OF_TOPICS }; int f_onRequest_01(MqttsnPublish* msg){ printf("inside f_onRequest_01()\n"); Payload pl; pl.getPayload(msg); pl.print(); printf("uint8: %d\n",pl.get_uint32(0)); printf("uint16: %d\n",pl.get_uint32(1)); printf("uint32: %d\n",pl.get_uint32(2)); printf("int8: %d\n",pl.get_uint32(3)); printf("int16: %d\n",pl.get_int32(4)); printf("int32: %d\n",pl.get_int32(5)); printf("float: %g \n",pl.get_float(6)); uint16_t len; printf("str: %s \n",pl.get_str(7,&len)); PUBLISH(tp_response_01,&pl,QOS1); return 0; } int f_onRequest_02(MqttsnPublish* msg){ printf("inside f_onRequest_02()\n"); PUBLISH(tp_response_02,"topic/rsp/02", 12,1); return 0; } /*-------------- List of Task invoked by PUBLISH -----------*/ SUBSCRIBE_LIST = { //{ MQString* topic, on_publish1, QOS }, {tp_request_01, f_onRequest_01, QOS1}, {tp_request_02, f_onRequest_02, QOS1}, END_OF_SUBSCRIBE_LIST }; /*================================================== * Application setup *=================================================*/ void setup(){ printf("Client start\n"); } /*============== End of Program ==============*/ #endif // LINUX ================================================ FILE: Client/src/SoilMoistureClientSample.ino ================================================ /* * SoilMoisture.ino * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #include #include #include #include #include /*============================================ * * MQTT-SN Client Application for Arduino * *===========================================*/ #ifdef NETWORK_XBEE XBEE_APP_CONFIG = { { 9600, //Baudrate 0, //Serial PortNo (for Arduino App) 0 //Device (for linux App) }, { "ARD02", //ClientId 300, //KeepAlive true, //Clean session false, //EndDevice "willTopic", //WillTopic or 0 DO NOT USE NULL STRING "" ! "willMessage" //WillMessage or 0 DO NOT USE NULL STRING "" ! } }; #endif #ifdef NETWORK_UDP UDP_APP_CONFIG = { { {225,1,1,1}, // Multicast group IP 1883, // Multicast group Port {192,168,11,18}, // Local IP (for Arduino App) 12001, // Local PortNo {0x90,0xa2,0xda,0x0f,0x53,0xa5} // MAC address (for Arduino App) }, { "ARD02", //ClientId 300, //KeepAlive true, //Clean session false, //EndDevice "willTopic", //WillTopic or 0 DO NOT USE NULL STRING "" ! "willMessage" //WillMessage or 0 DO NOT USE NULL STRING "" ! } }; #endif /*------------------------------------------------------ * Create Topic *------------------------------------------------------*/ MQString* topic1 = new MQString("ty4tw/tp1"); MQString* topic2 = new MQString("ty4tw/tp2"); MQString* tpMeasure = new MQString("ty4tw/soilReg"); /*------------------------------------------------------ * Tasks invoked by Timer *------------------------------------------------------*/ #define PIN5 5 // 3.3V supply port #define MCOUNT 10 // measurement count #define PIN0 0 // measurement port #define RP 20 // resistance [K ohom] int measure(){ int val = 0; pinMode(PIN5,OUTPUT); digitalWrite(PIN5,1); for(uint8_t cnt = 0; cnt < MCOUNT; cnt++){ delay(50); val += analogRead(PIN0); } digitalWrite(PIN5,0); int soilR = 1023 * RP / (val /MCOUNT) - RP; if(soilR < 0){ soilR = 9999; } Payload pl(30); pl.set_array(3); pl.set_uint32(GETUTC()); pl.set_int32(soilR); pl.set_str("Kohom"); return PUBLISH(tpMeasure,&pl,QOS1); } int task1(){ Payload pl = Payload(36); pl.set_array(9); pl.set_int32(30); pl.set_int32(255); pl.set_int32(70000); pl.set_str("abcdef"); pl.set_int32(-16); pl.set_int32(-60); pl.set_int32(-300); pl.set_int32(-70000); pl.set_float(1000.01); return PUBLISH(topic1,&pl,QOS1); } /*--------------- List of task invoked by Timer ------------*/ TASK_LIST = { //{ MQString* topic, executing duration in second}, {measure, 40}, {task1,6}, //{task2,6}, END_OF_TASK_LIST}; /*------------------------------------------------------ * Tasks invoked by PUBLISH command Packet *------------------------------------------------------*/ TOPICS_IN_CALLBACK = { END_OF_TOPICS }; int on_publish2(MqttsnPublish* msg){ theApplication->indicatorOff(); return 0; } /*------------ Link Callback to Topic -------------*/ SUBSCRIBE_LIST = { //{topic1, on_publish1, QOS1}, //{topic2, on_publish2, QOS1}, END_OF_SUBSCRIBE_LIST}; /*------------------------------------------------------ * Tasks invoked by INT0 interuption *------------------------------------------------------*/ void interruptCallback(){ //NOP } /*------------------------------------------------------ * Arduino setup() function *------------------------------------------------------*/ void setup(){ } ================================================ FILE: Client/src/lib/MQTTSN_Application.h ================================================ /* * MQTTSN_Application.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef MATTSNAPPLICATION_H_ #define MATTSNAPPLICATION_H_ /**************************************** Select Platform and Network *****************************************/ /*----------- Select Platform ---------*/ #ifndef ARDUINO #define LINUX //#define MBED #endif /*--------- Select byte order ----------*/ #define CPU_LITTLEENDIANN //#define CPU_BIGENDIANN /*-------- Select Network -------------*/ #define NETWORK_XBEE //#define NETWORK_UDP /*--- XBee Buffer Flow Control --*/ #ifdef NETWORK_XBEE //#define XBEE_FLOWCTL_CRTSCTS #endif /*====================================== * Debug Flag ======================================*/ //#define NW_DEBUG //#define MQTTSN_DEBUG #define DEBUG /**************************************** MQTT-SN Packet length *****************************************/ #ifdef ARDUINO #define MQTTSN_MAX_FRAME_SIZE 70 #else #ifdef NETWORK_XBEE #define MQTTSN_MAX_FRAME_SIZE 70 #else #ifdef NETWORK_UDP #define MQTTSN_MAX_FRAME_SIZE 1024 #endif #endif #endif /**************************************** Application config structures *****************************************/ #ifdef LINUX typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; #endif #ifdef MBED #include "mbed.h" #endif #ifdef ARDUINO #include #endif typedef struct { const char* nodeId; uint16_t keepAlive; bool cleanSession; bool endDevice; const char* willTopic; const char* willMsg; }MqttsnConfig; typedef struct { long baudrate; uint8_t portNo; char* device; }XBeeConfig; typedef struct { XBeeConfig netCfg; MqttsnConfig mqttsnCfg; }XBeeAppConfig; typedef struct { uint8_t ipAddress[4]; uint16_t gPortNo; uint8_t ipLocal[4]; uint16_t uPortNo; uint8_t macAddr[6]; }UdpConfig; typedef struct { UdpConfig netCfg; MqttsnConfig mqttsnCfg; }UdpAppConfig; /*====================================== MACROs for Application =======================================*/ #ifdef NETWORK_XBEE #define XBEE_APP_CONFIG XBeeAppConfig theAppConfig #define APP_CONFIG XBeeAppConfig #define NETWORK_CONFIG XBeeConfig #endif #ifdef NETWORK_UDP #define UDP_APP_CONFIG UdpAppConfig theAppConfig #define APP_CONFIG UdpAppConfig #define NETWORK_CONFIG UdpConfig #endif #define TASK_LIST TaskList theTaskList[] #define END_OF_TASK_LIST {0,0} #define SUBSCRIBE_LIST OnPublishList theOnPublishList[] #define END_OF_SUBSCRIBE_LIST {0,0,0} #define TOPICS_IN_CALLBACK MQString* theTopics[] #define END_OF_TOPICS 0 #define PUBLISH(...) theApplication->publish(__VA_ARGS__) #define SUBSCRIBE(...) theApplication->subscribe(__VA_ARGS__) #define UNSUBSCRIBE(...) theApplication->unsubscribe(__VA_ARGS__) #define DISCONNECT() theApplication->disconnect() #define SETRETAIN(...) theApplication->setRetain(__VA_ARGS__) /*====================================== MACROs for debugging ========================================*/ #ifdef ARDUINO #ifdef NW_DEBUG #define D_NWSTACK(...) debug.print(__VA_ARGS__) #define D_NWSTACKLN(... ) debug.println(__VA_ARGS__) #define D_NWSTACKW(...) debug.print(__VA_ARGS__) #define D_NWSTACKF(...) #else #define D_NWSTACK(...) #define D_NWSTACKLN(...) #define D_NWSTACKW(...) #define D_NWSTACKF(...) #endif #ifdef MQTTSN_DEBUG #define D_MQTT(...) debug.print(__VA_ARGS__) #define D_MQTTW(...) debug.print(__VA_ARGS__) #define D_MQTTLN(...) debug.println(__VA_ARGS__) #define D_MQTTF(...) #else #define D_MQTT(...) #define D_MQTTLN(...) #define D_MQTTW(...) #define D_MQTTF(...) #endif #else #ifdef NW_DEBUG #define D_NWSTACKF(...) printf(__VA_ARGS__) #define D_NWSTACKW(...) printf(__VA_ARGS__) #define D_NWSTACKLN(...) #define D_NWSTACK(...) #else #define D_NWSTACK(...) #define D_NWSTACKLN(...) #define D_NWSTACKW(...) #define D_NWSTACKF(...) #endif #ifdef MQTTSN_DEBUG #define D_MQTTF(...) printf(__VA_ARGS__) #define D_MQTTW(...) printf("%s",__VA_ARGS__) #define D_MQTTLN(...) #define D_MQTT(...) #else #define D_MQTT(...) #define D_MQTTLN(...) #define D_MQTTW(...) #define D_MQTTF(...) #endif #endif #endif /* MATTSNAPPLICATION_H_ */ ================================================ FILE: Client/src/lib/Network.h ================================================ /* * Network.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef NEWORK_H_ #define NEWORK_H_ #ifndef ARDUINO #include "MQTTSN_Application.h" #else #include #endif /*********************************** * Send Request Type ***********************************/ enum SendReqType{ NoReq = 0, UcastReq, BcastReq }; /*================================= * Network stacks ==================================*/ #ifdef NETWORK_XBEE #ifdef ARDUINO #include #else #include "zbeeStack.h" #endif #endif #ifdef NETWORK_UDP #ifdef ARDUINO #include #else #include "udpStack.h" #endif #endif namespace tomyClient { /*********************************** * MQTT-SN Client's state ***********************************/ enum NodeStatus { NdDisconnected = 0, NdActive, NdAsleep, NdAwaik, NdLost }; #define PACKET_SENDED 0 #define PACKET_ERROR_RESPONSE -1 #define PACKET_ERROR_UNKOWN -2 #define PACKET_ERROR_NODATA -3 #define PACKET_MODEM_STATUS -4 } /* end of namespace */ #endif /* NEWORK_H_ */ ================================================ FILE: Client/src/lib/mqUtil.cpp ================================================ /* * mqUtil.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef ARDUINO #include "MQTTSN_Application.h" #include "mqUtil.h" #include "stdio.h" #include "string.h" #else #include #include #include #include #endif /* ARDUINO */ #ifdef MBED #include "mbed.h" #endif /* MBED */ using namespace std; using namespace tomyClient; /*===================================== Global functions ======================================*/ #ifdef CPU_LITTLEENDIANN /*--- For Little endianness ---*/ uint16_t getUint16(uint8_t* pos){ uint16_t val = ((uint16_t)*pos++ << 8); return val += *pos; } void setUint16(uint8_t* pos, uint16_t val){ *pos++ = (val >> 8) & 0xff; *pos = val & 0xff; } uint32_t getUint32(uint8_t* pos){ uint32_t val = uint32_t(*pos++) << 24; val += uint32_t(*pos++) << 16; val += uint32_t(*pos++) << 8; return val += *pos++; } void setUint32(uint8_t* pos, uint32_t val){ *pos++ = (val >> 24) & 0xff; *pos++ = (val >> 16) & 0xff; *pos++ = (val >> 8) & 0xff; *pos = val & 0xff; } float getFloat32(uint8_t* pos){ union{ float flt; uint8_t d[4]; }val; val.d[3] = *pos++; val.d[2] = *pos++; val.d[1] = *pos++; val.d[0] = *pos; return val.flt; } void setFloat32(uint8_t* pos, float flt){ union{ float flt; uint8_t d[4]; }val; val.flt = flt; *pos++ = val.d[3]; *pos++ = val.d[2]; *pos++ = val.d[1]; *pos = val.d[0]; } #endif // CPU_LITTLEENDIANN /*--- For Big endianness ---*/ #ifdef CPU_BIGENDIANN uint16_t getUint16(uint8_t* pos){ uint16_t val = *pos++; return val += ((uint16_t)*pos++ << 8); } void setUint16(uint8_t* pos, uint16_t val){ *pos++ = val & 0xff; *pos = (val >> 8) & 0xff; } uint32_t getUint32(uint8_t* pos){ long val = uint32_t(*(pos + 3)) << 24; val += uint32_t(*(pos + 2)) << 16; val += uint32_t(*(pos + 1)) << 8; return val += *pos; } void setUint32(uint8_t* pos, uint32_t val){ *pos++ = val & 0xff; *pos++ = (val >> 8) & 0xff; *pos++ = (val >> 16) & 0xff; *pos = (val >> 24) & 0xff; } float getFloat32(uint8_t* pos){ union{ float flt; uint8_t d[4]; }val; val.d[0] = *pos++; val.d[1] = *pos++; val.d[2] = *pos++; val.d[3] = *pos; return val.flt; } void setFloat32(uint8_t* pos, float flt){ union{ float flt; uint8_t d[4]; }val; val.flt = flt; *pos++ = val.d[0]; *pos++ = val.d[1]; *pos++ = val.d[2]; *pos = val.d[3]; } #endif // CPU_BIGENDIANN /*========================================= Class XBeeTimer =========================================*/ #ifdef ARDUINO /** * for Arduino */ uint32_t XTimer::_unixTime; uint32_t XTimer::_epochTime; uint32_t XTimer::_timerStopTimeAccum; bool XTimer::_utcFlag; XTimer::XTimer(){ stop(); } void XTimer::initialize(){ _unixTime = 0; _epochTime = 0; _timerStopTimeAccum = 0; _utcFlag = false; } void XTimer::start(uint32_t msec){ _startTime = millis(); _millis = msec; _currentTime = 0; _timeupUnixTime = getUnixTime() + msec / 1000; } bool XTimer::isTimeUp(){ return isTimeUp(_millis); } bool XTimer::isTimeUp(uint32_t msec){ if(_utcFlag){ _utcFlag = false; if(_timeupUnixTime > 1000000000 && _unixTime){ return (getUnixTime() >= _timeupUnixTime); }else{ return false; } }else{ if ( _startTime){ _currentTime = millis(); if ( _currentTime < _startTime){ return (0xffffffff - _startTime + _currentTime > msec); }else{ return (_currentTime - _startTime > msec); } }else{ return false; } } } void XTimer::stop(){ _startTime = 0; _millis = 0; _currentTime = 0; _timeupUnixTime = 0; } void XTimer::setUnixTime(uint32_t utc){ _epochTime = millis(); _timerStopTimeAccum = 0; _unixTime = utc; } uint32_t XTimer::getUnixTime(){ uint32_t tm = _timerStopTimeAccum + millis(); if (_epochTime > tm ){ return _unixTime + (uint32_t)((0xffffffff - tm - _epochTime) / 1000); }else{ return _unixTime + (uint32_t)((tm - _epochTime) / 1000); } } void XTimer::setStopTimeDuration(uint32_t msec){ _timerStopTimeAccum += msec; } void XTimer::changeUTC(){ _utcFlag = true; } #endif #ifdef MBED /** * for MBED */ XTimer::XTimer(){ stop(); } void XTimer::start(uint32_t msec){ _timer.start(); _millis = msec; _timeupTime = time(0) + (uint32_t)(msec/1000UL); } bool XTimer::isTimeUp(){ return isTimeUp(_millis); } bool XTimer::isTimeUp(uint32_t msec){ if(_utcFlg){ if(_timeupTime > 100000000){ return( time(0) > _timeupTime); }else{ return false; } }else{ return _timer.read_ms() > msec; } } void XTimer::stop(){ _timer.stop(); _millis = 0; _timeupTime = 0; } void XTimer::changeUTC(){ _utcFlg = true; } #endif #ifdef LINUX /** * for LINUX */ XTimer::XTimer(){ _startTime.tv_sec = 0; _millis = 0; } XTimer::~XTimer(){ } void XTimer::start(uint32_t msec){ gettimeofday(&_startTime, 0); _millis = msec; } bool XTimer::isTimeUp(void){ return isTimeUp(_millis); } bool XTimer::isTimeUp(uint32_t msec){ struct timeval curTime; uint32_t secs, usecs; if (_startTime.tv_sec == 0){ return false; }else{ gettimeofday(&curTime, 0); secs = (curTime.tv_sec - _startTime.tv_sec) * 1000; usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0; return ((secs + usecs) > (uint32_t)msec); } } void XTimer::stop(){ _startTime.tv_sec = 0; _millis = 0; } #endif ================================================ FILE: Client/src/lib/mqUtil.h ================================================ /* * mqUtil.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef XTIMER_H_ #define XTIMER_H_ #if defined(ARDUINO) #include #if ARDUINO >= 100 #include "Arduino.h" #include #else #if ARDUINO < 100 #include "WProgram.h" #include #endif #endif #define XB_CTS_PIN 3 // XBee CTS #define XB_SLEEP_PIN 4 // XBee Pinhybernate #else #include "MQTTSN_Application.h" #endif /* ARDUINO */ #ifdef LINUX #include #endif #ifdef MBED #include "mbed.h" #endif namespace tomyClient { #ifdef ARDUINO /*============================================ XBeeTimer for Arduino ============================================*/ class XTimer{ public: XTimer(); ~XTimer(){}; void start(uint32_t msec = 0); bool isTimeUp(uint32_t msec); bool isTimeUp(void); void stop(); static uint32_t getUnixTime(); static void setUnixTime(uint32_t utc); static void setStopTimeDuration(uint32_t msec); static void initialize(); static void changeUTC(); private: uint32_t _startTime; uint32_t _currentTime; uint32_t _millis; uint32_t _timeupUnixTime; static uint32_t _unixTime; static uint32_t _epochTime; static uint32_t _timerStopTimeAccum; static bool _utcFlag; }; #endif #ifdef MBED /*============================================ XBeeTimer for MBED ============================================*/ class XTimer{ public: XTimer(); ~XTimer(){}; void start(uint32_t msec = 0); bool isTimeUp(uint32_t msec); bool isTimeUp(void); void stop(void); void changeUTC(void); private: Timer _timer; time_t _startTime; uint32_t _millis; time_t _timeupTime; bool _utcFlg; }; #endif #ifdef LINUX /*============================================ XBeeTimer ============================================*/ class XTimer{ public: XTimer(); ~XTimer(); void start(uint32_t msec = 0); bool isTimeUp(uint32_t msec); bool isTimeUp(void); void stop(void); void changeUTC(void){}; private: struct timeval _startTime; uint32_t _millis; }; #endif } #endif /* XTIMER_H_ */ ================================================ FILE: Client/src/lib/mqttsn.cpp ================================================ /* * mqttsn.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef ARDUINO #include "MQTTSN_Application.h" #else #include #endif #ifdef ARDUINO #include #include #if defined(MQTTSN_DEBUG) || defined(ZBEE_DEBUG) #include extern SoftwareSerial debug; #endif #endif /* ARDUINO */ #ifdef MBED #include "mbed.h" #include "Network.h" #include "mqttsn.h" #endif /* MBED */ #ifdef LINUX #include "Network.h" #include "mqttsn.h" #include #include #include #include #include #include #include #include #include #include #endif /* LINUX */ using namespace std; using namespace tomyClient; extern uint16_t getUint16(uint8_t* pos); extern uint32_t getUint32(uint8_t* pos); extern float getFloat32(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); extern void setFloat32(uint8_t* pos, float val); /*===================================== Class MQString =====================================*/ MQString::MQString(){ //_length = 0; _constStr = 0; _str = 0; } MQString::MQString(const char* str){ if (strlen(str)){ _constStr = str; }else{ _constStr = 0; } _str = 0; } MQString::MQString(char* str){ if (strlen(str)){ _str = str; }else{ _str = 0; } _constStr = 0; } MQString::~MQString(){ if (_str){ free(_str); } } uint16_t MQString::getCharLength(){ if(_str){ return strlen(_str); } return strlen(_constStr); } int MQString::comp(MQString* str){ if (_str){ if(str->getStr()){ return (strcmp(_str, str->getStr())); }else if(str->getConstStr()){ return (strcmp(_str, str->getConstStr())); } }else if(_constStr){ if(str->getStr()){ return (strcmp(_constStr, str->getStr())); }else if(str->getConstStr()){ return (strcmp(_constStr, str->getConstStr())); } } return 1; } int MQString::comp(const char* str){ if(_str){ return (strcmp(_str, str)); }else if (_constStr){ return (strcmp(_constStr, str)); } return 1; } int MQString::ncomp(MQString* str, uint16_t len){ if (_str){ return strncmp(_str, str->getStr(), (long)len); }else if (_constStr){ return strncmp(_constStr, str->getConstStr(), (long)len); } return 1; } bool MQString::operator==(MQString &str){ return (comp(&str) == 0); } bool MQString::operator!=(MQString &str){ return (comp(&str) != 0); } void MQString::copy(MQString* str){ if (str->isConst()){ _constStr = getConstStr(); }else{ _str = str->getStr(); } } MQString* MQString::create(){ char* newStr = (char*)calloc(getCharLength()+ 1, sizeof(char)); memcpy(newStr, getConstStr(), getCharLength()); MQString* newPtr = new MQString((const char*)newStr); return newPtr; } void MQString::copy(const char* str){ _constStr = str; _str = 0; freeStr(); } void MQString::copy(char* str){ freeStr(); _str = (char*)calloc(strlen(str) + 1, sizeof(char)); _constStr = 0; strcpy(_str, str); } void MQString::copy(uint8_t* str, uint8_t len){ freeStr(); _str = (char*)calloc(len + 1, sizeof(char)); _constStr = 0; memcpy(_str, str, len); } void MQString::writeBuf(uint8_t* buf){ if (_str){ memcpy(buf, _str, strlen(_str)); }else if (_constStr){ memcpy(buf, _constStr, strlen(_constStr)); } } void MQString::readBuf(uint8_t* buf){ _str = 0; _constStr = (const char*)buf; } uint8_t MQString::getChar(uint8_t index){ if (_str){ return (index < strlen(_str) ? _str[index]: 0); }else if (_constStr){ return (index < strlen(_constStr) ? _constStr[index]: 0); } return 0; } char* MQString::getStr(){ return (_str ? _str : 0); } const char* MQString::getConstStr(){ return (_constStr ? _constStr : 0); } bool MQString::isConst(){ return (_constStr ? true : false); } void MQString::freeStr(){ if (_str){ free(_str); _str = 0; } } /*===================================== Class MqttsnMessage ======================================*/ MqttsnMessage::MqttsnMessage(){ _msgBuff = 0; _flags = 0; _flags = 0; _length = 0; _status = 0; _type = 0; } MqttsnMessage::~MqttsnMessage(){ if (_msgBuff != 0){ delete(_msgBuff); } } void MqttsnMessage::reset(){ _msgBuff = 0; _length = 0; _status = 0; _type = 0; } void MqttsnMessage::setType(uint8_t type){ _type = type; if ( _msgBuff != 0){ if(_length > 255){ _msgBuff[3] = type; }else{ _msgBuff[1] = type; } } } void MqttsnMessage::setFlags(uint8_t flg){ _flags = flg; if ( _msgBuff != 0){ if(_length > 255){ _msgBuff[4] = flg; }else{ _msgBuff[2] = flg; } } } void MqttsnMessage::setLength(uint16_t length){ _length = length; if ( _msgBuff != 0){ if(_length > 255){ _msgBuff[0] = 0x01; setUint16(_msgBuff + 1, _length); }else{ _msgBuff[0] = length; } } } void MqttsnMessage::setQos(uint8_t qos){ _flags &= 0x9f; if(qos == QOS1){ _flags |= 0x20; }else if(qos == QOS2){ _flags |= 0x40; } setFlags(_flags); } bool MqttsnMessage::setBody(uint8_t* body){ if (allocateBody()) { if(_length > 255){ _msgBuff[0] = 0x01; setUint16(_msgBuff + 1, _length); _msgBuff[3] = _type; memcpy(_msgBuff + 4, body, _length - 4); }else{ _msgBuff[0] = _length; _msgBuff[1] = _type; memcpy(_msgBuff + 2, body, _length - MQTTSN_HEADER_SIZE); } return true; }else{ return false; } } bool MqttsnMessage::allocateBody(){ if ( _length > 0 ) { if (_msgBuff){ free(_msgBuff); } _msgBuff = (uint8_t*)calloc(_length + 1, sizeof(uint8_t)); if ( _msgBuff){ if(_length > 255){ _msgBuff[0] = 0x01; setUint16(_msgBuff + 1, _length); _msgBuff[3] = _type; _msgBuff[4] = _flags; }else{ _msgBuff[0] = _length; _msgBuff[1] = _type; _msgBuff[2] = _flags; } return true; }else{ return false; } }else{ return false; } } void MqttsnMessage::setDup(){ if(_msgBuff && (_type == MQTTSN_TYPE_PUBLISH || _type == MQTTSN_TYPE_SUBSCRIBE)){ _flags |= 0x80; getBody()[0] = _flags ; } } void MqttsnMessage::setStatus(uint8_t stat){ _status = stat; } uint8_t MqttsnMessage::getQos(){ return (_flags & (MQTTSN_FLAG_QOS_1 | MQTTSN_FLAG_QOS_2)) >> 5; } uint8_t MqttsnMessage::getLength(){ return _length; } uint8_t MqttsnMessage::getType(){ return _type; } uint8_t MqttsnMessage::getFlags(){ return _flags; } uint8_t MqttsnMessage::getStatus(){ return _status; } uint8_t* MqttsnMessage::getBody(){ if(_length > 255){ return _msgBuff + 4; }else{ return _msgBuff + MQTTSN_HEADER_SIZE; } } uint16_t MqttsnMessage::getBodyLength(){ if(_length > 255){ return _length - 4; }else{ return _length - MQTTSN_HEADER_SIZE; } } uint16_t MqttsnMessage::getFrameLength(){ return _length; } uint8_t* MqttsnMessage::getMsgBuff(){ return _msgBuff; } void MqttsnMessage::setMsgBuff(uint8_t* msgBuff){ _msgBuff = msgBuff; } bool MqttsnMessage::copy(MqttsnMessage* src){ setLength(src->getLength()); setType(src->getType()); setFlags(src->getFlags()); setStatus(src->getStatus()); _msgBuff = src->_msgBuff; src->setMsgBuff(0); if (_msgBuff == 0){ return false; } return true; } const char* MqttsnMessage::getMsgTypeName(){ switch(_type){ case 0x00: return "ADVERTIZE"; case 0x01: return "SEARCGW"; case 0x02: return "GWINFO"; case 0x04: return "CONNECT"; case 0x05: return "CONNACK"; case 0x06: return "WILLTOPICREQ"; case 0x07: return "WILLTOPIC"; case 0x08: return "WILLMSGREQ"; case 0x09: return "WILLMSG"; case 0x0a: return "REGISTER"; case 0x0b: return "REGACK"; case 0x0c: return "PUBLISH"; case 0x0d: return "PUBACK"; case 0x0e: return "PUBCOMP"; case 0x0f: return "PUBREC"; case 0x10: return "PUBREL"; case 0x12: return "SUBSCRIBE"; case 0x13: return "SUBACK"; case 0x14: return "UNSUBSCRIBE"; case 0x15: return "UNSUBACK"; case 0x16: return "PINGREQ"; case 0x17: return "PINGRESP"; case 0x18: return "DISCONNECT"; default: return ""; } } /*===================================== Class MqttsnAdvrtise ======================================*/ MqttsnAdvertise::MqttsnAdvertise():MqttsnMessage(){ setLength(5); setType(MQTTSN_TYPE_ADVERTISE); allocateBody(); } MqttsnAdvertise::~MqttsnAdvertise(){ } void MqttsnAdvertise::setGwId(uint8_t id){ getBody()[0] = id; } void MqttsnAdvertise::MqttsnAdvertise::setDuration(uint16_t duration){ uint8_t* pos = getBody() + 1; setUint16(pos, duration); } uint8_t MqttsnAdvertise::getGwId(){ return getBody()[0]; } uint16_t MqttsnAdvertise::getDuration(){ uint8_t* pos = getBody() + 1; return getUint16(pos); } /*===================================== Class MqttsnSearchgw ======================================*/ MqttsnSearchGw::MqttsnSearchGw():MqttsnMessage(){ setLength(3); setType(MQTTSN_TYPE_SEARCHGW); allocateBody(); } MqttsnSearchGw::~MqttsnSearchGw(){ } void MqttsnSearchGw::setRadius(uint8_t radius){ getBody()[0] = radius; } uint8_t MqttsnSearchGw::getRadius(){ return getBody()[0]; } /*===================================== Class MqttsnGwinfo ======================================*/ MqttsnGwInfo::MqttsnGwInfo():MqttsnMessage(){ setLength(3); setType(MQTTSN_TYPE_GWINFO); allocateBody(); } MqttsnGwInfo::~MqttsnGwInfo(){ } uint8_t MqttsnGwInfo::getGwId(){ return getBody()[0]; } void MqttsnGwInfo::setGwId(uint8_t id){ getBody()[0] = id; } /*===================================== Class MqttsnConnect ======================================*/ MqttsnConnect::MqttsnConnect(MQString* id):MqttsnMessage(){ setLength(id->getCharLength() + 6); allocateBody(); setType(MQTTSN_TYPE_CONNECT); getBody()[1] = MQTTSN_PROTOCOL_ID; id->writeBuf(getBody() + 4); } MqttsnConnect::~MqttsnConnect(){ } void MqttsnConnect::setDuration(uint16_t msec){ setUint16((uint8_t*)getBody() + 2, msec); } uint16_t MqttsnConnect::getDuration(){ return getUint16((uint8_t*)getBody() + 2); } void MqttsnConnect::setClientId(MQString* id){ id->writeBuf(getBody() + 4); setLength(id->getCharLength() + 6); } uint8_t* MqttsnConnect::getClientId(){ return getBody() + 6; } void MqttsnConnect::setFrame(uint8_t* data, uint8_t len){ setLength(len + MQTTSN_HEADER_SIZE); allocateBody(); memcpy(getBody(), data, len); getBody()[2] = getUint16(data + 4); getBody()[0] = *(data + 2); } /*===================================== Class MqttsnConnack ======================================*/ MqttsnConnack::MqttsnConnack():MqttsnMessage(){ setLength(3); setType(MQTTSN_TYPE_CONNACK); allocateBody(); } MqttsnConnack::~MqttsnConnack(){ } void MqttsnConnack::setReturnCode(uint8_t rc){ getBody()[0] = rc; } uint8_t MqttsnConnack::getReturnCode(){ return getBody()[0]; } /*===================================== Class MqttsnWillTopicReq ======================================*/ MqttsnWillTopicReq::MqttsnWillTopicReq():MqttsnMessage(){ setLength(2); setType(MQTTSN_TYPE_WILLTOPICREQ); allocateBody(); } MqttsnWillTopicReq::~MqttsnWillTopicReq(){ } /*===================================== Class MqttsnWillTopic ======================================*/ MqttsnWillTopic::MqttsnWillTopic():MqttsnMessage(){ setLength(3); setType(MQTTSN_TYPE_WILLTOPIC); allocateBody(); _flags = 0; } MqttsnWillTopic::~MqttsnWillTopic(){ } void MqttsnWillTopic::setWillTopic(MQString* topic){ setLength(topic->getCharLength() + 3); allocateBody(); topic->writeBuf(getBody() + 1); _msgBuff[2] = _flags; _ustring.copy(topic); } MQString* MqttsnWillTopic::getWillTopic(){ if (_msgBuff){ return &_ustring; }else{ return 0; } } bool MqttsnWillTopic::isWillRequired(){ return getBody()[0] && MQTTSN_FLAG_WILL; } /*===================================== Class MqttsnWillMsgReq ======================================*/ MqttsnWillMsgReq::MqttsnWillMsgReq():MqttsnMessage(){ setLength(2); setType(MQTTSN_TYPE_WILLMSGREQ); allocateBody(); } MqttsnWillMsgReq::~MqttsnWillMsgReq(){ } /*===================================== Class MqttsnWillMsg ======================================*/ MqttsnWillMsg::MqttsnWillMsg():MqttsnMessage(){ setLength(2); setType(MQTTSN_TYPE_WILLMSG); allocateBody(); } MqttsnWillMsg::~MqttsnWillMsg(){ } void MqttsnWillMsg::setWillMsg(MQString* msg){ setLength(2 + msg->getCharLength()); allocateBody(); msg->writeBuf(getBody()); } char* MqttsnWillMsg::getWillMsg(){ if (_msgBuff){ return (char*)getBody(); }else{ return 0; } } /*===================================== Class MqttsnRegister ======================================*/ MqttsnRegister::MqttsnRegister():MqttsnMessage(){ setLength(6); setType(MQTTSN_TYPE_REGISTER); allocateBody(); _topicId = 0; _msgId = 0; } MqttsnRegister::~MqttsnRegister(){ } void MqttsnRegister::setTopicId(uint16_t topicId){ if (_msgBuff){ setUint16(getBody(), topicId); } _topicId = topicId; } uint16_t MqttsnRegister::getTopicId(){ return _topicId; } void MqttsnRegister::setMsgId(uint16_t msgId){ if (_msgBuff){ setUint16(getBody() + 2, msgId); } _msgId = msgId; } uint16_t MqttsnRegister::getMsgId(){ return _msgId; } void MqttsnRegister::setTopicName(MQString* topicName){ setLength(6 + topicName->getCharLength()); allocateBody(); topicName->writeBuf(getBody() + 4); setTopicId(_topicId); setMsgId(_msgId); } void MqttsnRegister::setFrame(uint8_t* data, uint8_t len){ setLength(len + MQTTSN_HEADER_SIZE); allocateBody(); memcpy(getBody(), data, len); _topicId = getUint16(data); _msgId = getUint16(data + 2); _ustring.readBuf(getBody() + 4); } void MqttsnRegister::setFrame(NWResponse* resp){ setFrame(resp->getPayload() + MQTTSN_HEADER_SIZE, resp->getPayload(0) - MQTTSN_HEADER_SIZE); } MQString* MqttsnRegister::getTopicName(){ return &_ustring; } /*===================================== Class MqttsnRegAck ======================================*/ MqttsnRegAck::MqttsnRegAck():MqttsnMessage(){ setLength(7); setType(MQTTSN_TYPE_REGACK); allocateBody(); } MqttsnRegAck::~MqttsnRegAck(){ } void MqttsnRegAck::setTopicId(uint16_t topicId){ setUint16((uint8_t*)getBody(), topicId); } uint16_t MqttsnRegAck::getTopicId(){ return getUint16((unsigned char*)getBody()); } void MqttsnRegAck::setMsgId(uint16_t msgId){ setUint16(getBody()+ 2,msgId); } uint16_t MqttsnRegAck::getMsgId(){ return getUint16((unsigned char*)getBody()+ 2); } void MqttsnRegAck::setReturnCode(uint8_t rc){ getBody()[4] = rc; } uint8_t MqttsnRegAck::getReturnCode(){ return (uint8_t)getBody()[4]; } /*===================================== Class MqttsnPublish ======================================*/ MqttsnPublish::MqttsnPublish():MqttsnMessage(){ setLength(7); setType(MQTTSN_TYPE_PUBLISH); allocateBody(); _topicId = 0; _topic = 0; _msgId = 0; } MqttsnPublish::~MqttsnPublish(){ } void MqttsnPublish::setTopicId(uint16_t id){ setUint16((uint8_t*)(getBody() + 1), id); _topicId = id; } uint16_t MqttsnPublish::getTopicId(){ return _topicId; } MQString* MqttsnPublish::getTopic(MQString* topic){ char tp[3]; tp[0] = (char)*(getBody() + 1); tp[1] = (char)*(getBody() + 2); tp[2] = 0; topic->copy(tp); return topic; } void MqttsnPublish::setTopic(MQString* topic){ if(topic->getCharLength() == 2){ topic->writeBuf((uint8_t*)(getBody() + 1)); memcpy((void*)&_topicId,(getBody() + 1), 2); _flags &= 0xfc; _flags |= MQTTSN_TOPIC_TYPE_SHORT; } } void MqttsnPublish::setMsgId(uint16_t msgId){ setUint16((uint8_t*)(getBody() + 3), msgId); _msgId = msgId; } uint16_t MqttsnPublish::getMsgId(){ return _msgId; } void MqttsnPublish::setData(uint8_t* data, uint16_t len){ setLength(7 + len); allocateBody(); memcpy(getBody() + 5, data, len); setTopicId(_topicId); setMsgId(_msgId); } void MqttsnPublish::setData(MQString* str){ setLength(7 + str->getCharLength()); allocateBody(); setTopicId(_topicId); setMsgId(_msgId); str->writeBuf(getBody() + 5); } uint8_t* MqttsnPublish::getData(){ return (uint8_t*)(getBody() + 5); } uint16_t MqttsnPublish::getDataLength(){ return this->getBodyLength() - 5; } void MqttsnPublish::setFrame(uint8_t* data, uint16_t len){ if(len > 255){ setLength(len + MQTTSN_HEADER_SIZE + 2); }else{ setLength(len + MQTTSN_HEADER_SIZE); } allocateBody(); memcpy(getBody(), data, len); _topicId = getUint16(data + 1); _msgId = getUint16(data + 3); _flags = *data; } void MqttsnPublish::setFrame(NWResponse* resp){ setFrame(resp->getBody(), resp->getBodyLength()); } void MqttsnPublish::setPayload(Payload* payload){ } /*===================================== Class MqttsnPubAck ======================================*/ MqttsnPubAck::MqttsnPubAck():MqttsnMessage(){ setLength(7); setType(MQTTSN_TYPE_PUBACK); allocateBody(); } MqttsnPubAck::~MqttsnPubAck(){ } void MqttsnPubAck::setTopicId(uint16_t topicId){ setUint16((uint8_t*)getBody(), topicId); } uint16_t MqttsnPubAck::getTopicId(){ return getUint16((unsigned char*)getBody()); } void MqttsnPubAck::setMsgId(uint16_t msgId){ setUint16(getBody()+ 2,msgId); } uint16_t MqttsnPubAck::getMsgId(){ return getUint16((unsigned char*)getBody()+ 2); } void MqttsnPubAck::setReturnCode(uint8_t rc){ getBody()[4] = rc; } uint8_t MqttsnPubAck::getReturnCode(){ return (uint8_t)getBody()[4]; } /*===================================== Class MqttsnPubRec ======================================*/ MqttsnPubRec::MqttsnPubRec(){ setLength(4); setType(MQTTSN_TYPE_PUBREC); allocateBody(); } MqttsnPubRec::~MqttsnPubRec(){ } uint16_t MqttsnPubRec::getMsgId(){ return getUint16(getBody()); } void MqttsnPubRec::setMsgId(uint16_t msgId){ setUint16(getBody(),msgId); } /*===================================== Class MqttsnPubRel ======================================*/ MqttsnPubRel::MqttsnPubRel(){ setLength(4); setType(MQTTSN_TYPE_PUBREL); allocateBody(); } MqttsnPubRel::~MqttsnPubRel(){ } /*===================================== Class MqttsnPubComp ======================================*/ MqttsnPubComp::MqttsnPubComp(){ setLength(4); setType(MQTTSN_TYPE_PUBCOMP); allocateBody(); } MqttsnPubComp::~MqttsnPubComp(){ } /*===================================== Class MqttsnSubscribe ======================================*/ MqttsnSubscribe::MqttsnSubscribe(){ setLength(5); setType(MQTTSN_TYPE_SUBSCRIBE); allocateBody(); _topicId = 0; _msgId = 0; _flags = 0; } MqttsnSubscribe::~MqttsnSubscribe(){ } void MqttsnSubscribe::setTopicId(uint16_t predefinedId){ setLength(7); allocateBody(); setMsgId(_msgId); setUint16((uint8_t*)(getBody() + 3), predefinedId); setFlags(_flags | MQTTSN_TOPIC_TYPE_PREDEFINED); _topicId = predefinedId; } uint16_t MqttsnSubscribe::getTopicId(){ if (_msgBuff){ _topicId = getUint16(getBody() +3); } return _topicId; } void MqttsnSubscribe::setMsgId(uint16_t msgId){ _msgId = msgId; if (_msgBuff){ setUint16((uint8_t*)(getBody() + 1), msgId); } } uint16_t MqttsnSubscribe::getMsgId(){ if (_msgBuff){ _msgId = getUint16(getBody() + 1); } return _msgId; } void MqttsnSubscribe::setTopicName(MQString* data){ setLength(5 + data->getCharLength()); allocateBody(); data->writeBuf(getBody() + 3); setMsgId(_msgId); setFlags((_flags & 0xe0) | MQTTSN_TOPIC_TYPE_NORMAL); _ustring.copy(data); } MQString* MqttsnSubscribe::getTopicName(){ return &_ustring; } void MqttsnSubscribe::setFrame(uint8_t* data, uint8_t len){ setLength(len + MQTTSN_HEADER_SIZE); allocateBody(); memcpy(getBody(), data, len); _msgId = getUint16(data + 1); _flags = *data; if ((_flags & MQTTSN_TOPIC_TYPE) == MQTTSN_TOPIC_TYPE_PREDEFINED){ _topicId = getUint16(data + 3); }else{ _topicId = 0; _ustring.readBuf(data + 3); } } void MqttsnSubscribe::setFrame(NWResponse* resp){ setFrame(resp->getPayload() + MQTTSN_HEADER_SIZE, resp->getPayload(0) - MQTTSN_HEADER_SIZE); } /*===================================== Class MqttsnSubAck ======================================*/ MqttsnSubAck::MqttsnSubAck():MqttsnMessage(){ setLength(8); setType(MQTTSN_TYPE_SUBACK); allocateBody(); } MqttsnSubAck::~MqttsnSubAck(){ } void MqttsnSubAck::setTopicId(uint16_t id){ setUint16((uint8_t*)(getBody() + 1), id); } uint16_t MqttsnSubAck::getTopicId(){ return getUint16(getBody() + 1); } void MqttsnSubAck::setMsgId(uint16_t msgId){ setUint16((uint8_t*)(getBody() + 3), msgId); } uint16_t MqttsnSubAck::getMsgId(){ return getUint16(getBody() + 3); } void MqttsnSubAck::setReturnCode(uint8_t rc){ getBody()[6] = rc; } uint8_t MqttsnSubAck::getReturnCode(){ return getBody()[5]; } /*===================================== Class MqttsnUnsubscribe ======================================*/ MqttsnUnsubscribe::MqttsnUnsubscribe() : MqttsnSubscribe(){ setType(MQTTSN_TYPE_UNSUBSCRIBE); } MqttsnUnsubscribe::~MqttsnUnsubscribe(){ } /*===================================== Class MqttsnUnSubAck ======================================*/ MqttsnUnSubAck::MqttsnUnSubAck():MqttsnMessage(){ setLength(4); setType(MQTTSN_TYPE_UNSUBACK); allocateBody(); } MqttsnUnSubAck::~MqttsnUnSubAck(){ } void MqttsnUnSubAck::setMsgId(uint16_t msgId){ setUint16((uint8_t*)getBody(), msgId); } uint16_t MqttsnUnSubAck::getMsgId(){ return getUint16(getBody()); } /*===================================== Class MqttsnPingReq ======================================*/ MqttsnPingReq::MqttsnPingReq(MQString* id):MqttsnMessage(){ setLength(id->getCharLength() + 2); setType(MQTTSN_TYPE_PINGREQ); allocateBody(); id->writeBuf(getBody()); } MqttsnPingReq::~MqttsnPingReq(){ } char* MqttsnPingReq::getClientId(){ return (char*)getBody(); } /*===================================== Class MqttsnPingResp ======================================*/ MqttsnPingResp::MqttsnPingResp():MqttsnMessage(){ setLength(2); setType(MQTTSN_TYPE_PINGRESP); allocateBody(); } MqttsnPingResp::~MqttsnPingResp(){ } /*===================================== Class MqttsnDisconnect ======================================*/ MqttsnDisconnect::MqttsnDisconnect():MqttsnMessage(){ setLength(4); setType(MQTTSN_TYPE_DISCONNECT); allocateBody(); } MqttsnDisconnect::~MqttsnDisconnect(){ } void MqttsnDisconnect::setDuration(uint16_t duration){ setUint16((uint8_t*)getBody(), duration); } uint16_t MqttsnDisconnect::getDuration(){ return getUint16((uint8_t*)getBody()); } /*===================================== Class Topic ======================================*/ Topic::Topic(){ _topicStr = 0; _callback = 0; _topicId = 0; _status = 0; } Topic::~Topic(){ if (_topicStr){ delete _topicStr; } } uint8_t Topic::getStatus(){ return _status; } uint16_t Topic::getTopicId(){ return _topicId; } MQString* Topic::getTopicName(){ return _topicStr; } uint8_t Topic::getTopicLength(){ return _topicStr->getCharLength(); } TopicCallback Topic::getCallback(){ return _callback; } void Topic::setTopicId(uint16_t id){ _topicId = id; } void Topic::setStatus(uint8_t stat){ _topicId = stat; } void Topic::setTopicName(MQString* topic){ _topicStr = topic; } void Topic::setCallback(TopicCallback callback){ _callback = callback; } int Topic::execCallback(MqttsnPublish* msg){ if(_callback != 0){ return _callback(msg); } return 0; } void Topic::copy(Topic* src){ setTopicId(src->getTopicId()); setStatus(src->getStatus()); setCallback(src->getCallback()); setCallback(_callback); _topicStr = src->getTopicName(); } uint8_t Topic::isWildCard(){ if (getTopicName()->getChar(getTopicName()->getCharLength() - 1) == MQTTSN_TOPIC_SINGLE_WILDCARD){ return MQTTSN_TOPIC_SINGLE_WILDCARD; }else if (getTopicName()->getChar(getTopicName()->getCharLength() - 1) == MQTTSN_TOPIC_MULTI_WILDCARD){ return MQTTSN_TOPIC_MULTI_WILDCARD; } return 0; } bool Topic::isMatch(Topic* wildCard){ uint8_t pos = wildCard->getTopicName()->getCharLength() - 1; if (wildCard->isWildCard() == MQTTSN_TOPIC_SINGLE_WILDCARD && getTopicName()->ncomp(wildCard->getTopicName(), (long)pos) == 0 ){ for(; pos < getTopicName()->getCharLength(); pos++){ if (getTopicName()->getChar(pos) == '/'){ return false; } } return true; }else if(wildCard->isWildCard() == MQTTSN_TOPIC_MULTI_WILDCARD && getTopicName()->ncomp(wildCard->getTopicName(), (long)pos) == 0 ){ return true; } return false; } /*===================================== Class Topics ======================================*/ Topics::Topics(){ _sizeMax = 0; _elmCnt = 0; _topics = 0; } Topics::~Topics() { } bool Topics::allocate(uint8_t size){ _elmCnt = 0; _topics = (Topic*)calloc(size, sizeof(Topic)); if (_topics == 0){ _sizeMax = 0; return false; }else{ _sizeMax = size; return true; } } uint16_t Topics::getTopicId(MQString* topic){ Topic *p = getTopic(topic); if ( p != 0) { return p->getTopicId(); } return 0; } Topic* Topics::getTopic(MQString* topic) { for (int i = 0; i < _elmCnt; i++) { if ( topic->comp(_topics[i].getTopicName()) == 0) { return &_topics[i]; } } return 0; } Topic* Topics::getTopic(uint16_t id) { for (int i = 0; i < _elmCnt; i++) { if ( _topics[i].getTopicId() == id) { return &_topics[i]; } } return 0; } bool Topics::setTopicId(MQString* topic, uint16_t id){ Topic* p = getTopic(topic); if ( p != 0) { p->setTopicId(id); return true; }else{ return false; } } bool Topics::setCallback(MQString* topic, TopicCallback callback){ Topic* p = getTopic(topic); if ( p != 0) { p->setCallback(callback); return true; }else{ return false; } } bool Topics::setCallback(uint16_t topicId, TopicCallback callback){ Topic* p = getTopic(topicId); if ( p != 0) { p->setCallback(callback); return true; }else{ return false; } } int Topics::execCallback(uint16_t topicId, MqttsnPublish* msg){ Topic* p = getTopic(topicId); if ( p != 0) { return p->execCallback(msg); } return 0; } int Topics::execCallback(MQString* topic, MqttsnPublish* msg){ Topic* p = getTopic(topic); if ( p != 0) { return p->execCallback(msg); } return 0; } void Topics::addTopic(MQString* topic){ if (getTopic(topic) == 0){ if ( _elmCnt < _sizeMax){ _topics[_elmCnt].setTopicName(topic); _elmCnt++; }else{ Topic* saveTopics = _topics; Topic* newTopics = (Topic*)calloc(_sizeMax += MQTTSN_MAX_TOPICS + 1, sizeof(Topic)); if (newTopics != 0){ _topics = newTopics; for(int i = 0; i < _elmCnt; i++){ _topics[i].copy(&saveTopics[i]); saveTopics[i].setTopicName((MQString*)0); } _topics[_elmCnt].setTopicName(topic); _elmCnt++; if (saveTopics){ delete saveTopics; } } } } } Topic* Topics::match(MQString* topic){ for ( int i = 0; i< _elmCnt; i++){ if (_topics[i].isWildCard()){ if (getTopic(topic)->isMatch(&_topics[i])){ return &_topics[i]; } } } return 0; } void Topics::setSize(uint8_t size){ _sizeMax = size; } void Topics::clearTopic(void){ for( int i = 0; i < _elmCnt; i++){ if ( _topics[i].getTopicId() >= MQTTSN_TOPICID_NORMAL) { _elmCnt = i + 1; break; } } } /*===================================== Class Payload =====================================*/ Payload::Payload(){ _buff = _pos = 0; _len = 0; _elmCnt = 0; _memDlt = 0; } Payload::Payload(uint16_t len){ _buff = (uint8_t*)calloc(len, sizeof(uint8_t)); if(_buff == 0){ exit(-1); } _pos = _buff; _elmCnt = 0; _len = len; _memDlt = 1; } Payload::~Payload(){ if(_memDlt){ free(_buff); } } void Payload::init(){ _pos = _buff; _elmCnt = 0; } void Payload::getPayload(MqttsnPublish* msg){ if(_memDlt){ free(_buff); _memDlt = 0; } _buff = msg->getData(); _len = msg->getDataLength(); _pos = _buff + _len; /* for(uint8_t i; i < MSGPACK_MAX_ELEMENTS; i++){ if(getBufferPos(i) != 0){ _elmCnt++; }else{ break; } } */ _elmCnt = 6; } uint16_t Payload::getAvailableLength(){ return _len - (_pos - _buff); } uint16_t Payload::getLen(){ return _pos - _buff; } uint8_t* Payload::getBuf(){ return _buff; } /*====================== * setter ======================*/ int8_t Payload::set_uint32(uint32_t val){ if(getAvailableLength() < 6){ return -1; } if(val < 128){ *_pos++ = (uint8_t)val; }else if(val < 256){ *_pos++ = MSGPACK_UINT8; *_pos++ = (uint8_t)val; }else if(val < 65536){ *_pos++ = MSGPACK_UINT16; setUint16(_pos,(uint16_t) val); _pos += 2; }else{ *_pos++ = MSGPACK_UINT32; setUint32(_pos, val); _pos += 4; } _elmCnt++; return 0; } int8_t Payload::set_int32(int32_t val){ if(getAvailableLength() < 6){ return -1; } if((val > -32) && (val < 0)){ *_pos++ = val | MSGPACK_NEGINT; }else if((val >= 0) && (val < 128)){ *_pos++ = val; }else if(val > -128 && val < 128){ *_pos++ = MSGPACK_INT8; *_pos++ = (uint8_t)val; }else if(val > -32768 && val < 32768){ *_pos++ = MSGPACK_INT16; setUint16(_pos, (uint16_t)val); _pos += 2; }else{ *_pos++ = MSGPACK_INT32; setUint32(_pos, (uint32_t)val); _pos += 4; } _elmCnt++; return 0; } int8_t Payload::set_float(float val){ if(getAvailableLength() < 6){ return -1; } *_pos++ = MSGPACK_FLOAT32; setFloat32(_pos, val); _pos += 4; _elmCnt++; return 0; } int8_t Payload::set_str(char* val){ return set_str((const char*) val); } int8_t Payload::set_str(const char* val){ if(getAvailableLength() < strlen(val) + 3){ return -1; }else if(strlen(val) < 32){ *_pos++ = (uint8_t)strlen(val) | MSGPACK_FIXSTR; }else if(strlen(val) < 256){ *_pos++ = MSGPACK_STR8; *_pos++ = (uint8_t)strlen(val); }else if(strlen(val) < 65536){ *_pos++ = MSGPACK_STR16; setUint16(_pos, (uint16_t)strlen(val)); _pos += 2; } memcpy(_pos, val, strlen(val)); _pos += strlen(val); return 0; } int8_t Payload::set_array(uint8_t val){ if(getAvailableLength() < (uint16_t)val+ 1){ return -1; } if(val < 16){ *_pos++ = MSGPACK_ARRAY15 | val; }else{ *_pos++ = MSGPACK_ARRAY16; setUint16(_pos,(uint16_t)val); _pos += 2; } _elmCnt++; return 0; } /*====================== * getter ======================*/ uint8_t Payload::getArray(uint8_t index){ uint8_t rc = 0; uint8_t* val = getBufferPos(index); if(val != 0){ if(*val == MSGPACK_ARRAY15){ rc = *val & 0x0F; }else if(*val == MSGPACK_ARRAY16){ rc = (uint8_t)getUint16(val + 1); } } return rc; } uint32_t Payload::get_uint32(uint8_t index){ uint32_t rc = 0; uint8_t* val = getBufferPos(index); if(val != 0){ if(*val == MSGPACK_UINT32){ rc = getUint32(val + 1); }else if(*val == MSGPACK_UINT16){ rc = (uint32_t)getUint16(val + 1); }else if(*val == MSGPACK_UINT8){ rc = (uint32_t)*(val + 1); }else if(*val < 128){ rc = (uint32_t)*val; } } return rc; } int32_t Payload::get_int32(uint8_t index){ int32_t rc = 0; uint8_t* val = getBufferPos(index); if(val != 0){ if(*val == MSGPACK_INT32){ rc = (int32_t) getUint32(val + 1); }else if(*val == MSGPACK_INT16){ uint16_t d16 = getUint16(val + 1); if(d16 >= 32768){ rc = d16 - 65536; }else{ rc = (int32_t)d16; } }else if(*val == MSGPACK_INT8){ rc = (int32_t)*(val + 1); }else if((*val & MSGPACK_NEGINT) == MSGPACK_NEGINT){ *val &= ~MSGPACK_NEGINT; rc = ((int32_t)*val) * -1; }else{ rc = (int32_t) *val; } } return rc; } float Payload::get_float(uint8_t index){ uint8_t* val = getBufferPos(index); if(val != 0){ if(*val == MSGPACK_FLOAT32){ return getFloat32(val + 1); } } return 0; } const char* Payload::get_str(uint8_t index, uint16_t* len){ uint8_t* val = getBufferPos(index); if(val != 0){ if(*val == MSGPACK_STR16){ *len = getUint16(val + 1); return (const char*)(val + 3); }else if(*val == MSGPACK_STR8){ *len = *(val + 1); return (const char*)(val + 2); }else if(*val & MSGPACK_FIXSTR){ *len = *val & (~MSGPACK_FIXSTR); return (const char*)(val + 1); } } *len = 0; return (const char*) 0; } uint8_t* Payload::getBufferPos(uint8_t index){ uint8_t* bpos = 0; uint8_t* pos = _buff; for(uint8_t i = 0; i <= index; i++){ bpos = pos; switch(*pos){ case MSGPACK_FALSE: case MSGPACK_TRUE: pos++; break; case MSGPACK_UINT8: case MSGPACK_INT8: pos += 2; break; case MSGPACK_UINT16: case MSGPACK_INT16: case MSGPACK_ARRAY16: pos += 3; break; case MSGPACK_UINT32: case MSGPACK_INT32: case MSGPACK_FLOAT32: pos += 5; break; case MSGPACK_STR8: pos += *(pos + 1) + 2; break; case MSGPACK_STR16: pos += getUint16(pos + 1) + 3; break; default: if((*pos < MSGPACK_POSINT) || ((*pos & MSGPACK_NEGINT) == MSGPACK_NEGINT) || ((*pos & MSGPACK_ARRAY15) == MSGPACK_ARRAY15)) { pos++; }else if((*pos & MSGPACK_FIXSTR) == MSGPACK_FIXSTR){ pos += *pos & (~MSGPACK_FIXSTR); } } /* if((pos - _buff) >= _len){ return 0; } */ } return bpos; } void Payload::print(){ for(uint8_t* pos = _buff; pos < _pos; pos++){ printf(" 0x%x", *pos); } printf("\n"); } /*===================================== Class PublishHandller ======================================*/ PublishHandller::PublishHandller(){ } PublishHandller::~PublishHandller(){ } int PublishHandller::exec(MqttsnPublish* msg, Topics* topics){ MQString tp = MQString(); if((msg->getFlags() && MQTTSN_TOPIC_TYPE) == MQTTSN_TOPIC_TYPE_SHORT){ if (topics->getTopic(msg->getTopic(&tp))){ return topics->getTopic(msg->getTopic(&tp))->execCallback(msg); } }else{ if (topics->getTopic(msg->getTopicId())){ return topics->getTopic(msg->getTopicId())->execCallback(msg); } } return 0; } /////////////////// End of File /////////////// ================================================ FILE: Client/src/lib/mqttsn.h ================================================ /* * mqttsn.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef MQTTS_H_ #define MQTTS_H_ #ifdef ARDUINO #include #else #include "MQTTSN_Application.h" #endif #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #include #include #endif #if defined(ARDUINO) && ARDUINO < 100 #include "WProgram.h" #include #include #endif #ifdef LINUX #include #include #include "Network.h" #endif #ifdef MBED #include "mbed.h" #include "Network.h" #endif /* [sec] */ #define MQTTSN_DEFAULT_KEEPALIVE 3600 // 1H #define MQTTSN_DEFAULT_DURATION 900 // 15min #define MQTTSN_TIME_SEARCHGW 3 #define MQTTSN_TIME_RETRY 10 #define MQTTSN_TIME_WAIT 300 // 5min #define MQTTSN_RETRY_COUNT 5 #define MQTTSN_MAX_TOPICS 15 #define MQTTSN_MAX_PACKET_LENGTH 60 #define MQTTSN_TYPE_ADVERTISE 0x00 #define MQTTSN_TYPE_SEARCHGW 0x01 #define MQTTSN_TYPE_GWINFO 0x02 #define MQTTSN_TYPE_CONNECT 0x04 #define MQTTSN_TYPE_CONNACK 0x05 #define MQTTSN_TYPE_WILLTOPICREQ 0x06 #define MQTTSN_TYPE_WILLTOPIC 0x07 #define MQTTSN_TYPE_WILLMSGREQ 0x08 #define MQTTSN_TYPE_WILLMSG 0x09 #define MQTTSN_TYPE_REGISTER 0x0A #define MQTTSN_TYPE_REGACK 0x0B #define MQTTSN_TYPE_PUBLISH 0x0C #define MQTTSN_TYPE_PUBACK 0x0D #define MQTTSN_TYPE_PUBCOMP 0x0E #define MQTTSN_TYPE_PUBREC 0x0F #define MQTTSN_TYPE_PUBREL 0x10 #define MQTTSN_TYPE_SUBSCRIBE 0x12 #define MQTTSN_TYPE_SUBACK 0x13 #define MQTTSN_TYPE_UNSUBSCRIBE 0x14 #define MQTTSN_TYPE_UNSUBACK 0x15 #define MQTTSN_TYPE_PINGREQ 0x16 #define MQTTSN_TYPE_PINGRESP 0x17 #define MQTTSN_TYPE_DISCONNECT 0x18 #define MQTTSN_TYPE_WILLTOPICUPD 0x1A #define MQTTSN_TYPE_WILLTOPICRESP 0x1B #define MQTTSN_TYPE_WILLMSGUPD 0x1C #define MQTTSN_TYPE_WILLMSGRESP 0x1D #define MQTTSN_TOPIC_TYPE_NORMAL 0x00 #define MQTTSN_TOPIC_TYPE_PREDEFINED 0x01 #define MQTTSN_TOPIC_TYPE_SHORT 0x02 #define MQTTSN_TOPIC_TYPE 0x03 #define MQTTSN_FLAG_DUP 0x80 #define MQTTSN_FLAG_QOS_0 0x0 #define MQTTSN_FLAG_QOS_1 0x20 #define MQTTSN_FLAG_QOS_2 0x40 #define MQTTSN_FLAG_QOS_N1 0xc0 #define MQTTSN_FLAG_RETAIN 0x10 #define MQTTSN_FLAG_WILL 0x08 #define MQTTSN_FLAG_CLEAN 0x04 #define MQTTSN_PROTOCOL_ID 0x01 #define MQTTSN_HEADER_SIZE 2 #define MQTTSN_RC_ACCEPTED 0x00 #define MQTTSN_RC_REJECTED_CONGESTION 0x01 #define MQTTSN_RC_REJECTED_INVALID_TOPIC_ID 0x02 #define MQTTSN_RC_REJECTED_NOT_SUPPORTED 0x03 #define MQTTSN_MSG_REQUEST 1 #define MQTTSN_MSG_RESEND_REQ 2 #define MQTTSN_MSG_WAIT_ACK 3 #define MQTTSN_MSG_COMPLETE 4 #define MQTTSN_MSG_REJECTED 5 #define MQTTSN_GW_INIT 0 #define MQTTSN_GW_SEARCHING 1 #define MQTTSN_GW_FOUND 2 #define MQTTSN_GW_CONNECTED 3 #define MQTTSN_GW_DISCONNECTED 4 #define MQTTSN_GW_LOST 5 #define MQTTSN_ERR_NO_ERROR 0 #define MQTTSN_ERR_NOT_CONNECTED -11 #define MQTTSN_ERR_RETRY_OVER -12 #define MQTTSN_ERR_GATEWAY_LOST -13 #define MQTTSN_ERR_CANNOT_ADD_REQUEST -14 #define MQTTSN_ERR_NO_TOPICID -15 #define MQTTSN_ERR_REJECTED -16 #define MQTTSN_ERR_WAIT_GWINFO -17 #define MQTTSN_ERR_OUT_OF_MEMORY -18 #define MQTTSN_ERR_PING_REQUIRED -19 #define MQTTSN_ERR_ACK_TIMEOUT -20 #define MQTTSN_ERR_PINGRESP_TIMEOUT -21 #define MQTTSN_ERR_INVALID_TOPICID -22 #define MQTTSN_ERR_NO_DATA -23 #define MQTTSN_ERR_REBOOT_REQUIRED -24 #define MQTTSN_READ_RESP_ONCE_MORE -25 #define MQTTSN_TOPIC_MULTI_WILDCARD '#' #define MQTTSN_TOPIC_SINGLE_WILDCARD '+' #define MQTTSN_TOPICID_NORMAL 256 #define MQTTSN_TOPICID_PREDEFINED_TIME 0x0001 #define MQTTSN_TOPIC_PREDEFINED_TIME ("$GW/01") #define QOS0 0 #define QOS1 1 #define QOS2 2 #define MSGPACK_FALSE 0xc2 #define MSGPACK_TRUE 0xc3 #define MSGPACK_POSINT 0x80 #define MSGPACK_NEGINT 0xe0 #define MSGPACK_UINT8 0xcc #define MSGPACK_UINT16 0xcd #define MSGPACK_UINT32 0xce #define MSGPACK_INT8 0xd0 #define MSGPACK_INT16 0xd1 #define MSGPACK_INT32 0xd2 #define MSGPACK_FLOAT32 0xca #define MSGPACK_FIXSTR 0xa0 #define MSGPACK_STR8 0xd9 #define MSGPACK_STR16 0xda #define MSGPACK_ARRAY15 0x90 #define MSGPACK_ARRAY16 0xdc #define MSGPACK_MAX_ELEMENTS 50 // Less than 256 using namespace tomyClient; /*===================================== Class MQString =====================================*/ class MQString{ public: MQString(); MQString(const char*); MQString(char*); ~MQString(); uint16_t getCharLength(); int comp(MQString* str); int comp(const char* str); int ncomp(MQString* str, uint16_t n); void copy(MQString* str); void copy(const char* str); void copy(char* str); void copy(uint8_t* str, uint8_t len); MQString* create(); void writeBuf(uint8_t* buf); void readBuf(uint8_t* buf); uint8_t getChar(uint8_t index); char* getStr(); const char* getConstStr(); bool isConst(); bool operator==(MQString&); bool operator!=(MQString&); private: void freeStr(); char* _str; const char* _constStr; }; /*===================================== Class MqttsnMessage =====================================*/ class MqttsnMessage { public: MqttsnMessage(); ~MqttsnMessage(); void setLength(uint16_t length); void setType(uint8_t type); bool setBody(uint8_t* body); bool allocateBody(); void setStatus(uint8_t stat); void setDup(); void setQos(uint8_t qos); void setRetain(bool flg); void setFlags(uint8_t flag); uint8_t getLength(); uint8_t getType(); uint8_t getFlags(); uint8_t getStatus(); uint8_t getQos(); uint8_t* getBody(); uint8_t* getMsgBuff(); uint16_t getFrameLength(); uint16_t getBodyLength(); bool isDup(); bool copy(MqttsnMessage* src); void reset(); void setMsgBuff(uint8_t* buff); const char* getMsgTypeName(); protected: uint8_t* _msgBuff; uint8_t _flags; private: uint8_t _status; // 1:request 2:sending 3:resending 4:waitingAck 5:complite uint8_t _type; uint16_t _length; }; /*===================================== Class MqttsnAdvertize ======================================*/ class MqttsnAdvertise : public MqttsnMessage { public: MqttsnAdvertise(); ~MqttsnAdvertise(); void setGwId(uint8_t id); void setDuration(uint16_t duration); uint8_t getGwId(); uint16_t getDuration(); private: }; /*===================================== Class MqttsnSearchGw ======================================*/ class MqttsnSearchGw : public MqttsnMessage { public: MqttsnSearchGw(); ~MqttsnSearchGw(); void setRadius(uint8_t radius); uint8_t getRadius(); private: }; /*===================================== Class MqttsnGwinfo ======================================*/ class MqttsnGwInfo : public MqttsnMessage { public: MqttsnGwInfo(); ~MqttsnGwInfo(); void setGwId(uint8_t id); uint8_t getGwId(); private: }; /*===================================== Class MqttsnConnect ======================================*/ class MqttsnConnect : public MqttsnMessage { public: MqttsnConnect(MQString* id); ~MqttsnConnect(); void setDuration(uint16_t msec); void setClientId(MQString* id); uint8_t* getClientId(); uint16_t getDuration(); void setFrame(uint8_t* data, uint8_t len); private: }; /*===================================== Class MqttsnConnack ======================================*/ class MqttsnConnack : public MqttsnMessage { public: MqttsnConnack(); ~MqttsnConnack(); void setReturnCode(uint8_t rc); uint8_t getReturnCode(); private: }; /*===================================== Class MqttsnWillTopicReq ======================================*/ class MqttsnWillTopicReq : public MqttsnMessage { public: MqttsnWillTopicReq(); ~MqttsnWillTopicReq(); private: }; /*===================================== Class MqttsnWillTopic ======================================*/ class MqttsnWillTopic : public MqttsnMessage { public: MqttsnWillTopic(); ~MqttsnWillTopic(); void setWillTopic(MQString* topic); MQString* getWillTopic(); bool isWillRequired(); private: MQString _ustring; }; /*===================================== Class MqttsnWillMsgReq ======================================*/ class MqttsnWillMsgReq : public MqttsnMessage { public: MqttsnWillMsgReq(); ~MqttsnWillMsgReq(); private: }; /*===================================== Class MqttsnWillMsg ======================================*/ class MqttsnWillMsg : public MqttsnMessage { public: MqttsnWillMsg(); ~MqttsnWillMsg(); void setWillMsg(MQString* msg); char* getWillMsg(); private: }; /*===================================== Class MqttsnRegister ======================================*/ class MqttsnRegister : public MqttsnMessage { public: MqttsnRegister(); ~MqttsnRegister(); void setTopicId(uint16_t topicId); uint16_t getTopicId(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); void setTopicName(MQString* topicName); void setFrame(uint8_t* data, uint8_t len); void setFrame(NWResponse* resp); MQString* getTopicName(); private: uint16_t _topicId; uint16_t _msgId; MQString _ustring; }; /*===================================== Class MqttsnRegAck ======================================*/ class MqttsnRegAck : public MqttsnMessage { public: MqttsnRegAck(); ~MqttsnRegAck(); void setTopicId(uint16_t topicId); uint16_t getTopicId(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); void setReturnCode(uint8_t rc); uint8_t getReturnCode(); private: }; /*===================================== Class MqttsnPublish ======================================*/ class Payload; class MqttsnPublish : public MqttsnMessage { public: MqttsnPublish(); ~MqttsnPublish(); void setTopicId(uint16_t id); void setTopic(MQString* topic); void setMsgId(uint16_t msgId); void setData(uint8_t* data, uint16_t len); void setData(MQString* str); void setFrame(uint8_t* data, uint16_t len); void setFrame(NWResponse* resp); void setPayload(Payload* payload); MQString* getTopic(MQString* topic); uint16_t getMsgId(); uint16_t getTopicId(); uint8_t* getData(); uint16_t getDataLength(); private: uint16_t _topicId; uint16_t _msgId; MQString* _topic; }; /*===================================== Class MqttsnPubAck ======================================*/ class MqttsnPubAck : public MqttsnMessage { public: MqttsnPubAck(); ~MqttsnPubAck(); void setTopicId(uint16_t id); uint16_t getTopicId(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); void setReturnCode(uint8_t rc); uint8_t getReturnCode(); private: }; /*===================================== Class MqttsnPubRec ======================================*/ class MqttsnPubRec : public MqttsnMessage { public: MqttsnPubRec(); ~MqttsnPubRec(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); private: }; /*===================================== Class MqttsnPubRel ======================================*/ class MqttsnPubRel : public MqttsnPubRec { public: MqttsnPubRel(); ~MqttsnPubRel(); private: }; /*===================================== Class MqttsnPubComp ======================================*/ class MqttsnPubComp : public MqttsnPubRec { public: MqttsnPubComp(); ~MqttsnPubComp(); private: }; /*===================================== Class MqttsnSubscribe ======================================*/ class MqttsnSubscribe : public MqttsnMessage { public: MqttsnSubscribe(); ~MqttsnSubscribe(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); uint16_t getTopicId(); MQString* getTopicName(); void setTopicId(uint16_t predefinedId); void setFrame(uint8_t* data, uint8_t len); void setFrame(NWResponse* resp); void setTopicName(MQString* topicName); protected: uint16_t _topicId; uint16_t _msgId; MQString _ustring; }; /*===================================== Class MqttsnSubAck ======================================*/ class MqttsnSubAck : public MqttsnMessage { public: MqttsnSubAck(); ~MqttsnSubAck(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); void setTopicId(uint16_t topicId); uint16_t getTopicId(); void setReturnCode(uint8_t rc); uint8_t getReturnCode(); private: }; /*===================================== Class MqttsnUnsubscribe ======================================*/ class MqttsnUnsubscribe : public MqttsnSubscribe { public: MqttsnUnsubscribe(); ~MqttsnUnsubscribe(); private: }; /*===================================== Class MqttsnUnSubAck ======================================*/ class MqttsnUnSubAck : public MqttsnMessage { public: MqttsnUnSubAck(); ~MqttsnUnSubAck(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); private: }; /*===================================== Class MqttsnPingReq ======================================*/ class MqttsnPingReq : public MqttsnMessage { public: MqttsnPingReq(MQString* id); ~MqttsnPingReq(); char* getClientId(); private: }; /*===================================== Class MqttsnPingResp ======================================*/ class MqttsnPingResp : public MqttsnMessage { public: MqttsnPingResp(); ~MqttsnPingResp(); private: }; /*===================================== Class MqttsnDisconnect ======================================*/ class MqttsnDisconnect : public MqttsnMessage { public: MqttsnDisconnect(); ~MqttsnDisconnect(); void setDuration(uint16_t duration); uint16_t getDuration(); private: }; /*===================================== Class Topic ======================================*/ typedef int (*TopicCallback)(MqttsnPublish*); class Topic { public: Topic(); ~Topic(); uint8_t getStatus(); uint16_t getTopicId(); MQString* getTopicName(); uint8_t getTopicLength(); uint8_t getTopicType(); TopicCallback getCallback(); void setTopicId(uint16_t id); void setTopicName(MQString* topic); void setStatus(uint8_t stat); int execCallback(MqttsnPublish* msg); void copy(Topic* src); void setCallback(TopicCallback callback); uint8_t isWildCard(); bool isMatch(Topic* wildCard); private: uint16_t _topicId; uint8_t _status; MQString* _topicStr; TopicCallback _callback; }; /*===================================== Class Topics ======================================*/ class Topics { public: Topics(); ~Topics(); bool allocate(uint8_t topicsSize); uint16_t getTopicId(MQString* topic); Topic* getTopic(MQString* topic); Topic* getTopic(uint16_t topicId); bool setTopicId(MQString* topic, uint16_t id); bool setCallback(MQString* topic, TopicCallback callback); bool setCallback(uint16_t topicId, TopicCallback callback); int execCallback(uint16_t topicId, MqttsnPublish* msg); int execCallback(MQString* topic, MqttsnPublish* msg); void addTopic(MQString* topic); Topic* match(MQString* topic); void setSize(uint8_t size); void clearTopic(void); private: uint8_t _sizeMax; uint8_t _elmCnt; Topic* _topics; }; /*===================================== Class Payload =====================================*/ class Payload{ public: Payload(); Payload(uint16_t len); ~Payload(); void init(void); int8_t set_uint32(uint32_t val); int8_t set_int32(int32_t val); int8_t set_float(float val); int8_t set_str(char* val); int8_t set_str(const char* val); int8_t set_array(uint8_t val); uint8_t getArray(uint8_t index); uint32_t get_uint32(uint8_t index); int32_t get_int32(uint8_t index); float get_float(uint8_t index); const char* get_str(uint8_t index, uint16_t* len); void getPayload(MqttsnPublish* msg); uint16_t getAvailableLength(); uint16_t getLen(); uint8_t* getBuf(); void print(); private: uint8_t* getBufferPos(uint8_t index); uint8_t* _buff; uint16_t _len; uint8_t _elmCnt; uint8_t* _pos; uint8_t _memDlt; }; /*===================================== Class Publish Handler ======================================*/ class PublishHandller { public: PublishHandller(); ~PublishHandller(); int exec(MqttsnPublish* msg, Topics* topics); }; #endif /* MQTTS_H_ */ ================================================ FILE: Client/src/lib/mqttsnClient.cpp ================================================ /* * mqttsnClient.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/11/25 * Author: Tomoaki YAMAGUCHI * Version: 1.1.1 */ #ifdef ARDUINO #endif /* ARDUINO */ #ifdef ARDUINO #include #include #include #if defined(MQTTSN_DEBUG) || defined(NW_DEBUG) || defined(DEBUG) #include extern SoftwareSerial debug; #endif #else #include "MQTTSN_Application.h" #include "mqUtil.h" #include "mqttsnClient.h" #endif #ifdef MBED #include "mbed.h" #endif /* MBED */ #ifdef LINUX #include #include #include #include #include #include #include #include #include #include #endif /* LINUX */ using namespace std; using namespace tomyClient; extern OnPublishList theOnPublishList[]; extern APP_CONFIG theAppConfig; extern MQString* theTopics[]; extern uint16_t getUint16(uint8_t* pos); extern uint32_t getUint32(uint8_t* pos); extern float getFloat32(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); extern void setFloat32(uint8_t* pos, float val); static MqttsnClient* theMqttsn; /*================================================================= Class MqttsnnClient ================================================================*/ void ResponseHandler(NWResponse* resp, int* returnCode){ theMqttsn->recieveMessageHandler(resp, returnCode); } MqttsnClient::MqttsnClient(){ _network = new Network(); _network->setRxHandler(ResponseHandler); _sendQ = new SendQue(); _duration = 0; _clientId = new MQString(); _clientFlg = 0; _nRetry = MQTTSN_RETRY_COUNT; _nRetryCnt = 0; _tRetry = 0; _willTopic = _willMessage = 0; _clientStatus.setKeepAlive(MQTTSN_DEFAULT_KEEPALIVE); _msgId = 0; _topics.allocate(MQTTSN_MAX_TOPICS + 1); _sendFlg = false; _subscribingFlg = false; theMqttsn = this; } MqttsnClient::~MqttsnClient(){ _sendQ->deleteAllRequest(); delete _network; } int MqttsnClient::initialize(APP_CONFIG config){ _clientId->copy(config.mqttsnCfg.nodeId); MQString* pre1 = new MQString(MQTTSN_TOPIC_PREDEFINED_TIME); _topics.addTopic(pre1); _topics.setTopicId(pre1,MQTTSN_TOPICID_PREDEFINED_TIME); return _network->initialize(config.netCfg); } void MqttsnClient::subscribe(){ for(int i = 0; theOnPublishList[i].pubCallback; i++){ subscribe(theOnPublishList[i].topic, theOnPublishList[i].pubCallback, theOnPublishList[i].qos); } } void MqttsnClient::createTopics(){ for(int i = 0; theTopics[i]; i++){ registerTopic(theTopics[i]); } } void MqttsnClient::setSubscribing(bool flg){ _clientStatus.setSubscribing(flg); } int MqttsnClient::readPacket(){ return _network->readPacket(1); // XBee: Modem Staus, UDP: neglect } Topics* MqttsnClient::getTopics(){ return &_topics; } void MqttsnClient::setKeepAlive(uint16_t sec){ _clientStatus.setKeepAlive(sec); } void MqttsnClient::setWillTopic(MQString* topic){ _willTopic = topic; _clientFlg |= MQTTSN_FLAG_WILL; } void MqttsnClient::setWillMessage(MQString* msg){ _willMessage = msg; _clientFlg |= MQTTSN_FLAG_WILL; } void MqttsnClient::setRetain(bool retain){ if(retain){ _clientFlg |= MQTTSN_FLAG_RETAIN; }else{ _clientFlg &= (~MQTTSN_FLAG_RETAIN); } } void MqttsnClient::setSleepMode(){ _clientStatus.setModeSleep(); } void MqttsnClient::setClean(bool clean){ if(clean){ _clientFlg |= MQTTSN_FLAG_CLEAN; }else{ _clientFlg ^= MQTTSN_FLAG_CLEAN; } } bool MqttsnClient::isCleanSession(){ return _clientFlg && MQTTSN_FLAG_CLEAN; } void MqttsnClient::setRetryMax(uint8_t cnt){ _nRetry = cnt; } void MqttsnClient::setGwAddress(){ _network->setGwAddress(); } MQString* MqttsnClient::getClientId(){ return _clientId; } ClientStatus* MqttsnClient::getClientStatus(){ return &_clientStatus; } uint16_t MqttsnClient::getNextMsgId(){ _msgId++; if (_msgId == 0){ _msgId = 1; } return _msgId; } uint8_t MqttsnClient::getMsgRequestType(){ if (_sendQ->getMessage(0)){ return _sendQ->getMessage(0)->getType(); }else{ return 0; } } uint8_t MqttsnClient::getMsgRequestStatus(){ return _sendQ->getStatus(0); } uint8_t MqttsnClient::getMsgRequestCount(){ return _sendQ->getCount(); } void MqttsnClient::setMsgRequestStatus(uint8_t stat){ _sendQ->setStatus(0,stat); } void MqttsnClient::clearMsgRequest(){ _sendQ->deleteRequest(0); } void MqttsnClient::createTopic(MQString* topic, TopicCallback callback){ _topics.addTopic(topic); _topics.setCallback(topic, callback); } void MqttsnClient::delayTime(uint16_t maxTime){ #ifdef ARDUINO srand((uint32_t)millis( )); uint32_t tm = rand() % (maxTime * 1000); #else srand((uint32_t)time( 0 )); uint32_t tm = (rand() % (maxTime * 1000)); #endif XTimer delayTimer; delayTimer.start(tm); while(!delayTimer.isTimeUp()){ _network->readPacket(); } } void MqttsnClient::copyMsg(MqttsnMessage* msg, NWResponse* recvMsg){ memcpy(msg->getMsgBuff(), recvMsg->getPayload(), recvMsg->getPayload(0)); } /*======================================================== Send a MQTT-S Message (add the send request) ==========================================================*/ int MqttsnClient::requestSendMsg(MqttsnMessage* mqttsMsgPtr){ int index = _sendQ->addRequest((MqttsnMessage*)mqttsMsgPtr); _sendQ->setStatus(index, MQTTSN_MSG_REQUEST); return MQTTSN_ERR_NO_ERROR; } /*======================================================== Send a MQTT-S Message (add to the top of the send request) ==========================================================*/ int MqttsnClient::requestPrioritySendMsg(MqttsnMessage* mqttsMsgPtr){ _sendQ->addPriorityRequest((MqttsnMessage*)mqttsMsgPtr); _sendQ->setStatus(0, MQTTSN_MSG_REQUEST); return MQTTSN_ERR_NO_ERROR; } /*======================================================== Execute sending a MQTT-S Message ==========================================================*/ /*------------- send Message once -----------------*/ int MqttsnClient::exec(){ int rc; if (!_clientStatus.isGatewayAlive()){ D_MQTTW("Gateway is Dead.\r\n"); _clientStatus.init(); } /* if(_sendFlg){ return MQTTSN_ERR_NO_ERROR; }else{ //_sendFlg = true; } */ while(true){ rc = sendRecvMsg(); if (rc == MQTTSN_ERR_RETRY_OVER){ if (getMsgRequestType() == MQTTSN_TYPE_WILLTOPIC || getMsgRequestType() == MQTTSN_TYPE_WILLMSG || getMsgRequestType() == MQTTSN_TYPE_PINGREQ || getMsgRequestType() == MQTTSN_TYPE_PUBLISH || getMsgRequestType() == MQTTSN_TYPE_REGISTER || getMsgRequestType() == MQTTSN_TYPE_SUBSCRIBE || getMsgRequestType() == MQTTSN_TYPE_CONNECT || getMsgRequestType() == MQTTSN_TYPE_UNSUBSCRIBE || getMsgRequestType() == MQTTSN_TYPE_PUBREC || getMsgRequestType() == MQTTSN_TYPE_SEARCHGW || getMsgRequestType() == MQTTSN_TYPE_PUBREL) { _clientStatus.init(); } }else if(rc == MQTTSN_ERR_REBOOT_REQUIRED){ _clientStatus.init(); }else if(rc != MQTTSN_ERR_NO_ERROR && rc != MQTTSN_ERR_INVALID_TOPICID){ continue; } break; } clearMsgRequest(); // _sendFlg = false; return rc; } /*============================= * Send or Receive Message ==============================*/ int MqttsnClient::sendRecvMsg(){ int rc = MQTTSN_ERR_NO_ERROR; if (!_clientStatus.isGatewayAlive()){ D_MQTTW("Gateway is Dead.\r\n"); _clientStatus.init(); } /*======= Establish Connection ===========*/ if (_clientStatus.isLost() ||_clientStatus.isSearching() ){ /*------------ Send SEARCHGW --------------*/ if (getMsgRequestType() != MQTTSN_TYPE_SEARCHGW){ searchGw(0); //ZB_BROADCAST_RADIUS_MAX_HOPS } _clientStatus.sendSEARCHGW(); _network->resetGwAddress(); rc = broadcast(MQTTSN_TIME_RETRY); if ( rc != MQTTSN_ERR_NO_ERROR){ return rc; } } if (!_clientStatus.isConnected() && !_clientStatus.isSearching()){ /*----------- Send CONNECT ----------*/ if (getMsgRequestType() != MQTTSN_TYPE_CONNECT){ connect(); } rc = unicast(MQTTSN_TIME_RETRY); if ( rc != MQTTSN_ERR_NO_ERROR){ return rc; } } if(_clientStatus.isOnConnected()){ /*----------- ready to send ----------*/ _clientStatus.setAvailableToSend(); /*----------- in case of clean session ----------*/ if(isCleanSession() && !_clientStatus.isSubscribing()){ _clientStatus.setSubscribing(true); // re-entrant control subscribe(); _clientStatus.setSubscribing(false); // re-entrant control } } if (getMsgRequestStatus() == MQTTSN_MSG_REQUEST || getMsgRequestStatus() == MQTTSN_MSG_RESEND_REQ){ /*====== Send Message =======*/ if (_clientStatus.isAvailableToSend()){ rc = unicast(MQTTSN_TIME_RETRY); }else{ rc = MQTTSN_ERR_NOT_CONNECTED; } } /*======= Receive Message ===========*/ _network->readPacket(); // Receive MQTT-S Message if (_clientStatus.isPINGREQRequired()){ /*-------- Send PINGREQ -----------*/ if(getMsgRequestType() != MQTTSN_TYPE_PINGREQ){ pingReq(_clientId); } rc = unicast(MQTTSN_TIME_RETRY); } return rc; } /*------------------------------------ * Broad cast the MQTT-S Message -------------------------------------*/ int MqttsnClient::broadcast(uint16_t packetReadTimeout){ int retry = 0; while(retry < _nRetry){ D_MQTTW("Bcast "); D_MQTTLN(_sendQ->getMessage(0)->getMsgTypeName()); D_MQTTF("%s\r\n", _sendQ->getMessage(0)->getMsgTypeName()); #if defined(DEBUG) && defined(ARDUINO) debug.print("Bcast "); debug.println(_sendQ->getMessage(0)->getMsgTypeName()); #endif _network->send(_sendQ->getMessage(0)->getMsgBuff(), _sendQ->getMessage(0)->getLength(),BcastReq); _respTimer.start(packetReadTimeout * 1000); setMsgRequestStatus(MQTTSN_MSG_WAIT_ACK); while(!_respTimer.isTimeUp()){ if(_network->readPacket() != PACKET_ERROR_NODATA){ if (getMsgRequestStatus() == MQTTSN_MSG_COMPLETE){ clearMsgRequest(); return MQTTSN_ERR_NO_ERROR; }else if(getMsgRequestStatus() == MQTTSN_MSG_REJECTED){ //clearMsgRequest(); return MQTTSN_ERR_REBOOT_REQUIRED; } } } setMsgRequestStatus(MQTTSN_MSG_REQUEST); retry++; } //clearMsgRequest(); return MQTTSN_ERR_RETRY_OVER; } /*------------------------------------ * Unicast the MQTT-S Message -------------------------------------*/ int MqttsnClient::unicast(uint16_t packetReadTimeout){ int retry = 0; while(retry < _nRetry){ if (getMsgRequestStatus() == MQTTSN_MSG_RESEND_REQ){ /* ------ Re send Time delay -------*/ #ifdef ARDUINO delay(MQTTSN_TIME_WAIT * 1000UL); #else #ifdef MBED wait_ms(MQTTSN_TIME_WAIT * 1000); #else usleep(MQTTSN_TIME_WAIT * 1000000); #endif #endif setMsgRequestStatus(MQTTSN_MSG_REQUEST); } /*------ Send Top message in SendQue -----*/ if (getMsgRequestStatus() != MQTTSN_MSG_REQUEST){ return MQTTSN_ERR_NO_ERROR; } D_MQTTW("Ucast "); D_MQTTLN(_sendQ->getMessage(0)->getMsgTypeName()); D_MQTTF("%s\r\n", _sendQ->getMessage(0)->getMsgTypeName()); #if defined(DEBUG) && defined(ARDUINO) debug.print("Ucast "); debug.println(_sendQ->getMessage(0)->getMsgTypeName()); #endif _network->send(_sendQ->getMessage(0)->getMsgBuff(), _sendQ->getMessage(0)->getLength(), UcastReq); _clientStatus.setLastSendTime(); _sendQ->getMessage(0)->setDup(); _respTimer.start(packetReadTimeout * 1000UL); setMsgRequestStatus(MQTTSN_MSG_WAIT_ACK); while(!_respTimer.isTimeUp()){ if ((getMsgRequestType() == MQTTSN_TYPE_PUBLISH && _sendQ->getMessage(0)->getQos() == 0 ) || getMsgRequestType() == MQTTSN_TYPE_PUBACK || getMsgRequestType() == MQTTSN_TYPE_REGACK || getMsgRequestType() == MQTTSN_TYPE_PUBCOMP || getMsgRequestStatus() == MQTTSN_MSG_COMPLETE ){ //clearMsgRequest(); return MQTTSN_ERR_NO_ERROR; }else if(getMsgRequestType() == MQTTSN_TYPE_DISCONNECT ){ _clientStatus.recvDISCONNECT(); //clearMsgRequest(); return MQTTSN_ERR_NO_ERROR; }else if (getMsgRequestStatus() == MQTTSN_MSG_REJECTED){ //clearMsgRequest(); return MQTTSN_ERR_REJECTED; } /*----- Read response ----*/ int rc = _network->readPacket(); if(rc == MQTTSN_READ_RESP_ONCE_MORE){ rc = _network->readPacket(); } if(rc == MQTTSN_ERR_INVALID_TOPICID){ //clearMsgRequest(); return rc; }else if(rc == PACKET_MODEM_STATUS ){ break; } /*---- WILLTOPICREQ ,WILLMESSAGEREQ PUBREC are received ---*/ if (getMsgRequestStatus() == MQTTSN_MSG_REQUEST && (getMsgRequestType() == MQTTSN_TYPE_WILLTOPIC || getMsgRequestType() == MQTTSN_TYPE_WILLMSG || getMsgRequestType() == MQTTSN_TYPE_PUBREL)){ retry = 0; break; } } setMsgRequestStatus(MQTTSN_MSG_REQUEST); retry++; } return MQTTSN_ERR_RETRY_OVER; } /*======================================== * Create & send the MQTT-S Messages =========================================*/ #ifdef MQTTSN_DEBUG const char* gateWayLost = " Gateway lost\r\n"; #endif /*--------- REGISTER ------*/ int MqttsnClient::registerTopic(MQString* topic){ MqttsnRegister mqttsMsg = MqttsnRegister(); mqttsMsg.setTopicName(topic); mqttsMsg.setMsgId(getNextMsgId()); _topics.addTopic(topic); D_MQTTW("\nREGISTER SEND Topic = "); D_MQTTLN(topic->getConstStr()); D_MQTTF("%s\r\n", topic->getConstStr()); requestPrioritySendMsg((MqttsnMessage*)&mqttsMsg); return exec(); } /*--------- PUBLISH ------*/ int MqttsnClient::publish(MQString* topic, const char* data, int dataLength, uint8_t qos){ if(!_clientStatus.isAvailableToSend()){ return MQTTSN_ERR_NOT_CONNECTED; } MqttsnPublish mqttsMsg = MqttsnPublish(); uint16_t topicId = _topics.getTopicId(topic); if (topic->getCharLength() == 2 && topicId == 0){ _topics.addTopic(topic); if(topic->getStr()){ topicId = getUint16((uint8_t*)topic->getStr()); }else{ topicId = getUint16((uint8_t*)topic->getConstStr()); } _topics.setTopicId(topic, topicId); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_SHORT); mqttsMsg.setTopicId(topicId); }else{ mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_NORMAL); if(topicId){ mqttsMsg.setTopicId(topicId); }else{ registerTopic(topic); mqttsMsg.setTopicId(_topics.getTopicId(topic)); } } mqttsMsg.setQos(qos); mqttsMsg.setData((uint8_t*)data, (uint8_t)dataLength); if (qos){ mqttsMsg.setMsgId(getNextMsgId()); } requestSendMsg((MqttsnMessage*)&mqttsMsg); D_MQTTW("PUBLISH SEND msgID = "); D_MQTTLN(mqttsMsg.getMsgId(),DEC); D_MQTTF("%d\r\n", mqttsMsg.getMsgId()); int rc = exec(); if (rc == MQTTSN_ERR_INVALID_TOPICID){ registerTopic(topic); } return rc; } /*--------- PUBLISH ------*/ int MqttsnClient::publish(MQString* topic, MQString* data, uint8_t qos){ if(data->getStr()){ return publish(topic, (const char*)data->getStr(),data->getCharLength(), qos); }else if(data->getConstStr()){ return publish(topic, data->getConstStr(),data->getCharLength(), qos); } return MQTTSN_ERR_NO_DATA; } /*--------- PUBLISH ------*/ int MqttsnClient::publish(MQString* topic, Payload* payload, uint8_t qos){ return publish(topic, (const char*)(payload->getBuf()), payload->getLen(), qos); } /*--------- PUBLISH ------*/ int MqttsnClient::publish(uint16_t predefinedId, const char* data, int dataLength, uint8_t qos){ MqttsnPublish mqttsMsg = MqttsnPublish(); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_PREDEFINED); mqttsMsg.setTopicId(predefinedId); mqttsMsg.setQos(qos); mqttsMsg.setData((uint8_t*)data, (uint8_t)dataLength); if (qos){ mqttsMsg.setMsgId(getNextMsgId()); } requestSendMsg((MqttsnMessage*)&mqttsMsg); return exec(); } /*--------- SUBSCRIBE ------*/ int MqttsnClient::subscribe(MQString* topic, TopicCallback callback, uint8_t qos){ MqttsnSubscribe mqttsMsg = MqttsnSubscribe(); uint16_t topicId = _topics.getTopicId(topic); if (topic->getCharLength() == 2 && topicId == 0){ if(topic->getStr()){ topicId = getUint16((uint8_t*)topic->getStr()); }else{ topicId = getUint16((uint8_t*)topic->getConstStr()); } _topics.addTopic(topic); _topics.setTopicId(topic, topicId); _topics.setCallback(topic, callback); mqttsMsg.setTopicName(topic); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_SHORT); }else{ mqttsMsg.setTopicName(topic); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_NORMAL); _topics.addTopic(topic); _topics.setCallback(topic, callback); } mqttsMsg.setMsgId(getNextMsgId()); mqttsMsg.setQos(qos); requestSendMsg((MqttsnMessage*)&mqttsMsg); return exec(); } /*--------- SUBSCRIBE ------*/ int MqttsnClient::subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos){ MqttsnSubscribe mqttsMsg = MqttsnSubscribe(); mqttsMsg.setTopicId(predefinedId); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_PREDEFINED); mqttsMsg.setMsgId(getNextMsgId()); _topics.setCallback(predefinedId, callback); requestSendMsg((MqttsnMessage*)&mqttsMsg); return exec(); } /*--------- UNSUBSCRIBE ------*/ int MqttsnClient::unsubscribe(MQString* topic){ MqttsnUnsubscribe mqttsMsg = MqttsnUnsubscribe(); uint16_t topicId = _topics.getTopicId(topic); if (topic->getCharLength() == 2 && topicId > 0){ mqttsMsg.setTopicName(topic); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_SHORT); }else{ mqttsMsg.setTopicId(topicId); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_NORMAL); } mqttsMsg.setMsgId(getNextMsgId()); requestSendMsg((MqttsnMessage*)&mqttsMsg); return exec(); } /*--------- UNSUBSCRIBE ------*/ int MqttsnClient::unsubscribe(uint16_t predefinedId){ MqttsnUnsubscribe mqttsMsg = MqttsnUnsubscribe(); mqttsMsg.setTopicId(predefinedId); mqttsMsg.setMsgId(getNextMsgId()); mqttsMsg.setFlags(_clientFlg | MQTTSN_TOPIC_TYPE_PREDEFINED); requestSendMsg((MqttsnMessage*)&mqttsMsg); return exec(); } /*--------- DISCONNECT ------*/ int MqttsnClient::disconnect(uint16_t duration){ MqttsnDisconnect mqttsMsg = MqttsnDisconnect(); if (duration){ mqttsMsg.setDuration(duration); } requestSendMsg((MqttsnMessage*)&mqttsMsg); return exec(); } /*==== private Messages ====*/ /*--------- SEARCHGW ------*/ int MqttsnClient::searchGw(uint8_t radius){ MqttsnSearchGw mqttsMsg = MqttsnSearchGw(); mqttsMsg.setRadius(radius); delayTime(MQTTSN_TIME_SEARCHGW); return requestPrioritySendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- CONNECT ------*/ int MqttsnClient::connect(){ MqttsnConnect mqttsMsg = MqttsnConnect(_clientId); mqttsMsg.setDuration(_clientStatus.getKeepAlive()); mqttsMsg.setFlags(_clientFlg); return requestPrioritySendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- WILLTOPIC ------*/ int MqttsnClient::willTopic(){ MqttsnWillTopic mqttsMsg = MqttsnWillTopic(); mqttsMsg.setWillTopic(_willTopic); mqttsMsg.setFlags(_clientFlg & 0x70); return requestSendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- WILLMSG ------*/ int MqttsnClient::willMsg(){ MqttsnWillMsg mqttsMsg = MqttsnWillMsg(); mqttsMsg.setWillMsg(_willMessage); return requestSendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- PUBACK ------*/ int MqttsnClient::pubAck(uint16_t topicId, uint16_t msgId, uint8_t rc){ MqttsnPubAck mqttsMsg = MqttsnPubAck(); mqttsMsg.setTopicId(topicId); mqttsMsg.setMsgId(msgId); mqttsMsg.setReturnCode(rc); D_MQTTW("\nPUBACK SEND MsgId = "); D_MQTTLN(msgId,DEC); D_MQTTF("%d", msgId); return requestPrioritySendMsg((MqttsnMessage*)&mqttsMsg); //return requestSendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- PUBREC ------*/ int MqttsnClient::pubRec(uint16_t msgId){ MqttsnPubRec mqttsMsg = MqttsnPubRec(); mqttsMsg.setMsgId(msgId); return requestPrioritySendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- PUBREL ------*/ int MqttsnClient::pubRel(uint16_t msgId){ MqttsnPubRel mqttsMsg = MqttsnPubRel(); mqttsMsg.setMsgId(msgId); return requestPrioritySendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- PUBCOMP ------*/ int MqttsnClient::pubComp(uint16_t msgId){ MqttsnPubComp mqttsMsg = MqttsnPubComp(); mqttsMsg.setMsgId(msgId); return requestPrioritySendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- REGACK ------*/ int MqttsnClient::regAck(uint16_t topicId, uint16_t msgId, uint8_t rc){ MqttsnRegAck mqttsMsg = MqttsnRegAck(); mqttsMsg.setTopicId(topicId); mqttsMsg.setMsgId(msgId); mqttsMsg.setReturnCode(rc); return requestSendMsg((MqttsnMessage*)&mqttsMsg); } /*--------- PINGREQ ------*/ int MqttsnClient::pingReq(MQString* clientId){ MqttsnPingReq mqttsMsg = MqttsnPingReq(clientId); return requestSendMsg((MqttsnMessage*)&mqttsMsg); } /* =================================================== Procedures for Received Messages =====================================================*/ void MqttsnClient::recieveMessageHandler(NWResponse* recvMsg, int* returnCode){ uint8_t msgType = recvMsg->getType(); #if defined(DEBUG) && defined(ARDUINO) debug.print("Receive Msg=0x"); debug.println(msgType,HEX); #endif if ( (_clientStatus.isSearching() && msgType != MQTTSN_TYPE_GWINFO) || (_clientStatus.isSubscribing() && msgType == MQTTSN_TYPE_PUBLISH ) || (getMsgRequestType() == MQTTSN_TYPE_PUBLISH && getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK && msgType == MQTTSN_TYPE_PUBLISH ) ) { D_MQTTW("Ignore Received Message\r\n"); #if defined(DEBUG) && defined(ARDUINO) debug.println("Ignore Received Message"); #endif /*--------- GWINFO ----------*/ }else if (msgType == MQTTSN_TYPE_GWINFO && recvMsg->getPayloadLength() == 3){ D_MQTTW("GWINFO recv\r\n"); MqttsnGwInfo mqMsg = MqttsnGwInfo(); copyMsg(&mqMsg, recvMsg); if (getMsgRequestType() == MQTTSN_TYPE_SEARCHGW){ if(_clientStatus.recvGWINFO(&mqMsg)){ setMsgRequestStatus(MQTTSN_MSG_COMPLETE); }else{ setMsgRequestStatus(MQTTSN_MSG_REJECTED); } if(isCleanSession()){ _topics.clearTopic(); } _network->setGwAddress(); } /*--------- REGISTER ----------*/ }else if (msgType == MQTTSN_TYPE_REGISTER){ if(_clientStatus.isAvailableToSend()){ D_MQTTW("REGISTER recv\r\n"); MqttsnRegister mqMsg = MqttsnRegister(); mqMsg.setFrame(recvMsg); uint16_t topicId = _topics.getTopicId(mqMsg.getTopicName()); if (topicId == 0){ if (_topics.match(mqMsg.getTopicName())){ MQString* mqStr = mqMsg.getTopicName()->create(); _topics.addTopic(mqStr); _topics.setTopicId(mqStr,mqMsg.getTopicId()); _topics.setCallback(mqMsg.getTopicId(),_topics.match(mqStr)->getCallback()); } } if (mqMsg.getMsgId() != 0){ regAck(mqMsg.getTopicId(), mqMsg.getMsgId(), MQTTSN_RC_ACCEPTED); if(getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK){ *returnCode = MQTTSN_READ_RESP_ONCE_MORE; } }else{ D_MQTTW("RegAck is not required\r\n"); } }else{ D_MQTTW("REGISTER recv. Client is not Active\r\n"); } /*--------- PUBLISH --------*/ }else if (msgType == MQTTSN_TYPE_PUBLISH){ if(_clientStatus.isAvailableToSend()){ _clientStatus.setSubscribing(true); MqttsnPublish mqMsg = MqttsnPublish(); mqMsg.setFrame(recvMsg); D_MQTTW("PUBLISH RECV msgID = "); D_MQTTLN(mqMsg.getMsgId(),DEC); D_MQTTF("%d\r\n", mqMsg.getMsgId()); if (mqMsg.getQos() == QOS1){ pubAck(mqMsg.getTopicId(), mqMsg.getMsgId(), MQTTSN_RC_ACCEPTED); unicast(MQTTSN_TIME_RETRY); }else if(mqMsg.getQos() == QOS2){ pubRec(mqMsg.getMsgId()); unicast(MQTTSN_TIME_RETRY); } if(getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK){ *returnCode = MQTTSN_READ_RESP_ONCE_MORE; } _pubHdl.exec(&mqMsg,&_topics); // Execute Callback routine _clientStatus.setSubscribing(false); }else{ D_MQTTW("PUBLISH recv Client is not Active\r\n"); } /*=========== Response =========*/ /*--------- PUBACK ----------*/ }else if (msgType == MQTTSN_TYPE_PUBACK && (getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK && getMsgRequestType() == MQTTSN_TYPE_PUBLISH)){ MqttsnPubAck mqMsg = MqttsnPubAck(); copyMsg(&mqMsg, recvMsg); D_MQTTW("\nPUBACK RECV MsgId = "); D_MQTTLN(mqMsg.getMsgId(),DEC); D_MQTTF("%d", mqMsg.getMsgId()); D_MQTTW(" RC="); D_MQTTLN(mqMsg.getReturnCode(),DEC); D_MQTTF("%d\r\n", mqMsg.getReturnCode()); if (mqMsg.getMsgId() == getUint16(_sendQ->getMessage(0)->getBody() + 3)){ if (mqMsg.getReturnCode() == MQTTSN_RC_ACCEPTED){ setMsgRequestStatus(MQTTSN_MSG_COMPLETE); }else if (mqMsg.getReturnCode() == MQTTSN_RC_REJECTED_CONGESTION){ setMsgRequestStatus(MQTTSN_MSG_RESEND_REQ); }else if (mqMsg.getReturnCode() == MQTTSN_RC_REJECTED_INVALID_TOPIC_ID){ *returnCode = MQTTSN_ERR_INVALID_TOPICID; setMsgRequestStatus(MQTTSN_MSG_REJECTED); } }else{ //D_MQTTW("MsgId dosn't match.\r\n"); } /*--------- PINGRESP ----------*/ }else if (msgType == MQTTSN_TYPE_PINGRESP){ D_MQTTW("PINGRESP recv\r\n"); if (getMsgRequestType() == MQTTSN_TYPE_PINGREQ){ _clientStatus.recvPINGRESP(); setMsgRequestStatus(MQTTSN_MSG_COMPLETE); } /*--------- ADVERTISE ----------*/ }else if (msgType == MQTTSN_TYPE_ADVERTISE){ D_MQTTW("ADVERTISE recv\r\n"); MqttsnAdvertise mqMsg = MqttsnAdvertise(); copyMsg(&mqMsg, recvMsg); _clientStatus.recvADVERTISE(&mqMsg); if(getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK){ *returnCode = MQTTSN_READ_RESP_ONCE_MORE; } /*--------- CONNACK ----------*/ }else if (msgType == MQTTSN_TYPE_CONNACK){ if ((getMsgRequestType() == MQTTSN_TYPE_CONNECT || getMsgRequestType() == MQTTSN_TYPE_WILLMSG)){ MqttsnConnack mqMsg = MqttsnConnack(); copyMsg(&mqMsg, recvMsg); D_MQTTW("CONNACK recv RC="); D_MQTTLN(mqMsg.getReturnCode(),DEC); D_MQTTF("%d\r\n", mqMsg.getReturnCode()); if (mqMsg.getReturnCode() == MQTTSN_RC_ACCEPTED){ setMsgRequestStatus(MQTTSN_MSG_COMPLETE); _clientStatus.recvCONNACK(); }else{ setMsgRequestStatus(MQTTSN_MSG_REJECTED); *returnCode = MQTTSN_ERR_REJECTED; clearMsgRequest(); _clientStatus.recvDISCONNECT(); } } D_MQTTW("\r\n"); /*--------- REGACK ----------*/ }else if (msgType == MQTTSN_TYPE_REGACK){ D_MQTTW("REGACK recv\r\n"); if (getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK && getMsgRequestType() == MQTTSN_TYPE_REGISTER){ MqttsnRegAck mqMsg = MqttsnRegAck(); copyMsg(&mqMsg, recvMsg); if (mqMsg.getMsgId() == getUint16(_sendQ->getMessage(0)->getBody() + 2)){ if (getUint16((uint8_t*)_sendQ->getMessage(0)->getBody()+4)){ if (mqMsg.getReturnCode() == MQTTSN_RC_ACCEPTED){ setMsgRequestStatus(MQTTSN_MSG_COMPLETE); MQString topic; topic.readBuf(_sendQ->getMessage(0)->getBody() + 4); _topics.setTopicId(&topic, mqMsg.getTopicId()); }else if (mqMsg.getReturnCode() == MQTTSN_RC_REJECTED_CONGESTION){ setMsgRequestStatus(MQTTSN_MSG_RESEND_REQ); }else{ *returnCode = MQTTSN_ERR_REJECTED; } } } } /*--------- SUBACK ----------*/ }else if (msgType == MQTTSN_TYPE_SUBACK && getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK){ MqttsnSubAck mqMsg = MqttsnSubAck(); copyMsg(&mqMsg, recvMsg); D_MQTT("\nSUBACK RC="); D_MQTTLN(mqMsg.getReturnCode(),HEX); D_MQTTF("\nSUBACK RC=%d\r\n", mqMsg.getReturnCode()); if (mqMsg.getMsgId() == getUint16(_sendQ->getMessage(0)->getBody() + 1)){ if (mqMsg.getReturnCode() == MQTTSN_RC_ACCEPTED){ setMsgRequestStatus(MQTTSN_MSG_COMPLETE); if (_sendQ->getMessage(0)->getBodyLength() > 5){ // TopicName is not Id MQString topic; topic.copy(_sendQ->getMessage(0)->getBody() + 3, _sendQ->getMessage(0)->getBodyLength() - 3); _topics.setTopicId(&topic, mqMsg.getTopicId()); } }else if (mqMsg.getReturnCode() == MQTTSN_RC_REJECTED_CONGESTION){ setMsgRequestStatus(MQTTSN_MSG_RESEND_REQ); }else{ *returnCode = MQTTSN_ERR_REJECTED; // Return Code } } /*--------- UNSUBACK ----------*/ }else if (msgType == MQTTSN_TYPE_UNSUBACK && getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK){ D_MQTTW("UNSUBACK recv\r\n"); MqttsnUnSubAck mqMsg = MqttsnUnSubAck(); copyMsg(&mqMsg, recvMsg); if (mqMsg.getMsgId() == getUint16(_sendQ->getMessage(0)->getBody() + 1)){ setMsgRequestStatus(MQTTSN_MSG_COMPLETE); } /*--------- DISCONNECT ----------*/ }else if (msgType == MQTTSN_TYPE_DISCONNECT){ D_MQTTW("DISCONNECT recv\r\n"); setMsgRequestStatus(MQTTSN_MSG_COMPLETE); _clientStatus.recvDISCONNECT(); /*--------- WILLTOPICREQ ----------*/ }else if (msgType == MQTTSN_TYPE_WILLTOPICREQ){ D_MQTTW("WILLTOPICREQ recv\r\n"); if (getMsgRequestType() == MQTTSN_TYPE_CONNECT){ clearMsgRequest(); //setMsgRequestStatus(MQTTSN_MSG_COMPLETE); MqttsnWillTopic mqMsg = MqttsnWillTopic(); mqMsg.setFlags(0); // ToDo: add WillQoS, WillRetain to appConfig mqMsg.setWillTopic(_willTopic); requestPrioritySendMsg((MqttsnMessage*)&mqMsg); } /*--------- WILLMSGREQ -----------*/ }else if (msgType == MQTTSN_TYPE_WILLMSGREQ){ D_MQTTW("WILLMSGREQ recv\r\n"); if (getMsgRequestType() == MQTTSN_TYPE_WILLTOPIC){ clearMsgRequest(); //setMsgRequestStatus(MQTTSN_MSG_COMPLETE); MqttsnWillMsg mqMsg = MqttsnWillMsg(); mqMsg.setWillMsg(_willMessage); requestPrioritySendMsg((MqttsnMessage*)&mqMsg); } /*--------- PUBREC ----------*/ }else if (msgType == MQTTSN_TYPE_PUBREC && (getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK && getMsgRequestType() == MQTTSN_TYPE_PUBLISH)){ MqttsnPubRec mqMsg = MqttsnPubRec(); copyMsg(&mqMsg, recvMsg); D_MQTTW("\nPUBREC recv\r\n"); if (mqMsg.getMsgId() == getUint16(_sendQ->getMessage(0)->getBody() + 3)){ MqttsnPubRel mqrMsg = MqttsnPubRel(); mqrMsg.setMsgId(mqMsg.getMsgId()); requestPrioritySendMsg((MqttsnMessage*)&mqrMsg); } /*--------- PUBREL ----------*/ }else if (msgType == MQTTSN_TYPE_PUBREL && (getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK && getMsgRequestType() == MQTTSN_TYPE_PUBREC)){ MqttsnPubRel mqMsg = MqttsnPubRel(); copyMsg(&mqMsg, recvMsg); D_MQTTW("\nPUBREL recv\r\n"); if (mqMsg.getMsgId() == getUint16(_sendQ->getMessage(0)->getBody())){ clearMsgRequest(); // delete PUBREC MqttsnPubComp mqrMsg = MqttsnPubComp(); mqrMsg.setMsgId(mqMsg.getMsgId()); requestPrioritySendMsg((MqttsnMessage*)&mqMsg); } /*--------- PUBCOMP ----------*/ }else if (msgType == MQTTSN_TYPE_PUBCOMP && (getMsgRequestStatus() == MQTTSN_MSG_WAIT_ACK && getMsgRequestType() == MQTTSN_TYPE_PUBREL)){ MqttsnPubComp mqMsg = MqttsnPubComp(); copyMsg(&mqMsg, recvMsg); D_MQTTW("\nPUBCOMP recv\r\n"); if (mqMsg.getMsgId() == getUint16(_sendQ->getMessage(0)->getBody())){ clearMsgRequest(); // delete request of PUBREL setMsgRequestStatus(MQTTSN_MSG_COMPLETE); // PUBLISH complete } }else{ *returnCode = PACKET_ERROR_NODATA; } } /*===================================== Class SendQue ======================================*/ SendQue::SendQue(){ _queCnt = 0; _queSize = SENDQ_SIZE; } SendQue::~SendQue(){ for( int i = 0; i < _queCnt; i++){ delete _msg[i]; } } int SendQue::addRequest(MqttsnMessage* msg){ if ( _queCnt < _queSize){ D_MQTTW("\nAdd SendQue size = "); D_MQTT(_queCnt + 1, DEC); D_MQTT(" Msg = 0x"); D_MQTTLN(msg->getMsgTypeName()); D_MQTTF("%d Msg = 0x%x\r\n", _queCnt + 1, msg->getType()); #if defined(DEBUG) && defined(ARDUINO) debug.print("\nAdd SendQue size = "); debug.print(_queCnt + 1, DEC); debug.print(" Msg="); debug.println(msg->getMsgTypeName()); #endif _msg[_queCnt] =new MqttsnMessage(); _msg[_queCnt++]->copy(msg); return _queCnt - 1; } return MQTTSN_ERR_CANNOT_ADD_REQUEST; // Over Que size } int SendQue::addPriorityRequest(MqttsnMessage* msg){ if ( _queCnt < _queSize){ _queCnt++; } D_MQTTW("\nAdd SendQue Top Size = "); D_MQTT(_queCnt, DEC); D_MQTT(" Msg = 0x"); D_MQTTLN(msg->getType(), HEX); D_MQTTF("%d Msg = 0x%x", _queCnt, msg->getType()); #if defined(DEBUG) && defined(ARDUINO) debug.print("\nAdd SendQue Top size = "); debug.print(_queCnt, DEC); debug.print(" Msg="); debug.print(msg->getMsgTypeName()); #endif for(int i = _queCnt-1; i > 0; i--){ _msg[i] = _msg[i - 1]; } _msg[0] = new MqttsnMessage(); _msg[0]->copy(msg); for(int i = 1; i < _queCnt; i++){ D_MQTT( " Msg = 0x"); D_MQTT(_msg[i]->getType(), HEX); D_MQTTF(" Msg = 0x%x ", _msg[i]->getType()); #if defined(DEBUG) && defined(ARDUINO) debug.print(" Msg="); debug.print(_msg[i]->getMsgTypeName()); #endif } D_MQTTW("\r\n"); #if defined(DEBUG) && defined(ARDUINO) debug.println(); #endif return 0; } int SendQue::deleteRequest(uint8_t index){ if ( index < _queCnt){ delete _msg[index]; _queCnt--; D_MQTTW("\nDelete SendQue Size = "); D_MQTT(_queCnt, DEC); D_MQTTF("%d", _queCnt); #if defined(DEBUG) && defined(ARDUINO) debug.print("\nDelete SendQue Size = "); debug.print(_queCnt, DEC); #endif for(int i = index; i < _queCnt; i++){ _msg[i] = _msg[i + 1]; D_MQTT( " Msg = 0x"); D_MQTT(_msg[i]->getType(), HEX); D_MQTTF(" Msg = 0x%x ", _msg[i]->getType()); #if defined(DEBUG) && defined(ARDUINO) debug.print(" Msg="); debug.print(_msg[i]->getMsgTypeName()); #endif } D_MQTTW("\r\n"); #if defined(DEBUG) && defined(ARDUINO) debug.println(); #endif for(int i = _queCnt; i < _queSize; i++){ _msg[i] = 0; } return 0; } return -2; } void SendQue::deleteAllRequest(){ while ( _queCnt > 0){ deleteRequest(0); } } void SendQue::setStatus(uint8_t index, uint8_t status){ if ( index < _queCnt){ _msg[index]->setStatus(status); } } void SendQue::setQueSize(uint8_t sz){ _queSize = sz; } MqttsnMessage* SendQue::getMessage(uint8_t index){ if ( index < _queCnt){ return _msg[index]; } return 0; } int SendQue::getStatus(uint8_t index){ if ( index < _queCnt){ return _msg[index]->getStatus(); } return -1; } uint8_t SendQue::getCount(){ return _queCnt; } /*===================================== Class ClientStatus ======================================*/ ClientStatus::ClientStatus(){ init(); _gwId = 0; _sleepModeFlg = false; _onConnectFlg = false; _subscribingFlg = false; } ClientStatus::~ClientStatus(){ } void ClientStatus::init(){ _gwStat = GW_LOST; _clStat = CL_DISCONNECTED; _keepAliveDuration = MQTTSN_DEFAULT_DURATION; _advertiseDuration = MQTTSN_DEFAULT_KEEPALIVE; _advertiseTimer.stop(); _keepAliveTimer.stop(); _onConnectFlg = false; _subscribingFlg = false; } void ClientStatus::changeUTC(){ _keepAliveTimer.changeUTC(); // changeUTC() is static } bool ClientStatus::isLost(){ if(_gwStat == GW_LOST){ return true; }else{ return false; } } bool ClientStatus::isSearching(){ if(_gwStat == GW_SEARCHING){ return true; }else{ return false; } } bool ClientStatus::isConnected(){ if(_gwStat == GW_FIND && _clStat != CL_DISCONNECTED){ return true; }else{ return false; } } bool ClientStatus::isOnConnected(){ return _onConnectFlg; } bool ClientStatus::isSubscribing(){ return _subscribingFlg; } bool ClientStatus::isAvailableToSend(){ if((_gwStat == GW_FIND) && ((_clStat == CL_ACTIVE) || (_clStat == CL_ASLEEP))){ return true; }else{ return false; } } bool ClientStatus::isPINGREQRequired(){ if(_sleepModeFlg){ _keepAliveTimer.changeUTC(); } return (_keepAliveTimer.isTimeUp() && isConnected()); } bool ClientStatus::isGatewayAlive(){ if(_sleepModeFlg){ _advertiseTimer.changeUTC(); } return (_advertiseTimer.isTimeUp() ? false : true); } uint16_t ClientStatus::getKeepAlive(){ return _keepAliveDuration; } void ClientStatus::setKeepAlive(uint16_t sec){ _keepAliveDuration = sec; } void ClientStatus::sendSEARCHGW(){ _gwStat = GW_SEARCHING; } bool ClientStatus::recvGWINFO(MqttsnGwInfo* gwi){ bool rc = true; if (_gwStat == GW_SEARCHING){ _gwStat = GW_FIND; if(_gwId != gwi->getGwId() && _gwId != 0){ rc = false; } _gwId = gwi->getGwId(); } return rc; } void ClientStatus::recvADVERTISE(MqttsnAdvertise* adv){ if ( adv->getGwId() == _gwId ){ _advertiseDuration = (adv->getDuration() > 60 ? adv->getDuration() + adv->getDuration() / 10 : adv->getDuration() + adv->getDuration() / 2); _advertiseTimer.start((uint32_t)(_advertiseDuration * 1000UL)); } } void ClientStatus::recvCONNACK(){ _onConnectFlg = true; } void ClientStatus::recvDISCONNECT(){ _clStat = CL_DISCONNECTED; _advertiseTimer.stop(); } void ClientStatus::setLastSendTime(){ _keepAliveTimer.start((uint32_t)(_keepAliveDuration * 1000UL)); } void ClientStatus::recvPINGRESP(){ setLastSendTime(); } void ClientStatus::setAvailableToSend(){ _clStat = CL_ACTIVE; _onConnectFlg = false; } void ClientStatus::setSubscribing(bool stat){ _subscribingFlg = stat; } void ClientStatus::setModeSleep(){ _sleepModeFlg = true; } /*=================== End of file ====================*/ ================================================ FILE: Client/src/lib/mqttsnClient.h ================================================ /* * mqttsnClient.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef MQTTSCLIENT_H_ #define MQTTSCLIENT_H_ #ifdef LINUX #define SENDQ_SIZE 20 #else #define SENDQ_SIZE 5 #endif #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #include #include #include #include #include #else #if defined(ARDUINO) && ARDUINO < 100 #include "WProgram.h" #include #include #include #include #else #ifdef LINUX #include #endif #include #include "MQTTSN_Application.h" #include "Network.h" #include "mqUtil.h" #include "mqttsn.h" #endif #endif #define GW_LOST 0 #define GW_SEARCHING 1 #define GW_FIND 2 #define CL_DISCONNECTED 0 #define CL_ACTIVE 1 #define CL_ASLEEP 2 #define CL_AWAKE 3 using namespace tomyClient; typedef struct { int (*callback)(void); uint32_t sec; }TaskList; typedef struct { MQString* topic; int (*pubCallback)(MqttsnPublish*); uint8_t qos; }OnPublishList; typedef struct { uint32_t prevTime; uint32_t interval; int (*callback)(void); }MQ_TimerTbl; /*===================================== Class ClientStatus ======================================*/ class ClientStatus{ public: ClientStatus(); ~ClientStatus(); bool isLost(); bool isSearching(); bool isConnected(); bool isOnConnected(); bool isSubscribing(); bool isAvailableToSend(); bool isPINGREQRequired(); bool isGatewayAlive(); uint16_t getKeepAlive(); void setKeepAlive(uint16_t sec); void sendSEARCHGW(); bool recvGWINFO(MqttsnGwInfo* gwi); void recvADVERTISE(MqttsnAdvertise* adv); void recvCONNACK(); void recvDISCONNECT(); void recvPINGRESP(); void setAvailableToSend(); void setSubscribing(bool); void setLastSendTime(); void setModeSleep(); void init(); private: void changeUTC(); uint8_t _gwId; uint8_t _gwStat; uint8_t _clStat; bool _onConnectFlg; bool _subscribingFlg; uint16_t _keepAliveDuration; // PINGREQ interval uint16_t _advertiseDuration; // Gateway heart beat XTimer _keepAliveTimer; XTimer _advertiseTimer; bool _sleepModeFlg; }; /*===================================== Class SendQue (FIFO) ======================================*/ class SendQue { public: SendQue(); ~SendQue(); int addRequest(MqttsnMessage* msg); int addPriorityRequest(MqttsnMessage* msg); void setStatus(uint8_t index, uint8_t status); MqttsnMessage* getMessage(uint8_t index); int getStatus(uint8_t index); uint8_t getCount(); int deleteRequest(uint8_t index); void deleteAllRequest(); void setQueSize(uint8_t sz); private: uint8_t _queSize; uint8_t _queCnt; MqttsnMessage* _msg[SENDQ_SIZE]; }; /*===================================== Class MqttsnClient ======================================*/ class MqttsnClient { public: MqttsnClient(); ~MqttsnClient(); Topics* getTopics(); int initialize(APP_CONFIG config); void subscribe(); void setSubscribing(bool); void setKeepAlive(uint16_t sec); void setWillTopic(MQString* topic); void setWillMessage(MQString* msg); void setSleepMode(void); void setRetain(bool retain); void setClean(bool clean); void setRetryMax(uint8_t cnt); void setGwAddress(); MQString* getClientId(); ClientStatus* getClientStatus(); bool isCleanSession(); int publish(MQString* topic, const char* data, int dataLength, uint8_t qos = 1); int publish(MQString* topic, MQString* data, uint8_t qos = 1); int publish(uint16_t predifinedId, const char* data, int dataLength, uint8_t qos = 1); int publish(MQString* topic, Payload* payload, uint8_t qos = 1); int registerTopic(MQString* topic); int subscribe(MQString* topic, TopicCallback callback, uint8_t qos = 1); int subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos); int unsubscribe(MQString* topic); int unsubscribe(uint16_t predefinedId); int disconnect(uint16_t duration = 0); void createTopics(); void recieveMessageHandler(NWResponse* msg, int* returnCode); void publishHdl(MqttsnPublish* msg); void recvMsg(uint16_t msec); int exec(); int readPacket(); uint8_t getMsgRequestCount(); private: int sendRecvMsg(); void clearMsgRequest(); int requestSendMsg(MqttsnMessage* msg); int requestPrioritySendMsg(MqttsnMessage* mqttsMsgPtr); int broadcast(uint16_t packetReadTimeout); int unicast(uint16_t packetReadTimeout); int searchGw(uint8_t radius); int connect(); int pingReq(MQString* clietnId); int willTopic(); int willMsg(); int pubAck(uint16_t topicId, uint16_t msgId, uint8_t rc); int pubRec(uint16_t msgId); int pubRel(uint16_t msgId); int regAck(uint16_t topicId, uint16_t msgId, uint8_t rc); int pubComp(uint16_t msgId); uint8_t getMsgRequestType(); uint8_t getMsgRequestStatus(); void setMsgRequestStatus(uint8_t stat); void createTopic(MQString* topic, TopicCallback callback); void delayTime(uint16_t baseTime); void copyMsg(MqttsnMessage* msg, NWResponse* recvMsg); uint16_t getNextMsgId(); Network* _network; Topics _topics; SendQue* _sendQ; XTimer _respTimer; PublishHandller _pubHdl; uint16_t _duration; MQString* _clientId; uint8_t _clientFlg; uint8_t _nRetry; uint8_t _nRetryCnt; uint16_t _tRetry; MQString* _willTopic; MQString* _willMessage; uint16_t _msgId; ClientStatus _clientStatus; bool _sendFlg; bool _subscribingFlg; }; #endif /* MQTTSCLIENT_H_ */ ================================================ FILE: Client/src/lib/mqttsnClientAppFw4Arduino.cpp ================================================ /* * mqttsnClientAppAppFw4Arduino.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/11/25 * Author: Tomoaki YAMAGUCHI * Version: 1.1.1 */ #ifdef ARDUINO #include #include #include #include #if defined(MQTTSN_DEBUG) || defined(ZBEE_DEBUG) || defined(DEBUG) #include extern SoftwareSerial debug; #endif using namespace std; using namespace tomyClient; volatile uint8_t MQ_ErrFlag = MQ_OFF; volatile uint8_t MQ_cnt = 0; enum MQ_INT_STATUS MQ_intStat; enum MQ_INT_STATUS MQ_wdtStat; extern uint32_t getUint32(uint8_t* pos); extern APP_CONFIG theAppConfig; extern TaskList theTaskList[]; extern void interruptCallback(void); MqttsnClientApplication* theApplication = new MqttsnClientApplication(); void loop(){ theApplication->registerInt0Callback(interruptCallback); theApplication->addTask(); theApplication->setKeepAlive(theAppConfig.mqttsnCfg.keepAlive); theApplication->setClean(theAppConfig.mqttsnCfg.cleanSession); if(theAppConfig.mqttsnCfg.willTopic){ MQString* willTpc = new MQString(theAppConfig.mqttsnCfg.willTopic); theApplication->setWillTopic(willTpc); } if(theAppConfig.mqttsnCfg.willMsg){ MQString* willMsg = new MQString(theAppConfig.mqttsnCfg.willMsg); theApplication->setWillMessage(willMsg); } if(theAppConfig.mqttsnCfg.endDevice){ theApplication->setZBPinHibernate(); } theApplication->initialize(theAppConfig); if(theAppConfig.mqttsnCfg.endDevice){ theApplication->startSleepMode(); }else{ theApplication->startWdt(); } while(true){ theApplication->run(); } } /*------------------------------- * Set WDT Interrupt procedure --------------------------------*/ ISR (WDT_vect) { cli(); MCUSR = 0; wdt_reset(); WDTCSR |= B00011000; // WDCE:on, WDE:on WDTCSR = 0x00; MQ_wdtStat = INT_WDT; sei(); } /*------------------------------- * INT0 Interrupt procedure --------------------------------*/ void MQInt0(){ detachInterrupt(0); MQ_intStat = INT0_LL; } /*------------------------------- * Set WDT --------------------------------*/ void MQwatchdogEnable(){ // Turn on WDT cli(); MCUSR = 0; wdt_reset(); WDTCSR |= B00011000; // WDCE:on, WDE:on WDTCSR = MQ_WDT_TIME; MQ_wdtStat = WAIT; sei(); } /*-------------------------------- Dummy function ---------------------------------*/ void IntHandleDummy(){ } /*-------------------------------- reset Arduino ---------------------------------*/ //void (*resetArduino)(void) = 0; void resetArduino(){ #ifdef DEBUG debug.println("Reset"); #endif asm volatile("jmp 0000"); } /*-------------------------------- set UnixTime ---------------------------------*/ int setUTC(MqttsnPublish* msg){ XTimer::setUnixTime(getUint32(msg->getData())); return 0; } /*======================================== Class MqttsnClientApplication =========================================*/ MqttsnClientApplication::MqttsnClientApplication(){ _txFlag = false; _intHandler = IntHandleDummy; _sleepFlg = false; _deviceType = ZB_ROUTER_DEVICE; } MqttsnClientApplication::~MqttsnClientApplication(){ } void MqttsnClientApplication::addTask(){ for(int i = 0; theTaskList[i].callback; i++){ _wdTimer.registerCallback(theTaskList[i].sec, theTaskList[i].callback); } } void MqttsnClientApplication::setSubscribe(){ _mqttsn.setSubscribing(true); // re-entrant control _mqttsn.subscribe(); _mqttsn.subscribe(MQTTSN_TOPICID_PREDEFINED_TIME, setUTC,QOS0); _mqttsn.setSubscribing(false); } void MqttsnClientApplication::initialize(APP_CONFIG config){ //blinkIndicator(100); _mqttsn.initialize(config); XTimer::initialize(); setSubscribe(); } int MqttsnClientApplication::run(){ wakeupXB(); _mqttsn.readPacket(); //ModemeStatus or Stored packet _mqttsn.readPacket(); checkInterupt(); // WDT routines are executed int rc = _mqttsn.exec(); if(rc == MQTTSN_ERR_REBOOT_REQUIRED){ resetArduino(); }else if(rc == MQTTSN_ERR_NO_ERROR){ sleepXB(); sleepApp(); // waiting WDT interruption } return 0; } void MqttsnClientApplication::setKeepAlive(uint16_t sec){ _mqttsn.setKeepAlive(sec); } void MqttsnClientApplication::setWillTopic(MQString* willTopic){ _mqttsn.setWillTopic(willTopic); } void MqttsnClientApplication::setWillMessage(MQString* willMsg){ _mqttsn.setWillMessage(willMsg); } void MqttsnClientApplication::setRetain(bool retain){ _mqttsn.setRetain(retain); } void MqttsnClientApplication::setClean(bool clean){ _mqttsn.setClean(clean); } /*----------- Sleep related functions ------------*/ void MqttsnClientApplication::startWdt(){ _wdTimer.start(); } void MqttsnClientApplication::stopWdt(){ _wdTimer.stop(); } void MqttsnClientApplication::sleepApp(){ if(_deviceType == ZB_PIN_HIBERNATE && _sleepFlg){ #if defined(DEBUG) && defined(ARDUINO) debug.println("sleep"); #endif set_sleep_mode(SLEEP_MODE_PWR_SAVE); MQwatchdogEnable(); sleep_enable(); MQ_wdtStat = WAIT; sleep_mode(); // waiting WDT interrupt sleep_disable(); XTimer::setStopTimeDuration(MQ_WDT_TIME_MSEC); } } void MqttsnClientApplication::sleepXB(){ if(_deviceType == ZB_PIN_HIBERNATE && _sleepFlg){ pinMode(XB_SLEEP_PIN, INPUT); } } void MqttsnClientApplication::wakeupXB(){ if(_deviceType == ZB_PIN_HIBERNATE){ pinMode(XB_SLEEP_PIN, OUTPUT); digitalWrite(XB_SLEEP_PIN, LOW); delay(20); } } void MqttsnClientApplication::startSleepMode(){ if(_deviceType == ZB_PIN_HIBERNATE){ _sleepFlg = true; MQ_intStat = WAIT; MQ_wdtStat = WAIT; setInterrupt(); }else{ _sleepFlg = false; } } void MqttsnClientApplication::setZBPinHibernate(){ _deviceType = ZB_PIN_HIBERNATE; pinMode(MQ_INT0_PIN,INPUT_PULLUP); wakeupXB(); _mqttsn.getClientStatus()->setModeSleep(); } /*-------------- Interrupt related functions ------*/ void MqttsnClientApplication::checkInterupt(){ // interrupt Event if (MQ_intStat == INT0_LL){ MQ_intStat = INT0_WAIT_HL; interruptHandler(); setInterrupt(); } // WDT event if (MQ_wdtStat == INT_WDT){ _wdTimer.wakeUp(); // check interval & execute callback _wdTimer.start(); // WDT restart } } void MqttsnClientApplication::interruptHandler(){ wakeupXB(); _intHandler(); sleepXB(); } void MqttsnClientApplication::setInterrupt(){ if (MQ_intStat == INT0_WAIT_HL){ while(digitalRead(MQ_INT0_PIN) == 0){ // wait LL to HL } } MQ_intStat = WAIT; attachInterrupt(0,MQInt0,LOW); } /*-------------------- MQTT-SN functions ---------------*/ int MqttsnClientApplication::registerTopic(MQString* topic){ return _mqttsn.registerTopic(topic); } int MqttsnClientApplication::publish(MQString* topic, const char* data, int dataLength, uint8_t qos){ return _mqttsn.publish(topic, data, dataLength, qos); } int MqttsnClientApplication::publish(MQString* topic, Payload* payload, uint8_t qos){ return _mqttsn.publish(topic, payload, qos); } int MqttsnClientApplication::subscribe(MQString* topic, TopicCallback callback, uint8_t qos){ return _mqttsn.subscribe(topic, callback,qos); } int MqttsnClientApplication::subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos){ return _mqttsn.subscribe(predefinedId, callback, qos); } int MqttsnClientApplication::publish(uint16_t predefinedId, const char* data, int dataLength, uint8_t qos){ return _mqttsn.publish(predefinedId, data, dataLength, qos); } int MqttsnClientApplication::unsubscribe(MQString* topic){ return _mqttsn.unsubscribe(topic); } int MqttsnClientApplication::disconnect(uint16_t duration){ return _mqttsn.disconnect(duration); } /*------------- UTC functions -------------*/ uint32_t MqttsnClientApplication::getUnixTime(){ return XTimer::getUnixTime(); } /* #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; void MqttsnClientApplication::getDateTime(char* buf) { uint16_t year; uint8_t month; uint8_t mLen; uint8_t day; uint8_t hour; uint8_t min; uint8_t sec; uint16_t days; uint32_t utc; utc = getUnixTime(); sec = utc % 60; utc /= 60; min = utc % 60; utc /= 60; hour = utc % 24; utc /= 24; year = days = 0; while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= utc) { year++; } days -= LEAP_YEAR(year) ? 366 : 365; year += 1970; utc -= days; days = 0; for (month = 0; month < 12; month++) { if (month == 1) { if (LEAP_YEAR(year)) { mLen = 29; } else { mLen = 28; } } else { mLen = monthDays[month]; } if (utc >= mLen) { utc -= mLen; } else { break; } } month += 1; day = utc + 1; sprintf(buf,"GMT%4d%2d%2d%2d%2d%2d",year,month,day,hour,min,sec); char* pos = buf + 7; for(int i = 0; i < 10; i++){ if(*( pos + i) == 0x20){ *(pos + i) = 0x30; } } } */ /*-------------- Indicator --------------*/ void MqttsnClientApplication::indicatorOn(){ digitalWrite(MQ_LED_PIN,MQ_ON); } void MqttsnClientApplication::indicatorOff(){ digitalWrite(MQ_LED_PIN,MQ_OFF); } void MqttsnClientApplication::blinkIndicator(int msec){ digitalWrite(MQ_LED_PIN,MQ_ON); delay(msec); digitalWrite(MQ_LED_PIN,MQ_OFF); } /*-------------- Callback related functions ---------------*/ void MqttsnClientApplication::registerInt0Callback(void (*callback)()){ _intHandler = callback; } void MqttsnClientApplication::refleshWdtCallbackTable(){ _wdTimer.refleshRegisterTable(); } /*====================================== Class WdTimer ========================================*/ WdTimer::WdTimer(void) { _timerTbls = 0; _timerCnt = 0; _initFlg = true; } void WdTimer::start(void) { MQwatchdogEnable(); } void WdTimer::stop(void){ cli(); MCUSR = 0; wdt_reset(); WDTCSR |= B00011000; // WDCE:on, WDE:on WDTCSR = 0x00; MQ_wdtStat = WAIT; sei(); } bool WdTimer::wakeUp(void){ bool rcflg = false; int rc; for(uint8_t i = 0; i < _timerCnt; i++) { if ((_timerTbls[i].prevTime + _timerTbls[i].interval < getUnixTime()) || _initFlg){ #if defined(DEBUG) && defined(ARDUINO) debug.println("Task start"); #endif rc = (_timerTbls[i].callback)(); if(rc == MQTTSN_ERR_REBOOT_REQUIRED || rc == MQTTSN_ERR_INVALID_TOPICID){ resetArduino(); } _timerTbls[i].prevTime = getUnixTime(); rcflg = true; #if defined(DEBUG) && defined(ARDUINO) debug.println("Task end"); #endif } } _initFlg = false; return rcflg; } int WdTimer::registerCallback(uint32_t sec, int (*callback)(void)){ MQ_TimerTbl *savTbl = _timerTbls; MQ_TimerTbl *newTbl = (MQ_TimerTbl*)calloc(_timerCnt + 1,sizeof(MQ_TimerTbl)); if ( newTbl != 0 ) { _timerTbls = newTbl; for(uint8_t i = 0; i < _timerCnt; i++ ){ _timerTbls[i].prevTime = savTbl[i].prevTime; _timerTbls[i].interval = savTbl[i].interval; _timerTbls[i].callback = savTbl[i].callback; } free(savTbl); //_timerTbls[_timerCnt].prevTime = getUnixTime(); _timerTbls[_timerCnt].prevTime = (uint32_t)0; _timerTbls[_timerCnt].interval = sec; _timerTbls[_timerCnt].callback = callback; _timerCnt++; return MQTTSN_ERR_NO_ERROR; } return MQTTSN_ERR_OUT_OF_MEMORY; } void WdTimer::refleshRegisterTable(){ for(uint8_t i = 0; i < _timerCnt; i++) { _timerTbls[i].prevTime = getUnixTime(); } } #endif /* ARDUINO */ ================================================ FILE: Client/src/lib/mqttsnClientAppFw4Arduino.h ================================================ /* * mqttsnClientAppFw4Arduino.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifdef ARDUINO #ifndef MQTTSNCLIENTAPPLICATION_H_ #define MQTTSNCLIENTAPPLICATION_H_ #include #include #include #include #include #include #include #include #include #include #define MQ_LED_PIN 13 #define MQ_INT0_PIN 2 #define MQ_SLEEP_PIN 4 // Connect to XBee DTR for hibernation mode #define MQ_ERROR_RECOVERY_DURATION_ON 8 #define MQ_ON 1 #define MQ_OFF 0 #define ZB_ROUTER_DEVICE 0 #define ZB_PIN_HIBERNATE 1 #define MQ_WDT_ERR (B01100000) // Error Indication time #define MQ_WDT_TIME (B01000110) // 1 Sec #define MQ_WDT_TIME_MSEC 1000 //#define MQ_WDT_TIME (B01000111) // 2 Secs //#define MQ_WDT_TIME_MSEC 2000 //#define MQ_WDT_TIME (B01100000) // 4 Secs //#define MQ_WDT_TIME_MSEC 4000 //#define MQ_WDT_TIME (B01100001) // 8 Secs //#define MQ_WDT_TIME_MSEC 8000 enum MQ_INT_STATUS{ WAIT, INT0_LL, INT0_WAIT_HL, INT_WDT}; #define INDICATOR_ON() theApplication->indicatorOn() #define INDICATOR_OFF() theApplication->indicatorOff() #define BLINK_INDICATOR(...) theApplication->blinkIndicator(__VA_ARGS__) #define GETUTC() theApplication->getUnixTime() //#define GET_DATETIME(...) theApplication->getDateTime(__VA_ARGS__) extern void setUint32(uint8_t*, uint32_t); extern uint32_t getUint32(uint8_t*); extern void setUint16(uint8_t*, uint16_t); extern uint16_t getUint16(uint8_t*); /*====================================== Class WdTimer ========================================*/ class WdTimer:public XTimer { public: WdTimer(void); int registerCallback(uint32_t sec, int (*proc)(void)); void refleshRegisterTable(); void start(void); void stop(void); bool wakeUp(void); private: MQ_TimerTbl *_timerTbls; uint8_t _timerCnt; bool _initFlg; }; /*====================================== Class MqttsnClientApplication ========================================*/ class MqttsnClientApplication{ public: MqttsnClientApplication(); ~MqttsnClientApplication(); void registerInt0Callback(void (*callback)()); void registerWdtCallback(long sec, int (*callback)(void)); void refleshWdtCallbackTable(); int initialize(APP_CONFIG config); int setSubscribe(); void setKeepAlive(uint16_t msec); void setWillTopic(MQString* willTopic); void setWillMessage(MQString* willMsg); void setRetain(bool retain); void setClean(bool clean); void setClientId(MQString* id); void setZBPinHibernate(); void blinkIndicator(int msec); void startSleepMode(); void subscribe(void); void addTask(void); int registerTopic(MQString* topic); int publish(MQString* topic, const char* data, int dataLength, uint8_t qos = 1); int publish(uint16_t predefinedId, const char* data, int dataLength, uint8_t qos = 1); int publish(MQString* topic, Payload* payload, uint8_t qos); int subscribe(MQString* topic, TopicCallback callback, uint8_t qos = 1); int subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos = 1); int unsubscribe(MQString* topic); int disconnect(uint16_t duration); void startWdt(); void stopWdt(); int run(); void setUnixTime(MqttsnPublish* msg); uint32_t getUnixTime(); void getDateTime(char* buf); void reboot(); void indicatorOn(); void indicatorOff(); private: void checkInterupt(); void interruptHandler(); void setInterrupt(); void sleepXB(); void wakeupXB(); void sleepApp(); MqttsnClient _mqttsn; bool _txFlag; bool _sleepFlg; uint8_t _deviceType; WdTimer _wdTimer; XTimer _keepAliveTimer; XTimer _advertiseTimer; void (*_intHandler)(void); }; extern MqttsnClientApplication* theApplication; #else #endif /*ARDUINO*/ #endif /* MQTTSNCLIENTAPPLICATION_H_ */ ================================================ FILE: Client/src/lib/mqttsnClientAppFw4Linux.cpp ================================================ /* * mqttsnClientAppAppFwLinux.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef ARDUINO #include "MQTTSN_Application.h" #ifdef LINUX #include "mqttsnClientAppFw4Linux.h" #include #include #include #include #include #include using namespace std; using namespace tomyClient; MqttsnClientApplication* theApplication = new MqttsnClientApplication(); extern TaskList theTaskList[]; extern void setup(); extern MQString theTopics[]; #ifdef NETWORK_XBEE XBeeAppConfig theAppConfig = { { 0, 0, 0 },{ 0, 0, false, false, 0, 0 } }; #endif #ifdef NETWORK_UDP UdpAppConfig theAppConfig = {{ {0,0,0,0}, 0, {0,0,0,0}, 0, {0,0,0,0,0,0} },{ 0, 0, false, false, 0, 0 } }; #endif /*======================================== main function =========================================*/ int main(int argc, char **argv){ theApplication->addTask(); setup(); theApplication->initialize(argc, argv); theApplication->run(); return 0; } /*======================================== Class MqttsnClientApplication =========================================*/ MqttsnClientApplication::MqttsnClientApplication(){ } MqttsnClientApplication::~MqttsnClientApplication(){ } void MqttsnClientApplication::startWdt(){ _wdTimer.start(); } void MqttsnClientApplication::stopWdt(){ _wdTimer.stop(); } /*------------ Client execution forever --------------*/ int MqttsnClientApplication::run(){ while(true){ _wdTimer.wakeUp(); _mqttsn.readPacket(); int rc = _mqttsn.exec(); if(rc == MQTTSN_ERR_REBOOT_REQUIRED){ _mqttsn.subscribe(); } } return 0; } void MqttsnClientApplication::initialize(int argc, char** argv){ int arg; unsigned int val; char* id = 0; MQString* willTopic; MQString* willMsg; #ifdef NETWORK_XBEE unsigned int br = B57600; char* dev = 0; #endif #ifdef NETWORK_UDP char* ipAddr = 0; uint16_t gPortNo = 0; uint16_t uPortNo = 0; #endif while((arg = getopt(argc, argv, "hcb:d:u:i:k:t:m:g:p:"))!= -1){ switch(arg){ case 'h': printf("Usage: -b: [baudrate] (XBee)\n"); printf(" -d: [device] (XBee)\n"); printf(" -g: [groupIp] (UDP)\n"); printf(" -p: [group portNo] (UDP)\n"); printf(" -u: [client portNo] (UDP)\n"); printf(" -c: CleanSession\n"); printf(" -i: [ClientId]\n"); printf(" -k: [keepAliveTime in second]\n"); printf(" -t: [willTopic]\n"); printf(" -m: [willMessage]\n"); exit(0); break; case 'c': _mqttsn.setClean(true); break; case 'i': id = strdup(optarg); break; case 't': willTopic = new MQString((const char*)optarg); _mqttsn.setWillTopic(willTopic); break; case 'm': willMsg = new MQString((const char*)optarg); _mqttsn.setWillMessage(willMsg); break; case 'k': val = atoi(optarg); _mqttsn.setKeepAlive(val); break; #ifdef NETWORK_XBEE case 'd': dev = strdup(optarg); break; case 'b': val = atoi(optarg); switch(val){ case 9600: br = B9600; break; case 19200: br =B19200; break; case 38400: br =B38400; break; case 57600: br =B57600; break; case 115200: br = B115200; break; default: printf("Invalid baudrate!\n"); exit(-1); } break; #endif #ifdef NETWORK_UDP case 'g': ipAddr = optarg; break; case 'p': gPortNo = atoi(optarg); break; case 'u': uPortNo = atoi(optarg); break; #endif case '?': printf("Unrecognized option! %c\n", arg); exit(-1); } } #ifdef NETWORK_XBEE if(br && dev){ theAppConfig.netCfg.baudrate = br;   theAppConfig.netCfg.device = strdup(dev); }else{ printf("argument error\n"); exit(1); } #endif #ifdef NETWORK_UDP if(gPortNo && ipAddr[0] && uPortNo){ theAppConfig.netCfg.gPortNo = gPortNo; theAppConfig.netCfg.uPortNo = uPortNo; uint32_t ipaddr = inet_addr(ipAddr); theAppConfig.netCfg.ipAddress[0] = (ipaddr & 0xff000000) >> 24; theAppConfig.netCfg.ipAddress[1] = (ipaddr & 0x00ff0000) >> 16; theAppConfig.netCfg.ipAddress[2] = (ipaddr & 0x0000ff00) >> 8; theAppConfig.netCfg.ipAddress[3] = (ipaddr & 0x000000ff); }else{ printf("argument error\n"); exit(1); } #endif if(id){ theAppConfig.mqttsnCfg.nodeId = strdup(id); }else{ theAppConfig.mqttsnCfg.nodeId ="node"; } _mqttsn.initialize(theAppConfig); setSubscribe(); } void MqttsnClientApplication::setSubscribe(){ _mqttsn.setSubscribing(true); _mqttsn.createTopics(); _mqttsn.subscribe(); _mqttsn.setSubscribing(false); } void MqttsnClientApplication::addTask(){ for(int i = 0; theTaskList[i].sec; i++){ _wdTimer.registerCallback(theTaskList[i].sec, theTaskList[i].callback); } } int MqttsnClientApplication::publish(MQString* topic, const char* data, int dataLength, uint8_t qos){ return _mqttsn.publish(topic, data, dataLength, qos); } int MqttsnClientApplication::publish(uint16_t predefinedId, const char* data, int dataLength, uint8_t qos){ return _mqttsn.publish(predefinedId, data, dataLength, qos); } int MqttsnClientApplication::publish(MQString* topic, Payload* payload, uint8_t qos){ return _mqttsn.publish(topic, payload, qos); } int MqttsnClientApplication::subscribe(MQString* topic, TopicCallback callback, uint8_t qos){ return _mqttsn.subscribe(topic, callback,qos); } int MqttsnClientApplication::subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos){ return _mqttsn.subscribe(predefinedId, callback, qos); } int MqttsnClientApplication::unsubscribe(MQString* topic){ return _mqttsn.unsubscribe(topic); } int MqttsnClientApplication::disconnect(uint16_t duration){ return _mqttsn.disconnect(duration); } void MqttsnClientApplication::setRetain(bool flag){ _mqttsn.setRetain(flag); } /*-------------- Callback related functions ---------------*/ void MqttsnClientApplication::refleshWdtCallbackTable(){ _wdTimer.refleshRegisterTable(); } /*====================================== Class WdTimer ========================================*/ WdTimer::WdTimer(void) { _timerTbls = 0; _timerCnt = 0; _initFlg = true; } void WdTimer::start(void) { //MQwatchdogEnable(); } void WdTimer::stop(void){ // } bool WdTimer::wakeUp(void){ bool rcflg = false; int rc; for(uint8_t i = 0; i < _timerCnt; i++) { if ((_timerTbls[i].prevTime + _timerTbls[i].interval < (uint32_t)time(0)) || _initFlg){ rc = (_timerTbls[i].callback)(); if(rc == MQTTSN_ERR_REBOOT_REQUIRED){ theApplication->setSubscribe(); } _timerTbls[i].prevTime = time(0); rcflg = true; } } _initFlg = false; return rcflg; } int WdTimer::registerCallback(uint32_t sec, int (*callback)(void)){ MQ_TimerTbl *savTbl = _timerTbls; MQ_TimerTbl *newTbl = (MQ_TimerTbl*)calloc((unsigned int)_timerCnt + 1,sizeof(MQ_TimerTbl)); if ( newTbl != 0 ) { _timerTbls = newTbl; for(uint8_t i = 0; i < _timerCnt; i++ ){ _timerTbls[i].prevTime = savTbl[i].prevTime; _timerTbls[i].interval = savTbl[i].interval; _timerTbls[i].callback = savTbl[i].callback; } free(savTbl); _timerTbls[_timerCnt].prevTime = time(0); _timerTbls[_timerCnt].interval = sec; _timerTbls[_timerCnt].callback = callback; _timerCnt++; return MQTTSN_ERR_NO_ERROR; } return MQTTSN_ERR_OUT_OF_MEMORY; } void WdTimer::refleshRegisterTable(){ for(uint8_t i = 0; i < _timerCnt; i++) { _timerTbls[i].prevTime = time(0); } } #endif #endif ================================================ FILE: Client/src/lib/mqttsnClientAppFw4Linux.h ================================================ /* * mqttsnClientAppFw4Linux.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifdef LINUX #ifndef MQTTSNCLIENTAPPLICATION_H_ #define MQTTSNCLIENTAPPLICATION_H_ #include "MQTTSN_Application.h" #include "mqttsnClient.h" #include "mqUtil.h" /*====================================== Class WdTimer ========================================*/ class WdTimer:public XTimer { public: WdTimer(void); int registerCallback(uint32_t sec, int (*proc)(void)); void refleshRegisterTable(); void start(void); void stop(void); bool wakeUp(void); private: MQ_TimerTbl *_timerTbls; uint8_t _timerCnt; bool _initFlg; }; /*====================================== Class MqttsnClientApplication ========================================*/ class MqttsnClientApplication{ public: MqttsnClientApplication(); ~MqttsnClientApplication(); void refleshWdtCallbackTable(); void initialize(int argc, char** argv); void setSubscribe(); int publish(MQString* topic, const char* data, int dataLength, uint8_t qos = 1); int publish(uint16_t predefinedId, const char* data, int dataLength, uint8_t qos = 1); int publish(MQString* topic, Payload* payload, uint8_t qos); int subscribe(MQString* topic, TopicCallback callback, uint8_t qos = 1); int subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos = 1); int unsubscribe(MQString* topic); int disconnect(uint16_t duration); void setRetain(bool flag); void addTask(); void startWdt(); void stopWdt(); int run(); private: MqttsnClient _mqttsn; WdTimer _wdTimer; XTimer _keepAliveTimer; XTimer _advertiseTimer; }; extern MqttsnClientApplication* theApplication; #else #endif /*LINUX*/ #endif /* MQTTSCLIENTAPPLICATION_H_ */ ================================================ FILE: Client/src/lib/mqttsnClientAppFw4mbed.cpp ================================================ /* * mqttsnClientAppAppFwmbed.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef ARDUINO #include "MQTTSN_Application.h" #ifdef MBED #include "mqttsnClientAppFw4mbed.h" #include #include #include #include using namespace std; using namespace tomyClient; MqttsnClientApplication* theApplication = new MqttsnClientApplication(); extern TaskList theTaskList[]; extern OnPublishList theOnPublishList[]; extern APP_CONFIG theAppConfig; extern void setup(); /*======================================== main function =========================================*/ int main(){ theApplication->setKeepAlive(theAppConfig.mqttsnCfg.keepAlive); theApplication->setClean(theAppConfig.mqttsnCfg.cleanSession); if(theAppConfig.mqttsnCfg.willTopic){ MQString* willTpc = new MQString(theAppConfig.mqttsnCfg.willTopic); theApplication->setWillTopic(willTpc); } if(theAppConfig.mqttsnCfg.willMsg){ MQString* willMsg = new MQString(theAppConfig.mqttsnCfg.willMsg); theApplication->setWillMessage(willMsg); } theApplication->addTask(); setup(); theApplication->initialize(theAppConfig); theApplication->run(); return 0; } /*======================================== Class MqttsnClientApplication =========================================*/ /*-------------------------------- set UnixTime ---------------------------------*/ int setUTC(MqttsnPublish* msg){ set_time(getUint32(msg->getData())); return 0; } MqttsnClientApplication::MqttsnClientApplication(){ } MqttsnClientApplication::~MqttsnClientApplication(){ } void MqttsnClientApplication::startWdt(){ _wdTimer.start(); } void MqttsnClientApplication::stopWdt(){ _wdTimer.stop(); } /*------------ Client execution forever --------------*/ int MqttsnClientApplication::run(){ while(true){ _wdTimer.wakeUp(); _mqttsn.readPacket(); int rc = _mqttsn.exec(); if(rc == MQTTSN_ERR_REBOOT_REQUIRED){ _mqttsn.subscribe(); } } } void MqttsnClientApplication::initialize(APP_CONFIG config){ _mqttsn.initialize(config); setSubscribe(); } void MqttsnClientApplication::setSubscribe(){ _mqttsn.setSubscribing(true); // re-entrant control _mqttsn.subscribe(); _mqttsn.subscribe(MQTTSN_TOPICID_PREDEFINED_TIME, setUTC,1); _mqttsn.setSubscribing(false); } void MqttsnClientApplication::addTask(){ for(int i = 0; theTaskList[i].sec; i++){ _wdTimer.registerCallback(theTaskList[i].sec, theTaskList[i].callback); } } void MqttsnClientApplication::setKeepAlive(uint16_t sec){ _mqttsn.setKeepAlive(sec); } void MqttsnClientApplication::setWillTopic(MQString* willTopic){ _mqttsn.setWillTopic(willTopic); } void MqttsnClientApplication::setWillMessage(MQString* willMsg){ _mqttsn.setWillMessage(willMsg); } void MqttsnClientApplication::setRetain(bool retain){ _mqttsn.setRetain(retain); } void MqttsnClientApplication::setClean(bool clean){ _mqttsn.setClean(clean); } int MqttsnClientApplication::publish(MQString* topic, const char* data, int dataLength, uint8_t qos){ return _mqttsn.publish(topic, data, dataLength, qos); } int MqttsnClientApplication::publish(uint16_t predefinedId, const char* data, int dataLength, uint8_t qos){ return _mqttsn.publish(predefinedId, data, dataLength, qos); } int MqttsnClientApplication::publish(MQString* topic, Payload* payload, uint8_t qos){ return _mqttsn.publish(topic, payload, qos); } int MqttsnClientApplication::subscribe(MQString* topic, TopicCallback callback, uint8_t qos){ return _mqttsn.subscribe(topic, callback,qos); } int MqttsnClientApplication::subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos){ return _mqttsn.subscribe(predefinedId, callback, qos); } int MqttsnClientApplication::unsubscribe(MQString* topic){ return _mqttsn.unsubscribe(topic); } int MqttsnClientApplication::disconnect(uint16_t duration){ return _mqttsn.disconnect(duration); } /*-------------- Callback related functions ---------------*/ void MqttsnClientApplication::refleshWdtCallbackTable(){ _wdTimer.refleshRegisterTable(); } /*====================================== Class WdTimer ========================================*/ WdTimer::WdTimer(void) { _timerTbls = 0; _timerCnt = 0; _initFlg = true; } void WdTimer::start(void) { //MQwatchdogEnable(); } void WdTimer::stop(void){ // } bool WdTimer::wakeUp(void){ bool rcflg = false; int rc; for(uint8_t i = 0; i < _timerCnt; i++) { if ((_timerTbls[i].prevTime + _timerTbls[i].interval < (uint32_t)time(0)) || _initFlg){ rc = (_timerTbls[i].callback)(); if(rc == MQTTSN_ERR_REBOOT_REQUIRED){ theApplication->initialize(theAppConfig); } _timerTbls[i].prevTime = time(0); rcflg = true; } } _initFlg = false; return rcflg; } int WdTimer::registerCallback(uint32_t sec, int (*callback)(void)){ MQ_TimerTbl *savTbl = _timerTbls; MQ_TimerTbl *newTbl = (MQ_TimerTbl*)calloc(_timerCnt + 1,sizeof(MQ_TimerTbl)); if ( newTbl != 0 ) { _timerTbls = newTbl; for(uint8_t i = 0; i < _timerCnt; i++ ){ _timerTbls[i].prevTime = savTbl[i].prevTime; _timerTbls[i].interval = savTbl[i].interval; _timerTbls[i].callback = savTbl[i].callback; } free(savTbl); _timerTbls[_timerCnt].prevTime = time(0); _timerTbls[_timerCnt].interval = sec; _timerTbls[_timerCnt].callback = callback; _timerCnt++; return MQTTSN_ERR_NO_ERROR; } return MQTTSN_ERR_OUT_OF_MEMORY; } void WdTimer::refleshRegisterTable(){ for(uint8_t i = 0; i < _timerCnt; i++) { _timerTbls[i].prevTime = time(0); } } #endif #endif ================================================ FILE: Client/src/lib/mqttsnClientAppFw4mbed.h ================================================ /* * mqttsnClientAppFw4mbed.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifdef MBED #ifndef MQTTSNCLIENTAPPLICATION_H_ #define MQTTSNCLIENTAPPLICATION_H_ #include "mqttsnClient.h" extern uint16_t getUint16(uint8_t* pos); extern uint32_t getUint32(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); /*====================================== Class WdTimer ========================================*/ class WdTimer:public XTimer { public: WdTimer(void); int registerCallback(uint32_t sec, int (*proc)(void)); void refleshRegisterTable(); void start(void); void stop(void); bool wakeUp(void); private: MQ_TimerTbl *_timerTbls; uint8_t _timerCnt; bool _initFlg; }; /*====================================== Class MqttsnClientApplication ========================================*/ class MqttsnClientApplication{ public: MqttsnClientApplication(); ~MqttsnClientApplication(); void refleshWdtCallbackTable(); void initialize(APP_CONFIG config); void setSubscribe(); void setKeepAlive(uint16_t msec); void setWillTopic(MQString* willTopic); void setWillMessage(MQString* willMsg); void setRetain(bool retain); void setClean(bool clean); void setClientId(MQString* id); int publish(MQString* topic, const char* data, int dataLength, uint8_t qos = 1); int publish(uint16_t predefinedId, const char* data, int dataLength, uint8_t qos = 1); int publish(MQString* topic, Payload* payload, uint8_t qos); int subscribe(MQString* topic, TopicCallback callback, uint8_t qos = 1); int subscribe(uint16_t predefinedId, TopicCallback callback, uint8_t qos = 1); int unsubscribe(MQString* topic); int disconnect(uint16_t duration); void addTask(); void startWdt(); void stopWdt(); int run(); private: MqttsnClient _mqttsn; WdTimer _wdTimer; XTimer _keepAliveTimer; XTimer _advertiseTimer; }; extern MqttsnClientApplication* theApplication; #else #endif /*LINUX*/ #endif /* MQTTSCLIENTAPPLICATION_H_ */ ================================================ FILE: Client/src/lib/udpStack.cpp ================================================ /* * udpStack.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef ARDUINO #include "MQTTSN_Application.h" #include "Network.h" #else #include #include #endif #ifdef NETWORK_UDP #ifdef ARDUINO #include #include #include #include #include #if defined( NW_DEBUG) || defined(MQTTSN_DEBUG) #include extern SoftwareSerial debug; #endif #endif /* ARDUINO */ #ifdef MBED #include "mbed.h" #include "udpStack.h" #include "mqUtil.h" #endif /* MBED */ #ifdef LINUX #include "udpStack.h" #include "mqUtil.h" #include #include #include #include #include #include #include #include #include #include #include #endif /* LINUX */ using namespace std; using namespace tomyClient; extern uint16_t getUint16(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern uint32_t getUint32(uint8_t* pos); extern void setUint32(uint8_t* pos, uint32_t val); /*========================================= Class Network =========================================*/ Network::Network(){ _sleepflg = false; resetGwAddress(); } Network::~Network(){ } void Network::send(uint8_t* xmitData, uint8_t dataLen, SendReqType type){ if(type == BcastReq){ multicast(xmitData, (uint16_t)dataLen); }else if(type == UcastReq ){ unicast(xmitData, (uint16_t)dataLen, _gwIpAddress, _gwPortNo); } } int Network::readPacket(uint8_t type){ _returnCode = 0; if(checkRecvBuf()){ if(readApiFrame()){ if(_nlResp.isAvailable()){ if(_rxCallbackPtr){ _rxCallbackPtr(&_nlResp, &_returnCode); } } } } return _returnCode; } int Network::readApiFrame(){ uint16_t portNo = 0; uint32_t ipAddress = 0; uint16_t len; if (_nlResp.isAvailable() || _nlResp.isError()){ _nlResp.setAvailable(false); _nlResp.setErrorCode(NO_ERROR); } uint16_t recvLen = recv(_rxFrameDataBuf, MQTTSN_MAX_FRAME_SIZE, false, &ipAddress, &portNo); if( recvLen > 0){ if(*_rxFrameDataBuf == 0x01){ len = getUint16(_rxFrameDataBuf + 1); }else{ len = *_rxFrameDataBuf; } if( len != recvLen){ _nlResp.setErrorCode(PACKET_EXCEEDS_LENGTH); return false; }else if(_gwIpAddress && isUnicast() && (_nlResp.getAddress64().getLsb() != _gwIpAddress) && (_nlResp.getAddress16() != _gwPortNo)){ D_NWSTACKW(" Sender is not Gateway!\r\n" ); return false; }else{ _nlResp.setLength(len); _nlResp.setAvailable(true); _nlResp.setFrame(_rxFrameDataBuf); _nlResp.setAddress16(portNo); _nlResp.setAddress64(0,ipAddress); return true; } } return false; } void Network::setGwAddress(){ _gwPortNo = _nlResp.getAddress16(); _gwIpAddress = _nlResp.getAddress64().getLsb(); } void Network::resetGwAddress(void){ _gwIpAddress = 0; _gwPortNo = 0; } void Network::setRxHandler(void (*callbackPtr)(NWResponse* data, int* returnCode)){ _rxCallbackPtr = callbackPtr; } int Network::initialize(UdpConfig config){ return open(config); } void Network::setSleep(){ _sleepflg = true; } /*========================================= Class udpStack =========================================*/ #ifdef ARDUINO /** * For Arduino */ UdpPort::UdpPort(){ } UdpPort::~UdpPort(){ close(); } void UdpPort::close(){ } bool UdpPort::open(UdpConfig config){ _gIpAddr = IPAddress(config.ipAddress); _cIpAddr = IPAddress(config.ipLocal); _gPortNo = config.gPortNo; _uPortNo = config.uPortNo; memcpy(_macAddr, config.macAddr, 6); Ethernet.begin(_macAddr, _cIpAddr); if(_udpMulticast.beginMulti(_gIpAddr, _gPortNo) == 0){ return false; } if(_udpUnicast.begin(_uPortNo) == 0){ return false; } return true; } int UdpPort::unicast(const uint8_t* buf, uint32_t length, uint32_t ipAddress, uint16_t port ){ IPAddress ip = IPAddress(ipAddress); _udpUnicast.beginPacket(ip, port); _udpUnicast.write(buf, length); return _udpUnicast.endPacket(); } int UdpPort::multicast( const uint8_t* buf, uint32_t length ){ _udpMulticast.beginPacket(_gIpAddr, _gPortNo); _udpMulticast.write(buf, length); return _udpMulticast.endPacket(); } bool UdpPort::checkRecvBuf(){ int ps = _udpUnicast.parsePacket(); if(ps > 0){ _castStat = STAT_UNICAST; return true; }else if ( (ps = _udpMulticast.parsePacket()) > 0){ _castStat = STAT_MULTICAST; return true; } _castStat = 0; return 0; } int UdpPort::recv(uint8_t* buf, uint16_t len, bool flg, uint32_t* ipAddressPtr, uint16_t* portPtr){ return recvfrom ( buf, len, 0, ipAddressPtr, portPtr ); } int UdpPort::recvfrom ( uint8_t* buf, uint16_t len, int flags, uint32_t* ipAddressPtr, uint16_t* portPtr ){ IPAddress remoteIp; uint8_t packLen; if(_castStat == STAT_UNICAST){ packLen = _udpUnicast.read(buf, len); *portPtr = _udpUnicast.remotePort(); remoteIp = _udpUnicast.remoteIP(); }else if(_castStat == STAT_MULTICAST){ packLen = _udpMulticast.read(buf, len); *portPtr = _udpMulticast.remotePort(); remoteIp = _udpMulticast.remoteIP(); }else{ return 0; } memcpy(ipAddressPtr,remoteIp.raw_address(), 4); return packLen; } bool UdpPort::isUnicast(){ return ( _castStat == STAT_UNICAST); } #endif /* ARDUINO */ #ifdef MBED /** * For MBED */ #endif /* MBED */ #ifdef LINUX UdpPort::UdpPort(){ _disconReq = false; _sockfdUcast = -1; _sockfdMcast = -1; _castStat = 0; } UdpPort::~UdpPort(){ close(); } void UdpPort::close(){ if(_sockfdMcast > 0){ ::close( _sockfdMcast); _sockfdMcast = -1; if(_sockfdUcast > 0){ ::close( _sockfdUcast); _sockfdUcast = -1; } } } bool UdpPort::open(UdpConfig config){ const int reuse = 1; char loopch = 0; _gPortNo = htons(config.gPortNo); _gIpAddr = getUint32(config.ipAddress); _uPortNo = htons(config.uPortNo); if( _gPortNo == 0 || _gIpAddr == 0 || _uPortNo == 0){ return false; } _sockfdUcast = socket(AF_INET, SOCK_DGRAM, 0); if (_sockfdUcast < 0){ return false; } setsockopt(_sockfdUcast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = _uPortNo; addr.sin_addr.s_addr = INADDR_ANY; if( ::bind ( _sockfdUcast, (struct sockaddr*)&addr, sizeof(addr)) <0){ return false; } _sockfdMcast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (_sockfdMcast < 0){ return false; } struct sockaddr_in addrm; addrm.sin_family = AF_INET; addrm.sin_port = _gPortNo; addrm.sin_addr.s_addr = INADDR_ANY; setsockopt(_sockfdMcast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); if( ::bind ( _sockfdMcast, (struct sockaddr*)&addrm, sizeof(addrm)) <0){ return false; } if(setsockopt(_sockfdUcast, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)&loopch, sizeof(loopch)) <0 ){ D_NWSTACKW("error IP_MULTICAST_LOOP in UdpPort::open\n"); close(); return false; } if(setsockopt(_sockfdMcast, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)&loopch, sizeof(loopch)) <0 ){ D_NWSTACKW("error IP_MULTICAST_LOOP in UdpPPort::open\n"); close(); return false; } ip_mreq mreq; mreq.imr_interface.s_addr = INADDR_ANY; mreq.imr_multiaddr.s_addr = getUint32(config.ipAddress); if( setsockopt(_sockfdMcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) )< 0){ D_NWSTACKF("error IP_ADD_MEMBERSHIP in UdpPort::open\n"); close(); return false; } /* if( setsockopt(_sockfdUcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) )< 0){ D_NWSTACKF("error IP_ADD_MEMBERSHIP in UdpPort::open\n"); close(); return false; } */ return true; } bool UdpPort::isUnicast(){ return ( _castStat == STAT_UNICAST); } int UdpPort::unicast(const uint8_t* buf, uint32_t length, uint32_t ipAddress, uint16_t port ){ struct sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_port = port; dest.sin_addr.s_addr = ipAddress; int status = ::sendto( _sockfdUcast, buf, length, 0, (const sockaddr*)&dest, sizeof(dest) ); if( status < 0){ D_NWSTACKF("errno == %d in UdpPort::unicast\n", errno); }else{ D_NWSTACKF("sendto %s:%u [",inet_ntoa(dest.sin_addr),htons(port)); for(uint16_t i = 0; i < length ; i++){ D_NWSTACKF(" %02x", *(buf + i)); } D_NWSTACKF(" ]\n"); } return status; } int UdpPort::multicast( const uint8_t* buf, uint32_t length ){ struct sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_port = _gPortNo; dest.sin_addr.s_addr = _gIpAddr; int status = ::sendto( _sockfdMcast, buf, length, 0, (const sockaddr*)&dest, sizeof(dest) ); if( status < 0){ D_NWSTACKF("errno == %d in UdpPort::multicast\n", errno); }else{ D_NWSTACKF("sendto %s:%u [",inet_ntoa(dest.sin_addr),htons(_gPortNo)); for(uint16_t i = 0; i < length ; i++){ D_NWSTACKF(" %02x", *(buf + i)); } D_NWSTACKF(" ]\n"); } return errno; } bool UdpPort::checkRecvBuf(){ struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 500000; // 500 msec uint8_t buf[2]; fd_set recvfds; int maxSock = 0; FD_ZERO(&recvfds); FD_SET(_sockfdUcast, &recvfds); FD_SET(_sockfdMcast, &recvfds); if(_sockfdMcast > _sockfdUcast){ maxSock = _sockfdMcast; }else{ maxSock = _sockfdUcast; } select(maxSock + 1, &recvfds, 0, 0, &timeout); if(FD_ISSET(_sockfdUcast, &recvfds)){ if( ::recv(_sockfdUcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0){ _castStat = STAT_UNICAST; return true; } }else if(FD_ISSET(_sockfdMcast, &recvfds)){ if( ::recv(_sockfdMcast, buf, 1, MSG_DONTWAIT | MSG_PEEK) > 0){ _castStat = STAT_MULTICAST; return true; } } _castStat = 0; return false; } int UdpPort::recv(uint8_t* buf, uint16_t len, bool flg, uint32_t* ipAddressPtr, uint16_t* portPtr){ int flags = flg ? MSG_DONTWAIT : 0; return recvfrom (buf, len, flags, ipAddressPtr, portPtr ); } int UdpPort::recvfrom ( uint8_t* buf, uint16_t len, int flags, uint32_t* ipAddressPtr, uint16_t* portPtr ){ struct sockaddr_in sender; int status; socklen_t addrlen = sizeof(sender); memset(&sender, 0, addrlen); if(_castStat == STAT_UNICAST){ status = ::recvfrom( _sockfdUcast, buf, len, flags, (struct sockaddr*)&sender, &addrlen ); }else if(_castStat == STAT_MULTICAST){ status = ::recvfrom( _sockfdMcast, buf, len, flags, (struct sockaddr*)&sender, &addrlen ); }else{ return 0; } if (status < 0 && errno != EAGAIN) { D_NWSTACKF("errno == %d in UdpPort::recvfrom \n", errno); }else if(status > 0){ *ipAddressPtr = sender.sin_addr.s_addr; *portPtr = sender.sin_port; D_NWSTACKF("recved from %s:%u [",inet_ntoa(sender.sin_addr), htons(*portPtr)); for(uint16_t i = 0; i < status ; i++){ D_NWSTACKF(" %02x", *(buf + i)); } D_NWSTACKF(" ]\n"); }else{ return 0; } return status; } #endif /*========================================= Class NLLongAddress =========================================*/ NWAddress64::NWAddress64(){ _msb = _lsb = 0; } NWAddress64::NWAddress64(uint32_t msb, uint32_t lsb){ _msb = msb; _lsb = lsb; } uint32_t NWAddress64::getMsb(){ return _msb; } uint32_t NWAddress64::getLsb(){ return _lsb; } void NWAddress64::setMsb(uint32_t msb){ _msb = msb; } void NWAddress64::setLsb(uint32_t lsb){ _lsb = lsb; } /*========================================= Class ZBResponse =========================================*/ NWResponse::NWResponse(){ _addr16 = 0; } uint8_t NWResponse::getFrameLength(){ return _len; } void NWResponse::setLength(uint16_t len){ _len = len; } void NWResponse::setFrame(uint8_t* framePtr){ _frameDataPtr = framePtr; } NWAddress64& NWResponse::getAddress64(){ return _addr64; } uint16_t NWResponse::getAddress16(){ return _addr16; } void NWResponse::setAddress64(uint32_t msb, uint32_t lsb){ _addr64.setMsb(msb); _addr64.setLsb(lsb); } void NWResponse::setAddress16(uint16_t addr16){ _addr16 = addr16; } void NWResponse::setErrorCode(uint8_t errCode){ _errorCode = errCode; } void NWResponse::setAvailable(bool complete){ _complete = complete; } uint8_t NWResponse::getType(){ if(_len > 255){ return _frameDataPtr[3]; }else{ return _frameDataPtr[1]; } } uint8_t* NWResponse::getBody(){ if(_len > 255){ return _frameDataPtr + 4; }else{ return _frameDataPtr + 2; } } uint16_t NWResponse::getBodyLength(){ if(_len > 255){ return getPayloadLength() - 4; }else{ return getPayloadLength() - 2; } } uint8_t NWResponse::getPayload(uint8_t index){ return _frameDataPtr[index]; } uint8_t* NWResponse::getPayload(){ return _frameDataPtr; } uint8_t NWResponse::getPayloadLength(){ return _len; } void NWResponse::resetResponse(){ _addr64.setLsb(0); _addr64.setMsb(0); _addr16 = 0; _len = 0; _errorCode = 0; _complete = false;; } bool NWResponse::isAvailable(){ return _complete; } uint8_t NWResponse::isError(){ return _errorCode; } #endif /* NETWORK_UDP */ ================================================ FILE: Client/src/lib/udpStack.h ================================================ /* * udpStack.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef UDPSTACK_H_ #define UDPSTACK_H_ #ifdef ARDUINO #include #include #include #else #include "MQTTSN_Application.h" #include "mqUtil.h" #include "Network.h" #endif #ifdef NETWORK_UDP #ifdef ARDUINO #include #include #include #if ARDUINO >= 100 #include "Arduino.h" #include #else #if ARDUINO < 100 #include "WProgram.h" #include #endif #endif #endif /* ARDUINO */ #ifdef MBED #include "mbed.h" #endif #ifdef LINUX #include #include #include #include #include #include #include #include #include #endif #define STAT_UNICAST 1 #define STAT_MULTICAST 2 #define SOCKET_MAXHOSTNAME 200 #define SOCKET_MAXCONNECTIONS 5 #define SOCKET_MAXRECV 500 #define SOCKET_MAXBUFFER_LENGTH 500 // buffer size #define PACKET_TIMEOUT_CHECK 200 // msec using namespace std; namespace tomyClient { /*============================================ NWAddress64 =============================================*/ class NWAddress64 { public: NWAddress64(uint32_t msb, uint32_t lsb); NWAddress64(void); uint32_t getMsb(); uint32_t getLsb(); void setMsb(uint32_t msb); void setLsb(uint32_t lsb); private: uint32_t _msb; uint32_t _lsb; }; /*============================================ NWResponse =============================================*/ class NWResponse { public: NWResponse(); bool isAvailable(); uint8_t isError(); uint8_t getType(); uint8_t getFrameLength(); uint8_t getPayload(uint8_t index); uint8_t* getPayload(); uint8_t* getBody(); uint16_t getBodyLength(); uint8_t getPayloadLength(); uint16_t getAddress16(); NWAddress64& getAddress64(); void setLength(uint16_t len); // void setType(uint8_t type); void setFrame(uint8_t* framePtr); void setAddress64(uint32_t msb, uint32_t ipAddress); void setAddress16(uint16_t portNo); void setErrorCode(uint8_t); void setAvailable(bool); void resetResponse(); private: NWAddress64 _addr64; uint16_t _addr16; uint16_t _len; uint8_t* _frameDataPtr; uint8_t _type; uint8_t _errorCode; bool _complete; }; /*======================================== Class UpdPort =======================================*/ class UdpPort{ public: UdpPort(); virtual ~UdpPort(); bool open(NETWORK_CONFIG config); int unicast(const uint8_t* buf, uint32_t length, uint32_t ipaddress, uint16_t port ); int multicast( const uint8_t* buf, uint32_t length ); int recv(uint8_t* buf, uint16_t len, bool nonblock, uint32_t* ipaddress, uint16_t* port ); int recv(uint8_t* buf, uint16_t len, int flags); bool checkRecvBuf(); bool isUnicast(); private: void close(); int recvfrom ( uint8_t* buf, uint16_t len, int flags, uint32_t* ipaddress, uint16_t* port ); #ifdef LINUX int _sockfdUcast; int _sockfdMcast; uint16_t _gPortNo; uint16_t _uPortNo; uint32_t _gIpAddr; uint8_t _castStat; #endif #ifdef ARDUINO EthernetUDP _udpUnicast; EthernetUDP _udpMulticast; IPAddress _gIpAddr; IPAddress _cIpAddr; uint16_t _gPortNo; uint16_t _uPortNo; uint8_t* _macAddr; uint8_t _castStat; #endif bool _disconReq; }; #define NO_ERROR 0 #define PACKET_EXCEEDS_LENGTH 1 /*=========================================== Class Network ============================================*/ class Network : public UdpPort { public: Network(); ~Network(); void send(uint8_t* xmitData, uint8_t dataLen, SendReqType type); int readPacket(uint8_t type = 0); void setGwAddress(); void resetGwAddress(void); void setRxHandler(void (*callbackPtr)(NWResponse* data, int* returnCode)); void setSleep(); int initialize(UdpConfig config); private: int readApiFrame(); NWResponse _nlResp; uint32_t _gwIpAddress; uint16_t _gwPortNo; int _returnCode; bool _sleepflg; void (*_rxCallbackPtr)(NWResponse* data, int* returnCode); uint8_t _rxFrameDataBuf[MQTTSN_MAX_FRAME_SIZE]; }; } /* end of namespace */ #endif #endif /* UDPSTACK_H__ */ ================================================ FILE: Client/src/lib/zbeeStack.cpp ================================================ /* * zbeeStack.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef ARDUINO #include "MQTTSN_Application.h" #include "Network.h" #else #include #include #endif #ifdef NETWORK_XBEE #ifdef ARDUINO #include #include #if defined(MQTTSN_DEBUG) || defined(NW_DEBUG) || defined(DEBUG) #include extern SoftwareSerial debug; #endif #endif /* ARDUINO */ #ifdef MBED #include "mbed.h" #include "zbeeStack.h" #include "mqUtil.h" #endif /* MBED */ #ifdef LINUX #include "zbeeStack.h" #include "mqUtil.h" #include #include #include #include #include #include #include #include #include #include #endif /* LINUX */ using namespace std; using namespace tomyClient; extern uint16_t getUint16(uint8_t* pos); extern uint32_t getUint32(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); /*========================================= Class SerialPort =========================================*/ #ifdef ARDUINO /** * For Arduino */ SerialPort::SerialPort(){ _serialDev = 0; pinMode(XB_SLEEP_PIN, OUTPUT); digitalWrite(XB_SLEEP_PIN, LOW); } int SerialPort::open(XBeeConfig config){ //Port num overload. if (config.portNo == 0){ Serial.begin(config.baudrate); _serialDev = (Stream*) &Serial; } #if defined(UBRR1H) else if (config.portNo == 1){ Serial1.begin(config.baudrate); _serialDev = (Stream*) &Serial1; } #endif #if defined(UBRR2H) else if (config.portNo == 2){ Serial2.begin(config.baudrate); _serialDev = (Stream*) &Serial2; } #endif #if defined(UBRR3H) else if (config.portNo == 3){ Serial3.begin(config.baudrate); _serialDev = (Stream*) &Serial3; } #endif return 0; } bool SerialPort::checkRecvBuf(){ return _serialDev->available() > 0; } bool SerialPort::send(unsigned char b){ while(true){ if(digitalRead(XB_CTS_PIN) == LOW){ break; } } if(_serialDev->write(b) != 1){ return false; }else{ D_NWSTACK(" "); D_NWSTACK(b,HEX); return true; } } bool SerialPort::recv(unsigned char* buf){ if ( _serialDev->available() > 0 ){ buf[0] = _serialDev->read(); D_NWSTACK(" "); D_NWSTACK(*buf,HEX); return true; }else{ return false; } } void SerialPort::flush(void){ _serialDev->flush(); } #endif /* ARDUINO */ #ifdef MBED /** * For MBED */ SerialPort::SerialPort(){ _serialDev = new Serial(ZB_MBED_SERIAL_TXPIN, ZB_MBED_SERIAL_RXPIN); _head = _tail = 0; } void SerialPort::setBuff(void){ while(_serialDev->readable() > 0){ if( _tail != (_head + 1 == RING_BUFFER_SIZE ? 0 : _head + 1)){ // buffer full _data[_head] = _serialDev->getc(); if( ++_head == RING_BUFFER_SIZE){ _head = 0; } } } } int SerialPort::open(XBeeConfig config){ _serialDev->baud(config.baudrate); _serialDev->format(8,Serial::None,1); _serialDev->attach(this, &SerialPort::setBuff,Serial::RxIrq); return 0; } bool SerialPort::checkRecvBuf(){ return _head != _tail; } bool SerialPort::send(unsigned char b){ _serialDev->putc(b); D_NWSTACKF( " %x", b); return true; } bool SerialPort::recv(unsigned char* buf){ if(_head != _tail){ *buf = _data[_tail]; D_NWSTACKF( " %x",*buf ); if(++_tail == RING_BUFFER_SIZE){ _tail = 0; } return true; } *buf = 0; return false; } void SerialPort::flush(void){ _head = _tail = 0; } #endif /* MBED */ #ifdef LINUX SerialPort::SerialPort(){ _tio.c_iflag = IGNBRK | IGNPAR; #ifdef XBEE_FLOWCTRL_CRTSCTS _tio.c_cflag = CS8 | CLOCAL | CREAD | CRTSCTS; #else _tio.c_cflag = CS8 | CLOCAL | CREAD; #endif _tio.c_cc[VINTR] = 0; _tio.c_cc[VTIME] = 0; _tio.c_cc[VMIN] = 0; _fd = 0; } SerialPort::~SerialPort(){ if (_fd){ close(_fd); } } int SerialPort::open(XBeeConfig config){ return open(config.device, config.baudrate, false, 1); } int SerialPort::open(const char* devName, unsigned int boaurate, bool parity, unsigned int stopbit){ _fd = ::open(devName, O_RDWR | O_NOCTTY); if(_fd < 0){ return _fd; } if (parity){ _tio.c_cflag = _tio.c_cflag | PARENB; } if (stopbit == 2){ _tio.c_cflag = _tio.c_cflag | CSTOPB ; } switch(boaurate){ case B9600: case B19200: case B38400: case B57600: case B115200: if( cfsetspeed(&_tio, boaurate)<0){ return errno; } break; default: return -1; } return tcsetattr(_fd, TCSANOW, &_tio); } bool SerialPort::checkRecvBuf(){ return true; } bool SerialPort::send(unsigned char b){ if (write(_fd, &b,1) != 1){ return false; }else{ D_NWSTACKF( " %x", b); return true; } } bool SerialPort::recv(unsigned char* buf){ if(read(_fd, buf, 1) == 0){ return false; }else{ D_NWSTACKF( " %x",*buf ); return true; } } void SerialPort::flush(void){ tcsetattr(_fd, TCSAFLUSH, &_tio); } #endif /*========================================= Class XBeeAddress64 =========================================*/ NWAddress64::NWAddress64(){ _msb = _lsb = 0; } NWAddress64::NWAddress64(uint32_t msb, uint32_t lsb){ _msb = msb; _lsb = lsb; } uint32_t NWAddress64::getMsb(){ return _msb; } uint32_t NWAddress64::getLsb(){ return _lsb; } void NWAddress64::setMsb(uint32_t msb){ _msb = msb; } void NWAddress64::setLsb(uint32_t lsb){ _lsb = lsb; } /*========================================= Class XBResponse =========================================*/ XBResponse::XBResponse(){ reset(); } uint8_t XBResponse::getApiId(){ return _apiId; } uint8_t XBResponse::getMsbLength(){ return _msbLength; } uint8_t XBResponse::getLsbLength(){ return _frameLength; } uint8_t XBResponse::getChecksum(){ return _checksum; } uint8_t XBResponse::getFrameLength(){ return _frameLength; } uint8_t* XBResponse::getFrameDataPtr(){ return _frameDataPtr; } void XBResponse::setMsbLength(uint8_t msbLength){ _msbLength = msbLength; } void XBResponse::setLsbLength(uint8_t lsbLength){ _frameLength = lsbLength; } void XBResponse::setChecksum(uint8_t checksum){ _checksum = checksum; } void XBResponse::setFrameDataPtr(uint8_t* frameDataPtr){ _frameDataPtr = frameDataPtr; } void XBResponse::setFrameLength(uint8_t frameLength){ _frameLength = frameLength; } void XBResponse::setApiId(uint8_t api){ _apiId = api; } bool XBResponse::isAvailable(){ return _complete; } void XBResponse::setAvailable(bool complete){ _complete = complete; } bool XBResponse::isError(){ return _errorCode > 0; } uint8_t XBResponse::getErrorCode(){ return _errorCode; } void XBResponse::setErrorCode(uint8_t errorCode){ _errorCode = errorCode; } void XBResponse::reset(){ _apiId = 0; _msbLength = 0; _checksum = 0; _frameLength = 0; _errorCode = NO_ERROR; _complete = false; } /*========================================= Class XBModemStatus =========================================*/ XBModemStatus::XBModemStatus(){ } uint8_t XBModemStatus::getStatus(){ return *getFrameDataPtr(); } /*========================================= Class NWResponse =========================================*/ NWResponse::NWResponse(){ reset(); _remoteAddress16 = 0; _options = 0; } NWAddress64& NWResponse::getRemoteAddress64(){ return _remoteAddress64; } uint16_t NWResponse::getRemoteAddress16(){ return _remoteAddress16; } void NWResponse::setRemoteAddress64(NWAddress64& addr64){ _remoteAddress64 = addr64; } void NWResponse::setRemoteAddress64(){ _remoteAddress64.setMsb(getUint32(getFrameDataPtr())); _remoteAddress64.setLsb(getUint32(getFrameDataPtr() + 4)); } void NWResponse::setRemoteAddress16(uint16_t addr16){ _remoteAddress16 = addr16; } void NWResponse::setRemoteAddress16(){ _remoteAddress16 = (uint16_t(getFrameDataPtr()[8]) << 8) + (getFrameDataPtr()[9]); } uint8_t NWResponse::getType(){ return _frameDataPtr[ZB_RSP_DATA_OFFSET + 1]; } uint8_t NWResponse::getPayload(uint8_t index){ return _frameDataPtr[index + ZB_RSP_DATA_OFFSET]; } uint8_t* NWResponse::getBody(){ if(getFrameLength() > 255){ return _frameDataPtr + ZB_RSP_DATA_OFFSET + 4; }else{ return _frameDataPtr + ZB_RSP_DATA_OFFSET + 2; } } uint16_t NWResponse::getBodyLength(){ if(getFrameLength() > 255){ return getPayloadLength() - 4; }else{ return getPayloadLength() - 2; } } uint8_t* NWResponse::getPayload(){ return _frameDataPtr + ZB_RSP_DATA_OFFSET; } uint8_t NWResponse::getPayloadLength(){ return getFrameLength() - ZB_RSP_DATA_OFFSET; } uint8_t NWResponse::getOption(){ return _options; } void NWResponse::setOption(uint8_t options){ _options = options; } void NWResponse::setOption(){ _options = *(_frameDataPtr + ZB_RSP_DATA_OFFSET - 1); } bool NWResponse::isBrodcast(){ return ( _options && 0x02); } /*========================================= Class NWRequest =========================================*/ NWRequest::NWRequest(){ } uint8_t NWRequest::getFrameDataLength(){ return _payloadLength + ZB_REQ_DATA_OFFSET; } uint8_t* NWRequest::getPayload(){ return _payloadPtr; } uint8_t NWRequest::getPayloadLength(){ return _payloadLength; } uint8_t NWRequest::getBroadcastRadius(){ return _broadcastRadius; } uint8_t NWRequest::getOption(){ return _option; } void NWRequest::setBroadcastRadius(uint8_t broadcastRadius){ _broadcastRadius = broadcastRadius; } void NWRequest::setOption(uint8_t option){ _option = option; } void NWRequest::setPayload(uint8_t *payload){ _payloadPtr = payload; } void NWRequest::setPayloadLength(uint8_t payLoadLength){ _payloadLength = payLoadLength; } /*=========================================== Class Network ============================================*/ Network::Network(){ _serialPort = new SerialPort(); _rxCallbackPtr = 0; _returnCode = 0; _response.setFrameDataPtr(_responsePayload); _tm.stop(); _pos = 0; _escape = false; _checksumTotal = 0; _gwAddress64.setMsb(0L); _gwAddress64.setLsb(0L); _gwAddress16 = 0; _sleepflg = false; } Network::~Network(){ delete _serialPort; } int Network::initialize(XBeeConfig config){ return _serialPort->open(config); } void Network::setSleep(){ _sleepflg = true; } void Network::setRxHandler(void (*callbackPtr)(NWResponse* data, int* returnCode)){ _rxCallbackPtr = callbackPtr; } NWAddress64& Network::getRxRemoteAddress64(){ return _rxResp.getRemoteAddress64(); } uint16_t Network::getRxRemoteAddress16(){ return _rxResp.getRemoteAddress16(); } void Network::setResponse(NWResponse& response){ response.setApiId(_response.getApiId()); response.setAvailable(_response.isAvailable()); response.setChecksum(_response.getChecksum()); response.setErrorCode(_response.getErrorCode()); response.setFrameLength(_response.getFrameLength()); response.setMsbLength(_response.getMsbLength()); response.setLsbLength(_response.getLsbLength()); response.setFrameDataPtr(_responsePayload); response.setOption(); response.setRemoteAddress16(); response.setRemoteAddress64(); } void Network::setGwAddress(){ _gwAddress64.setMsb(getRxRemoteAddress64().getMsb()); _gwAddress64.setLsb(getRxRemoteAddress64().getLsb()); _gwAddress16 = getRxRemoteAddress16(); } void Network::resetGwAddress(void){ _gwAddress64.setMsb(0); _gwAddress64.setLsb(0); _gwAddress16 = 0; } void Network::setSerialPort(SerialPort *serialPort){ _serialPort = serialPort; } void Network::send(uint8_t* payload, uint8_t payloadLen, SendReqType type){ _txRequest.setOption(0); _txRequest.setPayload(payload); _txRequest.setPayloadLength(payloadLen); sendZBRequest(_txRequest, type); } int Network::readPacket(uint8_t type){ _returnCode = 0; if(_serialPort->checkRecvBuf()){ if(readApiFrame(PACKET_TIMEOUT_CHECK)){ if(_response.getApiId() == ZB_API_RESPONSE){ if (_rxCallbackPtr != 0){ _rxCallbackPtr(&_rxResp, &_returnCode); } }else if(_response.getApiId() == ZB_API_MODEMSTATUS){ if(type){ _returnCode = PACKET_MODEM_STATUS; } } } } return _returnCode; } bool Network::readApiFrame(uint16_t timeoutMillsec){ _pos = 0; _tm.start((uint32_t)timeoutMillsec); while(!_tm.isTimeUp()){ readApiFrame(); if(_response.isAvailable()){ D_NWSTACKW("\r\n<=== CheckSum OK\r\n\n"); if(_response.getApiId() == ZB_API_RESPONSE){ //_rxResp.setFrameDataPtr(_rxFrameDataBuf); setResponse(_rxResp); if(_gwAddress16 && (_rxResp.getOption() & 0x02 ) != 0x02 && (_gwAddress64.getMsb() != _rxResp.getRemoteAddress64().getMsb()) && (_gwAddress64.getLsb() != _rxResp.getRemoteAddress64().getLsb())){ D_NWSTACKW(" Sender is not Gateway!\r\n" ); return false; } return true; }else if(_response.getApiId() == ZB_API_MODEMSTATUS){ return true; } }else if(_response.isError()){ D_NWSTACKW("\r\n<=== Packet Error Code = "); D_NWSTACKLN(_response.getErrorCode(), DEC); D_NWSTACKF("%d\r\n",_response.getErrorCode() ); return false; } } return false; //Timeout } void Network::readApiFrame(){ if (_response.isAvailable() || _response.isError()){ resetResponse(); } while(read(&_byteData )){ if( _byteData == START_BYTE){ _pos = 1; continue; } // Check ESC if(_pos > 0 && _byteData == ESCAPE){ if(read(&_byteData )){ _byteData = 0x20 ^ _byteData; // decode }else{ _escape = true; continue; } } if(_escape){ _byteData = 0x20 ^ _byteData; _escape = false; } if(_pos >= API_ID_POS){ _checksumTotal+= _byteData; } switch(_pos){ case 0: break; case 1: _response.setMsbLength(_byteData); break; case 2: _response.setLsbLength(_byteData); break; case 3: D_NWSTACKW("\r\n===> Recv: "); _response.setApiId(_byteData); // API break; default: if(_pos > MQTTSN_MAX_FRAME_SIZE){ _response.setErrorCode(PACKET_EXCEEDS_BYTE_ARRAY_LENGTH); _pos = 0; return; }else if(_pos == (_response.getFrameLength() + 3)){ if((_checksumTotal & 0xff) == 0xff){ _response.setChecksum(_byteData); _response.setAvailable(true); _response.setErrorCode(NO_ERROR); }else{ _response.setErrorCode(CHECKSUM_FAILURE); } _response.setFrameLength(_pos - 4); // 4 = 2(packet len) + 1(Api) + 1(checksum) _pos = 0; _checksumTotal = 0; return; }else{ _response.getFrameDataPtr()[_pos - 4] = _byteData; } break; } _pos++; } } void Network::sendZBRequest(NWRequest& request, SendReqType type){ D_NWSTACKW("\r\n===> Send: "); sendByte(START_BYTE, false); // Start byte uint8_t msbLen = ((request.getFrameDataLength() + 1) >> 8) & 0xff; // 1 for Checksum uint8_t lsbLen = (request.getFrameDataLength() + 1) & 0xff; sendByte(msbLen, true); // Message Length sendByte(lsbLen, true); // Message Length sendByte(ZB_API_REQUEST, true); // API uint8_t checksum = 0; checksum+= ZB_API_REQUEST; sendByte(0x00, true); // Frame ID for(int i = 0; i < 10; i++){ sendByte(getAddrByte(i,type), true); // Gateway Address 64 & 16 checksum += getAddrByte(i,type); // or Broadcast Address } sendByte(request.getBroadcastRadius(), true); checksum += request.getBroadcastRadius(); sendByte(request.getOption(), true); checksum += request.getOption(); D_NWSTACKW("\r\n Payload: "); for( int i = 0; i < request.getPayloadLength(); i++ ){ sendByte(request.getPayload()[i], true); // Payload checksum+= request.getPayload()[i]; } checksum = 0xff - checksum; sendByte(checksum, true); flush(); // clear receive buffer D_NWSTACKW("\r\n<=== Send completed\r\n\n" ); } void Network::sendByte(uint8_t b, bool escape){ if(escape && (b == START_BYTE || b == ESCAPE || b == XON || b == XOFF)){ write(ESCAPE); write(b ^ 0x20); }else{ write(b); } } void Network::resetResponse(){ _pos = 0; _escape = 0; _response.reset(); _addr16 = 0; _addr32 = 0; } void Network::flush(){ _serialPort->flush(); } bool Network::write(uint8_t val){ return (_serialPort->send(val) ? true : false ); } bool Network::read(uint8_t *buff){ return _serialPort->recv(buff); } uint8_t Network::getAddrByte(uint8_t pos, SendReqType type){ uint8_t buf[4]; if(type == UcastReq){ if (pos == 0){ setUint32(buf, _gwAddress64.getMsb()); return buf[0]; }else if (pos == 1){ setUint32(buf, _gwAddress64.getMsb()); return buf[1]; }else if (pos == 2){ setUint32(buf, _gwAddress64.getMsb()); return buf[2]; }else if (pos == 3){ setUint32(buf, _gwAddress64.getMsb()); return buf[3]; }else if (pos == 4){ setUint32(buf, _gwAddress64.getLsb()); return buf[0]; }else if (pos == 5){ setUint32(buf, _gwAddress64.getLsb()); return buf[1]; }else if (pos == 6){ setUint32(buf, _gwAddress64.getLsb()); return buf[2]; }else if (pos == 7){ setUint32(buf, _gwAddress64.getLsb()); return buf[3]; }else if (pos == 8){ setUint16(buf,_gwAddress16); return buf[0]; }else if (pos == 9){ setUint16(buf,_gwAddress16); return buf[1]; } }else if(type == BcastReq){ if(pos < 6){ return 0x00; }else if((pos > 5) && (pos < 9)){ return 0xff; }else if(pos == 9){ return 0xfe; } } return 0; } #endif /* NETWORK_XBEE */ ================================================ FILE: Client/src/lib/zbeeStack.h ================================================ /* * zbeeStack.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: 2014/09/05 * Author: Tomoaki YAMAGUCHI * Version: 1.0.0 */ #ifndef ZBEESTACK_H_ #define ZBEESTACK_H_ #ifdef ARDUINO #include #else #include "MQTTSN_Application.h" #include "mqUtil.h" #include "Network.h" #endif #ifdef NETWORK_XBEE #if defined(ARDUINO) #include #include #if ARDUINO >= 100 #include "Arduino.h" #include #include #else #if ARDUINO < 100 #include "WProgram.h" #include #include #endif #endif #define XB_CTS_PIN 3 // XBee CTS #define XB_SLEEP_PIN 4 // XBee Pinhybernate #endif #ifdef MBED #include "mbed.h" #define ZB_MBED_SERIAL_TXPIN p13 #define ZB_MBED_SERIAL_RXPIN p14 #endif #ifdef LINUX #include #include #endif namespace tomyClient { #define START_BYTE 0x7e #define ESCAPE 0x7d #define XON 0x11 #define XOFF 0x13 #define ZB_API_REQUEST 0x10 #define ZB_API_RESPONSE 0x90 #define ZB_API_MODEMSTATUS 0x8A #define ZB_PACKET_ACKNOWLEGED 0x01 #define ZB_BROADCAST_PACKET 0x02 #define ZB_BROADCAST_RADIUS_MAX_HOPS 0 #define ZB_RSP_DATA_OFFSET 11 #define ZB_REQ_DATA_OFFSET 13 #define API_ID_POS 3 #define PACKET_OVERHEAD_LENGTH 6 #define ZB_MAX_NODEID 20 /*==== STATUS ====== */ #define SUCCESS 0x0 #define NO_ERROR 0 #define CHECKSUM_FAILURE 1 #define PACKET_EXCEEDS_BYTE_ARRAY_LENGTH 2 #define UNEXPECTED_START_BYTE 3 /* * Packet Read Constants */ #if defined(ARDUINO) || defined(MBED) #define PACKET_TIMEOUT_CHECK 300 #else #define PACKET_TIMEOUT_CHECK 200 #endif #define RING_BUFFER_SIZE 256 /*============================================ NWAddress64 =============================================*/ class NWAddress64 { public: NWAddress64(uint32_t msb, uint32_t lsb); NWAddress64(void); uint32_t getMsb(); uint32_t getLsb(); void setMsb(uint32_t msb); void setLsb(uint32_t lsb); private: uint32_t _msb; uint32_t _lsb; }; /*============================================ XBResponse =============================================*/ class XBResponse { public: XBResponse(); uint8_t getApiId(); uint8_t getMsbLength(); uint8_t getLsbLength(); uint8_t getChecksum(); uint8_t getFrameLength(); uint8_t* getFrameDataPtr(); void setApiId(uint8_t api); void setMsbLength(uint8_t msbLength); void setLsbLength(uint8_t lsbLength); void setChecksum(uint8_t checksum); void setFrameDataPtr(uint8_t* frameDataPtr); void setFrameLength(uint8_t frameLength); bool isAvailable(); void setAvailable(bool complete); bool isError(); void setErrorCode(uint8_t errorCode); void reset(); uint8_t getErrorCode(); protected: uint8_t* _frameDataPtr; private: uint8_t _msbLength; uint8_t _frameLength; uint8_t _apiId; uint8_t _checksum; uint8_t _errorCode; bool _complete; }; /*============================================ XBModemStatus =============================================*/ class XBModemStatus : public XBResponse{ public: XBModemStatus(); uint8_t getStatus(); }; /*============================================ NLResponse =============================================*/ class NWResponse : public XBResponse{ public: NWResponse(); uint8_t getPayload(uint8_t index); uint8_t getPayloadLength(); uint8_t getType(); uint8_t getOption(); uint8_t* getPayload(); uint8_t* getBody(); uint16_t getBodyLength(); uint16_t getRemoteAddress16(); NWAddress64& getRemoteAddress64(); void setRemoteAddress64(NWAddress64& addr64); void setRemoteAddress64(); void setRemoteAddress16(uint16_t addr16); void setRemoteAddress16(); void setOption(uint8_t options); void setOption(); bool isBrodcast(); private: NWAddress64 _remoteAddress64; uint16_t _remoteAddress16; uint8_t _options; }; /*============================================* NLRequest =============================================*/ class NWRequest { public: NWRequest(); ~NWRequest(){}; // uint8_t getFrameData(uint8_t pos); uint8_t getFrameDataLength(); uint8_t getBroadcastRadius(); uint8_t getOption(); uint8_t getPayloadLength(); uint8_t* getPayload(); void setBroadcastRadius(uint8_t broadcastRadius); void setOption(uint8_t option); void setPayload(uint8_t *payload); void setPayloadLength(uint8_t payLoadLength); private: uint8_t _broadcastRadius; uint8_t _option; uint8_t _payloadLength; uint8_t* _payloadPtr; }; /*=========================================== Serial Port ============================================*/ #ifdef ARDUINO #include class SerialPort{ public: SerialPort( ); int open(NETWORK_CONFIG config); bool send(unsigned char b); bool recv(unsigned char* b); void flush(); bool checkRecvBuf(); private: Stream* _serialDev; }; #endif /* ARDUINO */ #ifdef MBED /*------------------------- For MBED --------------------------*/ class SerialPort{ public: SerialPort( ); int open(XBeeConfig config); bool send(unsigned char b); bool recv(unsigned char* b); void flush(); bool checkRecvBuf(); void setBuff(void); void putc(uint8_t c); private: Serial* _serialDev; uint8_t _data[RING_BUFFER_SIZE]; int _head; int _tail; }; #endif /* MBED */ #ifdef LINUX /*------------------------- For Linux --------------------------*/ #include class SerialPort{ public: SerialPort(); ~SerialPort(); int open(XBeeConfig config); bool send(unsigned char b); bool recv(unsigned char* b); bool checkRecvBuf(); void flush(); private: int open(const char* devName, unsigned int boaurate, bool parity, unsigned int stopbit); int _fd; // file descriptor struct termios _tio; }; #endif /* LINUX */ /*=========================================== Class Network ============================================*/ class Network { public: Network(); ~Network(); void send(uint8_t* xmitData, uint8_t dataLen, SendReqType type); int readPacket(uint8_t type = 0); void setGwAddress(); void resetGwAddress(void); void setRxHandler(void (*callbackPtr)(NWResponse* data, int* returnCode)); int initialize(XBeeConfig config); private: void setSleep(); NWAddress64& getRxRemoteAddress64(); uint16_t getRxRemoteAddress16(); const char* getNodeId(); void setResponse(NWResponse& response); void setSerialPort(SerialPort *serialPort); void sendZBRequest(NWRequest& request, SendReqType type); int packetHandle(); void execCallback(); void readApiFrame(void); bool readApiFrame(uint16_t timeoutMillsec); void flush(); void resetResponse(); bool read(uint8_t* buff); bool write(uint8_t val); void sendByte(uint8_t, bool escape); uint8_t getAddrByte(uint8_t pos, SendReqType type); NWRequest _txRequest; NWResponse _rxResp; XBResponse _response; // Received data uint8_t _responsePayload[MQTTSN_MAX_FRAME_SIZE]; XTimer _tm; SerialPort* _serialPort; NWAddress64 _gwAddress64; uint16_t _gwAddress16; uint8_t _pos; uint8_t _byteData; uint8_t _checksumTotal; uint16_t _addr16; uint32_t _addr32; int _returnCode; bool _escape; bool _sleepflg; void (*_rxCallbackPtr)(NWResponse* data, int* returnCode); }; } #endif #endif /* ZBEESTACK_H_ */ ================================================ FILE: Client/src/mbedClientSample.cpp ================================================ /* * mbedClientSample.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "lib/MQTTSN_Application.h" #ifdef MBED #include "lib/mqttsnClientAppFw4mbed.h" using namespace std; using namespace tomyClient; /*============================================ * * MQTT-SN Client Application for mbed * *===========================================*/ XBEE_APP_CONFIG = { { 9600, //Baudrate (bps) 0, //Serial PortNo 0 //Device (for linux App) }, { "Node01", //NodeId 300, //KeepAlive (sec) false, //Clean session false, //EndDevice "willTopic", //WillTopic or 0 DO NOT USE 0 STRING! "willMessage" //WillMessage or 0 DO NOT USE 0 STRING! } }; /*------------------------------------------------------ * Create Topic *------------------------------------------------------*/ MQString* topic1 = new MQString("dev/indicator"); /*------------------------------------------------------ * Tasks invoked by Timer *------------------------------------------------------*/ bool led_flg = false; int task1(){ if(led_flg){ PUBLISH(topic1, "off", 3, QOS1); led_flg = false; }else{ PUBLISH(topic1, "on", 2, QOS1); led_flg = true; } return 0; } /*--------- Link Tasks to the Application ----------*/ TASK_LIST = { {task1, 60}, END_OF_TASK_LIST}; /*------------------------------------------------------ * Tasks invoked by PUBLISH command Packet *------------------------------------------------------*/ DigitalOut indicator(LED1); int blinkIndicator(MqttsnPublish* msg){ if( !strncmp("on", (const char*)msg->getData(),2)){ indicator = 1; }else if( !strncmp("off", (const char*)msg->getData(),3)){ indicator = 0; } return 0; } /*-------------- Link Tasks to Topic -------------------*/ SUBSCRIBE_LIST = { {topic1, blinkIndicator, QOS1}, END_OF_SUBSCRIBE_LIST}; /*================================================== * Application setup *=================================================*/ void setup(){ // nop } #endif ================================================ FILE: Gateway/Makefile ================================================ PROGNAME := TomyGateway SRCDIR := src SUBDIR := src/lib SRCS := $(SRCDIR)/TomyGateway.cpp \ $(SRCDIR)/BrokerRecvTask.cpp \ $(SRCDIR)/BrokerSendTask.cpp \ $(SRCDIR)/ClientRecvTask.cpp \ $(SRCDIR)/ClientSendTask.cpp \ $(SRCDIR)/GatewayControlTask.cpp \ $(SRCDIR)/GatewayResourcesProvider.cpp \ $(SUBDIR)/ProcessFramework.cpp \ $(SUBDIR)/Messages.cpp \ $(SUBDIR)/TCPStack.cpp \ $(SUBDIR)/TLSStack.cpp \ $(SUBDIR)/Topics.cpp \ $(SUBDIR)/UDPStack.cpp \ $(SUBDIR)/XXXXXStack.cpp \ $(SUBDIR)/ZBStack.cpp CXX := g++ CPPFLAGS += DEFS := LDFLAGS += LIBS += #LDADD := -lpthread -lrt -lssl -lcrypto LDADD := -lpthread -lrt -lwiringPi -lssl -lcrypto CXXFLAGS := -Wall -O3 OUTDIR := Build PROG := $(OUTDIR)/$(PROGNAME) OBJS := $(SRCS:%.cpp=$(OUTDIR)/%.o) DEPS := $(SRCS:%.cpp=$(OUTDIR)/%.d) .PHONY: install clean distclean all: $(PROG) -include $(DEPS) $(PROG): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(LDADD) $(OUTDIR)/%.o:%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< clean: rm -rf $(OUTDIR) install: cp -p $(PROG) ../../ ================================================ FILE: Gateway/README.md ================================================ MQTT-SN Gateway ====== This program is a Gateway over XBee and UDP. Select from the network layer in lib/Defines.h, shown in below. In case of UDP, Multicast is required for SEARCHGW and GWINFO messages. Client multicasts the SEARCHGW to find the gateway. Gateway multicasts the GWINFO from unicast port. Client can get the gateway IP and port using std::recvfrom() functions. If your client does not support SEARCHGW and GWINFO, you can skip the search gateway procedure. You can CONNECT to a portNo specified with -u parameter and Gateway's IP address directly. If you want to change to your own networkStack, i.e bluetooth, just modify the XXXXXXStack.cpp, .h and lib/Defines.h, ClientRecv.cpp, ClientSend.cpp files. Templates are built in already. Supported functions ------------------- * QOS Level 0, 1 and 2 * CONNECT, WILLTOPICREQ, WILLTOPIC, WILLMSGREQ, WILLMSG * REGISTER, SUBSCRIBE, PUBLISH, UNSUBSCRIBE, DISCONNECT * CONNACK, REGACK, SUBACK, PUBACK, PUBREL, PUBCOMP, UNSUBACK * ADVERTIZE, GWINFO Usage ------ ####1) Minimum requirements * Linux ( Windows can not execute this program.) * pthread, rt liblaries to be linked. * wiringPi for Raspberry Pi (http://wiringpi.com/download-and-install/) * In case of XBee, Three XBee S2 (one coordinator, one gateway and one client.) * or two XBee S1 (Digimesh, one for gateway and another for client) ####2) How to Build for XBee DigiMesh $ make for UDP $ make DEFS=-DNETWORK_UDP Makefile is in Gateway directory. TomyGateway (Executable) is created in Build directory. $ make install TomyGateway is copied to the directory repo located. $ make clean remove the Build directory. ####3) Start Gateway Prepare parameter file /usr/local/etc/tomygateway/config/param.conf BrokerName=test.mosquitto.org BrokerPortNo=1883 #LoginID= #Password= SerialDevice=/dev/ttyUSB0 BaudRate=57600 BroadcastIP=225.1.1.1 GatewayPortNo=2000 BroadcastPortNo=1883 GatewayID=1 KeepAlive=900 Prepare Key files for semaphore and sheared memory. file's contents is emply. /usr/local/etc/tomygateway/config/rbmutex.key /usr/local/etc/tomygateway/config/ringbuffer.key /usr/local/etc/tomygateway/config/semaphore.key Execute $ TomyGateway XBee configurations ---------------------- Serial interfacing of gateway. Coordinator is default setting. [BD] 6 57600 bps [D7] 1 CTS-Flow Control [D6] 1 RTS-Flow Control [AP] 2 API Enable Other values are defaults. Gateway configurations ---------------------- lib/Defines.h /*================================= * CPU TYPE ==================================*/ #define CPU_LITTLEENDIANN //#define CPU_BIGENDIANN /*================================= * Debug LOG ==================================*/ //#define DEBUG_NWSTACK // show network layer transactions. Raspberry Pi SD card img file ---------------------- 1) Download from https://drive.google.com/a/tomy-tech.com/?tab=mo#folders/0ByWDD8Fur4QcMGpuRWd2RWVtMDA 2) unzip and copy to SD card 3) root's password is root 4) Login ID is "gw" and password is "gw". xxx.xxx... is IP address DHCP assigned. $ ssh xxx.xxx.xxx.xxx -l gw -p 22022 5) Download latest version from github & compile as follows 6) $ rm -rf MQTT-SN 7) $ git clone https://github.com/ty4tw/MQTT-SN.git 8) $ cd MQTT-SN/Gateway 9) $ make CXXFLAGS=-DRASPBERRY_PI or $ make CXXFLAGS=-DRASPBERRY_PI DEFS=-DNETWORK_UDP 10) $ make install 11) reboot How to connect XBee to Raspberry Pi ---------------------- XBee Vcc ---> Raspberry Pi Pin 1 XBee Gnd ---> Raspberry Pi Pin 6 XBee RX ---> Raspberry Pi Pin 8 XBee TX ---> Raspberry Pi Pin 10 How to connect Indicators and power off switch ---------------------- Green LED ---> Raspberry Pi Pin 16 (Broker connected) RED LED ---> Raspberry Pi Pin 18 (Broker disconnected) Blue LED ---> Raspberry Pi Pin 22 (Sending/Receiving) PWR Off SW ---> Raspberry Pi Pin 11 (shutdown safely) Pin 11 -----+-----/\/\/\/----- +Vcc 3.3V | 10K | |+ SW | | GND How to monitor the Gateway ---------------------- $ sudo /home/gw/LogMonitor ================================================ FILE: Gateway/src/BrokerRecvTask.cpp ================================================ /* * BrokerRecvTask.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "BrokerRecvTask.h" #include "GatewayResourcesProvider.h" #include "GatewayDefines.h" #include "lib/ProcessFramework.h" #include "lib/Messages.h" #include #include #include #include extern char* currentDateTime(); BrokerRecvTask::BrokerRecvTask(GatewayResourcesProvider* res){ _res = res; _res->attach(this); _stableNetwork = true; } BrokerRecvTask::~BrokerRecvTask(){ } void BrokerRecvTask::run(){ char param[TOMYFRAME_PARAM_MAX]; if(_res->getParam("NetworkIsStable",param) == 0){ if(!strcasecmp(param, "NO")){ _stableNetwork = false; } } struct timeval timeout; LightIndicator* lightIndicator = _res->getLightIndicator(); ClientList* clist = _res->getClientList(); fd_set rset; fd_set wset; while(true){ timeout.tv_sec = 0; timeout.tv_usec = 500000; // 500 msec FD_ZERO(&rset); FD_ZERO(&wset); int maxSock = 0; int sockfd = 0; /*------- Prepare socket list to check -------*/ for( int i = 0; i < clist->getClientCount(); i++){ if((*clist)[i]){ if((*clist)[i]->getStack()->isValid()){ sockfd = (*clist)[i]->getStack()->getSock(); FD_SET(sockfd, &rset); FD_SET(sockfd, &wset); if(sockfd > maxSock){ maxSock = sockfd; } } }else{ break; } } if(maxSock == 0){ lightIndicator->greenLight(false); }else{ /*------- Check socket to receive -------*/ int activity = select( maxSock + 1 , &rset , 0 , 0 , &timeout); if (activity > 0){ for( int i = 0; i < clist->getClientCount(); i++){ if((*clist)[i]){ if((*clist)[i]->getStack()->isValid()){ int sockfd = (*clist)[i]->getStack()->getSock(); if(FD_ISSET(sockfd, &rset)){ recvAndFireEvent((*clist)[i]); lightIndicator->greenLight(true); } } }else{ break; } } } } } } /*----------------------------------------- Recv socket & Create MQTT Messages -----------------------------------------*/ void BrokerRecvTask::recvAndFireEvent(ClientNode* clnode){ uint8_t sbuff[SOCKET_MAXBUFFER_LENGTH * 5]; uint8_t buffer[SOCKET_MAXBUFFER_LENGTH]; memset(buffer, 0, SOCKET_MAXBUFFER_LENGTH); int recvLength = 0; uint8_t* packet = buffer; recvLength = clnode->getStack()->recv(packet,SOCKET_MAXBUFFER_LENGTH); if (recvLength == -1){ LOGWRITE(" Client : %s Error: BrokerRecvTask can't Receive data from Broker\n", clnode->getNodeId()->c_str()); clnode->disconnected(); } while(recvLength > 0){ if((*packet & 0xf0) == MQTT_TYPE_PUBACK){ MQTTPubAck* puback = new MQTTPubAck(); puback->deserialize(packet); puback->serialize(sbuff); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBACK", LEFTARROW, BROKER, msgPrint(sbuff, puback)); clnode->setBrokerRecvMessage(puback); }else if((*packet & 0xf0) == MQTT_TYPE_PUBREC){ MQTTPubRec* pubRec = new MQTTPubRec(); pubRec->deserialize(packet); pubRec->serialize(sbuff); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBREC", LEFTARROW, BROKER, msgPrint(sbuff, pubRec)); clnode->setBrokerRecvMessage(pubRec); }else if((*packet & 0xf0) == MQTT_TYPE_PUBREL){ MQTTPubRel* pubRel = new MQTTPubRel(); pubRel->deserialize(packet); pubRel->serialize(sbuff); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBREL", LEFTARROW, BROKER, msgPrint(sbuff, pubRel)); clnode->setBrokerRecvMessage(pubRel); }else if((*packet & 0xf0) == MQTT_TYPE_PUBCOMP){ MQTTPubComp* pubComp = new MQTTPubComp(); pubComp->deserialize(packet); pubComp->serialize(sbuff); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBCOMP", LEFTARROW, BROKER, msgPrint(sbuff, pubComp)); clnode->setBrokerRecvMessage(pubComp); }else if((*packet & 0xf0) == MQTT_TYPE_PUBLISH){ MQTTPublish* publish = new MQTTPublish(); if(!publish->deserialize(packet)){ clnode->disconnected(); clnode->getStack()->disconnect(); LOGWRITE("%s ill-formed UTF-8\n",currentDateTime()); } publish->serialize(sbuff); LOGWRITE(GREEN_FORMAT2, currentDateTime(), "PUBLISH", LEFTARROW, BROKER, msgPrint(sbuff, publish)); clnode->setBrokerRecvMessage(publish); }else if((*packet & 0xf0) == MQTT_TYPE_SUBACK){ MQTTSubAck* suback = new MQTTSubAck(); suback->deserialize(packet); suback->serialize(sbuff); LOGWRITE(FORMAT1, currentDateTime(), "SUBACK", LEFTARROW, BROKER, msgPrint(sbuff, suback)); clnode->setBrokerRecvMessage(suback); }else if((*packet & 0xf0) == MQTT_TYPE_PINGRESP){ MQTTPingResp* pingresp = new MQTTPingResp(); pingresp->deserialize(packet); pingresp->serialize(sbuff); LOGWRITE(FORMAT1, currentDateTime(), "PINGRESP", LEFTARROW, BROKER, msgPrint(sbuff, pingresp)); clnode->setBrokerRecvMessage(pingresp); }else if((*packet & 0xf0) == MQTT_TYPE_UNSUBACK){ MQTTUnsubAck* unsuback = new MQTTUnsubAck(); unsuback->deserialize(packet); unsuback->serialize(sbuff); LOGWRITE(FORMAT1, currentDateTime(), "UNSUBACK", LEFTARROW, BROKER, msgPrint(sbuff, unsuback)); clnode->setBrokerRecvMessage(unsuback); }else if((*packet & 0xf0) == MQTT_TYPE_CONNACK){ MQTTConnAck* connack = new MQTTConnAck(); connack->deserialize(packet); connack->serialize(sbuff); LOGWRITE(CYAN_FORMAT1, currentDateTime(), "CONNACK", LEFTARROW, BROKER, msgPrint(sbuff, connack)); clnode->setBrokerRecvMessage(connack); }else{ LOGWRITE("%s UNKOWN_TYPE packetLength=%d\n",currentDateTime(), recvLength); return; } Event* ev = new Event(); ev->setBrokerRecvEvent(clnode); _res->getGatewayEventQue()->post(ev); RemainingLength rl; rl.deserialize(packet + 1); uint16_t packetLength = 1 + rl.getSize() + rl.decode(); recvLength -= packetLength; packet += packetLength; } } char* BrokerRecvTask::msgPrint(uint8_t* buffer, MQTTMessage* msg){ char* buf = _printBuf; _res->getLightIndicator()->blueLight(true); sprintf(buf, " %02X", *buffer); buf += 3; for(int i = 0; i < msg->getRemainLength() + msg->getRemainLengthSize(); i++){ sprintf(buf, " %02X", *( buffer + 1 + i)); buf += 3; } *buf = 0; _res->getLightIndicator()->blueLight(false); return _printBuf; } ================================================ FILE: Gateway/src/BrokerRecvTask.h ================================================ /* * BrokerRecvTask.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef BROKERRECVTASK_H_ #define BROKERRECVTASK_H_ #include "lib/ProcessFramework.h" #include "lib/Messages.h" #include "GatewayResourcesProvider.h" class BrokerRecvTask : public Thread{ MAGIC_WORD_FOR_TASK; public: BrokerRecvTask(GatewayResourcesProvider* res); ~BrokerRecvTask(); void initialize(); void run(); char* msgPrint(uint8_t* buf, MQTTMessage* msg); private: void recvAndFireEvent(ClientNode*); GatewayResourcesProvider* _res; char _printBuf[SOCKET_MAXBUFFER_LENGTH * 5]; bool _stableNetwork; }; #endif /* BROKERRECVTASK_H_ */ ================================================ FILE: Gateway/src/BrokerSendTask.cpp ================================================ /* * BrokerSendTask.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "BrokerSendTask.h" #include "GatewayResourcesProvider.h" #include "GatewayDefines.h" #include "lib/ProcessFramework.h" #include "lib/Messages.h" #include "lib/Defines.h" #include #include #include #include #include extern char* currentDateTime(); BrokerSendTask::BrokerSendTask(GatewayResourcesProvider* res){ _res = res; _res->attach(this); } BrokerSendTask::~BrokerSendTask(){ if(_host){ delete _host; } if(_service){ delete _service; } } void BrokerSendTask::run(){ Event* ev = 0; MQTTMessage* srcMsg = 0; ClientNode* clnode = 0; char param[TOMYFRAME_PARAM_MAX]; if(_res->getParam("BrokerName",param) == 0){ _host = strdup(param); } if(_res->getParam("BrokerPortNo",param) == 0){ _service =strdup( param); } _light = _res->getLightIndicator(); while(true){ uint16_t length = 0; memset(_buffer, 0, SOCKET_MAXBUFFER_LENGTH); ev = _res->getBrokerSendQue()->wait(); clnode = ev->getClientNode(); srcMsg = clnode->getBrokerSendMessage(); if(srcMsg->getType() == MQTT_TYPE_PUBLISH){ MQTTPublish* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(BLUE_FORMAT, currentDateTime(), "PUBLISH", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); send(clnode, length); }else if(srcMsg->getType() == MQTT_TYPE_PUBACK){ MQTTPubAck* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(GREEN_FORMAT, currentDateTime(), "PUBACK", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); send(clnode, length); }else if(srcMsg->getType() == MQTT_TYPE_PUBREL){ MQTTPubRel* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(GREEN_FORMAT, currentDateTime(), "PUBREL", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); send(clnode, length); }else if(srcMsg->getType() == MQTT_TYPE_PINGREQ){ MQTTPingReq* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(FORMAT, currentDateTime(), "PINGREQ", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); send(clnode, length); }else if(srcMsg->getType() == MQTT_TYPE_SUBSCRIBE){ MQTTSubscribe* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(FORMAT, currentDateTime(), "SUBSCRIBE", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); send(clnode, length); }else if(srcMsg->getType() == MQTT_TYPE_UNSUBSCRIBE){ MQTTUnsubscribe* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(FORMAT, currentDateTime(), "UNSUBSCRIBE", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); send(clnode, length); }else if(srcMsg->getType() == MQTT_TYPE_CONNECT){ MQTTConnect* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(FORMAT, currentDateTime(), "CONNECT", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); clnode->connectSended(); send(clnode, length); }else if(srcMsg->getType() == MQTT_TYPE_DISCONNECT){ MQTTDisconnect* msg = static_cast(srcMsg); length = msg->serialize(_buffer); LOGWRITE(FORMAT, currentDateTime(), "DISCONNECT", RIGHTARROW, GREEN_BROKER, msgPrint(msg)); send(clnode, length); clnode->getStack()->disconnect(); } delete ev; } } int BrokerSendTask::send(ClientNode* clnode, int length){ int rc = -1; if(length <= 0){ return rc; } if( clnode->getStack()->isValid()){ rc = clnode->getStack()->send(_buffer, length); if(rc != length){ LOGWRITE("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37m Can't Xmit to the Broker. errno=%d\n", currentDateTime(), rc == -1 ? errno : 0); clnode->getStack()->disconnect(); clnode->disconnected(); }else{ _light->greenLight(true); } }else{ if(clnode->getStack()->connect(_host, _service)){ rc = clnode->getStack()->send(_buffer, length); if(rc != length){ LOGWRITE("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37m Can't Xmit to the Broker. errno=%d\n", currentDateTime(), rc == -1 ? errno : 0); clnode->getStack()->disconnect(); clnode->disconnected(); }else{ _light->greenLight(true); } }else{ LOGWRITE("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37m Can't connect to the Broker.\n", currentDateTime()); clnode->getStack()->disconnect(); clnode->disconnected(); } } return rc; } char* BrokerSendTask::msgPrint(MQTTMessage* msg){ char* buf = _printBuf; _light->blueLight(true); sprintf(buf, " %02X", *_buffer); buf += 3; for(int i = 0; i < msg->getRemainLength() + msg->getRemainLengthSize(); i++){ sprintf(buf, " %02X", *( _buffer + 1 + i)); buf += 3; } *buf = 0; _light->blueLight(false); return _printBuf; } ================================================ FILE: Gateway/src/BrokerSendTask.h ================================================ /* * BrokerSendTask.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef BROKERSENDTASK_H_ #define BROKERSENDTASK_H_ #include "lib/ProcessFramework.h" #include "lib/Messages.h" #include "GatewayResourcesProvider.h" class BrokerSendTask : public Thread{ MAGIC_WORD_FOR_TASK; public: BrokerSendTask(GatewayResourcesProvider* res); ~BrokerSendTask(); void run(); private: char* msgPrint(MQTTMessage* msg); int send(ClientNode* clnode, int length); GatewayResourcesProvider* _res; char _printBuf[SOCKET_MAXBUFFER_LENGTH * 5]; uint8_t _buffer[SOCKET_MAXBUFFER_LENGTH]; const char* _host; const char* _service; LightIndicator* _light; }; #endif /* BROKERSENDTASK_H_ */ ================================================ FILE: Gateway/src/ClientRecvTask.cpp ================================================ /* * ClientRecvTask.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "ClientRecvTask.h" #include "GatewayResourcesProvider.h" #include "GatewayDefines.h" #include "lib/ProcessFramework.h" #include "lib/Messages.h" #include "lib/ZBStack.h" #include "ErrorMessage.h" #include #include #include #include #include #include extern char* currentDateTime(); ClientRecvTask::ClientRecvTask(GatewayResourcesProvider* res){ _res = res; _res->attach(this); } ClientRecvTask::~ClientRecvTask(){ } void ClientRecvTask::run(){ NETWORK_CONFIG config; char param[TOMYFRAME_PARAM_MAX]; bool secure = false; // TCP #ifdef NETWORK_XBEE if(_res->getParam("BaudRate",param) == 0){ int val = atoi(param); switch(val){ case 9600: config.baudrate = B9600; break; case 19200: config.baudrate =B19200; break; case 38400: config.baudrate =B38400; break; case 57600: config.baudrate =B57600; break; case 115200: config.baudrate = B115200; break; default: THROW_EXCEPTION(ExFatal, ERRNO_APL_01, "Invalid baud rate!"); // ABORT } }else{ config.baudrate = B57600; } config.flag = O_RDONLY; if(_res->getParam("SerialDevice",param) == 0){ config.device = strdup(param); } if(_res->getParam("SecureConnection",param) == 0){ if(!strcasecmp(param, "YES")){ secure = true; // TLS } } _res->getClientList()->authorize(FILE_NAME_CLIENT_LIST, secure); _network = new Network(); #endif #ifdef NETWORK_UDP if(_res->getParam("BroadcastIP", param) == 0){ config.ipAddress = strdup(param); } if(_res->getParam("BroadcastPortNo",param) == 0){ config.gPortNo = atoi(param); } if(_res->getParam("GatewayPortNo",param) == 0){ config.uPortNo = atoi(param); } _network = _res->getNetwork(); #endif #ifdef NETWORK_XXXXX _network = _res->getNetwork(); #endif if(_network->initialize(config) < 0){ THROW_EXCEPTION(ExFatal, ERRNO_APL_01, "can't open the client port."); // ABORT } while(true){ NWResponse* resp = new NWResponse(); bool eventSetFlg = true; if(_network->getResponse(resp)){ Event* ev = new Event(); ClientNode* clnode = _res->getClientList()->getClient(resp->getClientAddress64(), resp->getClientAddress16()); if(!clnode){ if(resp->getMsgType() == MQTTSN_TYPE_CONNECT){ #ifdef NETWORK_XBEE ClientNode* node = _res->getClientList()->createNode(secure, resp->getClientAddress64(),0); #endif #ifdef NETWORK_UDP ClientNode* node = _res->getClientList()->createNode(secure, resp->getClientAddress64(), resp->getClientAddress16()); #endif #ifdef NETWORK_XXXXX ClientNode* node = _res->getClientList()->createNode(secure, resp->getClientAddress64(), resp->getClientAddress16()); #endif if(!node){ delete ev; LOGWRITE("Client is not authorized.\n"); continue; } MQTTSnConnect* msg = new MQTTSnConnect(); msg->absorb(resp); node->setClientAddress16(resp->getClientAddress16()); if(msg->getClientId()->size() > 0){ node->setNodeId(msg->getClientId()); } node->setClientRecvMessage(msg); ev->setClientRecvEvent(node); }else if(resp->getMsgType() == MQTTSN_TYPE_SEARCHGW){ MQTTSnSearchGw* msg = new MQTTSnSearchGw(); msg->absorb(resp); ev->setEvent(msg); }else{ eventSetFlg = false; } }else{ if (resp->getMsgType() == MQTTSN_TYPE_CONNECT){ MQTTSnConnect* msg = new MQTTSnConnect(); msg->absorb(resp); clnode->setClientRecvMessage(msg); clnode->setClientAddress16(resp->getClientAddress16()); ev->setClientRecvEvent(clnode); }else if(resp->getMsgType() == MQTTSN_TYPE_PUBLISH){ MQTTSnPublish* msg = new MQTTSnPublish(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if(resp->getMsgType() == MQTTSN_TYPE_PUBACK){ MQTTSnPubAck* msg = new MQTTSnPubAck(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if(resp->getMsgType() == MQTTSN_TYPE_PUBREL){ MQTTSnPubRel* msg = new MQTTSnPubRel(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_CONNECT){ MQTTSnConnect* msg = new MQTTSnConnect(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_PINGREQ){ MQTTSnPingReq* msg = new MQTTSnPingReq(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_DISCONNECT){ MQTTSnDisconnect* msg = new MQTTSnDisconnect(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_REGISTER){ MQTTSnRegister* msg = new MQTTSnRegister(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_REGACK){ MQTTSnRegAck* msg = new MQTTSnRegAck(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_UNSUBSCRIBE){ MQTTSnUnsubscribe* msg = new MQTTSnUnsubscribe(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_SUBSCRIBE){ MQTTSnSubscribe* msg = new MQTTSnSubscribe(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_WILLTOPIC){ MQTTSnWillTopic* msg = new MQTTSnWillTopic(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if (resp->getMsgType() == MQTTSN_TYPE_WILLMSG){ MQTTSnWillMsg* msg = new MQTTSnWillMsg(); msg->absorb(resp); clnode->setClientRecvMessage(msg); ev->setClientRecvEvent(clnode); }else if(resp->getMsgType() == MQTTSN_TYPE_SEARCHGW){ MQTTSnSearchGw* msg = new MQTTSnSearchGw(); clnode->disconnected(); msg->absorb(resp); ev->setEvent(msg); }else{ eventSetFlg = false; } } if(eventSetFlg){ _res->getGatewayEventQue()->post(ev); }else{ delete ev; } } delete resp; } } ================================================ FILE: Gateway/src/ClientRecvTask.h ================================================ /* * ClientRecvTask.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef CLIENTRECVTASK_H_ #define CLIENTRECVTASK_H_ #include "lib/ProcessFramework.h" #include "GatewayResourcesProvider.h" /*===================================== Class ClientRecvTask =====================================*/ class ClientRecvTask:public Thread{ MAGIC_WORD_FOR_TASK; public: ClientRecvTask(GatewayResourcesProvider*); ~ClientRecvTask(); void run(); private: GatewayResourcesProvider* _res; Network* _network; }; #endif /* CLIENTRECVTASK_H_ */ ================================================ FILE: Gateway/src/ClientSendTask.cpp ================================================ /* * ClientSendTask.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "ClientSendTask.h" #include "GatewayResourcesProvider.h" #include "lib/ProcessFramework.h" #include "lib/Messages.h" #include "ErrorMessage.h" #include #include #include #include #include #include ClientSendTask::ClientSendTask(GatewayResourcesProvider* res){ _res = res; _res->attach(this); } ClientSendTask::~ClientSendTask(){ } void ClientSendTask::run(){ NETWORK_CONFIG config; #ifdef NETWORK_XBEE char param[TOMYFRAME_PARAM_MAX]; bool secure = true; if(_res->getParam("BaudRate",param) == 0){ int val = atoi(param); switch(val){ case 9600: config.baudrate = B9600; break; case 19200: config.baudrate =B19200; break; case 38400: config.baudrate =B38400; break; case 57600: config.baudrate =B57600; break; case 115200: config.baudrate = B115200; break; default: THROW_EXCEPTION(ExFatal, ERRNO_APL_01, "Invalid baud rate!"); // ABORT } }else{ config.baudrate = B57600; } config.flag = O_WRONLY; if(_res->getParam("SerialDevice", param) == 0){ config.device = strdup(param); } if(_res->getParam("SecureConnection",param) == 0){ if(strcmp(param, "YES")){ secure = false; // TCP } } _res->getClientList()->authorize(FILE_NAME_CLIENT_LIST, secure); _network = new Network(); if(_network->initialize(config) < 0){ THROW_EXCEPTION(ExFatal, ERRNO_APL_01, "can't open the client port."); // ABORT } #endif #ifdef NETWORK_UDP _network = _res->getNetwork(); #endif #ifdef NETWORK_XXXXX _network = _res->getNetwork(); #endif while(true){ Event* ev = _res->getClientSendQue()->wait(); if(ev->getEventType() == EtClientSend){ MQTTSnMessage msg = MQTTSnMessage(); ClientNode* clnode = ev->getClientNode(); msg.absorb( clnode->getClientSendMessage() ); _network->unicast(clnode->getAddress64Ptr(), clnode->getAddress16(), msg.getMessagePtr(), msg.getMessageLength()); }else if(ev->getEventType() == EtBroadcast){ MQTTSnMessage msg = MQTTSnMessage(); msg.absorb( ev->getMqttSnMessage() ); _network->broadcast(msg.getMessagePtr(), msg.getMessageLength()); } delete ev; } } ================================================ FILE: Gateway/src/ClientSendTask.h ================================================ /* * ClientSendTask.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef CLIENTSENDTASK_H_ #define CLIENTSENDTASK_H_ #include "lib/ProcessFramework.h" #include "GatewayResourcesProvider.h" class ClientSendTask:public Thread{ MAGIC_WORD_FOR_TASK; public: ClientSendTask(GatewayResourcesProvider* res); ~ClientSendTask(); void run(); private: GatewayResourcesProvider* _res; Network* _network; }; #endif /* CLIENTSENDTASK_H_ */ ================================================ FILE: Gateway/src/ErrorMessage.h ================================================ /* * ErrorMessage.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef ERRORMESSAGE_H_ #define ERRORMESSAGE_H_ #define ERRNO_APL_01 1001 // can't open device. #define ERRNO_APL_02 1002 // Socket error #define ERRNO_APL_03 1003 // can't create a clientNode. #define ERRNO_APL_04 1004 // invalid GatewayId #define ERRNO_APL_05 1005 // KeepAliveTime is grater than 65536 Secs #endif /* ERRORMESSAGE_H_ */ ================================================ FILE: Gateway/src/GatewayControlTask.cpp ================================================ /* * GatewayControlTask.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include #include #include #include #include "GatewayControlTask.h" #include "lib/ProcessFramework.h" #include "GatewayResourcesProvider.h" #include "GatewayDefines.h" #include "lib/Messages.h" #include "ErrorMessage.h" extern char* currentDateTime(); extern uint16_t getUint16(uint8_t* pos); extern void setUint32(uint8_t* pos, uint32_t val); /*===================================== Class GatewayControlTask =====================================*/ GatewayControlTask::GatewayControlTask(GatewayResourcesProvider* res){ _res = res; _res->attach(this); _eventQue = 0; _protocol = MQTT_PROTOCOL_VER4; _loginId = ""; _password = ""; _secure = false; _stableNetwork = true; } GatewayControlTask::~GatewayControlTask(){ } void GatewayControlTask::run(){ Timer advertiseTimer; Timer sendUnixTimer; Event* ev = 0; char param[TOMYFRAME_PARAM_MAX]; if( _res->getParam("GatewayID", param) == 0){ _gatewayId = atoi(param); }else{ _gatewayId = 0; } if (_gatewayId == 0 || _gatewayId > 255){ THROW_EXCEPTION(ExFatal, ERRNO_APL_04, "Invalid Gateway Id"); // ABORT } int keepAlive = KEEP_ALIVE_TIME; if( _res->getParam("KeepAlive", param) == 0){ keepAlive =atoi(param); } if (keepAlive > 65536){ THROW_EXCEPTION(ExFatal, ERRNO_APL_05, "KeepAliveTime is grater than 65536 Secs"); // ABORT } if(_res->getParam("LoginID", param) == 0){ _loginId = strdup(param); } if(_res->getParam("Password", param) == 0){ _password = strdup(param); } if(_res->getParam("SecureConnection",param) == 0){ if(!strcasecmp(param, "YES")){ _secure = true; // TLS } } if(_res->getParam("NetworkIsStable",param) == 0){ if(!strcasecmp(param, "NO")){ _stableNetwork = false; } } _eventQue = _res->getGatewayEventQue(); advertiseTimer.start(keepAlive * 1000UL); LOGWRITE("%s TomyGateway started. %s %s\n", currentDateTime(),GATEWAY_NETWORK,GATEWAY_VERSION); while(true){ ev = _eventQue->timedwait(TIMEOUT_PERIOD); /*------ Check Client is Lost ---------*/ if(ev->getEventType() == EtTimeout){ ClientList* clist = _res->getClientList(); for( int i = 0; i < clist->getClientCount(); i++){ if((*clist)[i]){ (*clist)[i]->checkTimeover(); }else{ break; } } /*------ Check Keep Alive Timer & send Advertise ------*/ if(advertiseTimer.isTimeup()){ MQTTSnAdvertise* adv = new MQTTSnAdvertise(); adv->setGwId(_gatewayId); adv->setDuration(keepAlive); Event* ev1 = new Event(); ev1->setEvent(adv); //broadcast LOGWRITE(YELLOW_FORMAT2, currentDateTime(), "ADVERTISE", LEFTARROW, GATEWAY, msgPrint(adv)); _res->getClientSendQue()->post(ev1); advertiseTimer.start(keepAlive * 1000UL); sendUnixTimer.start(SEND_UNIXTIME_TIME * 1000UL); } /*------ Check Timer & send UixTime ------*/ if(sendUnixTimer.isTimeup()){ uint8_t buf[4]; uint32_t tm = time(0); setUint32(buf,tm); MQTTSnPublish* msg = new MQTTSnPublish(); msg->setTopicId(MQTTSN_TOPICID_PREDEFINED_TIME); msg->setTopicIdType(MQTTSN_TOPIC_TYPE_PREDEFINED); msg->setData(buf, 4); msg->setQos(0); Event* ev1 = new Event(); ev1->setEvent(msg); LOGWRITE(YELLOW_FORMAT2, currentDateTime(), "PUBLISH", LEFTARROW, GATEWAY, msgPrint(msg)); _res->getClientSendQue()->post(ev1); sendUnixTimer.stop(); } } /*------ Check SEARCHGW & send GWINFO ---------*/ else if(ev->getEventType() == EtBroadcast){ MQTTSnMessage* msg = ev->getMqttSnMessage(); LOGWRITE(YELLOW_FORMAT2, currentDateTime(), "SERCHGW", LEFTARROW, CLIENT, msgPrint(msg)); if(msg->getType() == MQTTSN_TYPE_SEARCHGW){ if(_res->getClientList()->getClientCount() < MAX_CLIENT_NODES ){ MQTTSnGwInfo* gwinfo = new MQTTSnGwInfo(); gwinfo->setGwId(_gatewayId); Event* ev1 = new Event(); ev1->setEvent(gwinfo); LOGWRITE(YELLOW_FORMAT1, currentDateTime(), "GWINFO", RIGHTARROW, CLIENT, msgPrint(gwinfo)); _res->getClientSendQue()->post(ev1); } } } /*------ Message form Clients ---------*/ else if(ev->getEventType() == EtClientRecv){ ClientNode* clnode = ev->getClientNode(); MQTTSnMessage* msg = clnode->getClientRecvMessage(); clnode->updateStatus(msg); if(msg->getType() == MQTTSN_TYPE_PUBLISH){ handleSnPublish(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_SUBSCRIBE){ handleSnSubscribe(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_UNSUBSCRIBE){ handleSnUnsubscribe(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_PINGREQ){ handleSnPingReq(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_PUBACK){ handleSnPubAck(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_WILLTOPIC){ handleSnWillTopic(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_WILLMSG){ handleSnWillMsg(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_CONNECT) { handleSnConnect(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_DISCONNECT){ handleSnDisconnect(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_REGISTER){ handleSnRegister(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_PUBREC){ handleSnPubRec(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_PUBREL){ handleSnPubRel(ev, clnode, msg); }else if(msg->getType() == MQTTSN_TYPE_PUBCOMP){ handleSnPubComp(ev, clnode, msg); }else{ LOGWRITE("%s Irregular ClientRecvMessage\n", currentDateTime()); } } /*------ Message form Broker ---------*/ else if(ev->getEventType() == EtBrokerRecv){ ClientNode* clnode = ev->getClientNode(); MQTTMessage* msg = clnode->getBrokerRecvMessage(); if(msg->getType() == MQTT_TYPE_PUBACK){ handlePuback(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_PINGRESP){ handlePingresp(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_SUBACK){ handleSuback(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_UNSUBACK){ handleUnsuback(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_CONNACK){ handleConnack(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_PUBLISH){ handlePublish(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_DISCONNECT){ handleDisconnect(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_PUBREC){ handlePubRec(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_PUBREL){ handlePubRel(ev, clnode, msg); }else if(msg->getType() == MQTT_TYPE_PUBCOMP){ handlePubComp(ev, clnode, msg); }else{ LOGWRITE("%s Irregular BrokerRecvMessage\n", currentDateTime()); } } delete ev; } } /*======================================================= Upstream ========================================================*/ /*------------------------------------------------------- * Upstream MQTTSnPublish -------------------------------------------------------*/ void GatewayControlTask::handleSnPublish(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(BLUE_FORMAT2, currentDateTime(), "PUBLISH", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnPublish* sPublish = new MQTTSnPublish(); MQTTPublish* mqMsg = new MQTTPublish(); sPublish->absorb(msg); Topic* tp = clnode->getTopics()->getTopic(sPublish->getTopicId()); if(tp || ((sPublish->getFlags() && MQTTSN_TOPIC_TYPE) == MQTTSN_TOPIC_TYPE_SHORT)){ if(tp){ mqMsg->setTopic(tp->getTopicName()); }else{ string str; mqMsg->setTopic(sPublish->getTopic(&str)); } if(sPublish->getMsgId()){ MQTTSnPubAck* sPuback = new MQTTSnPubAck(); sPuback->setMsgId(sPublish->getMsgId()); sPuback->setTopicId(sPublish->getTopicId()); if(clnode->getWaitedPubAck()){ delete clnode->getWaitedPubAck(); } clnode->setWaitedPubAck(sPuback); mqMsg->setMessageId(sPublish->getMsgId()); } mqMsg->setQos(sPublish->getQos()); if(sPublish->getFlags() & MQTTSN_FLAG_DUP){ mqMsg->setDup(); } if(sPublish->getFlags() & MQTTSN_FLAG_RETAIN){ mqMsg->setRetain(); } mqMsg->setPayload(sPublish->getData() , sPublish->getDataLength()); clnode->setBrokerSendMessage(mqMsg); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); }else{ if(sPublish->getMsgId()){ MQTTSnPubAck* sPuback = new MQTTSnPubAck(); sPuback->setMsgId(sPublish->getMsgId()); sPuback->setTopicId(sPublish->getTopicId()); sPuback->setReturnCode(MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); clnode->setClientSendMessage(sPuback); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(sPuback)); _res->getClientSendQue()->post(ev1); // Send PubAck INVALID_TOPIC_ID } } delete sPublish; } /*------------------------------------------------------- Upstream MQTTSnSubscribe -------------------------------------------------------*/ void GatewayControlTask::handleSnSubscribe(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT2, currentDateTime(), "SUBSCRIBE", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnSubscribe* sSubscribe = new MQTTSnSubscribe(); MQTTSubscribe* subscribe = new MQTTSubscribe(); sSubscribe->absorb(msg); uint8_t topicIdType = sSubscribe->getFlags() & 0x03; subscribe->setMessageId(sSubscribe->getMsgId()); if(sSubscribe->getFlags() & MQTTSN_FLAG_DUP ){ subscribe->setDup(); } if(sSubscribe->getFlags() & MQTTSN_FLAG_RETAIN){ subscribe->setRetain(); } subscribe->setQos(sSubscribe->getQos()); if(topicIdType != MQTTSN_FLAG_TOPICID_TYPE_RESV){ if(topicIdType == MQTTSN_FLAG_TOPICID_TYPE_PREDEFINED){ /*----- Predefined TopicId ------*/ MQTTSnSubAck* sSuback = new MQTTSnSubAck(); if(sSubscribe->getMsgId()){ // MessageID sSuback->setQos(sSubscribe->getQos()); sSuback->setTopicId(sSubscribe->getTopicId()); sSuback->setMsgId(sSubscribe->getMsgId()); if(sSubscribe->getTopicId() == MQTTSN_TOPICID_PREDEFINED_TIME){ sSuback->setReturnCode(MQTT_RC_ACCEPTED); }else{ sSuback->setReturnCode(MQTT_RC_REFUSED_IDENTIFIER_REJECTED); } clnode->setClientSendMessage(sSuback); Event* evsuback = new Event(); evsuback->setClientSendEvent(clnode); LOGWRITE(FORMAT1, currentDateTime(), "SUBACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(sSuback)); _res->getClientSendQue()->post(evsuback); } if(sSubscribe->getTopicId() == MQTTSN_TOPICID_PREDEFINED_TIME){ MQTTSnPublish* pub = new MQTTSnPublish(); pub->setTopicIdType(1); // pre-defined pub->setTopicId(MQTTSN_TOPICID_PREDEFINED_TIME); pub->setMsgId(clnode->getNextSnMsgId()); uint8_t buf[4]; uint32_t tm = time(0); setUint32(buf,tm); pub->setData(buf, 4); LOGWRITE(GREEN_FORMAT1, currentDateTime(), "PUBLISH", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(pub)); clnode->setClientSendMessage(pub); Event *evpub = new Event(); evpub->setClientSendEvent(clnode); _res->getClientSendQue()->post(evpub); } delete subscribe; }else{ uint16_t tpId; Topic* tp = clnode->getTopics()->getTopic(sSubscribe->getTopicName()); if (tp){ tpId = tp->getTopicId(); }else{ tpId = clnode->getTopics()->createTopic(sSubscribe->getTopicName()); } subscribe->setTopic(sSubscribe->getTopicName(), sSubscribe->getQos()); if(sSubscribe->getMsgId()){ MQTTSnSubAck* sSuback = new MQTTSnSubAck(); sSuback->setMsgId(sSubscribe->getMsgId()); sSuback->setTopicId(tpId); clnode->setWaitedSubAck(sSuback); } clnode->setBrokerSendMessage(subscribe); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); delete sSubscribe; return; } }else{ /*-- Irregular TopicIdType --*/ if(sSubscribe->getMsgId()){ MQTTSnSubAck* sSuback = new MQTTSnSubAck(); sSuback->setMsgId(sSubscribe->getMsgId()); sSuback->setTopicId(sSubscribe->getTopicId()); sSuback->setReturnCode(MQTT_RC_REFUSED_IDENTIFIER_REJECTED); clnode->setClientSendMessage(sSuback); Event* evun = new Event(); evun->setClientSendEvent(clnode); LOGWRITE(FORMAT1, currentDateTime(), "SUBACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(sSuback)); _res->getClientSendQue()->post(evun); // Send SUBACK to Client } delete subscribe; } delete sSubscribe; } /*------------------------------------------------------- Upstream MQTTSnUnsubscribe -------------------------------------------------------*/ void GatewayControlTask::handleSnUnsubscribe(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT2, currentDateTime(), "UNSUBSCRIBE", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnUnsubscribe* sUnsubscribe = new MQTTSnUnsubscribe(); MQTTUnsubscribe* unsubscribe = new MQTTUnsubscribe(); sUnsubscribe->absorb(msg); uint8_t topicIdType = sUnsubscribe->getFlags() & 0x03; unsubscribe->setMessageId(sUnsubscribe->getMsgId()); if(topicIdType != MQTTSN_FLAG_TOPICID_TYPE_RESV){ if(topicIdType == MQTTSN_FLAG_TOPICID_TYPE_SHORT){ unsubscribe->setTopicName(sUnsubscribe->getTopicName()); // TopicName }else if(clnode->getTopics()->getTopic(sUnsubscribe->getTopicId())){ if(topicIdType == MQTTSN_FLAG_TOPICID_TYPE_PREDEFINED) goto uslbl1; unsubscribe->setTopicName(sUnsubscribe->getTopicName()); } clnode->setBrokerSendMessage(unsubscribe); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); // UNSUBSCRIBE to Broker delete sUnsubscribe; return; } /*-- Irregular TopicIdType or MQTTSN_FLAG_TOPICID_TYPE_PREDEFINED --*/ uslbl1: if(sUnsubscribe->getMsgId()){ MQTTSnUnsubAck* sUnsuback = new MQTTSnUnsubAck(); sUnsuback->setMsgId(sUnsubscribe->getMsgId()); clnode->setClientSendMessage(sUnsuback); Event* evun = new Event(); evun->setClientSendEvent(clnode); LOGWRITE(FORMAT1, currentDateTime(), "UNSUBACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(sUnsuback)); _res->getClientSendQue()->post(evun); // Send UNSUBACK to Client } delete sUnsubscribe; } /*------------------------------------------------------- Upstream MQTTSnPingReq -------------------------------------------------------*/ void GatewayControlTask::handleSnPingReq(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT2, currentDateTime(), "PINGREQ", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTPingReq* pingReq = new MQTTPingReq(); clnode->setBrokerSendMessage(pingReq); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); } /*------------------------------------------------------- Upstream MQTTSnPubAck -------------------------------------------------------*/ void GatewayControlTask::handleSnPubAck(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(GREEN_FORMAT1, currentDateTime(), "PUBACK", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnPubAck* sPubAck = new MQTTSnPubAck(); MQTTPubAck* pubAck = new MQTTPubAck(); sPubAck->absorb(msg); pubAck->setMessageId(sPubAck->getMsgId()); clnode->setBrokerSendMessage(pubAck); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); delete sPubAck; } /*------------------------------------------------------- Upstream MQTTSnPubRec -------------------------------------------------------*/ void GatewayControlTask::handleSnPubRec(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(GREEN_FORMAT1, currentDateTime(), "PUBREC", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnPubRec* sPubRec = new MQTTSnPubRec(); MQTTPubRec* pubRec = new MQTTPubRec(); sPubRec->absorb(msg); pubRec->setMessageId(sPubRec->getMsgId()); clnode->setBrokerSendMessage(pubRec); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); delete sPubRec; } /*------------------------------------------------------- Upstream MQTTSnPubRel -------------------------------------------------------*/ void GatewayControlTask::handleSnPubRel(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(GREEN_FORMAT1, currentDateTime(), "PUBREL", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnPubRel* sPubRel = new MQTTSnPubRel(); MQTTPubRel* pubRel = new MQTTPubRel(); sPubRel->absorb(msg); pubRel->setMessageId(sPubRel->getMsgId()); clnode->setBrokerSendMessage(pubRel); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); delete sPubRel; } /*------------------------------------------------------- Upstream MQTTSnPubComp -------------------------------------------------------*/ void GatewayControlTask::handleSnPubComp(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(GREEN_FORMAT1, currentDateTime(), "PUBREL", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnPubComp* sPubComp= new MQTTSnPubComp(); MQTTPubComp* pubComp = new MQTTPubComp(); sPubComp->absorb(msg); pubComp->setMessageId(sPubComp->getMsgId()); clnode->setBrokerSendMessage(pubComp); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); delete sPubComp; } /*------------------------------------------------------- Upstream MQTTSnConnect -------------------------------------------------------*/ void GatewayControlTask::handleSnConnect(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT2, currentDateTime(), "CONNECT", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTConnect* mqMsg = 0; Topics* topics = clnode->getTopics(); MQTTSnConnect* sConnect = new MQTTSnConnect(); sConnect->absorb(msg); if (!_res->getClientList()->isAuthorized()){ clnode->setNodeId(sConnect->getClientId()); } if(clnode->isConnectSendable()){ mqMsg = new MQTTConnect(); mqMsg->setProtocol(_protocol); mqMsg->setClientId(clnode->getNodeId()); mqMsg->setKeepAliveTime(sConnect->getDuration()); if(_loginId != "" && _password != ""){ mqMsg->setUserName(&_loginId); mqMsg->setPassword(&_password); } clnode->setConnectMessage(mqMsg); if(sConnect->isCleanSession()){ if(topics){ delete topics; } topics = new Topics(); clnode->setTopics(topics); mqMsg->setCleanSessionFlg(); } } if(sConnect->isWillRequired()){ MQTTSnWillTopicReq* reqTopic = new MQTTSnWillTopicReq(); Event* evwr = new Event(); clnode->setClientSendMessage(reqTopic); evwr->setClientSendEvent(clnode); LOGWRITE(FORMAT1, currentDateTime(), "WILLTOPICREQ", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(reqTopic)); if(!clnode->isConnectSendable()){ clnode->setConnAckSaveFlg(); } _res->getClientSendQue()->post(evwr); // Send WILLTOPICREQ to Client }else{ if(clnode->isConnectSendable()){ clnode->setConnectMessage(0); Event* ev1 = new Event(); clnode->connectQued(); clnode->setBrokerSendMessage(mqMsg); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); } } delete sConnect; } /*------------------------------------------------------- Upstream MQTTSnWillTopic -------------------------------------------------------*/ void GatewayControlTask::handleSnWillTopic(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT1, currentDateTime(), "WILLTOPIC", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnWillTopic* snMsg = new MQTTSnWillTopic(); MQTTSnWillMsgReq* reqMsg = new MQTTSnWillMsgReq(); snMsg->absorb(msg); if(clnode->getConnectMessage()){ clnode->getConnectMessage()->setWillTopic(snMsg->getWillTopic()); clnode->getConnectMessage()->setWillQos(snMsg->getQos()); } clnode->setClientSendMessage(reqMsg); Event* evt = new Event(); evt->setClientSendEvent(clnode); LOGWRITE(FORMAT1, currentDateTime(), "WILLMSGREQ", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(reqMsg)); _res->getClientSendQue()->post(evt); // Send WILLMSGREQ to Client delete snMsg; } /*------------------------------------------------------- Upstream MQTTSnWillMsg -------------------------------------------------------*/ void GatewayControlTask::handleSnWillMsg(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT1, currentDateTime(), "WILLMSG", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnWillMsg* snMsg = new MQTTSnWillMsg(); snMsg->absorb(msg); if(clnode->getConnectMessage() && clnode->isConnectSendable()){ clnode->getConnectMessage()->setWillMessage(snMsg->getWillMsg()); clnode->connectQued(); clnode->setBrokerSendMessage(clnode->getConnectMessage()); clnode->setConnectMessage(0); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); }else{ MQTTSnConnack* connack = 0; if(!_secure && _stableNetwork){ connack = new MQTTSnConnack(); connack->setReturnCode(MQTTSN_RC_REJECTED_CONGESTION); clnode->setClientSendMessage(connack); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); //clnode->connackSended(connack->getReturnCode()); clnode->disconnected(); LOGWRITE(FORMAT1, currentDateTime(), "*CONNACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(connack)); _res->getClientSendQue()->post(ev1); }else{ connack = clnode->checkGetConnAck(); if(connack != 0){ LOGWRITE(CYAN_FORMAT1, currentDateTime(), "CONNACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(connack)); Event* ev1 = new Event(); clnode->setClientSendMessage(connack); clnode->connackSended(connack->getReturnCode()); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); }else if(clnode->isDisconnect() || clnode->isActive()){ connack = new MQTTSnConnack(); connack->setReturnCode(MQTTSN_RC_REJECTED_CONGESTION); clnode->setClientSendMessage(connack); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); clnode->connackSended(connack->getReturnCode()); LOGWRITE(FORMAT1, currentDateTime(), "*CONNACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(connack)); _res->getClientSendQue()->post(ev1); } } } delete snMsg; } /*------------------------------------------------------- Upstream MQTTSnDisconnect -------------------------------------------------------*/ void GatewayControlTask::handleSnDisconnect(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT2, currentDateTime(), "DISCONNECT", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnDisconnect* snMsg = new MQTTSnDisconnect(); MQTTDisconnect* mqMsg = new MQTTDisconnect(); snMsg->absorb(msg); clnode->setBrokerSendMessage(mqMsg); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); delete snMsg; } /*------------------------------------------------------- Upstream MQTTSnRegister -------------------------------------------------------*/ void GatewayControlTask::handleSnRegister(Event* ev, ClientNode* clnode, MQTTSnMessage* msg){ LOGWRITE(FORMAT2, currentDateTime(), "REGISTER", LEFTARROW, clnode->getNodeId()->c_str(), msgPrint(msg)); MQTTSnRegister* snMsg = new MQTTSnRegister(); MQTTSnRegAck* respMsg = new MQTTSnRegAck(); snMsg->absorb(msg); respMsg->setMsgId(snMsg->getMsgId()); uint16_t tpId = clnode->getTopics()->createTopic(snMsg->getTopicName()); respMsg->setTopicId(tpId); respMsg->setReturnCode(MQTTSN_RC_ACCEPTED); clnode->setClientSendMessage(respMsg); Event* evrg = new Event(); evrg->setClientSendEvent(clnode); LOGWRITE(FORMAT1, currentDateTime(), "REGACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(respMsg)); _res->getClientSendQue()->post(evrg); delete snMsg; } /*======================================================= Downstream ========================================================*/ /*------------------------------------------------------- Downstream MQTTPubAck -------------------------------------------------------*/ void GatewayControlTask::handlePuback(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTPubAck* mqMsg = static_cast(msg); MQTTSnPubAck* snMsg = clnode->getWaitedPubAck(); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); if(snMsg){ if(snMsg->getMsgId() == mqMsg->getMessageId()){ clnode->setWaitedPubAck(0); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); return; } } LOGWRITE("PUBACK MessageID is not the same as PUBLISH or PUBACK is not expected\n"); } /*------------------------------------------------------- Downstream MQTTPubRec -------------------------------------------------------*/ void GatewayControlTask::handlePubRec(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTSnPubRec* snMsg = new MQTTSnPubRec(); MQTTPubRec* mqMsg = static_cast(msg); snMsg->setMsgId(mqMsg->getMessageId()); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBREC", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } /*------------------------------------------------------- Downstream MQTTPubRel -------------------------------------------------------*/ void GatewayControlTask::handlePubRel(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTSnPubRel* snMsg = new MQTTSnPubRel(); MQTTPubRel* mqMsg = static_cast(msg); snMsg->setMsgId(mqMsg->getMessageId()); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBREL", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } /*------------------------------------------------------- Downstream MQTTPubComp -------------------------------------------------------*/ void GatewayControlTask::handlePubComp(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTSnPubComp* snMsg = new MQTTSnPubComp(); MQTTPubComp* mqMsg = static_cast(msg); snMsg->setMsgId(mqMsg->getMessageId()); LOGWRITE(BLUE_FORMAT1, currentDateTime(), "PUBCOMP", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } /*------------------------------------------------------- Downstream MQTTPingResp -------------------------------------------------------*/ void GatewayControlTask::handlePingresp(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTSnPingResp* snMsg = new MQTTSnPingResp(); //MQTTPingResp* mqMsg = static_cast(msg); LOGWRITE(FORMAT1, currentDateTime(), "PINGRESP", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } /*------------------------------------------------------- Downstream MQTTSubAck -------------------------------------------------------*/ void GatewayControlTask::handleSuback(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTSubAck* mqMsg = static_cast(msg); MQTTSnSubAck* snMsg = clnode->getWaitedSubAck(); if(snMsg){ if(snMsg->getMsgId() == mqMsg->getMessageId()){ clnode->setWaitedSubAck(0); if(mqMsg->getGrantedQos() == 0x80){ snMsg->setReturnCode(MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); }else{ snMsg->setReturnCode(MQTTSN_RC_ACCEPTED); snMsg->setQos(mqMsg->getGrantedQos()); } LOGWRITE(FORMAT1, currentDateTime(), "SUBACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } } } /*------------------------------------------------------- Downstream MQTTUnsubAck -------------------------------------------------------*/ void GatewayControlTask::handleUnsuback(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTUnsubAck* mqMsg = static_cast(msg); MQTTSnUnsubAck* snMsg = new MQTTSnUnsubAck(); snMsg->setMsgId(mqMsg->getMessageId()); LOGWRITE(FORMAT1, currentDateTime(), "UNSUBACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } /*------------------------------------------------------- Downstream MQTTConnAck -------------------------------------------------------*/ void GatewayControlTask::handleConnack(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTConnAck* mqMsg = static_cast(msg); MQTTSnConnack* snMsg = new MQTTSnConnack(); if(mqMsg->getReturnCd() == 0){ snMsg->setReturnCode(MQTTSN_RC_ACCEPTED); }else if(mqMsg->getReturnCd() == MQTT_RC_REFUSED_PROTOCOL_VERSION){ snMsg->setReturnCode(MQTTSN_RC_REJECTED_NOT_SUPPORTED); _protocol = (_protocol == MQTT_PROTOCOL_VER4) ? MQTT_PROTOCOL_VER3 : MQTT_PROTOCOL_VER4; }else if(mqMsg->getReturnCd() == MQTT_RC_REFUSED_SERVER_UNAVAILABLE){ snMsg->setReturnCode(MQTTSN_RC_REJECTED_CONGESTION); }else{ snMsg->setReturnCode(MQTTSN_RC_REJECTED_INVALID_TOPIC_ID); } if( clnode->checkConnAck(snMsg) == 0){ LOGWRITE(CYAN_FORMAT1, currentDateTime(), "CONNACK", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); clnode->connackSended(snMsg->getReturnCode()); clnode->setClientSendMessage(snMsg); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } // Send saved messages while sleeping if(clnode->isActive()){ while(clnode->getClientSleepMessage()){ Event* ev1 = new Event(); clnode->setClientSendMessage(clnode->getClientSleepMessage()); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } } } /*------------------------------------------------------- Downstream MQTTDisconnect -------------------------------------------------------*/ void GatewayControlTask::handleDisconnect(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTSnDisconnect* snMsg = new MQTTSnDisconnect(); //MQTTDisconnect* mqMsg = static_cast(msg); clnode->setClientSendMessage(snMsg); LOGWRITE(FORMAT1, currentDateTime(), "DISCONNECT", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } /*------------------------------------------------------- Downstream MQTTPublish -------------------------------------------------------*/ void GatewayControlTask::handlePublish(Event* ev, ClientNode* clnode, MQTTMessage* msg){ MQTTPublish* mqMsg = static_cast(msg); MQTTSnPublish* snMsg = new MQTTSnPublish(); string* tp = mqMsg->getTopic(); uint16_t tpId; if(tp->size() == 2){ tpId = getUint16((uint8_t*)tp); snMsg->setFlags(MQTTSN_TOPIC_TYPE_SHORT); }else{ tpId = clnode->getTopics()->getTopicId(tp); snMsg->setFlags(MQTTSN_TOPIC_TYPE_NORMAL); } if(tpId == 0){ /* ----- may be a publish message response of subscribed with '#' or '+' -----*/ tpId = clnode->getTopics()->createTopic(tp); if(tpId > 0){ MQTTSnRegister* regMsg = new MQTTSnRegister(); regMsg->setTopicId(tpId); regMsg->setTopicName(tp); if(clnode->isSleep()){ clnode->setClientSleepMessage(regMsg); LOGWRITE(FORMAT2, currentDateTime(), "REGISTER", RIGHTARROW, clnode->getNodeId()->c_str(), "is sleeping. Message was saved."); }else if(clnode->isActive()){ LOGWRITE(FORMAT2, currentDateTime(), "REGISTER", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(regMsg)); if(clnode->isSleep()){ clnode->setClientSleepMessage(regMsg); } clnode->setClientSendMessage(regMsg); Event* evrg = new Event(); evrg->setClientSendEvent(clnode); _res->getClientSendQue()->post(evrg); // Send Register first. } }else{ LOGWRITE("GatewayControlTask Can't create Topic %s\n", tp->c_str()); return; } } snMsg->setTopicId(tpId); snMsg->setMsgId(mqMsg->getMessageId()); snMsg->setData(mqMsg->getPayload(),mqMsg->getPayloadLength()); snMsg->setQos(mqMsg->getQos()); if(mqMsg->isDup()){ snMsg->setDup(); } if(mqMsg->isRetain()){ snMsg->setDup(); } if(clnode->isSleep()){ clnode->setClientSleepMessage(snMsg); LOGWRITE(GREEN_FORMAT1, currentDateTime(), "PUBLISH", RIGHTARROW, clnode->getNodeId()->c_str(), "is sleeping. Message was saved."); if(snMsg->getQos() == MQTTSN_FLAG_QOS_1){ snMsg->setQos(MQTTSN_FLAG_QOS_0); snMsg->setMsgId(0); MQTTPubAck* pubAck = new MQTTPubAck(); pubAck->setMessageId(mqMsg->getMessageId()); clnode->setBrokerSendMessage(pubAck); Event* ev1 = new Event(); ev1->setBrokerSendEvent(clnode); _res->getBrokerSendQue()->post(ev1); } }else if(clnode->isActive()){ clnode->setClientSendMessage(snMsg); LOGWRITE(GREEN_FORMAT1, currentDateTime(), "PUBLISH", RIGHTARROW, clnode->getNodeId()->c_str(), msgPrint(snMsg)); Event* ev1 = new Event(); ev1->setClientSendEvent(clnode); _res->getClientSendQue()->post(ev1); } } char* GatewayControlTask::msgPrint(MQTTSnMessage* msg){ char* buf = _printBuf; for(int i = 0; i < msg->getBodyLength(); i++){ sprintf(buf," %02X", *(msg->getBodyPtr() + i)); buf += 3; } *buf = 0; return _printBuf; } char* GatewayControlTask::msgPrint(MQTTMessage* msg){ uint8_t sbuf[512]; char* buf = _printBuf; msg->serialize(sbuf); for(int i = 0; i < msg->getRemainLength() + msg->getRemainLengthSize(); i++){ sprintf(buf, " %02X", *( sbuf + i)); buf += 3; } *buf = 0; return _printBuf; } ================================================ FILE: Gateway/src/GatewayControlTask.h ================================================ /* * GatewayControlTask.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef GATEWAYCONTROLTASK_H_ #define GATEWAYCONTROLTASK_H_ #include "lib/ZBStack.h" #include "lib/ProcessFramework.h" #include "GatewayResourcesProvider.h" /*===================================== Class GatewayControlTask =====================================*/ class GatewayControlTask : public Thread{ MAGIC_WORD_FOR_TASK; public: GatewayControlTask(GatewayResourcesProvider* res); ~GatewayControlTask(); void run(); private: EventQue* _eventQue; GatewayResourcesProvider* _res; char _printBuf[512]; uint8_t _protocol; uint8_t _gatewayId; string _loginId; string _password; bool _secure; bool _stableNetwork; void handleClientMessage(Event*); void handleBrokerMessage(Event*); void handleSnPublish(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnSubscribe(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnUnsubscribe(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnPingReq(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnPubAck(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnConnect(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnWillTopic(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnWillMsg(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnDisconnect(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnRegister(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnPubRec(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnPubRel(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handleSnPubComp(Event* ev, ClientNode* clnode, MQTTSnMessage* msg); void handlePuback(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handlePingresp(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handleSuback(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handleUnsuback(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handleConnack(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handlePublish(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handleDisconnect(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handlePubRec(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handlePubRel(Event* ev, ClientNode* clnode, MQTTMessage* msg); void handlePubComp(Event* ev, ClientNode* clnode, MQTTMessage* msg); char* msgPrint(MQTTSnMessage* msg); char* msgPrint(MQTTMessage* msg); }; #endif /* GATEWAYCONTROLTASK_H_ */ ================================================ FILE: Gateway/src/GatewayDefines.h ================================================ /* * GatewayDefines.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef GATEWAYDEFINES_H_ #define GATEWAYDEFINES_H_ #define GATEWAY_VERSION "(Ver 1.1.7)" #define BROKER "Broker" #define GREEN_BROKER "\x1b[0m\x1b[32mBroker\x1b[0m\x1b[37m" #define GATEWAY "Gateway" #define CLIENT "Client" #define LEFTARROW "<---" #define RIGHTARROW "--->" #define FORMAT "%s %-14s%-8s%-44s%s\n" #define FORMAT1 "%s %-14s%-8s%-26s%s\n" #define FORMAT2 "\n%s %-14s%-8s%-26s%s\n" #define RED_FORMAT1 "%s \x1b[0m\x1b[31m%-14s%-8s%-44s\x1b[0m\x1b[37m%s\n" #define RED_FORMAT2 "\n%s \x1b[0m\x1b[31m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define GREEN_FORMAT "%s \x1b[0m\x1b[32m%-14s%-8s%-44s\x1b[0m\x1b[37m%s\n" #define GREEN_FORMAT1 "%s \x1b[0m\x1b[32m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define GREEN_FORMAT2 "\n%s \x1b[0m\x1b[32m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define YELLOW_FORMAT1 "%s \x1b[0m\x1b[33m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define YELLOW_FORMAT2 "\n%s \x1b[0m\x1b[33m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define BLUE_FORMAT "%s \x1b[0m\x1b[34m%-14s%-8s%-44s\x1b[0m\x1b[37m%s\n" #define BLUE_FORMAT1 "%s \x1b[0m\x1b[34m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define BLUE_FORMAT2 "\n%s \x1b[0m\x1b[34m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define CYAN_FORMAT1 "%s \x1b[0m\x1b[36m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" #define SYAN_FORMAT2 "\n%s \x1b[0m\x1b[36m%-14s%-8s%-26s\x1b[0m\x1b[37m%s\n" /*=========================================== * Gateway Control Constants ===========================================*/ #define BROKER_HOST_NAME "localhost" #define BROKER_PORT "1883" #define KEEP_ALIVE_TIME 900 // 900 sec = 15 min #define TIMEOUT_PERIOD 10 // 10 sec = 10 sec #define SEND_UNIXTIME_TIME 30 // 30sec after KEEP_ALIVE_TIME #define MAX_CLIENT_NODES 500 /*========================================================== * Light Indicators ===========================================================*/ #define LIGHT_INDICATOR_GREEN 4 // RPi connector 16 #define LIGHT_INDICATOR_RED 5 // RPi connector 18 #define LIGHT_INDICATOR_BLUE 6 // RPi connector 22 #endif /* GATEWAYDEFINES_H_ */ ================================================ FILE: Gateway/src/GatewayResourcesProvider.cpp ================================================ /* * GatewayResourcesProvider.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "GatewayResourcesProvider.h" #include "GatewayDefines.h" #include "lib/ProcessFramework.h" #include "ErrorMessage.h" #include #include #include #include #ifdef RASPBERRY_PI #include #endif using namespace std; extern Process* theProcess; extern char* currentDateTime(); extern void setUint32(uint8_t* pos, uint32_t val); extern "C"{ int wiringPiSetup(void); void pinMode(int gpioNo, int mode); void digitalWrite(int gpioNo, int val); } GatewayResourcesProvider* theGatewayResources = 0; /*===================================== Class GatewayResourcesProvider =====================================*/ GatewayResourcesProvider::GatewayResourcesProvider(): MultiTaskProcess(){ theMultiTask = this; theProcess = this; resetRingBuffer(); _lightIndicator.greenLight(false); } GatewayResourcesProvider::~GatewayResourcesProvider(){ LOGWRITE("%s TomyGateway stop\n", currentDateTime()); _lightIndicator.greenLight(false); _lightIndicator.redLightOff(); } EventQue* GatewayResourcesProvider::getGatewayEventQue(){ return &_gatewayEventQue; } EventQue* GatewayResourcesProvider::getClientSendQue(){ return &_clientSendQue; } EventQue* GatewayResourcesProvider::getBrokerSendQue(){ return &_brokerSendQue; } ClientList* GatewayResourcesProvider::getClientList(){ return &_clientList; } Network* GatewayResourcesProvider::getNetwork(){ return &_network; } LightIndicator* GatewayResourcesProvider::getLightIndicator(){ return &_lightIndicator; } /*===================================== Class Client =====================================*/ ClientNode::ClientNode(){ ClientNode(false); } ClientNode::ClientNode(bool secure){ _msgId = 0; _snMsgId = 0; _status = Cstat_Disconnected; _keepAliveMsec = 0; _topics = new Topics(); _address64 = NWAddress64(); _nodeId = ""; _address16 = 0; _mqttConnect = 0; _waitedPubAck = 0; _waitedSubAck = 0; if(secure){ _stack = new TLSStack(true); }else{ _stack = new TLSStack(false); } _connAckSaveFlg = false; _connAck = 0; _waitWillMsgFlg = false; } ClientNode::~ClientNode(){ delete _topics; if(_mqttConnect){ delete _mqttConnect; } if(_waitedPubAck){ delete _waitedPubAck; } if(_waitedSubAck){ delete _waitedSubAck; } if(_stack){ delete _stack; } } void ClientNode::setWaitedPubAck(MQTTSnPubAck* msg){ _waitedPubAck = msg; } void ClientNode::setWaitedSubAck(MQTTSnSubAck* msg){ _waitedSubAck = msg; } MQTTSnPubAck* ClientNode::getWaitedPubAck(){ return _waitedPubAck; } MQTTSnSubAck* ClientNode::getWaitedSubAck(){ return _waitedSubAck; } uint16_t ClientNode::getNextMessageId(){ _msgId++; if (_msgId == 0){ _msgId++; } return _msgId; } uint8_t ClientNode::getNextSnMsgId(){ _snMsgId++; if (_snMsgId == 0){ _snMsgId++; } return _snMsgId; } MQTTMessage* ClientNode::getBrokerSendMessage(){ return _brokerSendMessageQue.getMessage(); } MQTTMessage* ClientNode::getBrokerRecvMessage(){ return _brokerRecvMessageQue.getMessage(); } MQTTSnMessage* ClientNode::getClientSendMessage(){ return _clientSendMessageQue.getMessage(); } MQTTSnMessage* ClientNode::getClientSleepMessage(){ return _clientSleepMessageQue.getMessage(); } MQTTSnMessage* ClientNode::getClientRecvMessage(){ return _clientRecvMessageQue.getMessage(); } MQTTConnect* ClientNode::getConnectMessage(){ return _mqttConnect; } TLSStack* ClientNode::getStack(){ return _stack; } void ClientNode::setBrokerSendMessage(MQTTMessage* msg){ _brokerSendMessageQue.push(msg); } void ClientNode::setBrokerRecvMessage(MQTTMessage* msg){ _brokerRecvMessageQue.push(msg); } void ClientNode::setClientSendMessage(MQTTSnMessage* msg){ _clientSendMessageQue.push(msg); } void ClientNode::setClientRecvMessage(MQTTSnMessage* msg){ updateStatus(msg); _clientRecvMessageQue.push(msg); } void ClientNode::setClientSleepMessage(MQTTSnMessage* msg){ updateStatus(msg); _clientSleepMessageQue.push(msg); } void ClientNode::setConnectMessage(MQTTConnect* msg){ _mqttConnect = msg; } void ClientNode::checkTimeover(){ if(_status == Cstat_Active && _keepAliveTimer.isTimeup()){ _status = Cstat_Lost; _stack->disconnect(); } } void ClientNode::setKeepAlive(MQTTSnMessage* msg){ MQTTSnConnect* cm = static_cast(msg); _keepAliveMsec = cm->getDuration() * 1000UL; _keepAliveTimer.start(_keepAliveMsec * 1.5); } bool ClientNode::isConnectSendable(){ if(_status == Cstat_Connecting || _status == Cstat_TryConnecting){ return false; }else{ return true; } } void ClientNode::updateStatus(ClientStatus stat){ _status = stat; } void ClientNode::connectSended(){ if(_status == Cstat_TryConnecting){ _status = Cstat_Connecting; if(_mqttConnect){ delete _mqttConnect; } _mqttConnect = 0; } } void ClientNode::connectQued(){ if(_status == Cstat_Disconnected || _status == Cstat_Lost){ _status = Cstat_TryConnecting; } } void ClientNode::disconnected(){ _status = Cstat_Disconnected; _connAckSaveFlg = false; _waitWillMsgFlg = false; } bool ClientNode::isDisconnect(){ return (_status == Cstat_Disconnected); } bool ClientNode::isActive(){ return (_status == Cstat_Active); } bool ClientNode::isSleep(){ return (_status == Cstat_Asleep); } void ClientNode::connackSended(int rc){ if(_status == Cstat_Connecting){ if(rc == MQTTSN_RC_ACCEPTED){ _status = Cstat_Active; }else{ disconnected(); } } } void ClientNode::updateStatus(MQTTSnMessage* msg){ if(((_status == Cstat_Disconnected) || (_status == Cstat_Lost)) && msg->getType() == MQTTSN_TYPE_CONNECT){ setKeepAlive(msg); }else if(_status == Cstat_Active){ switch(msg->getType()){ case MQTTSN_TYPE_PINGREQ: case MQTTSN_TYPE_PUBLISH: case MQTTSN_TYPE_SUBSCRIBE: case MQTTSN_TYPE_UNSUBSCRIBE: case MQTTSN_TYPE_PUBACK: case MQTTSN_TYPE_PUBCOMP: case MQTTSN_TYPE_PUBREL: case MQTTSN_TYPE_PUBREC: _keepAliveTimer.start(_keepAliveMsec * 1.5); break; case MQTTSN_TYPE_DISCONNECT:{ MQTTSnDisconnect* dcm = static_cast(msg); if(dcm->getDuration()){ _status = Cstat_Asleep; _keepAliveMsec = dcm->getDuration() * 1000UL; }else{ disconnected(); } } break; default: break; } }else if(_status == Cstat_Asleep){ if(msg->getType() == MQTTSN_TYPE_CONNECT){ setKeepAlive(msg); _status = Cstat_Connecting; }else if( msg->getType() == MQTTSN_TYPE_PINGREQ ){ MQTTSnPingReq* pr = static_cast(msg); if(pr->getClientId()) { _status = Cstat_Awake; } } }else if(_status == Cstat_Awake){ switch(msg->getType()){ case MQTTSN_TYPE_CONNECT: _status = Cstat_Connecting; setKeepAlive(msg); break; case MQTTSN_TYPE_DISCONNECT: disconnected(); break; case MQTTSN_TYPE_PINGRESP: _status = Cstat_Asleep; break; default: break; } } } int ClientNode::checkConnAck(MQTTSnConnack* msg){ if(_connAckSaveFlg || _waitWillMsgFlg){ _connAck = msg; return -1; }else{ return 0; } } MQTTSnConnack* ClientNode::checkGetConnAck(){ MQTTSnConnack* connAck = 0; if(!_connAck){ _waitWillMsgFlg = true; }else if(_connAckSaveFlg || _waitWillMsgFlg){ _connAckSaveFlg = 0; _waitWillMsgFlg = false; connAck = _connAck; _connAck = 0; return connAck; } return 0; } void ClientNode::setConnAckSaveFlg(){ _connAckSaveFlg = true; _connAck = 0; } void ClientNode::setWaitWillMsgFlg(){ _waitWillMsgFlg = true; } void ClientNode::deleteBrokerSendMessage(){ _brokerSendMessageQue.pop(); } void ClientNode::deleteBrokerRecvMessage(){ _brokerRecvMessageQue.pop(); } void ClientNode::deleteClientSendMessage(){ _clientSendMessageQue.pop(); } void ClientNode::deleteClientRecvMessage(){ _clientRecvMessageQue.pop(); } Topics* ClientNode::getTopics(){ return _topics; } NWAddress64* ClientNode::getAddress64Ptr(){ return &_address64; } uint16_t ClientNode::getAddress16(){ return _address16; } string* ClientNode::getNodeId(){ return &_nodeId; } void ClientNode::setMsb(uint32_t msb){ _address64.setMsb(msb); } void ClientNode::setLsb(uint32_t lsb){ _address64.setLsb(lsb); } void ClientNode::setClientAddress64(NWAddress64* addr){ setMsb(addr->getMsb()); setLsb(addr->getLsb()); } void ClientNode::setClientAddress16(uint16_t addr){ _address16 = addr; } void ClientNode::setNodeId(string* id){ _nodeId.assign(*id); } void ClientNode::setTopics(Topics* topics){ _topics = topics; } /*===================================== Class ClientList =====================================*/ ClientList::ClientList(){ _clientVector = new vector(); _clientVector->reserve(MAX_CLIENT_NODES); _clientCnt = 0; _authorize = false; } ClientList::~ClientList(){ _mutex.lock(); vector::iterator client = _clientVector->begin(); while((!_clientVector->empty()) && *client){ delete *client; _clientVector->erase(client); } _mutex.unlock(); } void ClientList::authorize(const char* fname, bool secure){ FILE* fp; char buf[258]; size_t pos; if((fp = fopen(fname, "r")) != 0){ while(fgets(buf, 256, fp) != 0){ string data = string(buf); while((pos = data.find_first_of("  \t\n")) != string::npos){ data.erase(pos, 1); } if(data.empty()){ continue; } pos = data.find_first_of(","); string addr = data.substr(0,pos); if(addr.size() == 16){ unsigned long msb, lsb; char hex[9]; strncpy(hex,addr.c_str(),8); msb = strtoul(hex,0,16); lsb = strtoul(addr.c_str() + 8,0,16); NWAddress64 addr64 = NWAddress64(msb, lsb); string id = data.substr(pos + 1); createNode(secure, &addr64,0,&id); }else{ LOGWRITE("Invalid address %s\n",data.c_str()); } } fclose(fp); _authorize = true; LOGWRITE("Clients are authorized.\n"); } } ClientNode* ClientList::createNode(bool secure, NWAddress64* addr64, uint16_t addr16, string* nodeId){ if(_clientCnt < MAX_CLIENT_NODES && !_authorize){ _mutex.lock(); vector::iterator client = _clientVector->begin(); while( client != _clientVector->end()){ if(((*client)->getAddress64Ptr() == addr64) && ((*client)->getAddress16() == addr16)){ return 0; }else{ ++client; } } ClientNode* node = new ClientNode(secure); node->setClientAddress64(addr64); node->setClientAddress16(addr16); if (nodeId){ node->setNodeId(nodeId); } _clientVector->push_back(node); _clientCnt++; _mutex.unlock(); return node; }else{ return getClient(addr64, addr16); } } void ClientList::erase(ClientNode* clnode){ uint16_t pos = 0; _mutex.lock(); vector::iterator client = _clientVector->begin(); while( (client != _clientVector->end()) && *client){ if((*client) == clnode){ delete(*client); _clientVector->erase(client); _clientCnt--; for(; pos < _clientCnt; pos++){ _clientVector[pos] = _clientVector[pos + 1]; } }else{ ++client; ++pos; } } _mutex.unlock(); } ClientNode* ClientList::getClient(NWAddress64* addr64, uint16_t addr16){ _mutex.lock(); vector::iterator client = _clientVector->begin(); while( (client != _clientVector->end()) && *client){ if(*((*client)->getAddress64Ptr()) == *addr64 && (*client)->getAddress16() == addr16){ _mutex.unlock(); return *client; }else{ ++client; } } _mutex.unlock(); return 0; } uint16_t ClientList::getClientCount(){ return _clientCnt; } ClientNode* ClientList::operator[](int pos){ _mutex.lock(); ClientNode* node = (*_clientVector)[pos]; _mutex.unlock(); return node; } bool ClientList::isAuthorized(){ return _authorize; } /*===================================== Class Event =====================================*/ Event::Event(){ _eventType = Et_NA; _clientNode = 0; _mqttSnMessage = 0; } Event::Event(EventType type){ _eventType = type; _clientNode = 0; _mqttSnMessage = 0; } Event::~Event(){ switch(_eventType){ case EtClientRecv: if(_clientNode){ _clientNode->deleteClientRecvMessage(); } break; case EtClientSend: if(_clientNode){ _clientNode->deleteClientSendMessage(); } break; case EtBrokerRecv: if(_clientNode){ _clientNode->deleteBrokerRecvMessage(); } break; case EtBrokerSend: if(_clientNode){ _clientNode->deleteBrokerSendMessage(); } break; case EtBroadcast: if(_mqttSnMessage){ delete _mqttSnMessage; } break; default: // Et_NA, EtTimeout break; } } EventType Event::getEventType(){ return _eventType; } void Event::setClientSendEvent(ClientNode* client){ _clientNode = client; _eventType = EtClientSend; } void Event::setClientRecvEvent(ClientNode* client){ _clientNode = client; _eventType = EtClientRecv; } void Event::setBrokerSendEvent(ClientNode* client){ _clientNode = client; _eventType = EtBrokerSend; } void Event::setBrokerRecvEvent(ClientNode* client){ _clientNode = client; _eventType = EtBrokerRecv; } void Event::setTimeout(){ _eventType = EtTimeout; } void Event::setEvent(MQTTSnMessage* msg){ _mqttSnMessage = msg; _eventType = EtBroadcast; } ClientNode* Event::getClientNode(){ return _clientNode; } MQTTSnMessage* Event::getMqttSnMessage(){ return _mqttSnMessage; } /*===================================== Class LightIndicator =====================================*/ LightIndicator::LightIndicator(){ _gpioAvailable = false; init(); _greenStatus = true; _blueStatus = true; greenLight(false); blueLight(false); } LightIndicator::~LightIndicator(){ } void LightIndicator::init(){ #ifdef RASPBERRY_PI if(wiringPiSetup() != -1){ pinMode(LIGHT_INDICATOR_GREEN, OUTPUT); pinMode(LIGHT_INDICATOR_RED, OUTPUT); pinMode(LIGHT_INDICATOR_BLUE, OUTPUT); _gpioAvailable = true; } #endif } void LightIndicator::greenLight(bool on){ if(on){ if(_greenStatus == 0){ _greenStatus = 1; //Turn Green on & turn Red off lit(LIGHT_INDICATOR_GREEN, 1); lit(LIGHT_INDICATOR_RED, 0); } }else{ if(_greenStatus == 1){ _greenStatus = 0; //Turn Green off & turn Red on lit(LIGHT_INDICATOR_GREEN, 0); lit(LIGHT_INDICATOR_RED, 1); } } } void LightIndicator::redLightOff(){ lit(LIGHT_INDICATOR_RED, 0); } void LightIndicator::blueLight(bool on){ if(on){ if(_blueStatus == 0){ _blueStatus = 1; lit(LIGHT_INDICATOR_BLUE, 1); } }else{ if(_blueStatus == 1){ _blueStatus = 0; lit(LIGHT_INDICATOR_BLUE, 0); } } } void LightIndicator::lit(int gpioNo, int onoff){ #ifdef RASPBERRY_PI if(_gpioAvailable){ digitalWrite(gpioNo,onoff); } #endif } ================================================ FILE: Gateway/src/GatewayResourcesProvider.h ================================================ /* * GatewayResourcesProvider.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef GATEWAY_RESOURCES_PROVIDER_H_ #define GATEWAY_RESOURCES_PROVIDER_H_ #include "lib/ProcessFramework.h" #include "lib/Messages.h" #include "lib/Topics.h" #include "lib/TLSStack.h" #define FILE_NAME_CLIENT_LIST "/usr/local/etc/tomygateway/config/clientList.conf" /*===================================== Class MessageQue =====================================*/ template class MessageQue{ public: MessageQue(); ~MessageQue(); T* getMessage(); void push(T*); void pop(); void clear(); private: queue _que; Mutex _mutex; }; enum ClientStatus { Cstat_Disconnected = 0, Cstat_TryConnecting, Cstat_Connecting, Cstat_Active, Cstat_Asleep, Cstat_Awake, Cstat_Lost }; /*===================================== Class ClientNode =====================================*/ class ClientNode{ public: ClientNode(); ClientNode(bool secure); ~ClientNode(); MQTTMessage* getBrokerSendMessage(); MQTTMessage* getBrokerRecvMessage(); MQTTSnMessage* getClientSendMessage(); MQTTSnMessage* getClientRecvMessage(); MQTTConnect* getConnectMessage(); MQTTSnPubAck* getWaitedPubAck(); MQTTSnSubAck* getWaitedSubAck(); MQTTSnMessage* getClientSleepMessage(); void setBrokerSendMessage(MQTTMessage*); void setBrokerRecvMessage(MQTTMessage*); void setClientSendMessage(MQTTSnMessage*); void setClientRecvMessage(MQTTSnMessage*); void setConnectMessage(MQTTConnect*); void setWaitedPubAck(MQTTSnPubAck* msg); void setWaitedSubAck(MQTTSnSubAck* msg); void setClientSleepMessage(MQTTSnMessage*); void deleteBrokerSendMessage(); void deleteBrokerRecvMessage(); void deleteClientSendMessage(); void deleteClientRecvMessage(); void checkTimeover(); void updateStatus(MQTTSnMessage*); void updateStatus(ClientStatus); void connectSended(); void connackSended(int rc); void connectQued(); void disconnected(); bool isConnectSendable(); uint16_t getNextMessageId(); uint8_t getNextSnMsgId(); Topics* getTopics(); TLSStack* getStack(); NWAddress64* getAddress64Ptr(); uint16_t getAddress16(); string* getNodeId(); void setMsb(uint32_t); void setLsb(uint32_t); void setClientAddress16(uint16_t addr); void setClientAddress64(NWAddress64* addr); void setTopics(Topics* topics); void setNodeId(string* id); int checkConnAck(MQTTSnConnack* msg); MQTTSnConnack* checkGetConnAck(); void setConnAckSaveFlg(); void setWaitWillMsgFlg(); bool isDisconnect(); bool isActive(); bool isSleep(); private: void setKeepAlive(MQTTSnMessage* msg); MessageQue _brokerSendMessageQue; MessageQue _brokerRecvMessageQue; MessageQue _clientSendMessageQue; MessageQue _clientRecvMessageQue; MessageQue _clientSleepMessageQue; MQTTConnect* _mqttConnect; MQTTSnPubAck* _waitedPubAck; MQTTSnSubAck* _waitedSubAck; uint16_t _msgId; uint8_t _snMsgId; Topics* _topics; ClientStatus _status; uint32_t _keepAliveMsec; Timer _keepAliveTimer; TLSStack* _stack; NWAddress64 _address64; uint16_t _address16; string _nodeId; bool _connAckSaveFlg; bool _waitWillMsgFlg; MQTTSnConnack* _connAck; }; /*===================================== Class ClientList =====================================*/ class ClientList{ public: ClientList(); ~ClientList(); void authorize(const char* fileName, bool secure); void erase(ClientNode*); ClientNode* getClient(NWAddress64* addr64, uint16_t addr16); ClientNode* createNode(bool secure, NWAddress64* addr64, uint16_t addr16, string* nodeId = 0); uint16_t getClientCount(); ClientNode* operator[](int); bool isAuthorized(); private: vector* _clientVector; Mutex _mutex; uint16_t _clientCnt; bool _authorize; }; /*===================================== Class Event ====================================*/ enum EventType{ Et_NA = 0, EtTimeout, EtBrokerSend, EtBrokerRecv, EtClientSend, EtClientRecv, EtBroadcast, EtSocketAlive }; class Event{ public: Event(); Event(EventType); ~Event(); EventType getEventType(); void setClientSendEvent(ClientNode*); void setBrokerSendEvent(ClientNode*); void setClientRecvEvent(ClientNode*); void setBrokerRecvEvent(ClientNode*); void setEvent(MQTTSnMessage*); void setTimeout(); ClientNode* getClientNode(); MQTTSnMessage* getMqttSnMessage(); private: EventType _eventType; ClientNode* _clientNode; MQTTSnMessage* _mqttSnMessage; }; /*===================================== Class LightIndicator =====================================*/ class LightIndicator{ public: LightIndicator(); ~LightIndicator(); void greenLight(bool); void blueLight(bool); void redLightOff(); private: void init(); void lit(int gpioNo, int onoff); bool _greenStatus; bool _blueStatus; bool _gpioAvailable; }; /*===================================== Class GatewayResourcesProvider =====================================*/ class GatewayResourcesProvider: public MultiTaskProcess{ public: GatewayResourcesProvider(); ~GatewayResourcesProvider(); EventQue* getGatewayEventQue(); EventQue* getClientSendQue(); EventQue* getBrokerSendQue(); ClientList* getClientList(); Network* getNetwork(); LightIndicator* getLightIndicator(); private: ClientList _clientList; EventQue _gatewayEventQue; EventQue _brokerSendQue; EventQue _clientSendQue; Network _network; LightIndicator _lightIndicator; }; /*===================================== Class MessageQue Implementation =====================================*/ template MessageQue::MessageQue(){ } template MessageQue::~MessageQue(){ clear(); } template T* MessageQue::getMessage(){ T* msg; if(!_que.empty()){ _mutex.lock(); msg = _que.front(); _mutex.unlock(); return msg; }else{ return 0; } } template void MessageQue::push(T* msg){ _mutex.lock(); _que.push(msg); _mutex.unlock(); } template void MessageQue::pop(){ if(!_que.empty()){ _mutex.lock(); delete _que.front(); _que.pop(); _mutex.unlock(); } } template void MessageQue::clear(){ _mutex.lock(); while(!_que.empty()){ delete _que.front(); _que.pop(); } _mutex.unlock(); } #endif /* GATEWAY_RESOURCES_PROVIDER_H_ */ ================================================ FILE: Gateway/src/TomyGateway.cpp ================================================ /* * A_ProgramStructure.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "GatewayResourcesProvider.h" #include "ClientRecvTask.h" #include "ClientSendTask.h" #include "BrokerRecvTask.h" #include "BrokerSendTask.h" #include "GatewayControlTask.h" #include "lib/ProcessFramework.h" const char* theCmdlineParameter = "b:d:i:h:p:g:u:l:w:k:"; /************************************** * Gateway Application **************************************/ GatewayResourcesProvider gwR = GatewayResourcesProvider(); GatewayControlTask th0 = GatewayControlTask(&gwR); ClientRecvTask th1 = ClientRecvTask(&gwR); ClientSendTask th2 = ClientSendTask(&gwR); BrokerRecvTask th3 = BrokerRecvTask(&gwR); BrokerSendTask th4 = BrokerSendTask(&gwR); ================================================ FILE: Gateway/src/lib/Defines.h ================================================ /* * Defines.h * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef DEFINES_H_ #define DEFINES_H_ /*================================= * Network Selection =================================*/ #if ! defined(NETWORK_UDP) && ! defined (NETWORK_XXXXX) #define NETWORK_XBEE #define GATEWAY_NETWORK "Network is XBee." #endif #ifdef NETWORK_UDP #define GATEWAY_NETWORK "Network is UDP." #endif #ifdef NETWORK_XXXXX #define GATEWAY_NETWORK "Network is XXXXX." #endif /*================================= * CPU TYPE ==================================*/ #define CPU_LITTLEENDIANN //#define CPU_BIGENDIANN /*================================= * Debug LOG ==================================*/ //#define DEBUG_NWSTACK /*================================= Debug Print functions ==================================*/ #ifdef DEBUG_NWSTACK #define D_NWSTACK(...) printf(__VA_ARGS__) #else #define D_NWSTACK(...) #endif /*================================= * Data Type ==================================*/ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef struct { long baudrate; char* device; unsigned int flag; }XBeeConfig; typedef struct { char* ipAddress; uint16_t gPortNo; uint16_t uPortNo; }UdpConfig; typedef struct { uint8_t param1; uint16_t param2; uint16_t param3; }XXXXXConfig; #ifdef NETWORK_XBEE #define NETWORK_CONFIG XBeeConfig #endif #ifdef NETWORK_UDP #define NETWORK_CONFIG UdpConfig #endif #ifdef NETWORK_XXXXX #define NETWORK_CONFIG XXXXXConfig #endif #endif /* DEFINES_H_ */ ================================================ FILE: Gateway/src/lib/Messages.cpp ================================================ /* * Messages.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "Defines.h" #include "ZBStack.h" #include "UDPStack.h" #include "ProcessFramework.h" #include "Messages.h" #include #include #include #include extern uint16_t getUint16(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); extern uint8_t* mqcalloc(uint8_t length); extern void utfSerialize(uint8_t* pos, string str); using namespace tomyGateway; bool isUtf8Valid(string& string) { int c,i,ix,n,j; for (i=0, ix=string.length(); i < ix; i++) { c = (uint8_t) string[i]; if (0x00 <= c && c <= 0x7f){ n=0; // 0bbbbbbb }else if ((c & 0xE0) == 0xC0){ n=1; // 110bbbbb }else if ( c==0xed && i<(ix-1) && ((uint8_t)string[i+1] & 0xa0)==0xa0){ return false; //U+D800 to U+DFFF }else if ((c & 0xF0) == 0xE0){ n=2; // 1110bbbb }else if ((c & 0xF8) == 0xF0){ n=3; // 11110bbb }else{ return false; } for (j=0; j 255){ _length = bodyLength + 4; }else{ _length = bodyLength + MQTTSN_HEADER_SIZE; } allocate(); memcpy(getBodyPtr(), body, bodyLength); } void MQTTSnMessage::allocate(){ if ( _length ) { if (_message){ free(_message); } _message = mqcalloc(_length); if(_length > 255){ *_message = 0x01; setUint32(_message + 1, _length); *(_message + 3) = _type; }else{ *_message = _length; *(_message + 1) = _type; } } } uint16_t MQTTSnMessage::getMessageLength(){ return _length; } uint8_t MQTTSnMessage::getType(){ return _type; } uint8_t* MQTTSnMessage::getBodyPtr(){ if( _length > 255){ return _message + 4; }else{ return _message + MQTTSN_HEADER_SIZE; } } uint16_t MQTTSnMessage::getBodyLength(){ if(_length > 255){ return _length - 4; }else{ return _length - MQTTSN_HEADER_SIZE; } } bool MQTTSnMessage::getMessage(uint16_t pos, uint8_t& val){ if(pos < 0 || pos >= _length){ return false; }else{ val = *(getMessagePtr() + pos); return true; } } uint8_t* MQTTSnMessage::getMessagePtr(){ return _message; } void MQTTSnMessage::absorb(MQTTSnMessage* src){ setMessageLength(src->getMessageLength()); setType(src->getType()); allocate(); memcpy(getBodyPtr(), src->getBodyPtr(), (size_t)src->getBodyLength()); } void MQTTSnMessage::absorb(NWResponse* src){ setMessageLength(src->getPayloadLength()); setType(src->getMsgType()); allocate(); memcpy(_message,src->getPayloadPtr(), (size_t)src->getPayloadLength()); } /*===================================== Class MQTTSnAdvertise ======================================*/ MQTTSnAdvertise::MQTTSnAdvertise():MQTTSnMessage(){ setMessageLength(5); setType(MQTTSN_TYPE_ADVERTISE); allocate(); } MQTTSnAdvertise::~MQTTSnAdvertise(){ } void MQTTSnAdvertise::setGwId(uint8_t id){ getBodyPtr()[0] = id; } void MQTTSnAdvertise::setDuration(uint16_t sec){ uint8_t* pos = getBodyPtr() + 1; setUint16(pos, sec); } uint8_t MQTTSnAdvertise::getGwId(){ return getBodyPtr()[0]; } uint16_t MQTTSnAdvertise::getDuration(){ uint8_t* pos = getBodyPtr() + 1; return getUint16(pos); } /*===================================== Class MQTTSnSearchGw ======================================*/ MQTTSnSearchGw::MQTTSnSearchGw(){ setMessageLength(3); setType(MQTTSN_TYPE_SEARCHGW); allocate(); } MQTTSnSearchGw::~MQTTSnSearchGw(){ } void MQTTSnSearchGw::setRadius(uint8_t radius){ getBodyPtr()[0] = radius; } uint8_t MQTTSnSearchGw::getRadius(){ return getBodyPtr()[0]; } void MQTTSnSearchGw::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnGwInfo ======================================*/ MQTTSnGwInfo::MQTTSnGwInfo(){ setMessageLength(3); setType(MQTTSN_TYPE_GWINFO); allocate(); } MQTTSnGwInfo::~MQTTSnGwInfo(){ } uint8_t MQTTSnGwInfo::getGwId(){ return getBodyPtr()[0]; } void MQTTSnGwInfo::setGwId(uint8_t id){ getBodyPtr()[0] = id; } /*===================================== Class MQTTSnConnect ======================================*/ MQTTSnConnect::MQTTSnConnect(){ setMessageLength(6); allocate(); setType(MQTTSN_TYPE_CONNECT); getBodyPtr()[1] = MQTTSN_PROTOCOL_ID; } MQTTSnConnect::MQTTSnConnect(string* id){ setMessageLength(id->size() + 6); allocate(); setType(MQTTSN_TYPE_CONNECT); getBodyPtr()[1] = MQTTSN_PROTOCOL_ID; id->copy((char*)getBodyPtr() + 4,id->size(),0); } MQTTSnConnect::~MQTTSnConnect(){ } void MQTTSnConnect::setFlags(uint8_t flg){ getBodyPtr()[0] = flg & 0x0c; } uint8_t MQTTSnConnect::getFlags(){ return getBodyPtr()[0]; } bool MQTTSnConnect::isCleanSession(){ return getBodyPtr()[0] & MQTTSN_FLAG_CLEAN; } bool MQTTSnConnect::isWillRequired(){ return getBodyPtr()[0] & MQTTSN_FLAG_WILL; } void MQTTSnConnect::setDuration(uint16_t sec){ setUint16((uint8_t*)getBodyPtr() + 2, sec); } uint16_t MQTTSnConnect::getDuration(){ return getUint16((uint8_t*)getBodyPtr() + 2); } void MQTTSnConnect::setClientId(string id){ _clientId = id; } string* MQTTSnConnect::getClientId(){ _clientId = string((char*)(getBodyPtr() + 4), getMessageLength() - 6 ); return &_clientId; } void MQTTSnConnect::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnConnect::absorb(MQTTSnMessage* src){ setMessageLength(src->getMessageLength()); setClientId(*getClientId()); setFlags(src->getBodyPtr()[0]); setDuration(getUint16(src->getBodyPtr() + 2)); MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnConnack ======================================*/ MQTTSnConnack::MQTTSnConnack(){ setMessageLength(3); setType(MQTTSN_TYPE_CONNACK); allocate(); } MQTTSnConnack::~MQTTSnConnack(){ } void MQTTSnConnack::setReturnCode(uint8_t rc){ getBodyPtr()[0] = rc; } uint8_t MQTTSnConnack::getReturnCode(){ return getBodyPtr()[0]; } /*===================================== Class MQTTSnWillTopicReq ======================================*/ MQTTSnWillTopicReq::MQTTSnWillTopicReq(){ setMessageLength(2); setType(MQTTSN_TYPE_WILLTOPICREQ); allocate(); } MQTTSnWillTopicReq::~MQTTSnWillTopicReq(){ } /*===================================== Class MQTTSnWillTopic ======================================*/ MQTTSnWillTopic::MQTTSnWillTopic(){ setMessageLength(3); setType(MQTTSN_TYPE_WILLTOPIC); allocate(); _flags = 0; } MQTTSnWillTopic::~MQTTSnWillTopic(){ } void MQTTSnWillTopic::setFlags(uint8_t flags){ flags &= 0x70; if (_message){ getBodyPtr()[0] = flags; } _flags = flags; } void MQTTSnWillTopic::setWillTopic(string* topic){ setMessageLength(topic->size() + 3); allocate(); topic->copy((char*)getBodyPtr() + 1,topic->size() ,0); _message[2] = _flags; _topicName = *topic; } string* MQTTSnWillTopic::getWillTopic(){ if (_message){ return &_topicName; }else{ return 0; } } bool MQTTSnWillTopic::isWillRequired(){ return getBodyPtr()[0] && MQTTSN_FLAG_WILL; } uint8_t MQTTSnWillTopic::getQos(){ return (_flags && (MQTTSN_FLAG_QOS_1 | MQTTSN_FLAG_QOS_2)) >> 5; } void MQTTSnWillTopic::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnWillTopic::absorb(MQTTSnMessage* src){ setFlags(src->getBodyPtr()[0]); _topicName = string((char*)src->getBodyPtr() + 1, src->getMessageLength() - 3); MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnWillMsgReq ======================================*/ MQTTSnWillMsgReq::MQTTSnWillMsgReq(){ setMessageLength(2); setType(MQTTSN_TYPE_WILLMSGREQ); allocate(); } MQTTSnWillMsgReq::~MQTTSnWillMsgReq(){ } /*===================================== Class MQTTSnWillMsg ======================================*/ MQTTSnWillMsg::MQTTSnWillMsg(){ setMessageLength(2); setType(MQTTSN_TYPE_WILLMSG); allocate(); } MQTTSnWillMsg::~MQTTSnWillMsg(){ } void MQTTSnWillMsg::setWillMsg(string* msg){ setMessageLength(2 + msg->size()); allocate(); msg->copy((char*)getBodyPtr(),msg->size(),0); _willMsg = *msg; } string* MQTTSnWillMsg::getWillMsg(){ return &_willMsg; } void MQTTSnWillMsg::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnWillMsg::absorb(MQTTSnMessage* src){ _willMsg = string((char*)src->getBodyPtr(), src->getMessageLength() - 2); MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnRegister ======================================*/ MQTTSnRegister::MQTTSnRegister(){ setMessageLength(6); setType(MQTTSN_TYPE_REGISTER); allocate(); _topicId = 0; _msgId = 0; } MQTTSnRegister::~MQTTSnRegister(){ } void MQTTSnRegister::setTopicId(uint16_t topicId){ if (_message){ setUint16(getBodyPtr(), topicId); } _topicId = topicId; } uint16_t MQTTSnRegister::getTopicId(){ return _topicId; } void MQTTSnRegister::setMsgId(uint16_t msgId){ if (_message){ setUint16(getBodyPtr() + 2, msgId); } _msgId = msgId; } uint16_t MQTTSnRegister::getMsgId(){ return _msgId; } void MQTTSnRegister::setTopicName(string* topicName){ setMessageLength(6 + topicName->size()); allocate(); topicName->copy((char*)getBodyPtr() + 4, topicName->size(),0); setTopicId(_topicId); setMsgId(_msgId); } /* void MQTTSnRegister::setFrame(uint8_t* data, uint8_t len){ //setMessageLength(len + MQTTSN_HEADER_SIZE); //allocate(); //memcpy(getBodyPtr(), data, len); _topicId = getUint16(data); _msgId = getUint16(data + 2); _topicName = string((char*)getBodyPtr() + 4, len - 4); } void MQTTSnRegister::setFrame(NWResponse* resp){ setFrame(resp->getPayloadPtr() + MQTTSN_HEADER_SIZE, resp->getPayloadPtr()[0] - MQTTSN_HEADER_SIZE); } */ string* MQTTSnRegister::getTopicName(){ return &_topicName; } void MQTTSnRegister::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnRegister::absorb(MQTTSnMessage* src){ _topicId = getUint16((uint8_t*)(src->getBodyPtr())); _msgId = getUint16((uint8_t*)(src->getBodyPtr() +2)); _topicName = string((char*)src->getBodyPtr() + 4, src->getMessageLength() - 6); MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnRegAck ======================================*/ MQTTSnRegAck::MQTTSnRegAck(){ setMessageLength(7); setType(MQTTSN_TYPE_REGACK); allocate(); } MQTTSnRegAck::~MQTTSnRegAck(){ } void MQTTSnRegAck::setTopicId(uint16_t topicId){ setUint16((uint8_t*)getBodyPtr(), topicId); } uint16_t MQTTSnRegAck::getTopicId(){ return getUint16((unsigned char*)getBodyPtr()); } void MQTTSnRegAck::setMsgId(uint16_t msgId){ setUint16(getBodyPtr()+ 2,msgId); } uint16_t MQTTSnRegAck::getMsgId(){ return getUint16((unsigned char*)getBodyPtr()+ 2); } void MQTTSnRegAck::setReturnCode(uint8_t rc){ getBodyPtr()[4] = rc; } uint8_t MQTTSnRegAck::getReturnCode(){ return (uint8_t)getBodyPtr()[4]; } void MQTTSnRegAck::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnPublish ======================================*/ MQTTSnPublish::MQTTSnPublish(){ setMessageLength(7); setType(MQTTSN_TYPE_PUBLISH); allocate(); _topicId = 0; _msgId = 0; _flags = 0; } MQTTSnPublish::~MQTTSnPublish(){ } void MQTTSnPublish::setFlags(uint8_t flags){ _flags = flags & 0xf3; getBodyPtr()[0] = _flags ; } uint8_t MQTTSnPublish::getFlags(){ return _flags; } uint8_t MQTTSnPublish::getTopicType(){ return _flags & MQTTSN_TOPIC_TYPE; } uint8_t MQTTSnPublish::getQos(){ return ((_flags >> 5) & 0x03); } void MQTTSnPublish::setQos(uint8_t qos){ _flags &= 0x9f; if( qos == 1){ _flags |= MQTTSN_FLAG_QOS_1; }else if( qos == 2){ _flags |= MQTTSN_FLAG_QOS_2; } setFlags(_flags); } void MQTTSnPublish::setDup(){ _flags |= 0x80; setFlags(_flags); } void MQTTSnPublish::setRetain(){ _flags |= 0x10; setFlags(_flags); } void MQTTSnPublish::setTopicIdType(uint8_t type){ switch(type){ case 0: _flags &= 0x9f; break; case 1: _flags &= 0x9f; _flags |= 0x01; break; default: break; } setFlags(_flags); } void MQTTSnPublish::setTopicId(uint16_t id){ setUint16((uint8_t*)(getBodyPtr() + 1), id); _topicId = id; } void MQTTSnPublish::setTopic(string* topic){ topic->copy((char*)(getBodyPtr() + 1), 2); _topicId = getUint16((uint8_t*)(getBodyPtr() + 1)); } string* MQTTSnPublish::getTopic(string* str){ char tp[3]; tp[0] = (char)*(getBodyPtr() + 1); tp[1] = (char)*(getBodyPtr() + 2); tp[2] = 0; str->copy(tp,2); return str; } uint16_t MQTTSnPublish::getTopicId(){ return _topicId; } void MQTTSnPublish::setMsgId(uint16_t msgId){ setUint16((uint8_t*)(getBodyPtr() + 3), msgId); _msgId = msgId; } uint16_t MQTTSnPublish::getMsgId(){ return _msgId; } void MQTTSnPublish::setData(uint8_t* data, uint8_t len){ setMessageLength(7 + len); allocate(); memcpy(getBodyPtr() + 5, data, len); setTopicId(_topicId); setMsgId(_msgId); setFlags(_flags); } uint8_t* MQTTSnPublish::getData(){ return (uint8_t*)(getBodyPtr() + 5); } uint16_t MQTTSnPublish::getDataLength(){ return getBodyLength() -5; } /* void MQTTSnPublish::setFrame(uint8_t* data, uint8_t len){ setMessageLength(len + MQTTSN_HEADER_SIZE); allocate(); memcpy(getBodyPtr(), data, len); _topicId = getUint16(data + 1); _msgId = getUint16(data + 3); _flags = *data; } void MQTTSnPublish::setFrame(NWResponse* resp){ setFrame(resp->getPayloadPtr() + MQTTSN_HEADER_SIZE, resp->getPayloadPtr()[0] - MQTTSN_HEADER_SIZE); } */ void MQTTSnPublish::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnPublish::absorb(MQTTSnMessage* src){ _msgId = getUint16((uint8_t*)(src->getBodyPtr() + 3)); _flags = src->getBodyPtr()[0]; _topicId = getUint16((uint8_t*)(src->getBodyPtr() + 1)); MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnPubAck ======================================*/ MQTTSnPubAck::MQTTSnPubAck(){ _topicId = 0; _msgId = 0; _returnCode = 0; setMessageLength(7); setType(MQTTSN_TYPE_PUBACK); allocate(); } MQTTSnPubAck::~MQTTSnPubAck(){ } void MQTTSnPubAck::setTopicId(uint16_t topicId){ setUint16((uint8_t*)getBodyPtr(), topicId); } uint16_t MQTTSnPubAck::getTopicId(){ return getUint16((unsigned char*)getBodyPtr()); } void MQTTSnPubAck::setMsgId(uint16_t msgId){ setUint16(getBodyPtr()+ 2,msgId); } uint16_t MQTTSnPubAck::getMsgId(){ return getUint16((unsigned char*)getBodyPtr()+ 2); } void MQTTSnPubAck::setReturnCode(uint8_t rc){ getBodyPtr()[4] = rc; } uint8_t MQTTSnPubAck::getReturnCode(){ return (uint8_t)getBodyPtr()[4]; } void MQTTSnPubAck::absorb(MQTTSnMessage* src){ MQTTSnMessage::absorb(src); } void MQTTSnPubAck::absorb(NWResponse* resp){ MQTTSnMessage::absorb(resp); } /*===================================== Class MQTTSnPubRec ======================================*/ MQTTSnPubRec::MQTTSnPubRec(){ _msgId = 0; setMessageLength(4); setType(MQTTSN_TYPE_PUBREC); allocate(); } MQTTSnPubRec::~MQTTSnPubRec(){ } void MQTTSnPubRec::setMsgId(uint16_t msgId){ setUint16(getBodyPtr(),msgId); } uint16_t MQTTSnPubRec::getMsgId(){ return getUint16((unsigned char*)getBodyPtr()); } /* void MQTTSnPubRec::absorb(NWResponse* resp){ MQTTSnMessage::absorb(resp); }*/ /*===================================== Class MQTTSnPubRel ======================================*/ MQTTSnPubRel::MQTTSnPubRel(){ _msgId = 0; setMessageLength(4); setType(MQTTSN_TYPE_PUBREL); allocate(); } MQTTSnPubRel::~MQTTSnPubRel(){ } /*===================================== Class MQTTSnPubComp ======================================*/ MQTTSnPubComp::MQTTSnPubComp(){ _msgId = 0; setMessageLength(4); setType(MQTTSN_TYPE_PUBCOMP); allocate(); } MQTTSnPubComp::~MQTTSnPubComp(){ } /*===================================== Class MQTTSnSubscribe ======================================*/ MQTTSnSubscribe::MQTTSnSubscribe(){ setMessageLength(5); setType(MQTTSN_TYPE_SUBSCRIBE); allocate(); _topicId = 0; _msgId = 0; _flags = 0; } MQTTSnSubscribe::~MQTTSnSubscribe(){ } void MQTTSnSubscribe::setFlags(uint8_t flags){ _flags = flags & 0xe3; if (_message){ getBodyPtr()[0] = _flags; } } uint8_t MQTTSnSubscribe::getFlags(){ return _flags; } uint8_t MQTTSnSubscribe::getQos(){ return ((_flags >> 5) & 0x03); } void MQTTSnSubscribe::setQos(uint8_t qos){ _flags &= 0x9f; if(qos == 1){ _flags |= MQTTSN_FLAG_QOS_1; } setFlags(_flags); } void MQTTSnSubscribe::setTopicId(uint16_t predefinedId){ setMessageLength(7); allocate(); setMsgId(_msgId); setUint16((uint8_t*)(getBodyPtr() + 3), predefinedId); setFlags(_flags | MQTTSN_TOPIC_TYPE_PREDEFINED); _topicId = predefinedId; } uint16_t MQTTSnSubscribe::getTopicId(){ if (_message){ _topicId = getUint16(getBodyPtr() +3); } return _topicId; } void MQTTSnSubscribe::setMsgId(uint16_t msgId){ _msgId = msgId; if (_message){ setUint16((uint8_t*)(getBodyPtr() + 1), msgId); } } uint16_t MQTTSnSubscribe::getMsgId(){ if (_message){ _msgId = getUint16(getBodyPtr() + 1); } return _msgId; } void MQTTSnSubscribe::setTopicName(string* data){ setMessageLength(5 + data->size()); allocate(); data->copy((char*)getBodyPtr() + 3, data->size(),0); setMsgId(_msgId); setFlags(_flags | MQTTSN_TOPIC_TYPE_NORMAL); _topicName = *data; } string* MQTTSnSubscribe::getTopicName(){ return &_topicName; } /* void MQTTSnSubscribe::setFrame(uint8_t* data, uint8_t len){ setMessageLength(len + MQTTSN_HEADER_SIZE); allocate(); memcpy(getBodyPtr(), data, len); _msgId = getUint16(data + 1); _flags = *data; if ((_flags & MQTTSN_TOPIC_TYPE) == MQTTSN_TOPIC_TYPE_NORMAL){ _topicId = 0; _topicName = string((char*)data + 3, len); }else{ _topicId = getUint16(data + 3); } } void MQTTSnSubscribe::setFrame(NWResponse* resp){ setFrame(resp->getPayloadPtr() + MQTTSN_HEADER_SIZE, resp->getPayloadPtr()[0] - MQTTSN_HEADER_SIZE); } */ void MQTTSnSubscribe::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnSubscribe::absorb(MQTTSnMessage* src){ _msgId = getUint16((uint8_t*)(src->getBodyPtr() +1)); _flags = src->getBodyPtr()[0]; if((_flags & MQTTSN_TOPIC_TYPE) == MQTTSN_TOPIC_TYPE_SHORT ){ _topicName = string((char*)src->getBodyPtr() + 3, src->getMessageLength() - 5); }else if((_flags & MQTTSN_TOPIC_TYPE) == MQTTSN_TOPIC_TYPE_NORMAL){ _topicName = string((char*)src->getBodyPtr() + 3, src->getMessageLength() - 5); }else if((_flags & MQTTSN_TOPIC_TYPE) == MQTTSN_TOPIC_TYPE_PREDEFINED){ _topicId = getUint16(getBodyPtr() +3); } MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnSubAck ======================================*/ MQTTSnSubAck::MQTTSnSubAck(){ setMessageLength(8); setType(MQTTSN_TYPE_SUBACK); _flags = 0; _topicId = 0; _msgId = 0; _returnCode = 0; allocate(); } MQTTSnSubAck::~MQTTSnSubAck(){ } void MQTTSnSubAck::setFlags(uint8_t flags){ _flags = flags & 0x60; getBodyPtr()[0] = _flags; } void MQTTSnSubAck::setQos(uint8_t qos){ _flags &= 0x9f; if(qos == 1){ _flags |= MQTTSN_FLAG_QOS_1; } setFlags(_flags); } uint8_t MQTTSnSubAck::getFlags(){ return _flags; } uint8_t MQTTSnSubAck::getQos(){ return (_flags >> 5) & 0x03; } void MQTTSnSubAck::setTopicId(uint16_t id){ _topicId = id; setUint16(getBodyPtr() + 1, id); } uint16_t MQTTSnSubAck::getTopicId(){ return _topicId; } void MQTTSnSubAck::setMsgId(uint16_t msgId){ _msgId = msgId; setUint16(getBodyPtr() + 3, msgId); } uint16_t MQTTSnSubAck::getMsgId(){ return _msgId; } void MQTTSnSubAck::setReturnCode(uint8_t rc){ _returnCode = rc; getBodyPtr()[5] = rc; } uint8_t MQTTSnSubAck::getReturnCode(){ return _returnCode; } /*===================================== Class MQTTSnUnsubscribe ======================================*/ MQTTSnUnsubscribe::MQTTSnUnsubscribe() : MQTTSnSubscribe(){ setType(MQTTSN_TYPE_UNSUBSCRIBE); } MQTTSnUnsubscribe::~MQTTSnUnsubscribe(){ } void MQTTSnUnsubscribe::setFlags(uint8_t flags){ if (_message){ getBodyPtr()[0] = flags & 0x03; } } string* MQTTSnUnsubscribe::getTopicName(){ return &_topicName; } uint16_t MQTTSnUnsubscribe::getTopicId(){ return _topicId; } void MQTTSnUnsubscribe::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnUnsubscribe::absorb(MQTTSnMessage* src){ MQTTSnSubscribe::absorb(src); } /*===================================== Class MQTTSnUnSubAck ======================================*/ MQTTSnUnsubAck::MQTTSnUnsubAck(){ _msgId = 0; setMessageLength(4); setType(MQTTSN_TYPE_UNSUBACK); allocate(); } MQTTSnUnsubAck::~MQTTSnUnsubAck(){ } void MQTTSnUnsubAck::setMsgId(uint16_t msgId){ setUint16((uint8_t*)getBodyPtr(), msgId); } uint16_t MQTTSnUnsubAck::getMsgId(){ return getUint16(getBodyPtr()); } /*===================================== Class MQTTSnPingReq ======================================*/ MQTTSnPingReq::MQTTSnPingReq(){ setMessageLength(2); setType(MQTTSN_TYPE_PINGREQ); allocate(); } MQTTSnPingReq::MQTTSnPingReq(string* id){ setMessageLength(id->size() + 2); setType(MQTTSN_TYPE_PINGREQ); allocate(); id->copy((char*)getBodyPtr(),id->size(),0); } MQTTSnPingReq::~MQTTSnPingReq(){ } char* MQTTSnPingReq::getClientId(){ return (char*)getBodyPtr(); } void MQTTSnPingReq::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } /*===================================== Class MQTTSnPingResp ======================================*/ MQTTSnPingResp::MQTTSnPingResp(){ setMessageLength(2); setType(MQTTSN_TYPE_PINGRESP); allocate(); } MQTTSnPingResp::~MQTTSnPingResp(){ } /*===================================== Class MQTTSnDisconnect ======================================*/ MQTTSnDisconnect::MQTTSnDisconnect(){ setMessageLength(4); setType(MQTTSN_TYPE_DISCONNECT); allocate(); } MQTTSnDisconnect::~MQTTSnDisconnect(){ } void MQTTSnDisconnect::setDuration(uint16_t duration){ setUint16((uint8_t*)getBodyPtr(), duration); } uint16_t MQTTSnDisconnect::getDuration(){ return getUint16((uint8_t*)getBodyPtr()); } void MQTTSnDisconnect::absorb(NWResponse* src){ MQTTSnMessage::absorb(src); } void MQTTSnDisconnect::absorb(MQTTSnMessage* src){ MQTTSnMessage::absorb(src); } /*===================================== Class RemaingLength ======================================*/ RemainingLength::RemainingLength(){ _size = _digit[0] = _digit[1] = _digit[2] = _digit[3] = 0; } RemainingLength::~RemainingLength(){ } void RemainingLength::encode(uint16_t len){ _size = 0; do{ uint8_t digit = len % 128; len = len / 128; if(len > 0){ digit |= 0x80; } _digit[_size++] = digit; }while(len > 0); } uint16_t RemainingLength::decode(){ uint16_t multiplier = 1; uint16_t value = 0; uint8_t digit; uint8_t pos = 0; do{ digit = _digit[pos++]; value += (digit & 0x7f) * multiplier; multiplier *= 128; }while((digit & 0x80) != 0); return value; } uint16_t RemainingLength::serialize(uint8_t* pos){ memcpy(pos, _digit, _size); return decode(); } void RemainingLength::deserialize(uint8_t* pos){ uint8_t i = 0; _size = 0; do{ _digit[i++] = *pos; _size++; }while((*pos++ & 0x80) != 0 ); } uint8_t RemainingLength::getSize(){ return _size; } /*===================================== Class MQTTMessage ======================================*/ MQTTMessage::MQTTMessage(){ _type = 0; _flags = 0; _messageId = 0; _remainLength = 0; _payload = 0; _userName = string(""); _password = string(""); _willTopic = string(""); _willMessage = string(""); _clientId = string(""); _topic = string(""); } MQTTMessage::~MQTTMessage(){ if(_payload){ free(_payload); } } uint8_t MQTTMessage::getType(){ return _type; } uint8_t MQTTMessage::getQos(){ return (_flags & 0x06) >> 1; } uint16_t MQTTMessage::getRemainLength(){ return _remainLength; } uint8_t MQTTMessage::getRemainLengthSize(){ RemainingLength remLen; remLen.encode(_remainLength); return remLen.getSize(); } bool MQTTMessage::isDup(){ return _flags & 0x80; } bool MQTTMessage::isRetain(){ return _flags & 0x01; } uint16_t MQTTMessage::serialize(uint8_t* buf){ RemainingLength remLen; remLen.encode(_remainLength); *buf++ = _type | _flags; remLen.serialize(buf); buf += remLen.getSize(); if(remLen.decode() > 0){ setUint16(buf, _messageId); } return 1 + remLen.getSize() + remLen.decode(); } bool MQTTMessage::deserialize(uint8_t* buf){ RemainingLength remLen; _type = *buf & 0xf0; _flags = *buf & 0x0f; remLen.deserialize(buf + 1); _remainLength = remLen.decode(); switch(_type){ case MQTT_TYPE_PINGRESP: return true; break; case MQTT_TYPE_UNSUBACK: case MQTT_TYPE_PUBACK: case MQTT_TYPE_PUBREC: case MQTT_TYPE_PUBREL: case MQTT_TYPE_PUBCOMP: _messageId = getUint16(buf + 2); break; default: return false; } return true; } void MQTTMessage::absorb(MQTTMessage* msg){ _type = msg->_type; _flags = msg->_flags; _messageId = msg->_messageId; _remainLength = msg->_remainLength; } void MQTTMessage::setType(uint8_t type){ _type = type; } void MQTTMessage::setQos(uint8_t qos){ _flags &= 0xf9; if(qos == 1){ _flags |= 0x02; }else if(qos == 2){ _flags |= 0x04; } } void MQTTMessage::setDup(){ _flags |= 0x08; } void MQTTMessage::setRetain(){ _flags |= 0x01; } /*===================================== Class MQTTDisconnect ======================================*/ MQTTDisconnect::MQTTDisconnect(){ _type = MQTT_TYPE_DISCONNECT; } MQTTDisconnect::~MQTTDisconnect(){ } /*===================================== Class MQTTPingReq ======================================*/ MQTTPingReq::MQTTPingReq(){ _type = MQTT_TYPE_PINGREQ; } MQTTPingReq::~MQTTPingReq(){ } /*===================================== Class MQTTPingResp ======================================*/ MQTTPingResp::MQTTPingResp(){ _type = MQTT_TYPE_PINGRESP; } MQTTPingResp::~MQTTPingResp(){ } /*===================================== Class MQTTConnAck ======================================*/ MQTTConnAck::MQTTConnAck(){ _type = MQTT_TYPE_CONNACK; _remainLength = 2; _returnCd = 0; } MQTTConnAck::~MQTTConnAck(){ } uint8_t MQTTConnAck::getReturnCd(){ return _returnCd; } bool MQTTConnAck::deserialize(uint8_t* buf){ MQTTMessage::deserialize(buf); if(_type != MQTT_TYPE_CONNACK){ return false; } buf += 3; _returnCd = *buf; return true; } /*===================================== Class MQTTUnsubAck ======================================*/ MQTTUnsubAck::MQTTUnsubAck(){ _type = MQTT_TYPE_CONNACK; _remainLength = 2; } MQTTUnsubAck::~MQTTUnsubAck(){ } void MQTTUnsubAck::setMessageId(uint16_t id){ _messageId = id; } uint16_t MQTTUnsubAck::getMessageId(){ return _messageId; } /*===================================== Class MQTTPubAck ======================================*/ MQTTPubAck::MQTTPubAck(){ _type = MQTT_TYPE_PUBACK; _remainLength = 2; } MQTTPubAck::~MQTTPubAck(){ } void MQTTPubAck::setMessageId(uint16_t id){ _messageId = id; } uint16_t MQTTPubAck::getMessageId(){ return _messageId; } /*===================================== Class MQTTPubRec ======================================*/ MQTTPubRec::MQTTPubRec(){ _type = MQTT_TYPE_PUBREC; _remainLength = 2; } MQTTPubRec::~MQTTPubRec(){ } void MQTTPubRec::setMessageId(uint16_t id){ _messageId = id; } uint16_t MQTTPubRec::getMessageId(){ return _messageId; } /*===================================== Class MQTTPubRel ======================================*/ MQTTPubRel::MQTTPubRel(){ _type = MQTT_TYPE_PUBREL; _remainLength = 2; } MQTTPubRel::~MQTTPubRel(){ } /*===================================== Class MQTTPubComp ======================================*/ MQTTPubComp::MQTTPubComp(){ _type = MQTT_TYPE_PUBCOMP; _remainLength = 2; } MQTTPubComp::~MQTTPubComp(){ } /*===================================== Class MQTTSubAck ======================================*/ MQTTSubAck::MQTTSubAck(){ _type = MQTT_TYPE_SUBACK; _remainLength = 3; _qos = 0; } MQTTSubAck::~MQTTSubAck(){ } void MQTTSubAck::setMessageId(uint16_t id){ _messageId = id; } uint16_t MQTTSubAck::getMessageId(){ return _messageId; } uint8_t MQTTSubAck::getGrantedQos(){ return _qos; } void MQTTSubAck::setGrantedQos0(){ _qos = 0; } void MQTTSubAck::setGrantedQos1(){ _qos = 1; } bool MQTTSubAck::deserialize(uint8_t* buf){ RemainingLength remLen; remLen.encode(_remainLength); _type = *buf & 0xf0; if(_type != MQTT_TYPE_SUBACK){ return false; } _flags = *buf++ & 0x0f; remLen.deserialize(buf); _messageId = getUint16(buf + remLen.getSize()); _qos = *(buf + remLen.getSize() + 2); return true; } /*===================================== Class MQTTUnsubscribe ======================================*/ MQTTUnsubscribe::MQTTUnsubscribe(){ _type = MQTT_TYPE_UNSUBSCRIBE; _remainLength = 0; } MQTTUnsubscribe::~MQTTUnsubscribe(){ } void MQTTUnsubscribe::setMessageId(uint16_t id){ _messageId = id; } uint16_t MQTTUnsubscribe::getMessageId(){ return _messageId; } void MQTTUnsubscribe::setTopicName(string* topic){ _topic = *topic; } uint16_t MQTTUnsubscribe::serialize(uint8_t* buf){ RemainingLength remLen; _remainLength = _topic.size() + 4; remLen.encode(_remainLength); *buf++ = _type | 0x02; remLen.serialize(buf); buf += remLen.getSize(); setUint16(buf, _messageId); buf += 2; utfSerialize(buf,_topic); return 1 + remLen.getSize() + remLen.decode(); } /*===================================== Class MQTTSubscribe ======================================*/ MQTTSubscribe::MQTTSubscribe(){ _type = MQTT_TYPE_SUBSCRIBE; _remainLength = 2; _qos = 0; setQos(1); } MQTTSubscribe::~MQTTSubscribe(){ } void MQTTSubscribe::setMessageId(uint16_t id){ _messageId = id; } uint16_t MQTTSubscribe::getMessageId(){ return _messageId; } void MQTTSubscribe::setTopic(string* topic, uint8_t qos){ _topic = *topic; _qos = qos; } uint16_t MQTTSubscribe::serialize(uint8_t* buf){ RemainingLength remLen; _remainLength = _topic.size() + 5; //length:2, Topic:n, QoS:1 remLen.encode(_remainLength); *buf++ = _type | 0x02; //SUBSCRIBE QoS1 remLen.serialize(buf); buf += remLen.getSize(); setUint16(buf, _messageId); buf += 2; utfSerialize(buf,_topic); buf += 2 + _topic.size(); *buf = _qos; return 1 + remLen.getSize() + remLen.decode(); } /*===================================== Class MQTTConnect ======================================*/ MQTTConnect::MQTTConnect() : MQTTMessage(){ _type = MQTT_TYPE_CONNECT; _connectFlags = 0;; _keepAliveTime = 0; _userName = string(""); _password = string(""); _willTopic = string(""); _willMessage = string(""); _clientId = string(""); _protocol = 0; } MQTTConnect::~MQTTConnect(){ } void MQTTConnect::setKeepAliveTime(uint16_t sec){ _keepAliveTime = sec; } void MQTTConnect::setUserName(string* userName){ _userName = *userName; _connectFlags &= 0x7e; _connectFlags |= 0x80; } void MQTTConnect::setPassword(string* pw){ _password = *pw; _connectFlags &= 0xbe; _connectFlags |= 0x40; } void MQTTConnect::setWillMessage(string* wm){ _willMessage = *wm; _connectFlags &= 0xfa; _connectFlags |= 0x04; } void MQTTConnect::setWillTopic(string* tp){ _willTopic = *tp; _connectFlags &= 0xfa; _connectFlags |= 0x04; } void MQTTConnect::setWillQos(uint8_t qos){ _connectFlags &= 0xe6; _connectFlags |= (qos << 3); } void MQTTConnect::setProtocol(uint8_t protocol){ _protocol = protocol; } void MQTTConnect::setClientId(string* cid){ _clientId = *cid; } void MQTTConnect::setCleanSessionFlg(){ _connectFlags &= 0xfc; _connectFlags |= 0x02; } uint16_t MQTTConnect::serialize(uint8_t* buf){ uint16_t len; string protocol; if(_protocol == MQTT_PROTOCOL_VER4){ protocol = MQTT_PROTOCOL_NAME4; len = 10; }else{ protocol = MQTT_PROTOCOL_NAME3; len = 12; } len += _clientId.size() + 2; if(_connectFlags & 0x0c){ // Will Topic & Message len += _willTopic.size() + 2; len += _willMessage.size() + 2; } if(_connectFlags & 0x80){ // User Name len += _userName.size() + 2; } if(_connectFlags & 0x40){ // Password len += _password.size() + 2; } RemainingLength remLen; remLen.encode(len); _remainLength = len; *buf++ = _type | _flags; remLen.serialize(buf); buf += remLen.getSize(); utfSerialize(buf, protocol); buf += protocol.size() + 2; *buf++ = _protocol; *buf++ = _connectFlags; setUint16(buf++, _keepAliveTime); utfSerialize(++buf,_clientId); // copy clienId buf += _clientId.size() + 2; if(_connectFlags & 0x0c){ // Will Topic & Message utfSerialize(buf,_willTopic); buf += _willTopic.size() + 2; utfSerialize(buf,_willMessage); buf += _willMessage.size() + 2; } if(_connectFlags & 0x80){ // User Name utfSerialize(buf,_userName); buf += _userName.size() + 2; } if(_connectFlags & 0x40){ // Password utfSerialize(buf,_password); } return 1 + remLen.getSize() + remLen.decode(); } /*===================================== Class MQTTPublish ======================================*/ MQTTPublish::MQTTPublish(){ _type = MQTT_TYPE_PUBLISH; //_topic = string(""); //_payload = 0; _len = 0; _messageId = 0; } MQTTPublish::~MQTTPublish(){ } void MQTTPublish::setMessageId(uint16_t id){ _messageId = id; } uint16_t MQTTPublish::getMessageId(){ return _messageId; } string* MQTTPublish::getTopic(){ return &_topic; } uint8_t* MQTTPublish::getPayload(){ return _payload; } uint8_t MQTTPublish::getPayloadLength(){ return _len; } void MQTTPublish::setTopic(string* topic){ _topic = *topic; } void MQTTPublish::setPayload(uint8_t* payload, uint8_t length){ if(_payload){ _remainLength -= _len; free(_payload); } _payload = mqcalloc(length); memcpy(_payload, payload, length); _len = length; _remainLength += length; } uint16_t MQTTPublish::serialize(uint8_t* buf){ RemainingLength remLen; _remainLength = _topic.size() + 2 + _len; if(getQos()){ _remainLength += 2; } remLen.encode(_remainLength); *buf++ = (_type & 0xf0) | (_flags & 0x0f); remLen.serialize(buf); buf += remLen.getSize(); utfSerialize(buf, _topic); buf += _topic.size() + 2; if(getQos()){ setUint16(buf, _messageId); buf += 2; } memcpy(buf, _payload, _len); return 1 + remLen.getSize() + remLen.decode(); } bool MQTTPublish::deserialize(uint8_t* buf){ uint8_t pos = 2; _type = *buf & 0xf0; if(_type != MQTT_TYPE_PUBLISH){ return false; } RemainingLength remLen; _flags = *buf & 0x0f; remLen.deserialize(buf + 1); _remainLength = remLen.decode(); buf += 1 + remLen.getSize(); _topic = string((char*)buf + 2, getUint16(buf)); if(!isUtf8Valid(_topic)){ return false; } buf += _topic.size() + 2; if(getQos()){ _messageId = getUint16(buf); buf += 2; pos += 2; } _len = _remainLength - _topic.size() - pos; _payload = mqcalloc(_len); memcpy(_payload, buf, _len); return true; } ================================================ FILE: Gateway/src/lib/Messages.h ================================================ /* * Messages.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef MESSAGES_H_ #define MESSAGES_H_ /* * MQTT-SN Message Type */ #define MQTTSN_TYPE_ADVERTISE 0x00 #define MQTTSN_TYPE_SEARCHGW 0x01 #define MQTTSN_TYPE_GWINFO 0x02 #define MQTTSN_TYPE_CONNECT 0x04 #define MQTTSN_TYPE_CONNACK 0x05 #define MQTTSN_TYPE_WILLTOPICREQ 0x06 #define MQTTSN_TYPE_WILLTOPIC 0x07 #define MQTTSN_TYPE_WILLMSGREQ 0x08 #define MQTTSN_TYPE_WILLMSG 0x09 #define MQTTSN_TYPE_REGISTER 0x0A #define MQTTSN_TYPE_REGACK 0x0B #define MQTTSN_TYPE_PUBLISH 0x0C #define MQTTSN_TYPE_PUBACK 0x0D #define MQTTSN_TYPE_PUBCOMP 0x0E #define MQTTSN_TYPE_PUBREC 0x0F #define MQTTSN_TYPE_PUBREL 0x10 #define MQTTSN_TYPE_SUBSCRIBE 0x12 #define MQTTSN_TYPE_SUBACK 0x13 #define MQTTSN_TYPE_UNSUBSCRIBE 0x14 #define MQTTSN_TYPE_UNSUBACK 0x15 #define MQTTSN_TYPE_PINGREQ 0x16 #define MQTTSN_TYPE_PINGRESP 0x17 #define MQTTSN_TYPE_DISCONNECT 0x18 #define MQTTSN_TYPE_WILLTOPICUPD 0x1A #define MQTTSN_TYPE_WILLTOPICRESP 0x1B #define MQTTSN_TYPE_WILLMSGUPD 0x1C #define MQTTSN_TYPE_WILLMSGRESP 0x1D /* * MQTT Message types */ #define MQTT_PROTOCOL_NAME3 "MQIsdp" #define MQTT_PROTOCOL_NAME4 "MQTT" #define MQTT_PROTOCOL_VER4 4 #define MQTT_PROTOCOL_VER3 3 #define MQTT_TYPE_CONNECT 0x10 #define MQTT_TYPE_CONNACK 0x20 #define MQTT_TYPE_PUBLISH 0x30 #define MQTT_TYPE_PUBACK 0x40 #define MQTT_TYPE_PUBREC 0x50 #define MQTT_TYPE_PUBREL 0x60 #define MQTT_TYPE_PUBCOMP 0x70 #define MQTT_TYPE_SUBSCRIBE 0x80 #define MQTT_TYPE_SUBACK 0x90 #define MQTT_TYPE_UNSUBSCRIBE 0xA0 #define MQTT_TYPE_UNSUBACK 0xB0 #define MQTT_TYPE_PINGREQ 0xC0 #define MQTT_TYPE_PINGRESP 0xD0 #define MQTT_TYPE_DISCONNECT 0xE0 #define MQTT_RC_ACCEPTED 0 #define MQTT_RC_REFUSED_PROTOCOL_VERSION 1 #define MQTT_RC_REFUSED_IDENTIFIER_REJECTED 2 #define MQTT_RC_REFUSED_SERVER_UNAVAILABLE 3 #define MQTT_RC_REFUSED_BAD_USERNAME_PASSWORD 4 #define MQTT_RC_REFUSED_NOT_AUTHORIZED 5 /* * Flags */ #define MQTTSN_FLAG_DUP 0x80 #define MQTTSN_FLAG_QOS_0 0x0 #define MQTTSN_FLAG_QOS_1 0x20 #define MQTTSN_FLAG_QOS_2 0x40 #define MQTTSN_FLAG_QOS_N1 0xc0 #define MQTTSN_FLAG_RETAIN 0x10 #define MQTTSN_FLAG_WILL 0x08 #define MQTTSN_FLAG_CLEAN 0x04 #define MQTTSN_FLAG_TOPICID_TYPE_NORMAL 0x00 #define MQTTSN_FLAG_TOPICID_TYPE_PREDEFINED 0x01 #define MQTTSN_FLAG_TOPICID_TYPE_SHORT 0x02 #define MQTTSN_FLAG_TOPICID_TYPE_RESV 0x03 #define MQTTSN_TOPIC_TYPE_NORMAL 0x00 #define MQTTSN_TOPIC_TYPE_PREDEFINED 0x01 #define MQTTSN_TOPIC_TYPE_SHORT 0x02 #define MQTTSN_TOPIC_TYPE 0x03 #define MQTTSN_PROTOCOL_ID 0x01 #define MQTTSN_HEADER_SIZE 2 /* * Return Code */ #define MQTTSN_RC_ACCEPTED 0x00 #define MQTTSN_RC_REJECTED_CONGESTION 0x01 #define MQTTSN_RC_REJECTED_INVALID_TOPIC_ID 0x02 #define MQTTSN_RC_REJECTED_NOT_SUPPORTED 0x03 #define MQTTSN_MSG_REQUEST 1 #define MQTTSN_MSG_RESEND_REQ 2 #define MQTTSN_MSG_WAIT_ACK 3 #define MQTTSN_MSG_COMPLETE 4 #define MQTTSN_MSG_REJECTED 5 #define MQTTSN_GW_INIT 0 #define MQTTSN_GW_SEARCHING 1 #define MQTTSN_GW_FOUND 2 #define MQTTSN_GW_CONNECTED 3 #define MQTTSN_GW_DISCONNECTED 4 #define MQTTSN_GW_LOST 5 #define MQTTSN_ERR_NO_ERROR 0 #define MQTTSN_ERR_NOT_CONNECTED -1 #define MQTTSN_ERR_RETRY_OVER -2 #define MQTTSN_ERR_GATEWAY_LOST -3 #define MQTTSN_ERR_CANNOT_ADD_REQUEST -4 #define MQTTSN_ERR_NO_TOPICID -5 #define MQTTSN_ERR_REJECTED -6 #define MQTTSN_ERR_WAIT_GWINFO -7 #define MQTTSN_ERR_OUT_OF_MEMORY -8 #define MQTTSN_ERR_PING_REQUIRED -9 #define MQTTSN_ERR_ACK_TIMEOUT -10 #define MQTTSN_ERR_PINGRESP_TIMEOUT -11 #include "ZBStack.h" #include "UDPStack.h" #include "ProcessFramework.h" #include using namespace std; using namespace tomyGateway; /*===================================== Class MQTTSnMessage =====================================*/ class MQTTSnMessage{ public: MQTTSnMessage(); ~MQTTSnMessage(); void setMessageLength(uint16_t length); void setType(uint8_t type); void setBody(uint8_t* body, uint16_t bodyLength); void setMessage(uint8_t* msg); uint8_t getType(); uint16_t getBodyLength(); uint16_t getMessageLength(); uint8_t* getMessagePtr(); uint8_t* getBodyPtr(); bool getMessage(uint16_t pos, uint8_t& val); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); protected: void allocate(); uint8_t* _message; private: uint16_t _length; uint8_t _type; }; /*===================================== Class MQTTSnAdvertize ======================================*/ class MQTTSnAdvertise : public MQTTSnMessage { public: MQTTSnAdvertise(); ~MQTTSnAdvertise(); void setGwId(uint8_t id); void setDuration(uint16_t duration); uint8_t getGwId(); uint16_t getDuration(); private: }; /*===================================== Class MQTTSnSearchGw ======================================*/ class MQTTSnSearchGw : public MQTTSnMessage { public: MQTTSnSearchGw(); ~MQTTSnSearchGw(); void setRadius(uint8_t radius); uint8_t getRadius(); void absorb(NWResponse* src); private: }; /*===================================== Class MQTTSnGwinfo ======================================*/ class MQTTSnGwInfo : public MQTTSnMessage { public: MQTTSnGwInfo(); ~MQTTSnGwInfo(); void setGwId(uint8_t id); uint8_t getGwId(); private: }; /*===================================== Class MQTTSnConnect ======================================*/ class MQTTSnConnect : public MQTTSnMessage { public: MQTTSnConnect(); MQTTSnConnect(string* id); ~MQTTSnConnect(); void setFlags(uint8_t flg); void setDuration(uint16_t msec); void setClientId(string id); uint8_t getFlags(); uint16_t getDuration(); string* getClientId(); bool isCleanSession(); bool isWillRequired(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); private: string _clientId; }; /*===================================== Class MQTTSnConnack ======================================*/ class MQTTSnConnack : public MQTTSnMessage { public: MQTTSnConnack(); ~MQTTSnConnack(); void setReturnCode(uint8_t rc); uint8_t getReturnCode(); private: }; /*===================================== Class MQTTSnWillTopicReq ======================================*/ class MQTTSnWillTopicReq : public MQTTSnMessage { public: MQTTSnWillTopicReq(); ~MQTTSnWillTopicReq(); private: }; /*===================================== Class MQTTSnWillTopic ======================================*/ class MQTTSnWillTopic : public MQTTSnMessage { public: MQTTSnWillTopic(); ~MQTTSnWillTopic(); void setFlags(uint8_t flags); void setWillTopic(string* topic); string* getWillTopic(); uint8_t getQos(); bool isWillRequired(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); private: uint8_t _flags; string _topicName; }; /*===================================== Class MQTTSnWillMsgReq ======================================*/ class MQTTSnWillMsgReq : public MQTTSnMessage { public: MQTTSnWillMsgReq(); ~MQTTSnWillMsgReq(); private: }; /*===================================== Class MQTTSnWillMsg ======================================*/ class MQTTSnWillMsg : public MQTTSnMessage { public: MQTTSnWillMsg(); ~MQTTSnWillMsg(); void setWillMsg(string* msg); string* getWillMsg(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); private: string _willMsg; }; /*===================================== Class MQTTSnRegister ======================================*/ class MQTTSnRegister : public MQTTSnMessage { public: MQTTSnRegister(); ~MQTTSnRegister(); void setTopicId(uint16_t topicId); void setMsgId(uint16_t msgId); void setTopicName(string* topicName); //void setFrame(uint8_t* data, uint8_t len); //void setFrame(NWResponse* resp); uint16_t getMsgId(); uint16_t getTopicId(); string* getTopicName(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); private: uint16_t _topicId; uint16_t _msgId; string _topicName; }; /*===================================== Class MQTTSnRegAck ======================================*/ class MQTTSnRegAck : public MQTTSnMessage { public: MQTTSnRegAck(); ~MQTTSnRegAck(); void setTopicId(uint16_t topicId); void setMsgId(uint16_t msgId); void setReturnCode(uint8_t rc); uint16_t getMsgId(); uint16_t getTopicId(); uint8_t getReturnCode(); void absorb(NWResponse* src); private: }; /*===================================== Class MQTTSnPublish ======================================*/ class MQTTSnPublish : public MQTTSnMessage { public: MQTTSnPublish(); ~MQTTSnPublish(); void setFlags(uint8_t flags); void setTopicId(uint16_t id); void setTopic(string* topic); void setMsgId(uint16_t msgId); void setData(uint8_t* data, uint8_t len); //void setFrame(uint8_t* data, uint8_t len); //void setFrame(NWResponse* resp); void setQos(uint8_t); void setDup(); void setRetain(); void setTopicIdType(uint8_t); uint16_t getTopicId(); string* getTopic(string* str); uint8_t getTopicType(); uint8_t getQos(); uint8_t getFlags(); uint8_t* getData(); uint16_t getDataLength(); uint16_t getMsgId(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); private: uint8_t _flags; uint16_t _topicId; uint16_t _msgId; }; /*===================================== Class MQTTSnPubAck ======================================*/ class MQTTSnPubAck : public MQTTSnMessage { public: MQTTSnPubAck(); ~MQTTSnPubAck(); void setTopicId(uint16_t id); void setMsgId(uint16_t msgId); void setReturnCode(uint8_t rc); uint8_t getReturnCode(); uint16_t getTopicId(); uint16_t getMsgId(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); private: uint16_t _topicId; uint16_t _msgId; uint8_t _returnCode; }; /*===================================== Class MQTTSnPubRec ======================================*/ class MQTTSnPubRec : public MQTTSnMessage { public: MQTTSnPubRec(); ~MQTTSnPubRec(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); //void absorb(MQTTSnMessage* src); //void absorb(NWResponse* src); protected: uint16_t _msgId; }; /*===================================== Class MQTTSnPubRel ======================================*/ class MQTTSnPubRel : public MQTTSnPubRec { public: MQTTSnPubRel(); ~MQTTSnPubRel(); }; /*===================================== Class MQTTSnPubRel ======================================*/ class MQTTSnPubComp : public MQTTSnPubRec { public: MQTTSnPubComp(); ~MQTTSnPubComp(); private: }; /*===================================== Class MQTTSnSubscribe ======================================*/ class MQTTSnSubscribe : public MQTTSnMessage { public: MQTTSnSubscribe(); ~MQTTSnSubscribe(); void setFlags(uint8_t flags); void setMsgId(uint16_t msgId); void setQos(uint8_t); void setTopicName(string* topicName); void setTopicId(uint16_t predefinedId); //void setFrame(uint8_t* data, uint8_t len); //void setFrame(NWResponse* resp);uint16_t getMsgId(); uint8_t getQos(); uint8_t getFlags(); uint16_t getTopicId(); uint16_t getMsgId(); string* getTopicName(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); protected: uint16_t _topicId; uint16_t _msgId; uint8_t _flags; string _topicName; }; /*===================================== Class MQTTSnSubAck ======================================*/ class MQTTSnSubAck : public MQTTSnMessage { public: MQTTSnSubAck(); ~MQTTSnSubAck(); void setFlags(uint8_t flags); void setQos(uint8_t qos); void setMsgId(uint16_t msgId); void setTopicId(uint16_t topicId); void setReturnCode(uint8_t rc); uint8_t getFlags(); uint8_t getQos(); uint8_t getReturnCode(); uint16_t getMsgId(); uint16_t getTopicId(); private: uint16_t _topicId; uint16_t _msgId; uint8_t _flags; uint8_t _returnCode; string _topicName; }; /*===================================== Class MQTTSnUnsubscribe ======================================*/ class MQTTSnUnsubscribe : public MQTTSnSubscribe { public: MQTTSnUnsubscribe(); ~MQTTSnUnsubscribe(); void setFlags(uint8_t flags); string* getTopicName(); uint16_t getTopicId(); void absorb(NWResponse* src); void absorb(MQTTSnMessage* src); private: }; /*===================================== Class MQTTSnUnSubAck ======================================*/ class MQTTSnUnsubAck : public MQTTSnMessage { public: MQTTSnUnsubAck(); ~MQTTSnUnsubAck(); void setMsgId(uint16_t msgId); uint16_t getMsgId(); private: uint16_t _msgId; }; /*===================================== Class MQTTSnPingReq ======================================*/ class MQTTSnPingReq : public MQTTSnMessage { public: MQTTSnPingReq(); MQTTSnPingReq(string* id); ~MQTTSnPingReq(); void setClientId(string* id); char* getClientId(); void absorb(NWResponse* src); private: }; /*===================================== Class MQTTSnPingResp ======================================*/ class MQTTSnPingResp : public MQTTSnMessage { public: MQTTSnPingResp(); ~MQTTSnPingResp(); private: }; /*===================================== Class MQTTSnDisconnect ======================================*/ class MQTTSnDisconnect : public MQTTSnMessage { public: MQTTSnDisconnect(); ~MQTTSnDisconnect(); void setDuration(uint16_t duration); uint16_t getDuration(); void absorb(MQTTSnMessage* src); void absorb(NWResponse* src); private: }; /*===================================== Class RemaingLength =====================================*/ class RemainingLength{ public: RemainingLength(); ~RemainingLength(); void encode(uint16_t); uint16_t decode(); uint16_t serialize(uint8_t* pos); void deserialize(uint8_t* pos); uint8_t getSize(); private: uint8_t _digit[4]; uint8_t _size; }; /*===================================== Class MQTTMessage ======================================*/ class MQTTMessage{ public: MQTTMessage(); ~MQTTMessage(); uint8_t getType(); uint8_t getQos(); // QOS0 = 0, QOS1 = 1 uint16_t getRemainLength(); uint8_t getRemainLengthSize(); bool isDup(); bool isRetain(); uint16_t serialize(uint8_t* buf); bool deserialize(uint8_t* buf); void setType(uint8_t); void setQos(uint8_t); void setDup(); void setRetain(); void absorb(MQTTMessage* msg); protected: uint8_t _type; uint8_t _flags; uint16_t _remainLength; uint16_t _messageId; uint8_t* _payload; string _userName; string _password; string _willTopic; string _willMessage; string _clientId; string _topic; }; /*===================================== Class MQTTPingReq ======================================*/ class MQTTPingReq : public MQTTMessage{ public: MQTTPingReq(); ~MQTTPingReq(); }; /*===================================== Class MQTTPingResp ======================================*/ class MQTTPingResp : public MQTTMessage{ public: MQTTPingResp(); ~MQTTPingResp(); }; /*===================================== Class MQTTDisconnect ======================================*/ class MQTTDisconnect : public MQTTMessage{ public: MQTTDisconnect(); ~MQTTDisconnect(); }; /*===================================== Class MQTTPubAck ======================================*/ class MQTTPubAck : public MQTTMessage{ public: MQTTPubAck(); ~MQTTPubAck(); void setMessageId(uint16_t); uint16_t getMessageId(); }; /*===================================== Class MQTTPubRec ======================================*/ class MQTTPubRec : public MQTTMessage{ public: MQTTPubRec(); ~MQTTPubRec(); void setMessageId(uint16_t); uint16_t getMessageId(); }; /*===================================== Class MQTTPubRel ======================================*/ class MQTTPubRel : public MQTTPubRec{ public: MQTTPubRel(); ~MQTTPubRel(); //void setMessageId(uint16_t); //uint16_t getMessageId(); }; /*===================================== Class MQTTPubComp ======================================*/ class MQTTPubComp : public MQTTPubRec{ public: MQTTPubComp(); ~MQTTPubComp(); //void setMessageId(uint16_t); //uint16_t getMessageId(); }; /*===================================== Class MQTTConnAck ======================================*/ class MQTTConnAck : public MQTTMessage{ public: MQTTConnAck(); ~MQTTConnAck(); uint8_t getReturnCd(); bool deserialize(uint8_t* buf); private: uint8_t _returnCd; }; /*===================================== Class MQTTUnsubAck ======================================*/ class MQTTUnsubAck : public MQTTMessage{ public: MQTTUnsubAck(); ~MQTTUnsubAck(); void setMessageId(uint16_t); uint16_t getMessageId(); }; /*===================================== Class MQTTSubAck ======================================*/ class MQTTSubAck : public MQTTMessage{ public: MQTTSubAck(); ~MQTTSubAck(); void setMessageId(uint16_t); uint16_t getMessageId(); uint8_t getGrantedQos(); void setGrantedQos0(); void setGrantedQos1(); bool deserialize(uint8_t* buf); private: uint8_t _qos; }; /*===================================== Class MQTTUnSubscribe ======================================*/ class MQTTUnsubscribe : public MQTTMessage{ public: MQTTUnsubscribe(); ~MQTTUnsubscribe(); void setMessageId(uint16_t); uint16_t getMessageId(); uint16_t serialize(uint8_t* buf); void setTopicName(string*); private: //string _topic; }; /*===================================== Class MQTTSubscribe ======================================*/ class MQTTSubscribe : public MQTTMessage{ public: MQTTSubscribe(); ~MQTTSubscribe(); void setMessageId(uint16_t); uint16_t getMessageId(); uint16_t serialize(uint8_t* buf); void setTopic(string* topic, uint8_t qos); private: //string _topic; uint8_t _qos; }; /*===================================== Class MQTTConnect ======================================*/ class MQTTConnect : public MQTTMessage{ public: MQTTConnect(); ~MQTTConnect(); void setProtocol(uint8_t); void setUserName(string*); void setPassword(string*); void setKeepAliveTime(uint16_t); void setWillMessage(string*); void setWillTopic(string*); void setWillQos(uint8_t); void setClientId(string*); void setCleanSessionFlg(); uint16_t serialize(uint8_t* buf); private: uint8_t _connectFlags; uint16_t _keepAliveTime; string _userName; string _password; string _willTopic; string _willMessage; string _clientId; uint8_t _protocol; }; /*===================================== Class MQTTPublish ======================================*/ class MQTTPublish : public MQTTMessage{ public: MQTTPublish(); ~MQTTPublish(); void setMessageId(uint16_t); void setPayload(uint8_t*, uint8_t); void setTopic(string*); string* getTopic(); uint16_t getMessageId(); uint8_t* getPayload(); uint8_t getPayloadLength(); uint16_t serialize(uint8_t* buf); bool deserialize(uint8_t* buf); private: //string _topic; uint16_t _len; }; #endif /* MESSAGES_H_ */ ================================================ FILE: Gateway/src/lib/ProcessFramework.cpp ================================================ /* * ProcessFramework.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "ProcessFramework.h" #include "Defines.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; extern const char* theCmdlineParameter; extern int optind; /*===================================== Global functions & variables ======================================*/ Process* theProcess = 0; MultiTaskProcess* theMultiTask = 0; static volatile int theSignaled = 0; static void signalHandler(int sig){ theSignaled = sig; } int main(int argc, char** argv){ try{ signal(SIGINT, signalHandler); theProcess->initialize(argc, argv); theProcess->run(); }catch(Exception& ex){ ex.writeMessage(); } return 0; } uint8_t* mqcalloc(uint8_t len){ uint8_t* pos = (uint8_t*)calloc(len, sizeof(uint8_t)); if( pos == 0){ THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't allocate memory."); } return pos; } #ifdef CPU_LITTLEENDIANN /*--- For Little endianness ---*/ uint16_t getUint16(uint8_t* pos){ uint16_t val = ((uint16_t)*pos++ << 8); return val += *pos; } void setUint16(uint8_t* pos, uint16_t val){ *pos++ = (val >> 8) & 0xff; *pos = val & 0xff; } uint32_t getUint32(uint8_t* pos){ uint32_t val = (uint32_t(*pos++ << 24)); val += (uint32_t(*pos++ << 16)); val += (uint32_t(*pos++ << 8)); return val += *pos++; } void setUint32(uint8_t* pos, uint32_t val){ *pos++ = (val >> 24) & 0xff; *pos++ = (val >> 16) & 0xff; *pos++ = (val >> 8) & 0xff; *pos = val & 0xff; } #endif #ifdef CPU_BIGENDIANN /*--- For Big endianness ---*/ uint16_t getUint16(uint8_t* pos){ uint16_t val = *pos++; return val += ((uint16_t)*pos++ << 8); } void setUint16(uint8_t* pos, uint16_t val){ *pos++ = val & 0xff; *pos = (val >> 8) & 0xff; } long getUint32(uint8_t* pos){ long val = (uint32_t(*(pos + 3)) << 24) + (uint32_t(*(pos + 2)) << 16) + (uint32_t(*(pos + 1)) << 8); return val += *pos; } void setUint32(uint8_t* pos, uint32_t val){ *pos++ = val & 0xff; *pos++ = (val >> 8) & 0xff; *pos++ = (val >> 16) & 0xff; *pos = (val >> 24) & 0xff; } #endif void utfSerialize(uint8_t* pos, string str){ setUint16(pos, (uint16_t)str.size()); str.copy((char*)pos + 2, str.size(), 0); } char theCurrentTime[32]; char* currentDateTime() { time_t now = time(0); struct tm tstruct; tstruct = *localtime(&now); strftime(theCurrentTime, sizeof(theCurrentTime), "%Y%m%d %H%M%S", &tstruct); return theCurrentTime; } /*===================================== Class Process ======================================*/ Process::Process(){ _argc = 0; _argv = 0; _rb = new RingBuffer(); _rbsem = new Semaphore(TOMYFRAME_RB_SEMAPHOR_NAME, 0); } Process::~Process(){ delete(_rb); delete(_rbsem); } void Process::run(){ } void Process::initialize(int argc, char** argv){ _argc = argc; _argv = argv; } int Process::getArgc(){ return _argc; } char** Process::getArgv(){ return _argv; } char* Process::getArgv(char option){ char arg; optind = 1; while((arg = getopt(_argc, _argv, theCmdlineParameter))!= -1 && (arg != 255)){ if(arg == option){ return optarg; } } return 0; } int Process::getParam(const char* parameter, char* value){ char str[TOMYFRAME_PARAM_MAX], param[TOMYFRAME_PARAM_MAX]; FILE *fp; int i = 0, j = 0; if ((fp = fopen(TOMYFRAME_CONFIG_FILE, "r")) == NULL) { LOGWRITE("No config file:[%s]\n", TOMYFRAME_CONFIG_FILE); return -1; } while(true) { if (fgets(str, TOMYFRAME_PARAM_MAX - 1, fp) == NULL) { fclose(fp); return -3; } if (!strncmp(str, parameter,strlen(parameter))) { while (str[i++] != '=') { ; } while (str[i] != '\n') { param[j++] = str[i++]; } param[j] = '\0'; for( i = strlen(param)-1; i >= 0 && isspace( param[i] ); i-- ) ; param[i+1] = '\0'; for( i = 0; isspace( param[i] ); i++ ) ; if( i > 0 ) { j = 0; while( param[i] ) param[j++] = param[i++]; param[j] = '\0'; } strcpy(value,param); fclose(fp); return 0; } } fclose(fp); return -2; } void Process::putLog(const char* format, ...){ _mt.lock(); va_list arg; va_start(arg, format); vsprintf(_rbdata, format, arg); va_end(arg); if(strlen(_rbdata)){ _rb->put(_rbdata); _rbsem->post(); } _mt.unlock(); } const char* Process::getLog(){ int len = 0; _mt.lock(); while((len = _rb->get(_rbdata, PROCESS_LOG_BUFFER_SIZE)) == 0){ _rbsem->wait(); } *(_rbdata + len) = 0; _mt.unlock(); return _rbdata; } void Process::resetRingBuffer(){ _rb->reset(); } int Process::checkSignal(){ return theSignaled; } /*===================================== Class MultiTaskProcess ======================================*/ MultiTaskProcess::MultiTaskProcess(){ theMultiTask = this; } MultiTaskProcess::~MultiTaskProcess(){ } void MultiTaskProcess::initialize(int argc, char** argv){ Process::initialize(argc, argv); list::iterator thread = _threadList.begin(); while( thread != _threadList.end()){ (*thread)->initialize(argc, argv); ++thread; } } void MultiTaskProcess::run(){ list::iterator thread = _threadList.begin(); while(thread != _threadList.end()){ (*thread)->start(); thread++; } _stopProcessEvent.wait(); thread = _threadList.begin(); while(thread != _threadList.end()){ (*thread)->cancel(); (*thread)->join(); thread++; } } Semaphore* MultiTaskProcess::getStopProcessEvent(){ return &_stopProcessEvent; } void MultiTaskProcess::attach(Thread* thread){ _threadList.push_back(thread); } char* MultiTaskProcess::getArgv(char option){ _mutex.lock(); char* arg = Process::getArgv(option); _mutex.unlock(); return arg; } int MultiTaskProcess::getParam(const char* parameter, char* value){ _mutex.lock(); int rc = Process::getParam(parameter, value); _mutex.unlock(); if(rc == -1){ THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "No config file."); } return rc; } /*===================================== Class Thread =====================================*/ Thread::Thread(){ _stopProcessEvent = theMultiTask->getStopProcessEvent(); _threadID = 0; } Thread::~Thread(){ } void* Thread::_run(void* runnable){ static_cast(runnable)->EXECRUN(); return 0; } void Thread::initialize(int argc, char** argv){ } pthread_t Thread::getID(){ return pthread_self(); } bool Thread::equals(pthread_t *t1, pthread_t *t2){ return (pthread_equal(*t1, *t2) ? false : true); } int Thread::start(void){ Runnable *runnable = this; return pthread_create(&_threadID, 0, _run, runnable); } int Thread::join(void){ return pthread_join(_threadID, 0); } int Thread::cancel(void){ return pthread_cancel(_threadID); } void Thread::stopProcess(void){ _stopProcessEvent->post(); } /*===================================== Class Mutex =====================================*/ Mutex::Mutex(void){ pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutex_init(&_mutex, &attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); _shmid = 0; _pmutex = 0; } Mutex::Mutex(const char* fileName){ pthread_mutexattr_t attr; key_t key = ftok(fileName, 1); if((_shmid = shmget(key, sizeof(pthread_mutex_t), IPC_CREAT | 0666)) < 0){ //perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a shared memory."); } _pmutex = (pthread_mutex_t*)shmat(_shmid, NULL, 0); if(_pmutex < 0 ){ //perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't attach shared memory for Mutex."); } pthread_mutexattr_init(&attr); if(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0) { //perror("Mutex pthread_mutexattr_setpshared"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a Mutex."); } if(pthread_mutex_init(_pmutex, &attr) != 0) { //perror("Mutex pthread_mutexattr_setpshared"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a Mutex."); } } Mutex::~Mutex(void){ if(_pmutex){ pthread_mutex_lock(_pmutex); pthread_mutex_unlock(_pmutex); pthread_mutex_destroy(_pmutex); }else{ pthread_mutex_lock(&_mutex); pthread_mutex_unlock(&_mutex); pthread_mutex_destroy(&_mutex); } if(_shmid){ shmctl(_shmid, IPC_RMID, NULL); } } void Mutex::lock(void){ if(_pmutex){ pthread_mutex_lock(_pmutex); }else{ try{ if(pthread_mutex_lock(&_mutex)){ throw; } }catch(char* errmsg){ //perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "The same thread can't aquire a mutex twice."); } } } void Mutex::unlock(void){ if(_pmutex){ pthread_mutex_unlock(_pmutex); }else{ try { if(pthread_mutex_unlock(&_mutex)){ throw; } }catch(char* errmsg){ //perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't release a mutex."); } } } /*===================================== Class Semaphore =====================================*/ Semaphore::Semaphore(){ Semaphore(0); } Semaphore::Semaphore(unsigned int val){ sem_init(&_sem, 0, val); _name = 0; _psem = 0; } Semaphore::Semaphore(const char* name,unsigned int val){ _psem = sem_open(name, O_CREAT, 0666, val); if(_psem == SEM_FAILED ){ //perror("Semaphore"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a Semaphore."); } _name = (char*)mqcalloc(strlen(name + 1)); strcpy(_name, name); } Semaphore::~Semaphore(){ if(_name){ sem_close(_psem); sem_unlink(_name); free((void*)_name); }else{ sem_destroy(&_sem); } } void Semaphore::post(void){ int val = 0; if(_psem){ sem_getvalue(_psem,&val); if(val <= 0){ sem_post(_psem); } }else{ sem_getvalue(&_sem,&val); if(val <= 0){ sem_post(&_sem); } } } void Semaphore::wait(void){ if(_psem){ sem_wait(_psem); }else{ sem_wait(&_sem); } } void Semaphore::timedwait(uint16_t millsec){ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += millsec / 1000; ts.tv_nsec = (millsec % 1000) * 1000000; if(_psem){ sem_timedwait(_psem, &ts); }else{ sem_timedwait(&_sem, &ts); } } /*========================================= Class RingBuffer =========================================*/ RingBuffer::RingBuffer(){ key_t key = ftok(TOMYFRAME_RINGBUFFER_KEY, 1); if((_shmid = shmget(key, RINGBUFFER_SIZE, IPC_CREAT | IPC_EXCL | 0666)) >= 0){ if((_shmaddr = (uint16_t*)shmat(_shmid, NULL, 0)) > 0 ){ _length = (uint16_t*)_shmaddr; _start = (uint16_t*)_length + sizeof(uint16_t*); _end = (uint16_t*)_start + sizeof(uint16_t*); _buffer = (char*)_end + sizeof(uint16_t*); _createFlg = true; *_length = RINGBUFFER_SIZE - sizeof(uint16_t*) * 3 - 16; *_start = *_end = 0; }else{ //perror("RingBuffer"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't attach shared memory."); } }else if((_shmid = shmget(key, RINGBUFFER_SIZE, IPC_CREAT | 0666)) >= 0){ if((_shmaddr = (uint16_t*)shmat(_shmid, NULL, 0)) > 0 ){ _length = (uint16_t*)_shmaddr; _start = (uint16_t*)_length + sizeof(uint16_t*); _end = (uint16_t*)_start + sizeof(uint16_t*); _buffer = (char*)_end + sizeof(uint16_t*); _createFlg = false; }else{ //perror("RingBuffer"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a shared memory."); } }else{ //perror("RingBuffer"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a shared memory."); } _pmx = new Mutex(TOMYFRAME_RB_MUTEX_KEY); } RingBuffer::~RingBuffer(){ if(_createFlg){ if(_shmid > 0){ shmctl(_shmid, IPC_RMID, NULL); } if(_pmx > 0){ delete _pmx; } }else{ if(_shmid > 0){ shmdt(_shmaddr); } } } void RingBuffer::put(char* data){ _pmx->lock(); uint16_t dlen = strlen(data); uint16_t blen = *_length - *_end; if(*_end > *_start){ if(dlen < blen){ strncpy(_buffer + *_end, data, dlen); if(*_end - *_start == 1){ // Buffer is empty. *_start = *_end; } *_end += dlen; }else{ strncpy(_buffer + *_end, data, blen); strncpy(_buffer, data + blen, dlen - blen); if(*_end - *_start == 1){ // Buffer is empty. *_start = *_end; *_end = dlen - blen; }else{ *_end = dlen - blen; *_start = *_end + 1; } } }else if(*_end == *_start){ if(dlen < blen){ strncpy(_buffer + *_end, data, dlen); *_end += dlen; }else{ const char* errmsg = "RingBuffer Error: data is too long"; strcpy(_buffer + *_end, errmsg); *_end += strlen(errmsg); } }else{ // *_end < *_start if(dlen < *_start - *_end){ strncpy(_buffer + *_end, data, dlen); *_end += dlen; *_start = *_end + 1; }else { if( dlen < blen){ strncpy(_buffer + *_end, data, dlen); *_end += dlen; *_start = *_end + 1; }else { strncpy(_buffer + *_end, data, blen); strncpy(_buffer, data + blen, dlen - blen); *_start = *_end; *_end = dlen - blen; } } } _pmx->unlock(); } int RingBuffer::get(char* buf, int length){ int len = 0; _pmx->lock(); if(*_end > *_start){ if(length > *_end - *_start){ len = *_end - *_start; if (len == 1){ len = 0; } strncpy(buf, _buffer + *_start, len); *_start = *_end - 1; }else{ len = length; strncpy(buf, _buffer + *_start, len); *_start = *_start + len; } }else if(*_end < *_start){ int blen = *_length - *_start; if(length > blen ){ strncpy(buf, _buffer + *_start, blen); *_start = 0; if(length - (blen + *_end) > 0){ strncpy(buf + blen , _buffer, *_end); len = blen + *_end; if(*_end > 0){ *_start = *_end - 1; } }else{ strncpy(buf + blen, _buffer, length - blen); len = length; *_start = length - blen; } }else{ strncpy(buf, _buffer + *_start, length); *_start += length; len = length; } } _pmx->unlock(); return len; } void RingBuffer::reset(){ _pmx->lock(); *_start = *_end = 0; _pmx->unlock(); } /*===================================== Class Exception ======================================*/ Exception::Exception(const ExceptionType type, const int exNo, const string& message){ _message = message; _type = type; _exNo = exNo; _fileName = 0; _functionName = 0; _line = 0; } Exception::Exception(const ExceptionType type, const int exNo, const string& message, const char* file, const char* function, const int line){ _message = message; _type = type; _exNo = exNo; _fileName = file; _functionName = function; _line = line; } Exception::~Exception() throw(){ } const char* Exception::what() const throw() { return _message.c_str(); } const char* Exception::getFileName(){ return _fileName; } const char* Exception::getFunctionName(){ return _functionName; } const int Exception::getLineNo(){ return _line; } const int Exception::getExceptionNo(){ return _exNo; } bool Exception::isFatal(){ return _type == ExFatal; } const char* Exception::strType(){ switch(_type){ case ExInfo: return "Info"; break; case ExWarn: return "Warn"; break; case ExError: return "Error"; break; case ExFatal: return "Fatal"; break; case ExDebug: return "Debug"; break; default: break; } return ""; } void Exception::writeMessage(){ fprintf(stdout, "%s %5s:%-6d %s line %-4d %s() : %s\n", currentDateTime(), strType(), getExceptionNo(), getFileName(), getLineNo(), getFunctionName(), what()); } /*========================================= Class Timer =========================================*/ Timer::Timer(){ stop(); } void Timer::start(uint32_t msec){ gettimeofday(&_startTime, 0); _millis = msec; } bool Timer::isTimeup(){ return isTimeup(_millis); } bool Timer::isTimeup(uint32_t msec){ struct timeval curTime; long secs, usecs; if (_startTime.tv_sec == 0){ return false; }else{ gettimeofday(&curTime, 0); secs = (curTime.tv_sec - _startTime.tv_sec) * 1000; usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0; return ((secs + usecs) > (long)msec); } } void Timer::stop(){ _startTime.tv_sec = 0; _millis = 0; } ================================================ FILE: Gateway/src/lib/ProcessFramework.h ================================================ /* * ProcessFramework.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef PROCESSFRAMEWORK_H_ #define PROCESSFRAMEWORK_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Defines.h" #include #include #include #define TOMYFRAME_PARAM_MAX 128 #define TOMYFRAME_CONFIG_FILE "/usr/local/etc/tomygateway/config/param.conf" #define TOMYFRAME_RINGBUFFER_KEY "/usr/local/etc/tomygateway/config/ringbuffer.key" #define TOMYFRAME_RB_MUTEX_KEY "/usr/local/etc/tomygateway/config/rbmutex.key" #define TOMYFRAME_RB_SEMAPHOR_NAME "/rbsemaphor" #define LOGWRITE theProcess->putLog //#define LOGWRITE printf #define RINGBUFFER_SIZE 16384 #define PROCESS_LOG_BUFFER_SIZE 2048 #define ERRNO_SYS_01 1 // Application Frame Error using namespace std; /*================================= * Data Type ==================================*/ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; /*===================================== Class Mutex ====================================*/ class Mutex{ public: Mutex(); Mutex(const char* name); ~Mutex(); void lock(void); void unlock(void); private: pthread_mutex_t _mutex; pthread_mutex_t* _pmutex; int _shmid; }; /*===================================== Class Semaphore ====================================*/ class Semaphore{ public: Semaphore(); Semaphore(unsigned int val); Semaphore(const char* name, unsigned int val); ~Semaphore(); void post(void); void wait(void); void timedwait(uint16_t millsec); private: sem_t* _psem; sem_t _sem; char* _name; }; /*===================================== Class EventQue ====================================*/ template class EventQue{ public: EventQue(); ~EventQue(); T* wait(void); T* timedwait(uint16_t millsec); int post(T*); int size(); private: queue _que; Mutex _mutex; Semaphore _sem; }; /*===================================== Class RingBuffer =====================================*/ class RingBuffer{ public: RingBuffer(); ~RingBuffer(); void put(char* buffer); int get(char* buffer, int bufferLength); void reset(); private: void* _shmaddr; uint16_t* _length; uint16_t* _start; uint16_t* _end; char* _buffer; int _shmid; Mutex* _pmx; bool _createFlg; }; /*===================================== Class Thread ====================================*/ #define MAGIC_WORD_FOR_TASK \ public: void EXECRUN(){try{run();}catch(Exception& ex){ex.writeMessage();\ if(ex.isFatal()){stopProcess();}}catch(...){throw;}} class Runnable{ public: Runnable(){} virtual ~Runnable(){} virtual void initialized(int argc, char** argv){} virtual void EXECRUN(){} }; class Thread : virtual public Runnable{ public: Thread(); ~Thread(); int start(void); int join(void); int cancel(void); static pthread_t getID(); static bool equals(pthread_t*, pthread_t*); void initialize(int argc, char** argv); void stopProcess(void); private: pthread_t _threadID; Semaphore* _stopProcessEvent; void (*_initializePtr)(int argc, char** argv); static void* _run(void*); }; /*===================================== Class Process ====================================*/ class Process{ public: Process(); virtual ~Process(); void initialize(int argc, char** argv); virtual void run(); int getArgc(); char** getArgv(); char* getArgv(char option); int getParam(const char* param, char* value); void putLog(const char* format, ...); void resetRingBuffer(); int checkSignal(); const char* getLog(void); private: int _argc; char** _argv; RingBuffer* _rb; Mutex _mt; Semaphore* _rbsem; char _rbdata[PROCESS_LOG_BUFFER_SIZE + 1]; }; extern Process* theProcess; /*===================================== Class MultiTaskProcess ====================================*/ class MultiTaskProcess: public Process{ friend int main(int, char**); friend class Thread; public: MultiTaskProcess(); virtual ~MultiTaskProcess(); void attach(Thread* thread); int getArgc(); char** getArgv(); char* getArgv(char option); int getParam(const char* param, char* value); protected: void initialize(int argc, char** argv); void run(); Semaphore* getStopProcessEvent(); private: list _threadList; Semaphore _stopProcessEvent; Mutex _mutex; }; extern MultiTaskProcess* theMultiTask; /*===================================== Class Exception =====================================*/ enum ExceptionType { ExInfo = 0, ExWarn, ExError, ExFatal, ExDebug }; #define THROW_EXCEPTION(type, exceptionNo, message) \ throw Exception(type, exceptionNo, message, __FILE__, __func__, __LINE__) class Exception : public exception { public: Exception(const ExceptionType type, const int exNo, const string& message); Exception(const ExceptionType type, const int exNo, const string& message, const char*, const char*, const int); virtual ~Exception() throw(); const char* getFileName(); const char* getFunctionName(); const int getLineNo(); const int getExceptionNo(); virtual const char* what() const throw(); void writeMessage(); bool isFatal(); private: const char* strType(); ExceptionType _type; int _exNo; string _message; const char* _fileName; const char* _functionName; int _line; }; /*============================================ Timer ============================================*/ class Timer { public: Timer(); void start(uint32_t msec = 0); bool isTimeup(uint32_t msec); bool isTimeup(void); void stop(); private: struct timeval _startTime; uint32_t _millis; }; /*===================================== Class EventQue =====================================*/ template EventQue::EventQue(){ } template EventQue::~EventQue(){ _mutex.lock(); while(!_que.empty()){ delete _que.front(); _que.pop(); } _mutex.unlock(); } template T* EventQue::wait(void){ T* ev; _sem.wait(); _mutex.lock(); ev = _que.front(); _que.pop(); _mutex.unlock(); return ev; } template T* EventQue::timedwait(uint16_t millsec){ T* ev; _sem.timedwait(millsec); _mutex.lock(); if(_que.empty()){ ev = new T(); ev->setTimeout(); }else{ ev = _que.front(); _que.pop(); } _mutex.unlock(); return ev; } template int EventQue::post(T* ev){ _mutex.lock(); _que.push(ev); _mutex.unlock(); _sem.post(); return 0; } template int EventQue::size(){ _mutex.lock(); int sz = _que.size(); _mutex.unlock(); return sz; } #endif /* PROCESSFRAMEWORK_H_ */ ================================================ FILE: Gateway/src/lib/TCPStack.cpp ================================================ /* * Socket.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "Defines.h" #include "TCPStack.h" #include #include #include #include #include #include #include using namespace std; extern char* currentDateTime(); /*======================================== Class TCPStack =======================================*/ TCPStack::TCPStack(){ _addrinfo = 0; _disconReq = false; _sockfd = -1; } TCPStack::~TCPStack(){ if(_addrinfo){ freeaddrinfo(_addrinfo); } } bool TCPStack::isValid(){ if(_sockfd > 0){ if(_disconReq){ close(); _sem.post(); }else{ return true; } } return false; } void TCPStack::disconnect(){ if ( _sockfd > 0 ){ _disconReq = true; _sem.wait(); } } void TCPStack::close(){ if(_sockfd > 0){ ::close(_sockfd); _sockfd = -1; _disconReq = false; if(_addrinfo){ freeaddrinfo(_addrinfo); _addrinfo = 0; } } } bool TCPStack::bind ( const char* service ){ if(isValid()){ return false; } addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if (_addrinfo){ freeaddrinfo(_addrinfo); } int err = getaddrinfo(0, service, &hints, &_addrinfo); if (err) { LOGWRITE("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),gai_strerror(err)); return false; } _sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol); if (_sockfd < 0){ return false; } int on = 1; if ( setsockopt ( _sockfd, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ){ return false; } if( ::bind ( _sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen ) <0){ return false; } return true; } bool TCPStack::listen() { if ( !isValid() ){ return false; } int listen_return = ::listen ( _sockfd, SOCKET_MAXCONNECTIONS ); if ( listen_return == -1 ){ return false; } return true; } bool TCPStack::accept ( TCPStack& new_socket ){ sockaddr_storage sa; socklen_t len = sizeof ( sa ); new_socket._sockfd = ::accept ( _sockfd, (struct sockaddr*) &sa, &len ); if ( new_socket._sockfd <= 0 ){ return false; }else{ return true; } } int TCPStack::send (const uint8_t* buf, uint16_t length ){ return ::send ( _sockfd, buf, length, MSG_NOSIGNAL ); } int TCPStack::recv ( uint8_t* buf, uint16_t len ){ return ::recv ( _sockfd, buf, len, 0 ); } bool TCPStack::connect ( const char* host, const char* service ){ if(isValid()){ return false; } addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; if (_addrinfo){ freeaddrinfo(_addrinfo); } int err = getaddrinfo(host, service, &hints, &_addrinfo); if (err) { LOGWRITE("\n%s \x1b[0m\x1b[31merror:\x1b[0m\x1b[37mgetaddrinfo(): %s\n", currentDateTime(),gai_strerror(err)); return false; } int sockfd = socket(_addrinfo->ai_family, _addrinfo->ai_socktype, _addrinfo->ai_protocol); if (sockfd < 0){ return false; } int on = 1; if ( setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ){ return false; } if( ::connect (sockfd, _addrinfo->ai_addr, _addrinfo->ai_addrlen ) <0){ //perror("TCPStack connect"); ::close(sockfd); return false; } _sockfd = sockfd; return true; } void TCPStack::setNonBlocking ( const bool b ){ int opts; opts = fcntl ( _sockfd, F_GETFL ); if ( opts < 0 ){ return; } if ( b ){ opts = ( opts | O_NONBLOCK ); }else{ opts = ( opts & ~O_NONBLOCK ); } fcntl ( _sockfd, F_SETFL,opts ); } ================================================ FILE: Gateway/src/lib/TCPStack.h ================================================ /* * TCPStack.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef TCPSTACK_H #define TCPSTACK_H #include #include #include #include #include #include #include #include "Defines.h" #include "Messages.h" #define SOCKET_MAXCONNECTIONS 5 #define SOCKET_MAXBUFFER_LENGTH 1280 // buffer size using namespace std; /*======================================== Class TCPStack =======================================*/ class TCPStack{ public: TCPStack(); virtual ~TCPStack(); void disconnect(); // Server initialization bool bind( const char* service ); bool listen(); bool accept( TCPStack& ); // Client initialization bool connect( const char* host, const char* service ); int send( const uint8_t* buf, uint16_t length ); int recv ( uint8_t* buf, uint16_t len ); void close(); void setNonBlocking( const bool ); bool isValid(); int getSock(){return _sockfd;} private: int _sockfd; addrinfo* _addrinfo; Semaphore _sem; bool _disconReq; }; #endif /* TCPSTACK_H */ ================================================ FILE: Gateway/src/lib/TLSStack.cpp ================================================ /* * TLSStack.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "Defines.h" #include "TLSStack.h" #include #include #include #include using namespace std; int TLSStack::_numOfInstance = 0; SSL_CTX* TLSStack::_ctx = 0; SSL_SESSION* TLSStack::_session = 0; /*======================================== Class TLSStack =======================================*/ TLSStack::TLSStack(){ TLSStack(true); } TLSStack::TLSStack(bool secure):TCPStack(){ char error[256]; if(secure){ _numOfInstance++; if(_ctx == 0){ SSL_load_error_strings(); SSL_library_init(); _ctx = SSL_CTX_new(TLSv1_2_client_method()); if(_ctx == 0){ ERR_error_string_n(ERR_get_error(), error, sizeof(error)); LOGWRITE("SSL_CTX_new() %s\n",error); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't create SSL context."); } if(!SSL_CTX_load_verify_locations(_ctx, 0,TLS_CA_DIR)){ ERR_error_string_n(ERR_get_error(), error, sizeof(error)); LOGWRITE("SSL_CTX_load_verify_locations() %s\n",error); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't load CA_LIST."); } } } _ssl = 0; _disconReq = false; _secureFlg = secure; _busy = false; } TLSStack::~TLSStack(){ if(_secureFlg){ _numOfInstance--; } if(_ssl){ SSL_free(_ssl); } if(_session && _numOfInstance == 0){ SSL_SESSION_free(_session); _session = 0; } if(_ctx && _numOfInstance == 0){ SSL_CTX_free(_ctx); _ctx = 0; ERR_free_strings(); } } bool TLSStack::connect ( const char* host, const char* service ){ char errmsg[256]; int rc = 0; char peer_CN[256]; SSL_SESSION* sess = 0; X509* peer; if(isValid()){ return false; } if(!TCPStack::connect(host, service)){ return false; } if(!_secureFlg){ return true; } SSL* ssl = SSL_new(_ctx); if(ssl == 0){ ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); LOGWRITE("SSL_new() %s\n",errmsg); return false; } rc = SSL_set_fd(ssl, TCPStack::getSock()); if(rc == 0){ SSL_free(ssl); return false; } if(_session){ rc = SSL_set_session(ssl, sess); }else{ rc = SSL_connect(ssl); } if(rc != 1){ ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); LOGWRITE("SSL_connect() %s\n",errmsg); SSL_free(ssl); return false; } if(SSL_get_verify_result(ssl) != X509_V_OK){ LOGWRITE("SSL_get_verify_result() error: Certificate doesn't verify.\n"); SSL_free(ssl); return false; } peer = SSL_get_peer_certificate(ssl); X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 256); if(strcasecmp(peer_CN, host)){ LOGWRITE("SSL_get_peer_certificate() error: Broker dosen't much host name.\n"); SSL_free(ssl); return false; } if(_session == 0){ _session = sess; } _ssl = ssl; return true; } int TLSStack::send (const uint8_t* buf, uint16_t length ){ char errmsg[256]; fd_set rset; fd_set wset; bool writeBlockedOnRead = false; int bpos = 0; if(_secureFlg){ _mutex.lock(); _busy = true; while(true){ FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(getSock(), &rset); FD_SET(getSock(), &wset); int activity = select( getSock() + 1 , &rset , &wset , 0 , 0); if (activity > 0){ if(FD_ISSET(getSock(),&wset) || (writeBlockedOnRead && FD_ISSET(getSock(),&rset))){ writeBlockedOnRead = false; int r = SSL_write(_ssl, buf + bpos, length); switch(SSL_get_error(_ssl, r)){ case SSL_ERROR_NONE: length -= r; bpos += r; if( length == 0){ _busy = false; _mutex.unlock(); return bpos; } break; case SSL_ERROR_WANT_WRITE: break; case SSL_ERROR_WANT_READ: writeBlockedOnRead = true; break; default: ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); LOGWRITE("TLSStack::send() default %s\n",errmsg); _busy = false; _mutex.unlock(); return -1; } } } } }else{ return TCPStack::send (buf, length); } } int TLSStack::recv ( uint8_t* buf, uint16_t len ){ char errmsg[256]; bool writeBlockedOnRead = false; bool readBlockedOnWrite = false; bool readBlocked = false; int rlen = 0; int bpos = 0; fd_set rset; fd_set wset; if(_secureFlg){ if(_busy){ return 0; } _mutex.lock(); _busy = true; loop: do{ readBlockedOnWrite = false; readBlocked = false; rlen = SSL_read(_ssl, buf + bpos, len - bpos); switch (SSL_get_error(_ssl, rlen)){ case SSL_ERROR_NONE: _busy = false; _mutex.unlock(); return rlen + bpos; break; case SSL_ERROR_ZERO_RETURN: SSL_shutdown(_ssl); _ssl = 0; TCPStack::close(); _busy = false; _mutex.unlock(); return -1; break; case SSL_ERROR_WANT_READ: readBlocked = true; break; case SSL_ERROR_WANT_WRITE: readBlockedOnWrite = true; break; default: ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); LOGWRITE("TLSStack::recv() default %s\n", errmsg); _busy = false; _mutex.unlock(); return -1; } }while(SSL_pending(_ssl) && !readBlocked); bpos += rlen; while(true){ FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(getSock(), &rset); FD_SET(getSock(), &wset); int activity = select( getSock() + 1 , &rset , &wset , 0 , 0); if (activity > 0){ if((FD_ISSET(getSock(),&rset) && !writeBlockedOnRead) || (readBlockedOnWrite && FD_ISSET(getSock(),&wset))){ goto loop; } }else{ ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg)); LOGWRITE("TLSStack::recv() select %s\n",errmsg); _busy = false; _mutex.unlock(); return -1; } } } return TCPStack::recv (buf, len); } bool TLSStack::isValid(){ if(!_secureFlg){ return TCPStack::isValid(); } if(_ssl){ if(_disconReq){ SSL_shutdown(_ssl); _ssl = 0; TCPStack::close(); _disconReq = false; }else{ return true; } } return false; } void TLSStack::disconnect(){ if (_ssl){ _disconReq = true; TCPStack::disconnect(); }else{ TCPStack::disconnect(); } } int TLSStack::getSock(){ return TCPStack::getSock(); } SSL* TLSStack::getSSL(){ if(_secureFlg){ return _ssl; }else{ return 0; } } bool TLSStack::isSecure(){ return _secureFlg; } ================================================ FILE: Gateway/src/lib/TLSStack.h ================================================ /* * TLSStack.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef TLSSTACK_H #define TLSSTACK_H #include #include #include #include #include "Defines.h" #include "Messages.h" #include "TCPStack.h" #define TLS_CA_DIR "/etc/ssl/certs" using namespace std; /*======================================== Class TLSStack =======================================*/ class TLSStack:public TCPStack{ public: TLSStack(); TLSStack(bool secure); virtual ~TLSStack(); bool connect( const char* host, const char* service ); void disconnect(); int send( const uint8_t* buf, uint16_t length ); int recv ( uint8_t* buf, uint16_t len ); bool isValid(); bool isSecure(); int getSock(); SSL* getSSL(); private: static SSL_CTX* _ctx; static int _numOfInstance; static SSL_SESSION* _session; SSL* _ssl; bool _secureFlg; bool _disconReq; Mutex _mutex; bool _busy; }; #endif /* TLSSTACK_H */ ================================================ FILE: Gateway/src/lib/Topics.cpp ================================================ /* * Topics.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "Topics.h" #include "Messages.h" #include extern uint16_t getUint16(uint8_t* pos); /*===================================== Class Topic ======================================*/ Topic::Topic(){ _topicId = 0; } Topic::Topic(string topic){ _topicId = 0; _topicStr = topic; } Topic::~Topic(){ } uint16_t Topic::getTopicId(){ return _topicId; } string* Topic::getTopicName(){ return &_topicStr; } uint8_t Topic::getTopicLength(){ return (uint8_t)_topicStr.size(); } void Topic::setTopicId(uint16_t id){ _topicId = id; } void Topic::setTopicName(string topic){ _topicStr = topic; } uint8_t Topic::isWildCard(uint8_t* pos){ unsigned int p = _topicStr.find("MQTTSN_TOPIC_SINGLE_WILDCARD", 0); if( p != string::npos){ *pos = p; return MQTTSN_TOPIC_SINGLE_WILDCARD; }else{ p = _topicStr.find("MQTTSN_TOPIC_MULTI_WILDCARD", 0); if( p != string::npos){ *pos = p; return MQTTSN_TOPIC_MULTI_WILDCARD; } } *pos = 0; return 0; } bool Topic::isMatch(Topic* topic){ uint8_t pos; uint8_t pos1; if (topic->isWildCard(&pos) == MQTTSN_TOPIC_SINGLE_WILDCARD && (_topicStr.compare(0, (unsigned int)pos, (const string)*(topic->getTopicName()), 0, (unsigned int)pos) == 0 )){ pos1 = pos + 2; pos = _topicStr.find("/", ++pos); if(pos == string::npos ){ return true; }else{ if(_topicStr.substr(pos) == topic->getTopicName()->substr(pos1)){ return true; }else{ return false; } } }else if(topic->isWildCard(&pos) == MQTTSN_TOPIC_MULTI_WILDCARD && (_topicStr.compare(0, (unsigned int)pos, (const string)*(topic->getTopicName()), 0, (unsigned int)pos) == 0 )){ return true; } return false; } /*===================================== Class Topics ======================================*/ Topics::Topics(){ Topic* tp = new Topic(string(MQTTSN_TOPIC_PREDEFINED_TIME)); tp->setTopicId(MQTTSN_TOPICID_PREDEFINED_TIME); _topics.push_back(tp); _cnt = 1; _nextTopicId = MQTTSN_TOPICID_NORMAL; } Topics::~Topics() { for (uint8_t i = 0; i < _topics.size(); i++) { if(_topics[i]){ delete _topics[i]; } } } uint16_t Topics::getTopicId(string* topic){ Topic *p = getTopic(topic); if ( p != 0) { return p->getTopicId(); } return 0; } Topic* Topics::getTopic(string* topic) { for (uint8_t i = 0; i < _cnt; i++) { if(_topics[i]){ if( *topic == *(_topics[i]->getTopicName())){ return _topics[i]; } } } return 0; } Topic* Topics::getTopic(uint16_t id) { for (uint8_t i = 0; i < _cnt; i++) { if(_topics[i]){ if ( _topics[i]->getTopicId() == id) { return _topics[i]; } } } return 0; } uint16_t Topics::createTopic(string* topic){ if (!getTopic(topic)){ if ( _cnt < MAX_TOPIC_COUNT){ Topic* tp = new Topic(); tp->setTopicName(*topic); if(tp->getTopicLength() == 2){ uint16_t id = getUint16((uint8_t*)tp->getTopicName()); tp->setTopicId(id); }else{ tp->setTopicId(getNextTopicId()); } _topics.push_back(tp); _cnt++; return _nextTopicId; }else{ return 0; } }else{ return getTopicId(topic); } } uint16_t Topics::getNextTopicId(){ if(++_nextTopicId < MQTTSN_TOPICID_NORMAL){ _nextTopicId = MQTTSN_TOPICID_NORMAL; } return _nextTopicId; } Topic* Topics::match(string* topic){ uint8_t pos; for ( uint8_t i = 0; i< _cnt; i++){ if(_topics[i]){ if ( _topics[i]->isWildCard(&pos)){ if (getTopic(topic)->isMatch(_topics[i])){ return _topics[i]; } } } } return 0; } ================================================ FILE: Gateway/src/lib/Topics.h ================================================ /* * Topics.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef TOPICS_H_ #define TOPICS_H_ #include "ProcessFramework.h" #include "Messages.h" #include #define MQTTSN_TOPIC_MULTI_WILDCARD '#' #define MQTTSN_TOPIC_SINGLE_WILDCARD '+' #define MQTTSN_TOPICID_NORMAL 256 #define MQTTSN_TOPICID_PREDEFINED_TIME 0x0001 #define MQTTSN_TOPIC_PREDEFINED_TIME ("$GW/01") #define MAX_TOPIC_COUNT 50 // Number of Topic Par ClientNode /*===================================== Class Topic ======================================*/ class Topic { public: Topic(); Topic(string topic); ~Topic(); uint16_t getTopicId(); uint8_t getTopicLength(); string* getTopicName(); void setTopicId(uint16_t id); void setTopicName(string topic); uint8_t isWildCard(uint8_t* pos); bool isMatch(Topic* wildCard); private: uint16_t _topicId; string _topicStr; }; /*===================================== Class Topics ======================================*/ class Topics { public: Topics(); ~Topics(); uint16_t createTopic(string* topic); uint16_t getTopicId(string* topic); uint16_t getNextTopicId(); Topic* getTopic(string* topic); Topic* getTopic(uint16_t topicId); Topic* match(string* topic); bool deleteTopic(string* topic); private: uint16_t _nextTopicId; uint8_t _cnt; vector _topics; }; #endif /* TOPICS_H_ */ ================================================ FILE: Gateway/src/lib/UDPStack.cpp ================================================ /* * UDPStack.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "Defines.h" #ifdef NETWORK_UDP #include #include #include #include #include #include #include #include #include #include #include #include #include "ProcessFramework.h" #include "UDPStack.h" using namespace std; using namespace tomyGateway; extern uint16_t getUint16(uint8_t* pos); extern uint32_t getUint32(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); /*========================================= Class Network =========================================*/ Network::Network(){ } Network::~Network(){ } void Network::unicast(NWAddress64* addr64, uint16_t addr16, uint8_t* payload, uint16_t payloadLength){ UDPPort::unicast(payload, payloadLength, addr64->getLsb(), addr16); } void Network::broadcast(uint8_t* payload, uint16_t payloadLength){ UDPPort::multicast(payload, payloadLength); } bool Network::getResponse(NWResponse* response){ uint32_t ipAddress = 0; uint16_t portNo = 0; uint16_t msgLen; uint8_t msgType; uint8_t* buf = response->getPayloadPtr(); uint16_t recvLen = UDPPort::recv(buf, MQTTSN_MAX_FRAME_SIZE, &ipAddress, &portNo); if(recvLen < 0){ return false; }else{ if(buf[0] == 0x01){ msgLen = getUint16(buf + 1); msgType = *(buf + 3); }else{ msgLen = (uint16_t)*(buf); msgType = *(buf + 1); } if(msgLen != recvLen){ return false; } response->setLength(msgLen); response->setMsgType(msgType); response->setClientAddress16(portNo); response->setClientAddress64(0, ipAddress); return true; } } int Network::initialize(UdpConfig config){ return UDPPort::open(config); } /*========================================= Class udpStack =========================================*/ UDPPort::UDPPort(){ _disconReq = false; _sockfdUnicast = -1; _sockfdMulticast = -1; _gPortNo = 0; _gIpAddr = 0; } UDPPort::~UDPPort(){ close(); } void UDPPort::close(){ if(_sockfdUnicast > 0){ ::close( _sockfdUnicast); _sockfdUnicast = -1; } if(_sockfdMulticast > 0){ ::close( _sockfdMulticast); _sockfdMulticast = -1; } } int UDPPort::open(UdpConfig config){ char loopch = 0; const int reuse = 1; if(config.uPortNo == 0 || config.gPortNo == 0){ return -1; } _gPortNo = htons(config.gPortNo); _gIpAddr = inet_addr(config.ipAddress); /*------ Create unicast socket --------*/ _sockfdUnicast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (_sockfdUnicast < 0){ return -1; } setsockopt(_sockfdUnicast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); sockaddr_in addru; addru.sin_family = AF_INET; addru.sin_port = htons(config.uPortNo); addru.sin_addr.s_addr = INADDR_ANY; if( ::bind ( _sockfdUnicast, (sockaddr*)&addru, sizeof(addru)) <0){ return -1; } if(setsockopt(_sockfdUnicast, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)&loopch, sizeof(loopch)) <0 ){ D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n"); close(); return -1; } /*------ Create Multicast socket --------*/ _sockfdMulticast = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (_sockfdMulticast < 0){ close(); return -1; } setsockopt(_sockfdMulticast, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); sockaddr_in addrm; addrm.sin_family = AF_INET; addrm.sin_port = _gPortNo; addrm.sin_addr.s_addr = INADDR_ANY; if( ::bind ( _sockfdMulticast, (sockaddr*)&addrm, sizeof(addrm)) <0){ return -1; } if(setsockopt(_sockfdMulticast, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)&loopch, sizeof(loopch)) <0 ){ D_NWSTACK("error IP_MULTICAST_LOOP in UDPPort::open\n"); close(); return -1; } ip_mreq mreq; mreq.imr_interface.s_addr = INADDR_ANY; mreq.imr_multiaddr.s_addr = _gIpAddr; if( setsockopt(_sockfdMulticast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))< 0){ D_NWSTACK("error Multicast IP_ADD_MEMBERSHIP in UDPPort::open\n"); perror("multicast"); close(); return -1; } if( setsockopt(_sockfdUnicast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))< 0){ D_NWSTACK("error Unicast IP_ADD_MEMBERSHIP in UDPPort::open\n"); close(); return -1; } return 0; } int UDPPort::unicast(const uint8_t* buf, uint32_t length, uint32_t ipAddress, uint16_t port ){ sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_port = port; dest.sin_addr.s_addr = ipAddress; int status = ::sendto( _sockfdUnicast, buf, length, 0, (const sockaddr*)&dest, sizeof(dest) ); if( status < 0){ D_NWSTACK("errno == %d in UDPPort::sendto\n", errno); } D_NWSTACK("sendto %s:%u length = %d\n",inet_ntoa(dest.sin_addr), htons(port), status); return status; } int UDPPort::multicast( const uint8_t* buf, uint32_t length ){ return unicast(buf, length,_gIpAddr, _gPortNo); } int UDPPort::recv(uint8_t* buf, uint16_t len, uint32_t* ipAddressPtr, uint16_t* portPtr){ fd_set recvfds; int maxSock = 0; FD_ZERO(&recvfds); FD_SET(_sockfdUnicast, &recvfds); FD_SET(_sockfdMulticast, &recvfds); if(_sockfdMulticast > _sockfdUnicast){ maxSock = _sockfdMulticast; }else{ maxSock = _sockfdUnicast; } select(maxSock + 1, &recvfds, 0, 0, 0); if(FD_ISSET(_sockfdUnicast, &recvfds)){ return recvfrom (_sockfdUnicast,buf, len, 0,ipAddressPtr, portPtr ); }else if(FD_ISSET(_sockfdMulticast, &recvfds)){ return recvfrom (_sockfdMulticast,buf, len, 0,ipAddressPtr, portPtr ); } return 0; } int UDPPort::recvfrom (int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, uint32_t* ipAddressPtr, uint16_t* portPtr ){ sockaddr_in sender; socklen_t addrlen = sizeof(sender); memset(&sender, 0, addrlen); int status = ::recvfrom( sockfd, buf, len, flags, (sockaddr*)&sender, &addrlen ); if ( status < 0 && errno != EAGAIN ) { D_NWSTACK("errno == %d in UDPPort::recvfrom\n", errno); return -1; } *ipAddressPtr = (uint32_t)sender.sin_addr.s_addr; *portPtr = (uint16_t)sender.sin_port; D_NWSTACK("recved from %s:%d length = %d\n",inet_ntoa(sender.sin_addr),htons(*portPtr),status); return status; } /*========================================= Class NLLongAddress =========================================*/ NWAddress64::NWAddress64(){ _msb = _lsb = 0; } NWAddress64::NWAddress64(uint32_t msb, uint32_t lsb){ _msb = msb; _lsb = lsb; } uint32_t NWAddress64::getMsb(){ return _msb; } uint32_t NWAddress64::getLsb(){ return _lsb; } void NWAddress64::setMsb(uint32_t msb){ _msb = msb; } void NWAddress64::setLsb(uint32_t lsb){ _lsb = lsb; } bool NWAddress64::operator==(NWAddress64& addr){ if(_msb == addr.getMsb() && _lsb == addr.getLsb()){ return true; }else{ return false; } } /*========================================= Class ZBResponse =========================================*/ NWResponse::NWResponse(){ _addr16 = 0; memset( _frameDataPtr, 0, MQTTSN_MAX_FRAME_SIZE); } uint8_t NWResponse::getFrameLength(){ return _len; } void NWResponse::setLength(uint16_t len){ _len = len; } NWAddress64* NWResponse::getClientAddress64(){ return &_addr64; } uint16_t NWResponse::getClientAddress16(){ return _addr16; } void NWResponse::setClientAddress64(uint32_t msb, uint32_t lsb){ _addr64.setMsb(msb); _addr64.setLsb(lsb); } void NWResponse::setClientAddress16(uint16_t addr16){ _addr16 = addr16; } void NWResponse::setMsgType(uint8_t type){ _type = type; } uint8_t NWResponse::getMsgType(){ if(_len > 255){ return _frameDataPtr[3]; }else{ return _frameDataPtr[1]; } } uint8_t* NWResponse::getBody(){ if(_len > 255){ return _frameDataPtr + 4; }else{ return _frameDataPtr + 2; } } uint16_t NWResponse::getBodyLength(){ if(_len > 255){ return getPayloadLength() - 4; }else{ return getPayloadLength() - 2; } } uint8_t NWResponse::getPayload(uint8_t index){ return _frameDataPtr[index + 2]; } uint8_t* NWResponse::getPayloadPtr(){ return _frameDataPtr; } uint8_t NWResponse::getPayloadLength(){ return _len; } #endif /* NETWORK_UDP */ ================================================ FILE: Gateway/src/lib/UDPStack.h ================================================ /* * UDPStack.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef UDPSTACK_H_ #define UDPSTACK_H_ #include "Defines.h" #ifdef NETWORK_UDP #include "ProcessFramework.h" #include #include #include #include #include #include #include #include #include /* * MQTTS Client's state */ #define MQTTS_DEVICE_DISCONNECTED 0 #define MQTTS_DEVICE_ACTIVE 1 #define MQTTS_DEVICE_ASLEEP 2 #define MQTTS_DEVICE_AWAKE 3 #define MQTTS_DEVICE_LOST 4 #define MQTTSN_MAX_FRAME_SIZE 1024 using namespace std; namespace tomyGateway{ /*============================================ NWAddress64 =============================================*/ class NWAddress64 { public: NWAddress64(uint32_t msb, uint32_t lsb); NWAddress64(void); uint32_t getMsb(); uint32_t getLsb(); void setMsb(uint32_t msb); void setLsb(uint32_t lsb); bool operator==(NWAddress64&); private: uint32_t _msb; uint32_t _lsb; }; /*============================================ NWResponse =============================================*/ class NWResponse { public: NWResponse(); uint8_t getMsgType(); uint8_t getFrameLength(); uint8_t getPayload(uint8_t index); uint8_t* getPayloadPtr(); uint8_t* getBody(); uint16_t getBodyLength(); uint8_t getPayloadLength(); uint16_t getClientAddress16(); NWAddress64* getClientAddress64(); void setLength(uint16_t len); void setMsgType(uint8_t type); void setClientAddress64(uint32_t msb, uint32_t ipAddress); void setClientAddress16(uint16_t portNo); private: NWAddress64 _addr64; uint16_t _addr16; uint16_t _len; uint8_t _type; uint8_t _frameDataPtr[MQTTSN_MAX_FRAME_SIZE]; }; /*======================================== Class UpdPort =======================================*/ class UDPPort{ public: UDPPort(); virtual ~UDPPort(); int open(UdpConfig config); int unicast(const uint8_t* buf, uint32_t length, uint32_t ipaddress, uint16_t port ); int multicast( const uint8_t* buf, uint32_t length ); int recv(uint8_t* buf, uint16_t len, uint32_t* ipaddress, uint16_t* port ); private: void close(); void setNonBlocking( const bool ); int recvfrom (int sockfd, uint8_t* buf, uint16_t len, uint8_t flags, uint32_t* ipaddress, uint16_t* port ); int _sockfdUnicast; int _sockfdMulticast; uint16_t _gPortNo; uint32_t _gIpAddr; bool _disconReq; }; /*=========================================== Class Network ============================================*/ class Network:public UDPPort{ public: Network(); ~Network(); void unicast(NWAddress64* addr64, uint16_t addr16, uint8_t* payload, uint16_t payloadLength); void broadcast(uint8_t* payload, uint16_t payloadLength); bool getResponse(NWResponse* response); int initialize(UdpConfig config); private: }; } /* end of namespace */ #endif /* NETWORK_UDP */ #endif /* UDPSTACK_H_ */ ================================================ FILE: Gateway/src/lib/XXXXXStack.cpp ================================================ /* * XXXXXStack.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "Defines.h" #ifdef NETWORK_XXXXX #include #include #include #include #include #include #include #include #include #include #include #include #include "ProcessFramework.h" #include "XXXXXStack.h" using namespace std; using namespace tomyGateway; extern uint16_t getUint16(uint8_t* pos); extern uint32_t getUint32(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); /*========================================= Class Network =========================================*/ Network::Network(){ } Network::~Network(){ } void Network::unicast(NWAddress64* addr64, uint16_t addr16, uint8_t* payload, uint16_t payloadLength){ XXXXXPort::unicast( ); } void Network::broadcast(uint8_t* payload, uint16_t payloadLength){ XXXXXPort::multicast( ); } bool Network::getResponse(NWResponse* response){ } int Network::initialize(XXXXXConfig config){ return XXXXXPort::initialize(config); } /*========================================= Class XXXXXPort =========================================*/ XXXXXPort::XXXXXPort(){ } XXXXXPort::~XXXXXPort(){ close(); } void XXXXXPort::close(){ } int XXXXXPort::initialize(){ return initialize(_config); } int XXXXXPort::initialize(UdpConfig config){ _config.param1 = config.param1; _config.param2 = config.param2; _config.param3 = config.param3; } int XXXXXPort::unicast( ){ } int XXXXXPort::multicast(){ } int XXXXXPort::recv(){ } /*========================================= Class NLLongAddress =========================================*/ NWAddress64::NWAddress64(){ _msb = _lsb = 0; } NWAddress64::NWAddress64(uint32_t msb, uint32_t lsb){ _msb = msb; _lsb = lsb; } uint32_t NWAddress64::getMsb(){ return _msb; } uint32_t NWAddress64::getLsb(){ return _lsb; } void NWAddress64::setMsb(uint32_t msb){ _msb = msb; } void NWAddress64::setLsb(uint32_t lsb){ _lsb = lsb; } bool NWAddress64::operator==(NWAddress64& addr){ if(_msb == addr.getMsb() && _lsb == addr.getLsb()){ return true; }else{ return false; } } /*========================================= Class ZBResponse =========================================*/ NWResponse::NWResponse(){ _addr16 = 0; memset( _frameDataPtr, 0, MQTTSN_MAX_FRAME_SIZE); } uint8_t NWResponse::getFrameLength(){ return _len; } void NWResponse::setLength(uint16_t len){ _len = len; } NWAddress64* NWResponse::getClientAddress64(){ return &_addr64; } uint16_t NWResponse::getClientAddress16(){ return _addr16; } void NWResponse::setClientAddress64(uint32_t msb, uint32_t lsb){ _addr64.setMsb(msb); _addr64.setLsb(lsb); } void NWResponse::setClientAddress16(uint16_t addr16){ _addr16 = addr16; } void NWResponse::setMsgType(uint8_t type){ _type = type; } uint8_t NWResponse::getMsgType(){ if(_len > 255){ return _frameDataPtr[3]; }else{ return _frameDataPtr[1]; } } uint8_t* NWResponse::getBody(){ if(_len > 255){ return _frameDataPtr + 4; }else{ return _frameDataPtr + 2; } } uint16_t NWResponse::getBodyLength(){ if(_len > 255){ return getPayloadLength() - 4; }else{ return getPayloadLength() - 2; } } uint8_t NWResponse::getPayload(uint8_t index){ return _frameDataPtr[index + 2]; } uint8_t* NWResponse::getPayloadPtr(){ return _frameDataPtr; } uint8_t NWResponse::getPayloadLength(){ return _len; } #endif /* NETWORK_XXXXX */ ================================================ FILE: Gateway/src/lib/XXXXXStack.h ================================================ /* * UDPStack.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef XXXXXSTACK_H_ #define XXXXXSTACK_H_ #include "Defines.h" #ifdef NETWORK_XXXXX #include "ProcessFramework.h" #include #include #include #include #include #include #include #include #include /* * MQTTS Client's state */ #define MQTTS_DEVICE_DISCONNECTED 0 #define MQTTS_DEVICE_ACTIVE 1 #define MQTTS_DEVICE_ASLEEP 2 #define MQTTS_DEVICE_AWAKE 3 #define MQTTS_DEVICE_LOST 4 #define MQTTSN_MAX_FRAME_SIZE 1024 using namespace std; namespace tomyGateway{ /*============================================ NWAddress64 =============================================*/ class NWAddress64 { public: NWAddress64(uint32_t msb, uint32_t lsb); NWAddress64(void); uint32_t getMsb(); uint32_t getLsb(); void setMsb(uint32_t msb); void setLsb(uint32_t lsb); bool operator==(NWAddress64&); private: uint32_t _msb; uint32_t _lsb; }; /*============================================ NWResponse =============================================*/ class NWResponse { public: NWResponse(); uint8_t getMsgType(); uint8_t getFrameLength(); uint8_t getPayload(uint8_t index); uint8_t* getPayloadPtr(); uint8_t* getBody(); uint16_t getBodyLength(); uint8_t getPayloadLength(); uint16_t getClientAddress16(); NWAddress64* getClientAddress64(); void setLength(uint16_t len); void setMsgType(uint8_t type); void setClientAddress64(uint32_t msb, uint32_t ipAddress); void setClientAddress16(uint16_t portNo); private: NWAddress64 _addr64; uint16_t _addr16; uint16_t _len; uint8_t _type; uint8_t _frameDataPtr[MQTTSN_MAX_FRAME_SIZE]; }; /*======================================== Class XXXXXPort =======================================*/ class XXXXXPort{ public: XXXXXPort(); virtual ~XXXXXPort(); int initialize(XXXXXConfig config); int initialize(); int unicast( ); int multicast( ); int recv( ); private: void close(); XXXXXConfig _config; }; /*=========================================== Class Network ============================================*/ class Network:public XXXXXPort{ public: Network(); ~Network(); void unicast(NWAddress64* addr64, uint16_t addr16, uint8_t* payload, uint16_t payloadLength); void broadcast(uint8_t* payload, uint16_t payloadLength); bool getResponse(NWResponse* response); int initialize(XXXXXConfig config); private: }; } /* end of namespace */ #endif /* NETWORK_UDP */ #endif /* UDPSTACK_H_ */ ================================================ FILE: Gateway/src/lib/ZBStack.cpp ================================================ /* * ZBeeStack.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "Defines.h" #ifdef NETWORK_XBEE #include "Messages.h" #include "ZBStack.h" #include "ProcessFramework.h" #include #include #include #include #include #include #include #include using namespace std; extern uint8_t* mqcalloc(uint8_t length); extern uint16_t getUint16(uint8_t* pos); extern uint32_t getUint32(uint8_t* pos); extern void setUint16(uint8_t* pos, uint16_t val); extern void setUint32(uint8_t* pos, uint32_t val); /*========================================= Class NWAddress64 =========================================*/ NWAddress64::NWAddress64(){ _msb = _lsb = 0; } NWAddress64::NWAddress64(uint32_t msb, uint32_t lsb){ _msb = msb; _lsb = lsb; } uint32_t NWAddress64::getMsb(){ return _msb; } uint32_t NWAddress64::getLsb(){ return _lsb; } void NWAddress64::setMsb(uint32_t msb){ _msb = msb; } void NWAddress64::setLsb(uint32_t lsb){ _lsb = lsb; } bool NWAddress64::operator==(NWAddress64& addr){ if(_msb == addr.getMsb() && _lsb == addr.getLsb()){ return true; }else{ return false; } } /*========================================= Class NWBResponse =========================================*/ NWResponse::NWResponse(){ _frameDataPtr = 0; _msbLength = 0; _lsbLength = 0; _checksum = 0; _frameLength = 0; _errorCode = NO_ERROR; _complete = false; _apiId = 0; } NWResponse::~NWResponse(){ if(_frameDataPtr){ free(_frameDataPtr); } } uint8_t NWResponse::getMsbLength(){ return _msbLength; } uint8_t NWResponse::getLsbLength(){ return _lsbLength; } uint8_t NWResponse::getChecksum(){ return _checksum; } uint8_t NWResponse::getFrameDataLength(){ return _frameLength; } uint8_t* NWResponse::getFrameData(){ return _frameDataPtr; } uint16_t NWResponse::getPacketLength() { return ((_msbLength << 8) & 0xff) + (_lsbLength & 0xff); } void NWResponse::setMsbLength(uint8_t msbLength){ _msbLength = msbLength; } void NWResponse::setLsbLength(uint8_t lsbLength){ _lsbLength = lsbLength; } void NWResponse::setChecksum(uint8_t checksum){ _checksum = checksum; } void NWResponse::setFrameDataLength(uint8_t frameLength){ _frameLength = frameLength; } void NWResponse::setFrameData(uint8_t *frameDataPtr){ _frameDataPtr = frameDataPtr; } bool NWResponse::isAvailable(){ return _complete; } void NWResponse::setAvailable(bool complete){ _complete = complete; } bool NWResponse::isError(){ return _errorCode > 0; } uint8_t NWResponse::getErrorCode(){ return _errorCode; } void NWResponse::setErrorCode(uint8_t errorCode){ _errorCode = errorCode; } void NWResponse::setApiId(uint8_t apiId){ _apiId = apiId; } void NWResponse::reset(){ if(_frameDataPtr){ free(_frameDataPtr); } _msbLength = 0; _lsbLength = 0; _checksum = 0; _frameLength = 0; _errorCode = NO_ERROR; _complete = false; } uint8_t NWResponse::getPayload(int index){ return getFrameData()[ZB_PAYLOAD_OFFSET + index]; } uint8_t* NWResponse::getPayloadPtr(){ return getFrameData() + ZB_PAYLOAD_OFFSET; } uint8_t NWResponse::getPayloadLength(){ return getFrameDataLength() - ZB_PAYLOAD_OFFSET; } uint16_t NWResponse::getClientAddress16(){ return getUint16(getFrameData() + 8); } uint32_t NWResponse::getRemoteAddressMsb(){ return getUint32(getFrameData()); } uint32_t NWResponse::getRemoteAddressLsb(){ return getUint32(getFrameData() + 4); } NWAddress64* NWResponse::getClientAddress64(){ return &_addr64; } uint8_t NWResponse::getOption(){ return getFrameData()[10]; } uint8_t NWResponse::getType(){ if(_frameLength > 255){ return getPayload(3); }else{ return getPayload(1); } } uint8_t NWResponse::getApiId(){ return _apiId; } uint8_t NWResponse::getMsgType(){ return getPayloadPtr()[1]; } bool NWResponse::isBroadcast(){ return ( getOption() && 0x02); } void NWResponse::absorb(NWResponse* resp){ if(_frameDataPtr){ free(_frameDataPtr); } _apiId = resp->getApiId(); _msbLength = resp->getMsbLength(); _lsbLength = resp->getLsbLength(); _checksum = resp->getChecksum(); _frameLength = resp->getFrameDataLength(); _errorCode = resp->getErrorCode(); _complete = resp->isAvailable(); _addr64.setMsb(resp->getRemoteAddressMsb()); _addr64.setLsb(resp->getRemoteAddressLsb()); _frameDataPtr = mqcalloc(resp->getFrameDataLength()); memcpy(_frameDataPtr, resp->getFrameData(), resp->getFrameDataLength()); } /*========================================= Class NWRequest =========================================*/ NWRequest::NWRequest(){ _apiId = 0x10; _addr16 = 0; _broadcastRadius = 0; _option = 0; _payloadPtr = 0; _payloadLength = 0; } NWRequest::~NWRequest(){ } NWAddress64& NWRequest::getAddress64(){ return _addr64; } uint16_t NWRequest::getAddress16(){ return _addr16; } uint8_t NWRequest::getApiId(){ return _apiId; } uint8_t NWRequest::getBroadcastRadius(){ return _broadcastRadius; } uint8_t NWRequest::getOption(){ return _option; } uint8_t* NWRequest::getPayloadPtr(){ return _payloadPtr; } uint8_t NWRequest::getPayloadLength(){ return _payloadLength; } void NWRequest::setClientAddress64(NWAddress64* addr64){ _addr64.setMsb(addr64->getMsb()); _addr64.setLsb(addr64->getLsb()); } void NWRequest::setClientAddress16(uint16_t addr16){ _addr16 = addr16; } void NWRequest::setBroadcastRadius(uint8_t broadcastRadius){ _broadcastRadius = broadcastRadius; } void NWRequest::setOption(uint8_t option){ _option = option; } void NWRequest::setApiId(uint8_t apiId){ _apiId = apiId; } void NWRequest::setPayload(uint8_t* payload){ _payloadPtr = payload; } void NWRequest::setPayloadLength(uint8_t payloadLength){ _payloadLength = payloadLength; } uint8_t NWRequest::getFrameData(uint8_t pos){ uint8_t buf[4]; if (pos == 0){ return 0; // Frame ID }else if (pos == 1){ setUint32(buf, _addr64.getMsb()); return buf[0]; }else if (pos == 2){ setUint32(buf, _addr64.getMsb()); return buf[1]; }else if (pos == 3){ setUint32(buf, _addr64.getMsb()); return buf[2]; }else if (pos == 4){ setUint32(buf, _addr64.getMsb()); return buf[3]; }else if (pos == 5){ setUint32(buf, _addr64.getLsb()); return buf[0]; }else if (pos == 6){ setUint32(buf, _addr64.getLsb()); return buf[1]; }else if (pos == 7){ setUint32(buf, _addr64.getLsb()); return buf[2]; }else if (pos == 8){ setUint32(buf, _addr64.getLsb()); return buf[3]; }else if (pos == 9){ setUint16(buf,_addr16); return buf[0]; }else if (pos == 10){ setUint16(buf,_addr16); return buf[1]; }else if (pos == 11){ return _broadcastRadius; }else if (pos == 12){ return _option; } return getPayloadPtr()[pos - ZB_TX_API_LENGTH -1 ]; } uint8_t NWRequest::getFrameDataLength(){ return ZB_TX_API_LENGTH + 1 + getPayloadLength(); } /*========================================= Class XBee =========================================*/ XBee::XBee(){ _pos = 0; _escape = false; _checksumTotal = 0; _response.setFrameData(mqcalloc(MAX_FRAME_DATA_SIZE)); _serialPort = new SerialPort(); _bd = 0; } XBee::~XBee(){ } int XBee::initialize(XBeeConfig config){ return _serialPort->open(config); } void XBee::readPacket(){ while(read(&_bd)){ // Check Start Byte if( _pos > 0 && _bd == START_BYTE){ _pos = 0; } // Check ESC if(_pos > 0 && _bd == ESCAPE){ if(read(&_bd )){ _bd = 0x20^_bd; // decode }else{ _escape = true; continue; } } if(_escape){ _bd = 0x20 ^ _bd; _escape = false; } if(_pos >= API_ID_INDEX){ _checksumTotal+= _bd; } switch(_pos){ case 0: if(_bd == START_BYTE){ _pos++; } break; case 1: _response.setMsbLength(_bd); _pos++; break; case 2: _response.setLsbLength(_bd); _pos++; D_NWSTACK("\r\n===> Recv start: "); break; case 3: _response.setApiId(_bd); _pos++; break; default: if(_pos > MAX_FRAME_DATA_SIZE){ _response.setErrorCode(PACKET_EXCEEDS_BYTE_ARRAY_LENGTH); return; }else if(_pos == (_response.getPacketLength() + 3)){ // 3 = 2(packet len) + 1(checksum) if((_checksumTotal & 0xff) == 0xff){ _response.setChecksum(_bd); _response.setAvailable(true); _response.setErrorCode(NO_ERROR); }else{ _response.setErrorCode(CHECKSUM_FAILURE); } _response.setFrameDataLength(_pos - 4); // 4 = 2(packet len) + 1(Api) + 1(checksum) _pos = 0; _checksumTotal = 0; return; }else{ uint8_t* buf = _response.getFrameData(); buf[_pos - 4] = _bd; _pos++; if (_response.getApiId() == XB_RX_RESPONSE && _pos == 15){ D_NWSTACK( "\r\n Payload: "); } } break; } } } bool XBee::receiveResponse(NWResponse* response){ while(true){ readPacket(); if(_response.isAvailable()){ D_NWSTACK("\r\n<=== CheckSum OK\r\n\n"); response->absorb(&_response); return true; }else if(_response.isError()){ D_NWSTACK("\r\n<=== Packet Error Code = %d\r\n\n",_response.getErrorCode()); _response.reset(); response->reset(); return false; } } return false; } void XBee::sendRequest(NWRequest &request){ D_NWSTACK("\r\n===> Send start: "); sendByte(START_BYTE, false); uint8_t msbLen = ((request.getFrameDataLength() + 1) >> 8) & 0xff; // 1 = 1B(Api) except Checksum uint8_t lsbLen = (request.getFrameDataLength() + 1) & 0xff; sendByte(msbLen, true); sendByte(lsbLen, true); sendByte(request.getApiId(), true); uint8_t checksum = 0; checksum+= request.getApiId(); for( int i = 0; i < request.getFrameDataLength(); i++ ){ if (request.getApiId() == XB_TX_REQUEST && i == 13){ D_NWSTACK("\r\n Payload: "); } sendByte(request.getFrameData(i), true); checksum+= request.getFrameData(i); } checksum = 0xff - checksum; sendByte(checksum, true); //flush(); // clear receive buffer D_NWSTACK("\r\n<=== Send completed\r\n\n" ); } void XBee::sendByte(uint8_t b, bool escape){ if(escape && (b == START_BYTE || b == ESCAPE || b == XON || b == XOFF)){ write(ESCAPE); write(b ^ 0x20); }else{ write(b); } } void XBee::resetResponse(){ _pos = 0; _escape = 0; _response.reset(); } void XBee::flush(){ _serialPort->flush(); } bool XBee::write(uint8_t val){ return (_serialPort->send(val) ? true : false ); } bool XBee::read(uint8_t *buff){ return _serialPort->recv(buff); } /*=========================================== Class Network ============================================*/ Network::Network(){ } Network::~Network(){ } void Network::unicast(NWAddress64* addr64, uint16_t addr16, uint8_t* payload, uint16_t payloadLength ){ _txRequest.setClientAddress64(addr64); _txRequest.setClientAddress16(addr16); _txRequest.setOption(0); _txRequest.setPayload(payload); _txRequest.setPayloadLength(payloadLength); sendRequest(_txRequest); } void Network::broadcast(uint8_t* payload, uint16_t payloadLength){ NWAddress64 addr; addr.setMsb(0); addr.setLsb(XB_BROADCAST_ADDRESS32); unicast(&addr, XB_BROADCAST_ADDRESS16, payload, payloadLength); } bool Network::getResponse(NWResponse* response){ return receiveResponse(response); } int Network::initialize(NETWORK_CONFIG config){ return XBee::initialize(config); } /*========================================= Class SerialPort =========================================*/ SerialPort::SerialPort(){ _tio.c_iflag = IGNBRK | IGNPAR; _tio.c_cflag = CS8 | CLOCAL | CREAD | CRTSCTS; _tio.c_cc[VINTR] = 0; _tio.c_cc[VTIME] = 0; _tio.c_cc[VMIN] = 1; _fd = 0; } SerialPort::~SerialPort(){ if (_fd){ close(_fd); } } int SerialPort::open(XBeeConfig config){ return open(config.device, config.baudrate, false, 1, config.flag); } int SerialPort::open(const char* devName, unsigned int baudrate, bool parity, unsigned int stopbit, unsigned int flg){ _fd = ::open(devName, flg | O_NOCTTY); if(_fd < 0){ return _fd; } if (parity){ _tio.c_cflag = _tio.c_cflag | PARENB; } if (stopbit == 2){ _tio.c_cflag = _tio.c_cflag | CSTOPB ; } switch(baudrate){ case B9600: case B19200: case B38400: case B57600: case B115200: if( cfsetspeed(&_tio, baudrate)<0){ return errno; } break; default: return -1; } return tcsetattr(_fd, TCSANOW, &_tio); } bool SerialPort::send(unsigned char b){ if (write(_fd, &b,1) != 1){ return false; }else{ D_NWSTACK( " %02x", b); return true; } } bool SerialPort::recv(unsigned char* buf){ if(read(_fd, buf, 1) == 0){ return false; }else{ D_NWSTACK( " %02x",buf[0] ); return true; } } void SerialPort::flush(void){ tcsetattr(_fd, TCSAFLUSH, &_tio); } #endif /* NETWORK_XBEE */ ================================================ FILE: Gateway/src/lib/ZBStack.h ================================================ /* * ZBStack.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef ZBSTACK_H_ #define ZBSTACK_H_ #include "Defines.h" #ifdef NETWORK_XBEE #include #include #include "ProcessFramework.h" #define START_BYTE 0x7e #define ESCAPE 0x7d #define XON 0x11 #define XOFF 0x13 #define MAX_FRAME_DATA_SIZE 128 #define XB_BROADCAST_ADDRESS32 0x0000ffff #define XB_BROADCAST_ADDRESS16 0xfffe #define DEFAULT_FRAME_ID 1 #define XB_PACKET_ACKNOWLEGED 0x01 #define XB_BROADCAST_PACKET 0x02 #define XB_BROADCAST_RADIUS_MAX_HOPS 0 #define API_ID_INDEX 3 #define PACKET_OVERHEAD_LENGTH 6 #define ZB_TX_API_LENGTH 12 #define ZB_PAYLOAD_OFFSET 11 /** * API ID Constant */ #define XB_TX_REQUEST 0x10 #define XB_RX_RESPONSE 0x90 /** * TX STATUS */ #define SUCCESS 0x0 #define NO_ERROR 0 #define CHECKSUM_FAILURE 1 #define PACKET_EXCEEDS_BYTE_ARRAY_LENGTH 2 #define UNEXPECTED_START_BYTE 3 #define NW_TX_UNICAST 0 #define NW_TX_BROADCAST 8 #define NW_MAX_NODEID 24 /* * MQTTS Client's state */ #define MQTTS_DEVICE_DISCONNECTED 0 #define MQTTS_DEVICE_ACTIVE 1 #define MQTTS_DEVICE_ASLEEP 2 #define MQTTS_DEVICE_AWAKE 3 #define MQTTS_DEVICE_LOST 4 namespace tomyGateway{ /*============================================ NWAddress64 =============================================*/ class NWAddress64 { public: NWAddress64(uint32_t msb, uint32_t lsb); NWAddress64(); uint32_t getMsb(); uint32_t getLsb(); void setMsb(uint32_t msb); void setLsb(uint32_t lsb); bool operator==(NWAddress64&); private: uint32_t _msb; uint32_t _lsb; }; /*============================================ NWResponse =============================================*/ class NWResponse { public: NWResponse(); ~NWResponse(); uint8_t getMsbLength(); uint8_t getLsbLength(); uint8_t getChecksum(); uint8_t getFrameDataLength(); uint8_t getOption(); uint8_t getType(); uint8_t getPayload(int index); uint8_t getPayloadLength(); uint8_t getPayloadOffset(); uint8_t getApiId(); uint8_t getMsgType(); uint8_t getErrorCode(); uint8_t* getFrameData(); uint8_t* getPayloadPtr(); uint16_t getPacketLength(); uint16_t getClientAddress16(); NWAddress64* getClientAddress64(); bool isBroadcast(); bool isAvailable(); bool isError(); void setApiId(uint8_t apiId); void setMsbLength(uint8_t msbLength); void setLsbLength(uint8_t lsbLength); void setChecksum(uint8_t checksum); void setFrameData(uint8_t *frameDataPtr); void setFrameDataLength(uint8_t frameLength); void setAvailable(bool complete); void setErrorCode(uint8_t errorCode); void reset(); void absorb(NWResponse* resp); protected: uint8_t *_frameDataPtr; private: uint32_t getRemoteAddressMsb(); uint32_t getRemoteAddressLsb(); uint8_t _apiId; uint8_t _msbLength; uint8_t _lsbLength; uint8_t _checksum; uint8_t _frameLength; uint8_t _errorCode; bool _complete; NWAddress64 _addr64; }; /*============================================ Class NWRequest =============================================*/ class NWRequest{ public: NWRequest(); NWRequest(NWAddress64 &addr64, uint8_t *payload, uint8_t payLoadLength); NWRequest(NWAddress64 &addr64, uint16_t addr16, uint8_t broadcastRadius, uint8_t option, uint8_t *payload, uint8_t payloadLength); ~NWRequest(); uint8_t* getPayloadPtr(); uint8_t getBroadcastRadius(); uint8_t getOption(); uint8_t getPayloadLength(); uint8_t getApiId(); uint8_t getFrameData(uint8_t pos); uint8_t getFrameDataLength(); uint16_t getAddress16(); NWAddress64& getAddress64(); void setApiId(uint8_t apiId); void setClientAddress64(NWAddress64* addr64); void setClientAddress16(uint16_t addr16); void setBroadcastRadius(uint8_t broadcastRadius); void setOption(uint8_t option); void setPayload(uint8_t *payload); void setPayloadLength(uint8_t payLoadLength); private: uint8_t _apiId; uint8_t _broadcastRadius; uint8_t _option; uint8_t _payloadLength; uint8_t* _payloadPtr; uint16_t _addr16; NWAddress64 _addr64; }; /*=========================================== SerialPort ============================================*/ #include class SerialPort{ public: SerialPort(); ~SerialPort(); int open(XBeeConfig config); bool send(unsigned char b); bool recv(unsigned char* b); void flush(); private: int open(const char* devName, unsigned int boaurate, bool parity, unsigned int stopbit, unsigned int flg); int _fd; // file descriptor struct termios _tio; }; /*============================================ XBee ============================================*/ class XBee { public: XBee(); ~XBee(); protected: int initialize(XBeeConfig config); bool receiveResponse(NWResponse* response); void sendRequest(NWRequest& request); private: void readPacket(void); bool read(uint8_t* buff); bool write(uint8_t val); void sendByte(uint8_t, bool escape); void resetResponse(); void flush(); SerialPort *_serialPort; NWResponse _response; bool _escape; uint8_t _pos; uint8_t _checksumTotal; uint8_t _bd; }; /*=========================================== Class NetworkStack ============================================*/ class Network : public XBee{ public: Network(); ~Network(); void unicast(NWAddress64* addr64, uint16_t addr16, uint8_t* payload, uint16_t payloadLength); void broadcast(uint8_t* payloadLength, uint16_t bodyLenght); bool getResponse(NWResponse* response); int initialize(NETWORK_CONFIG config); private: NWRequest _txRequest; }; } #endif /* NETWORK_XBEE */ #endif /* ZBSTACK_H_ */ ================================================ FILE: LogMonitor/Makefile ================================================ PROGNAME := LogMonitor SRCDIR := src SUBDIR := src/lib SRCS := $(SRCDIR)/LogMonitorApp.cpp \ $(SRCDIR)/LogMonitor.cpp \ $(SUBDIR)/ProcessFramework.cpp CXX := g++ CPPFLAGS += DEFS := LDFLAGS += LIBS += LDADD := -lpthread -lrt CXXFLAGS := -Wall -O3 OUTDIR := Build PROG := $(OUTDIR)/$(PROGNAME) OBJS := $(SRCS:%.cpp=$(OUTDIR)/%.o) DEPS := $(SRCS:%.cpp=$(OUTDIR)/%.d) .PHONY: install clean distclean all: $(PROG) -include $(DEPS) $(PROG): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(LDADD) $(OUTDIR)/%.o:%.cpp @if [ ! -e `dirname $@` ]; then mkdir -p `dirname $@`; fi $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(DEFS) -o $@ -c -MMD -MP -MF $(@:%.o=%.d) $< clean: rm -rf $(OUTDIR) install: cp -p $(PROG) ../../ ================================================ FILE: LogMonitor/src/LogMonitor.cpp ================================================ /* * LogMonitor.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef LOGMONITOR_H_ #define LOGMONITOR_H_ #include "lib/ProcessFramework.h" using namespace std; class LogMonitor:public Process{ public: LogMonitor(); ~LogMonitor(); void initialize(int argc, char** argv); void run(); }; LogMonitor::LogMonitor(){ theProcess = this; } LogMonitor::~LogMonitor(){ } void LogMonitor::initialize(int argc, char** argv){ Process::initialize(0, NULL); } void LogMonitor::run(){ while(true){ const char* data = getLog(); printf("%s", data); if(int rc = checkSignal()){ printf("\n\n\n"); THROW_EXCEPTION(ExInfo, rc, " Terminated normally\n"); } } } #endif /* LOGMONITOR_H_ */ ================================================ FILE: LogMonitor/src/LogMonitor.h ================================================ /* * LogMonitor.h * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef LOGMONITOR_H_ #define LOGMONITOR_H_ #include "lib/ProcessFramework.h" using namespace std; class LogMonitor:public Process{ public: LogMonitor(); ~LogMonitor(); void initialize(int argc, char** argv); void run(); }; #endif /* LOGMONITOR_H_ */ ================================================ FILE: LogMonitor/src/LogMonitorApp.cpp ================================================ /* * LogMonitorApp.cpp * * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "lib/ProcessFramework.h" #include "LogMonitor.h" /************************************** * LogMonitor Application **************************************/ const char* theCmdlineParameter = ""; LogMonitor lp = LogMonitor(); ================================================ FILE: LogMonitor/src/lib/Defines.h ================================================ /* * Defines.h * The BSD License * * Copyright (c) 2014, tomoaki@tomy-tech.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Created on: 2014/06/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef DEFINES_H_ #define DEFINES_H_ /*================================= * CPU TYPE ==================================*/ #define CPU_LITTLEENDIANN //#define CPU_BIGENDIANN /*================================= * Data Type ==================================*/ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #endif /* DEFINES_H_ */ ================================================ FILE: LogMonitor/src/lib/ProcessFramework.cpp ================================================ /* * ProcessFramework.cpp * * The MIT License (MIT) * * Copyright (c) 2015 tomoaki@tomy-tech.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Created on: 2015/05/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #include "ProcessFramework.h" #include "Defines.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; extern const char* theCmdlineParameter; extern int optind; /*===================================== Global functions & variables ======================================*/ Process* theProcess = 0; MultiTaskProcess* theMultiTask = 0; static volatile int theSignaled = 0; static void signalHandler(int sig){ assert(sig == SIGINT || sig == SIGHUP || sig == SIGTERM); theSignaled = sig; theProcess->releaseLog(); exit(-1); } int main(int argc, char** argv){ try{ signal(SIGHUP, signalHandler); signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); theProcess->initialize(argc, argv); theProcess->run(); }catch(Exception& ex){ ex.writeMessage(); } return 0; } uint8_t* mqcalloc(uint8_t len){ uint8_t* pos = (uint8_t*)calloc(len, sizeof(uint8_t)); if( pos == 0){ THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't allocate memory."); } return pos; } #ifdef CPU_LITTLEENDIANN /*--- For Little endianness ---*/ uint16_t getUint16(uint8_t* pos){ uint16_t val = ((uint16_t)*pos++ << 8); return val += *pos; } void setUint16(uint8_t* pos, uint16_t val){ *pos++ = (val >> 8) & 0xff; *pos = val & 0xff; } uint32_t getUint32(uint8_t* pos){ uint32_t val = (uint32_t(*pos++ << 24)); val += (uint32_t(*pos++ << 16)); val += (uint32_t(*pos++ << 8)); return val += *pos++; } void setUint32(uint8_t* pos, uint32_t val){ *pos++ = (val >> 24) & 0xff; *pos++ = (val >> 16) & 0xff; *pos++ = (val >> 8) & 0xff; *pos = val & 0xff; } #endif #ifdef CPU_BIGENDIANN /*--- For Big endianness ---*/ uint16_t getUint16(uint8_t* pos){ uint16_t val = *pos++; return val += ((uint16_t)*pos++ << 8); } void setUint16(uint8_t* pos, uint16_t val){ *pos++ = val & 0xff; *pos = (val >> 8) & 0xff; } long getUint32(uint8_t* pos){ long val = (uint32_t(*(pos + 3)) << 24) + (uint32_t(*(pos + 2)) << 16) + (uint32_t(*(pos + 1)) << 8); return val += *pos; } void setUint32(uint8_t* pos, uint32_t val){ *pos++ = val & 0xff; *pos++ = (val >> 8) & 0xff; *pos++ = (val >> 16) & 0xff; *pos = (val >> 24) & 0xff; } #endif void utfSerialize(uint8_t* pos, string str){ setUint16(pos, (uint16_t)str.size()); str.copy((char*)pos + 2, str.size(), 0); } char theCurrentTime[32]; char* currentDateTime() { time_t now = time(0); struct tm tstruct; tstruct = *localtime(&now); strftime(theCurrentTime, sizeof(theCurrentTime), "%Y%m%d %H%M%S", &tstruct); return theCurrentTime; } /*===================================== Class Process ======================================*/ Process::Process(){ _argc = 0; _argv = 0; _rb = new RingBuffer(); _rbsem = new Semaphore(TOMYFRAME_RB_SEMAPHOR_NAME, 0); } Process::~Process(){ delete(_rb); delete(_rbsem); } void Process::run(){ } void Process::initialize(int argc, char** argv){ _argc = argc; _argv = argv; } int Process::getArgc(){ return _argc; } char** Process::getArgv(){ return _argv; } char* Process::getArgv(char option){ char arg; optind = 1; while((arg = getopt(_argc, _argv, theCmdlineParameter))!= -1 && (arg != 255)){ if(arg == option){ return optarg; } } return 0; } int Process::getParam(const char* parameter, char* value){ char str[TOMYFRAME_PARAM_MAX], param[TOMYFRAME_PARAM_MAX]; FILE *fp; int i = 0, j = 0; if ((fp = fopen(TOMYFRAME_CONFIG_FILE, "r")) == NULL) { LOGWRITE("No config file:[%s]\n", TOMYFRAME_CONFIG_FILE); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "No config file."); return -1; } while(true) { if (fgets(str, TOMYFRAME_PARAM_MAX - 1, fp) == NULL) { fclose(fp); return -3; } if (!strncmp(str, parameter,strlen(parameter))) { while (str[i++] != '=') { ; } while (str[i] != '\n') { param[j++] = str[i++]; } param[j] = '\0'; for( i = strlen(param)-1; i >= 0 && isspace( param[i] ); i-- ) ; param[i+1] = '\0'; for( i = 0; isspace( param[i] ); i++ ) ; if( i > 0 ) { j = 0; while( param[i] ) param[j++] = param[i++]; param[j] = '\0'; } strcpy(value,param); fclose(fp); return 0; } } fclose(fp); return -1; } void Process::putLog(const char* format, ...){ _mt.lock(); va_list arg; va_start(arg, format); vsprintf(_rbdata, format, arg); va_end(arg); if(strlen(_rbdata)){ _rb->put(_rbdata); _rbsem->post(); } _mt.unlock(); } const char* Process::getLog(){ int len = 0; _mt.lock(); while((len = _rb->get(_rbdata, PROCESS_LOG_BUFFER_SIZE)) == 0){ _rbsem->wait(); } *(_rbdata + len) = 0; _mt.unlock(); return _rbdata; } void Process::releaseLog(void){ _mt.unlock(); } void Process::resetRingBuffer(){ _rb->reset(); } int Process::checkSignal(){ return theSignaled; } /*===================================== Class MultiTaskProcess ======================================*/ MultiTaskProcess::MultiTaskProcess(){ theMultiTask = this; } MultiTaskProcess::~MultiTaskProcess(){ } void MultiTaskProcess::initialize(int argc, char** argv){ Process::initialize(argc, argv); list::iterator thread = _threadList.begin(); while( thread != _threadList.end()){ (*thread)->initialize(argc, argv); ++thread; } } void MultiTaskProcess::run(){ list::iterator thread = _threadList.begin(); while(thread != _threadList.end()){ (*thread)->start(); thread++; } _stopProcessEvent.wait(); thread = _threadList.begin(); while(thread != _threadList.end()){ (*thread)->cancel(); (*thread)->join(); thread++; } } Semaphore* MultiTaskProcess::getStopProcessEvent(){ return &_stopProcessEvent; } void MultiTaskProcess::attach(Thread* thread){ _threadList.push_back(thread); } char* MultiTaskProcess::getArgv(char option){ _mutex.lock(); char* arg = Process::getArgv(option); _mutex.unlock(); return arg; } int MultiTaskProcess::getParam(const char* parameter, char* value){ _mutex.lock(); int rc = Process::getParam(parameter, value); _mutex.unlock(); return rc; } /*===================================== Class Thread =====================================*/ Thread::Thread(){ _stopProcessEvent = theMultiTask->getStopProcessEvent(); _threadID = 0; _stopProcessEvent = 0; } Thread::~Thread(){ } void* Thread::_run(void* runnable){ static_cast(runnable)->EXECRUN(); return 0; } void Thread::initialize(int argc, char** argv){ } pthread_t Thread::getID(){ return pthread_self(); } bool Thread::equals(pthread_t *t1, pthread_t *t2){ return (pthread_equal(*t1, *t2) ? false : true); } int Thread::start(void){ Runnable *runnable = this; return pthread_create(&_threadID, 0, _run, runnable); } int Thread::join(void){ return pthread_join(_threadID, 0); } int Thread::cancel(void){ return pthread_cancel(_threadID); } void Thread::stopProcess(void){ _stopProcessEvent->post(); } /*===================================== Class Mutex =====================================*/ Mutex::Mutex(void){ pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutex_init(&_mutex, &attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); _shmid = 0; _pmutex = 0; } Mutex::Mutex(const char* fileName){ pthread_mutexattr_t attr; key_t key = ftok(fileName, 1); if((_shmid = shmget(key, sizeof(pthread_mutex_t), IPC_CREAT | 0666)) < 0){ perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a shared memory."); } _pmutex = (pthread_mutex_t*)shmat(_shmid, NULL, 0); if(_pmutex < 0 ){ perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't attach shared memory for Mutex."); } pthread_mutexattr_init(&attr); if(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0) { perror("Mutex pthread_mutexattr_setpshared"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a Mutex."); } if(pthread_mutex_init(_pmutex, &attr) != 0) { perror("Mutex pthread_mutexattr_setpshared"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a Mutex."); } } Mutex::~Mutex(void){ if(_pmutex){ pthread_mutex_lock(_pmutex); pthread_mutex_unlock(_pmutex); pthread_mutex_destroy(_pmutex); }else{ pthread_mutex_lock(&_mutex); pthread_mutex_unlock(&_mutex); pthread_mutex_destroy(&_mutex); } if(_shmid){ shmctl(_shmid, IPC_RMID, NULL); } } void Mutex::lock(void){ if(_pmutex){ pthread_mutex_lock(_pmutex); }else{ try{ if(pthread_mutex_lock(&_mutex)){ throw; } }catch(char* errmsg){ perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "The same thread can't aquire a mutex twice."); } } } void Mutex::unlock(void){ if(_pmutex){ pthread_mutex_unlock(_pmutex); }else{ try { if(pthread_mutex_unlock(&_mutex)){ throw; } }catch(char* errmsg){ perror("Mutex"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't release a mutex."); } } } /*===================================== Class Semaphore =====================================*/ Semaphore::Semaphore(){ Semaphore(0); } Semaphore::Semaphore(unsigned int val){ sem_init(&_sem, 0, val); _name = 0; _psem = 0; } Semaphore::Semaphore(const char* name,unsigned int val){ _psem = sem_open(name, O_CREAT, 0666, val); if(_psem == SEM_FAILED ){ perror("Semaphore"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a Semaphore."); } _name = (char*)mqcalloc(strlen(name + 1)); strcpy(_name, name); } Semaphore::~Semaphore(){ if(_name){ sem_close(_psem); sem_unlink(_name); free((void*)_name); }else{ sem_destroy(&_sem); } } void Semaphore::post(void){ int val = 0; if(_psem){ sem_getvalue(_psem,&val); if(val <= 0){ sem_post(_psem); } }else{ sem_getvalue(&_sem,&val); if(val <= 0){ sem_post(&_sem); } } } void Semaphore::wait(void){ if(_psem){ sem_wait(_psem); }else{ sem_wait(&_sem); } } void Semaphore::timedwait(uint16_t millsec){ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += millsec / 1000; ts.tv_nsec = (millsec % 1000) * 1000000; if(_psem){ sem_timedwait(_psem, &ts); }else{ sem_timedwait(&_sem, &ts); } } /*========================================= Class RingBuffer =========================================*/ RingBuffer::RingBuffer(){ key_t key = ftok(TOMYFRAME_RINGBUFFER_KEY, 1); if((_shmid = shmget(key, RINGBUFFER_SIZE, IPC_CREAT | IPC_EXCL | 0666)) >= 0){ if((_shmaddr = (uint16_t*)shmat(_shmid, NULL, 0)) > 0 ){ _length = (uint16_t*)_shmaddr; _start = (uint16_t*)_length + sizeof(uint16_t*); _end = (uint16_t*)_start + sizeof(uint16_t*); _buffer = (char*)_end + sizeof(uint16_t*); _createFlg = true; *_length = RINGBUFFER_SIZE - sizeof(uint16_t*) * 3 - 16; *_start = *_end = 0; }else{ perror("RingBuffer"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "can't attach shared memory."); } }else if((_shmid = shmget(key, RINGBUFFER_SIZE, IPC_CREAT | 0666)) >= 0){ if((_shmaddr = (uint16_t*)shmat(_shmid, NULL, 0)) > 0 ){ _length = (uint16_t*)_shmaddr; _start = (uint16_t*)_length + sizeof(uint16_t*); _end = (uint16_t*)_start + sizeof(uint16_t*); _buffer = (char*)_end + sizeof(uint16_t*); _createFlg = false; }else{ perror("RingBuffer"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a shared memory."); } }else{ perror("RingBuffer"); THROW_EXCEPTION(ExFatal, ERRNO_SYS_01, "Can't create a shared memory."); } _pmx = new Mutex(TOMYFRAME_RB_MUTEX_KEY); } RingBuffer::~RingBuffer(){ if(_createFlg){ if(_shmid > 0){ shmctl(_shmid, IPC_RMID, NULL); } if(_pmx > 0){ delete _pmx; } }else{ if(_shmid > 0){ shmdt(_shmaddr); } } } void RingBuffer::put(char* data){ _pmx->lock(); uint16_t dlen = strlen(data); uint16_t blen = *_length - *_end; if(*_end > *_start){ if(dlen < blen){ strncpy(_buffer + *_end, data, dlen); if(*_end - *_start == 1){ // Buffer is empty. *_start = *_end; } *_end += dlen; }else{ strncpy(_buffer + *_end, data, blen); strncpy(_buffer, data + blen, dlen - blen); if(*_end - *_start == 1){ // Buffer is empty. *_start = *_end; *_end = dlen - blen; }else{ *_end = dlen - blen; *_start = *_end + 1; } } }else if(*_end == *_start){ if(dlen < blen){ strncpy(_buffer + *_end, data, dlen); *_end += dlen; }else{ const char* errmsg = "RingBuffer Error: data is too long"; strcpy(_buffer + *_end, errmsg); *_end += strlen(errmsg); } }else{ // *_end < *_start if(dlen < *_start - *_end){ strncpy(_buffer + *_end, data, dlen); *_end += dlen; *_start = *_end + 1; }else { if( dlen < blen){ strncpy(_buffer + *_end, data, dlen); *_end += dlen; *_start = *_end + 1; }else { strncpy(_buffer + *_end, data, blen); strncpy(_buffer, data + blen, dlen - blen); *_start = *_end; *_end = dlen - blen; } } } _pmx->unlock(); } int RingBuffer::get(char* buf, int length){ int len = 0; _pmx->lock(); if(*_end > *_start){ if(length > *_end - *_start){ len = *_end - *_start; if (len == 1){ len = 0; } strncpy(buf, _buffer + *_start, len); *_start = *_end - 1; }else{ len = length; strncpy(buf, _buffer + *_start, len); *_start = *_start + len; } }else if(*_end < *_start){ int blen = *_length - *_start; if(length > blen ){ strncpy(buf, _buffer + *_start, blen); *_start = 0; if(length - (blen + *_end) > 0){ strncpy(buf + blen , _buffer, *_end); len = blen + *_end; if(*_end > 0){ *_start = *_end - 1; } }else{ printf("length=%d blen=%d len = %d\n", length, blen, length - *_end ); strncpy(buf + blen, _buffer, length - blen); len = length; *_start = length - blen; } }else{ strncpy(buf, _buffer + *_start, length); *_start += length; len = length; } } _pmx->unlock(); return len; } void RingBuffer::reset(){ _pmx->lock(); *_start = *_end = 0; _pmx->unlock(); } /*===================================== Class Exception ======================================*/ Exception::Exception(const ExceptionType type, const int exNo, const string& message){ _message = message; _type = type; _exNo = exNo; _fileName = 0; _functionName = 0; _line = 0; } Exception::Exception(const ExceptionType type, const int exNo, const string& message, const char* file, const char* function, const int line){ _message = message; _type = type; _exNo = exNo; _fileName = file; _functionName = function; _line = line; } Exception::~Exception() throw(){ } const char* Exception::what() const throw() { return _message.c_str(); } const char* Exception::getFileName(){ return _fileName; } const char* Exception::getFunctionName(){ return _functionName; } const int Exception::getLineNo(){ return _line; } const int Exception::getExceptionNo(){ return _exNo; } bool Exception::isFatal(){ return _type == ExFatal; } const char* Exception::strType(){ switch(_type){ case ExInfo: return "Info"; break; case ExWarn: return "Warn"; break; case ExError: return "Error"; break; case ExFatal: return "Fatal"; break; case ExDebug: return "Debug"; break; default: break; } return ""; } void Exception::writeMessage(){ fprintf(stdout, "%s %5s:%-6d %s line %-4d %s() : %s\n", currentDateTime(), strType(), getExceptionNo(), getFileName(), getLineNo(), getFunctionName(), what()); } /*========================================= Class Timer =========================================*/ Timer::Timer(){ stop(); } void Timer::start(uint32_t msec){ gettimeofday(&_startTime, 0); _millis = msec; } bool Timer::isTimeup(){ return isTimeup(_millis); } bool Timer::isTimeup(uint32_t msec){ struct timeval curTime; long secs, usecs; if (_startTime.tv_sec == 0){ return false; }else{ gettimeofday(&curTime, 0); secs = (curTime.tv_sec - _startTime.tv_sec) * 1000; usecs = (curTime.tv_usec - _startTime.tv_usec) / 1000.0; return ((secs + usecs) > (long)msec); } } void Timer::stop(){ _startTime.tv_sec = 0; _millis = 0; } ================================================ FILE: LogMonitor/src/lib/ProcessFramework.h ================================================ /* * ProcessFramework.h * * The MIT License (MIT) * * Copyright (c) 2015 tomoaki@tomy-tech.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Created on: 2015/05/01 * Modified: * Author: Tomoaki YAMAGUCHI * Version: 0.0.0 */ #ifndef PROCESSFRAMEWORK_H_ #define PROCESSFRAMEWORK_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Defines.h" #include #include #include #define TOMYFRAME_PARAM_MAX 128 #define TOMYFRAME_CONFIG_FILE "/usr/local/etc/tomygateway/config/param.conf" #define TOMYFRAME_RINGBUFFER_KEY "/usr/local/etc/tomygateway/config/ringbuffer.key" #define TOMYFRAME_RB_MUTEX_KEY "/usr/local/etc/tomygateway/config/rbmutex.key" #define TOMYFRAME_RB_SEMAPHOR_NAME "/rbsemaphor" #define LOGWRITE theProcess->putLog //#define LOGWRITE printf #define RINGBUFFER_SIZE 16384 #define PROCESS_LOG_BUFFER_SIZE 2048 #define ERRNO_SYS_01 1 // Application Frame Error using namespace std; /*================================= * Data Type ==================================*/ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; /*===================================== Class Mutex ====================================*/ class Mutex{ public: Mutex(); Mutex(const char* name); ~Mutex(); void lock(void); void unlock(void); private: pthread_mutex_t _mutex; pthread_mutex_t* _pmutex; int _shmid; }; /*===================================== Class Semaphore ====================================*/ class Semaphore{ public: Semaphore(); Semaphore(unsigned int val); Semaphore(const char* name, unsigned int val); ~Semaphore(); void post(void); void wait(void); void timedwait(uint16_t millsec); private: sem_t* _psem; sem_t _sem; char* _name; }; /*===================================== Class EventQue ====================================*/ template class EventQue{ public: EventQue(); ~EventQue(); T* wait(void); T* timedwait(uint16_t millsec); int post(T*); int size(); private: queue _que; Mutex _mutex; Semaphore _sem; }; /*===================================== Class RingBuffer =====================================*/ class RingBuffer{ public: RingBuffer(); ~RingBuffer(); void put(char* buffer); int get(char* buffer, int bufferLength); void reset(); private: void* _shmaddr; uint16_t* _length; uint16_t* _start; uint16_t* _end; char* _buffer; int _shmid; Mutex* _pmx; bool _createFlg; }; /*===================================== Class Thread ====================================*/ #define MAGIC_WORD_FOR_TASK \ public: void EXECRUN(){try{run();}catch(Exception& ex){ex.writeMessage();\ if(ex.isFatal()){stopProcess();}}catch(...){throw;}} class Runnable{ public: Runnable(){} virtual ~Runnable(){} virtual void initialized(int argc, char** argv){} virtual void EXECRUN(){} }; class Thread : virtual public Runnable{ public: Thread(); ~Thread(); int start(void); int join(void); int cancel(void); static pthread_t getID(); static bool equals(pthread_t*, pthread_t*); void initialize(int argc, char** argv); void stopProcess(void); private: pthread_t _threadID; Semaphore* _stopProcessEvent; void (*_initializePtr)(int argc, char** argv); static void* _run(void*); }; /*===================================== Class Process ====================================*/ class Process{ public: Process(); virtual ~Process(); void initialize(int argc, char** argv); virtual void run(); int getArgc(); char** getArgv(); char* getArgv(char option); int getParam(const char* param, char* value); void putLog(const char* format, ...); void resetRingBuffer(); int checkSignal(); const char* getLog(void); void releaseLog(void); private: int _argc; char** _argv; RingBuffer* _rb; Mutex _mt; Semaphore* _rbsem; char _rbdata[PROCESS_LOG_BUFFER_SIZE + 1]; }; extern Process* theProcess; /*===================================== Class MultiTaskProcess ====================================*/ class MultiTaskProcess: public Process{ friend int main(int, char**); friend class Thread; public: MultiTaskProcess(); virtual ~MultiTaskProcess(); void attach(Thread* thread); int getArgc(); char** getArgv(); char* getArgv(char option); int getParam(const char* param, char* value); protected: void initialize(int argc, char** argv); void run(); Semaphore* getStopProcessEvent(); private: list _threadList; Semaphore _stopProcessEvent; Mutex _mutex; }; extern MultiTaskProcess* theMultiTask; /*===================================== Class Exception =====================================*/ enum ExceptionType { ExInfo = 0, ExWarn, ExError, ExFatal, ExDebug }; #define THROW_EXCEPTION(type, exceptionNo, message) \ throw Exception(type, exceptionNo, message, __FILE__, __func__, __LINE__) class Exception : public exception { public: Exception(const ExceptionType type, const int exNo, const string& message); Exception(const ExceptionType type, const int exNo, const string& message, const char*, const char*, const int); virtual ~Exception() throw(); const char* getFileName(); const char* getFunctionName(); const int getLineNo(); const int getExceptionNo(); virtual const char* what() const throw(); void writeMessage(); bool isFatal(); private: const char* strType(); ExceptionType _type; int _exNo; string _message; const char* _fileName; const char* _functionName; int _line; }; /*============================================ Timer ============================================*/ class Timer { public: Timer(); void start(uint32_t msec = 0); bool isTimeup(uint32_t msec); bool isTimeup(void); void stop(); private: struct timeval _startTime; uint32_t _millis; }; /*===================================== Class EventQue =====================================*/ template EventQue::EventQue(){ } template EventQue::~EventQue(){ _mutex.lock(); while(!_que.empty()){ delete _que.front(); _que.pop(); } _mutex.unlock(); } template T* EventQue::wait(void){ T* ev; _sem.wait(); _mutex.lock(); ev = _que.front(); _que.pop(); _mutex.unlock(); return ev; } template T* EventQue::timedwait(uint16_t millsec){ T* ev; _sem.timedwait(millsec); _mutex.lock(); if(_que.empty()){ ev = new T(); ev->setTimeout(); }else{ ev = _que.front(); _que.pop(); } _mutex.unlock(); return ev; } template int EventQue::post(T* ev){ _mutex.lock(); _que.push(ev); _mutex.unlock(); _sem.post(); return 0; } template int EventQue::size(){ _mutex.lock(); int sz = _que.size(); _mutex.unlock(); return sz; } #endif /* PROCESSFRAMEWORK_H_ */ ================================================ FILE: README.md ================================================ MQTT-SN over UDP and XBee ====== ***Updated Gateway has been contributed to paho.*** ***Latest Gateway can connect to AWS IoT.*** https://github.com/eclipse/paho.mqtt-sn.embedded-c/tree/gateway * MQTT-SN Gateway over XBee or UDP (running on linux) * MQTT-SN Client over XBee (running on linux, Arduino and mbed) * MQTT-SN Client over UDP (running on linux and Arduino) AsyncMQTT-SN is available. https://github.com/ty4tw/AsyncMQTT-SN Supported functions ------------------- * QOS Level 0 and 1 * SEARCHGW, GWINFO * CONNECT, WILLTOPICREQ, WILLTOPIC, WILLMSGREQ, WILLMSG * PINGREQ, PINGRESP * CONNACK, REGISTER, REGACK, SUBACK, PUBACK, UNSUBACK * SUBSCRIBE, PUBLISH, UNSUBSCRIBE, DISCONNECT Implemented control flows: Application program executes PUBLISH() function, Protocol flow as berrow is conducted automaticaly. Client Gateway Broker | | | PUBLISH() -->| --- SERCHGW ----> | | | <-- GWINFO ----- | | | --- CONNECT ----> | | | <--WILLTOPICREQ-- | | | --- WILLTOPIC --> | | | <-- WILLMSGREQ -- | | | --- WILLMSG ----> | ---- CONNECT ----> |(accepted) | <-- CONNACK ----- | <--- CONNACK ----- | | --- PUBLISH ----> | | | <-- PUBACK ----- | (invalid TopicId) | | --- REGISTER ---> | | | <-- REGACK ----- | | | --- PUBLISH ----> | ---- PUBLISH ----> |(accepted) | <-- PUBACK ----- | <---- PUBACK ----- | | | | // // // | | | SUBSCRIBE() -->| --- SUBSCRIBE --> | ---- SUBSCRIBE --> | [set Callback] | <-- SUBACK ------ | <--- SUBACK ------ | | | | // // // | | | | <-- REGISTER ---- | <--- PUBLISH ----- |<-- PUBLISH [exec Callback] | <-- PUBLISH ---- | | | --- PUBACK ---> | ---- PUBACK ----> |--> PUBACK | | | License ------------------- This source code is available under the BSD license