Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Craggs2014-10-10 18:04:08 -0400
committerIan Craggs2014-10-10 18:04:08 -0400
commit0768b17824ccc49048e2737868b3704e88483d81 (patch)
tree66f740d57f8905bfa769521f8fa6931935011cb8
parent36fa1d8e880ed2d0b9263434051b3b0656c232cb (diff)
downloadorg.eclipse.paho.mqtt-sn.apps-master.tar.gz
org.eclipse.paho.mqtt-sn.apps-master.tar.xz
org.eclipse.paho.mqtt-sn.apps-master.zip
Initial commit of the MQTT-SN C clientHEADmaster
-rw-r--r--apps/MQTTSN-C-Client/readme.txt34
-rw-r--r--apps/MQTTSN-C-Client/src/application.c322
-rw-r--r--apps/MQTTSN-C-Client/src/mqttsn/gp_api.h193
-rw-r--r--apps/MQTTSN-C-Client/src/mqttsn/mqtts-core.c1407
-rw-r--r--apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.c181
-rw-r--r--apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.h60
-rw-r--r--apps/MQTTSN-C-Client/src/mqttsn/mqtts_api.h426
7 files changed, 2623 insertions, 0 deletions
diff --git a/apps/MQTTSN-C-Client/readme.txt b/apps/MQTTSN-C-Client/readme.txt
new file mode 100644
index 0000000..e227ee4
--- /dev/null
+++ b/apps/MQTTSN-C-Client/readme.txt
@@ -0,0 +1,34 @@
+This package provides a reference implementation of the client side of the MQTT-SN (MQTT for Sensor Networks)
+protocol.
+
+The reference implementation consists of the following files: - application.c This is a sample application which demonstrates how the MQTT-SN client API could be used. - mqtts/mqtts_api.h This file defines the MQTT-SN client API, which includes verbs such as connect,
+ disconnect, register, publish, etc. for communicating with the gateway/broker.
+ The use of these verbs is explained below. It also defines the various parameters
+ values required for the operation of the MQTT-SN protocol. - mqtts/mqtts-core.c This file provides the platform-neutral (generic) reference implementation of
+ the client. It contains the client handling of the MQTT-SN protocol. - mqtts/mqtts-timer.c This is the implementation of timer functions which are required by the MQTT-SN protocol. - mqtts/mqtts-timer.h The header file for the timer functions. - mqtts/gp_api.h This header file defines the interface between the platform-neutral client implementation
+ and a generic platform. To port the reference implementation to a specific hardware platform,
+ the functions defined in this header file have to be implemented.
+ To port the client reference implementation to a specific hardware platform, the following functions need to be
+implemented by the platform (see also file gp_api.h): 1. unsigned char gp_timer_new(void (*timeout_funccb)(void)); This function is called by the client to request the creation of a new timer. The pointer to the function
+to be called back when the timer times out is given as parameter. If the timer could be created,
+the platform assigns to it a one-byte identity and returns that identity to the MQTT-SN client. The client
+will use this identity later on to start, stop, and end the timer. If the timer could not be created,
+the value 0xFF should returned. 2. void gp_timer_start(unsigned char id, unsigned char msb, unsigned char lsb); This function is called by the client to request the start of a timer. The byte id is the identity of the
+timer that should be started (this id was returned to the client when the timer was created). The two-byte long
+time-out value (in seconds) is indicated by msb and lsb, with msb containing the most significant byte and lsb
+the least significant byte of the value. 3. void gp_timer_stop(unsigned char id); This function is called by the client to request the stop a timer. The identity of the timer to be stopped
+is indicated by the parameter id. 4. void gp_timer_end(unsigned char id); This function is called by the client to indicate that it does not need a timer anymore. The identity of the
+timer to be freed is indicated by the parameter id. 5. void gp_network_msg_send(unsigned char *msg, unsigned char *dest, unsigned char length); This function is called by the client when it wants to send a MQTT-SN message. The pointer *msg points to
+the first byte of the array which contains the MQTT-SN message to be sent. The length of the message is indicated
+by this first byte. The array containing the destination address is pointed by *dest and its length is indicated
+by the parameter length. 6. void gp_network_msg_broadcast(unsigned char *msg, unsigned char radius); This function is called by the client when it wants to broadcast a MQTT-SN message. The pointer *msg points
+to the first byte of the array containing the MQTT-SN message to be broadcasted. The length of the MQTT-SN
+message is indicated by this first byte. The parameter radius indicates the broadcast radius. 7. void gpcb_network_msg_received(unsigned char *msg, unsigned char *sender, unsigned char length); This callback function is called by the platform when it receives a MQTT-SN message. The first byte of the
+message received is indicated by the pointer *msg; this first byte also contains the length of the message.
+The address of the sender is indicated by the pointer *sender, and its length by the parameter length.
+The platform can release the buffer containing the message when this function returns. 8. unsigned char gp_byte_get(unsigned char *msg, unsigned char index); This function is called by the client to get a byte of a MQTT-SN message just received by the platform
+and indicated to it by the callback function gpcb_network_msg_received(…). The pointer *msg is the one
+in the callback function, and the parameter index is the index of the byte to get. Note that the first
+byte of the MQTT-SN message has the index 1! Note also that the client will call this function only
+while it processes the callback function gpcb_network_msg_received(…).
+ \ No newline at end of file
diff --git a/apps/MQTTSN-C-Client/src/application.c b/apps/MQTTSN-C-Client/src/application.c
new file mode 100644
index 0000000..f3e48de
--- /dev/null
+++ b/apps/MQTTSN-C-Client/src/application.c
@@ -0,0 +1,322 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+/**
+ * Description : MQTT-SN application template
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mqttsn/mqtts_api.h"
+#include "mqttsn/gp_api.h"
+
+
+
+static mqtts_CONNECT_Parms conn_p;
+static mqtts_REGISTER_Parms reg_p;
+static mqtts_PUBLISH_Parms pub_p;
+static mqtts_SUBSCRIBE_Parms sub_p;
+static mqtts_UNSUBSCRIBE_Parms usub_p;
+
+/* Codes and functions that are inside an (#if MQTTS_DEBUG, #endif)-block are
+ * optional. They could e.g. used to exchange debug information with
+ * the hw device via a serial port
+ */
+/**** function prototype */
+void appInit(void);
+
+/**
+ * Programming model: appRun() will be called regularly by the operating system
+ * (e.g. by a round-robin scheduler) of the hw device
+ **/
+void appRun(void) {
+ static unsigned char initiated=0;
+ // init app only once
+ if (initiated==0) {
+ initiated=1;
+ appInit();
+ } else {
+ /* define here what app has to do regularly */
+ }
+}
+
+
+/**
+ * Initialization: start mqtts client and ask it to connect to a gw
+ */
+
+void appInit(void) {
+
+ /* CONNECT parameters */
+ conn_p.flagCleanSession=0;
+ conn_p.flagWill =0;
+ conn_p.flagWillQOS=0;
+ conn_p.flagWillRetain=0;
+
+ conn_p.flpProtocolID=0x01;
+ conn_p.flpDuration[0] = 0; /* Keep Alive Timer MostSignificantByte */
+ conn_p.flpDuration[1] = 15; /* Keep Alive Timer LSB = 15 sec */
+
+ conn_p.vlpClientID = (unsigned char *)"mqttsSampleAppl";
+ conn_p.vlpClientID_length = 15;
+
+ conn_p.vlpWillMsg = NULL;
+ conn_p.vlpWillMsg_length = 0;
+ conn_p.vlpWillTopic = NULL;
+ conn_p.vlpWillTopic_length = 0;
+
+ /* start mqtts and ask it to connect to a gw */
+ mqtts_startStack();
+ if (mqtts_connect(&conn_p)!= MQTTS_OK) {
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"connect error\r\n",15);
+#endif
+ }
+
+}
+
+#if MQTTS_DEBUG
+/**
+ * appHandleCmd() could be called e.g. when a character is typed in a terminal
+ * and sent to the hw device via a serial port.
+ * Its aim is to demonstrate the capabilities of mqtts, e.g
+ * requesting the sending of a REGISTER message
+ * requesting the sending of a PUBLISH message
+ * etc.
+ */
+void appHandleCmd(unsigned char cmd) { //cmd: character typed in terminal
+
+ switch(cmd) {
+ case '\r':
+ case '\n':
+ gp_debug((unsigned char*)"sample app\r\n", 12);
+ break;
+
+ case 'a':
+ gp_debug((unsigned char*)"start stack\r\n",13);
+ mqtts_startStack();
+ break;
+
+ case 't':
+ gp_debug((unsigned char*)"stop stack\r\n",12);
+ mqtts_stopStack();
+ break;
+
+ case 'c': /* ask mqtts to connect to a gw */
+ if (mqtts_connect(&conn_p)== MQTTS_OK) {
+ gp_debug((unsigned char*)"waiting for ready\r\n",19);
+ } else {
+ gp_debug((unsigned char*)"connect error!\r\n",16);
+ }
+ break;
+
+ case 'd':
+ gp_debug((unsigned char*)"sending disconnect ... \r\n",25);
+ if (mqtts_disconnect()!=MQTTS_OK) {
+ gp_debug((unsigned char*)"disc error!\r\n",13);
+ }
+ break;
+
+ case 'r':
+ gp_debug((unsigned char*)"send REGISTER, topic: wsn/data\r\n",32);
+ reg_p.vlpTopic = (unsigned char *)"wsn/data";
+ reg_p.vlpTopic_length = 8;
+ mqtts_register(&reg_p);
+ break;
+
+ case 'p':
+ gp_debug((unsigned char*)"send PUBLISH \"PUB QoS 0\" with QoS 0\r\n",37);
+ pub_p.flagQOS = 0;
+ pub_p.flagRetain = 0;
+ pub_p.flagTopicIdType = 0;
+ pub_p.vlpData = (unsigned char *)"PUB QoS 0";
+ pub_p.vlpData_length = 5;
+ mqtts_publish(&pub_p);
+ break;
+
+ case 'q':
+ gp_debug((unsigned char*)"send PUBLISH \"PUB QoS 1\" with QoS 1\r\n",37);
+ pub_p.flagQOS = 1;
+ pub_p.vlpData = (unsigned char *)"PUB QoS 1";
+ pub_p.vlpData_length = 5;
+ mqtts_publish(&pub_p);
+ break;
+
+ case 's':
+ gp_debug((unsigned char*)"send SUBSCRIBE to topic: wsn/cmd\r\n",34);
+ sub_p.flagQOS = 0;
+ sub_p.flagTopicIdType = 0;
+ sub_p.vlpTopic = (unsigned char *)"wsn/cmd";
+ sub_p.vlpTopic_length = 7;
+ mqtts_subscribe(&sub_p);
+ break;
+
+ case 'u':
+ gp_debug((unsigned char*)"send UNSUBSCRIBE topic: wsn/cmd\r\n",33);
+ usub_p.flagTopicIdType= 0;
+ usub_p.vlpTopic= (unsigned char *)"wsn/cmd";
+ usub_p.vlpTopic_length = 7;
+ mqtts_unsubscribe(&usub_p);
+ break;
+
+ default:
+ gp_debug((unsigned char*)"unknown cmd\r\n",13);
+ }
+
+}
+#endif
+
+/*****************************************************
+ * mqtts callback functions
+ *****************************************************/
+
+/**
+ * CONNECT sent to gw, client is waiting for answer from gw */
+void mqttscb_connect_sent(void)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"CONNECT sent\r\n",14);
+#endif
+}
+
+/**
+ * client is now connected to a gw, app can now start publishing, ... */
+void mqttscb_connected(void)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"connected\r\n",11);
+#endif
+}
+
+/**
+ * client is disconnected, app has to call mqtts_connect() again */
+void mqttscb_disconnected(unsigned char returnCode)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"disconnected\r\n",15);
+#endif
+}
+
+/**
+ * REGACK received, app can now use topic id for publishing */
+void mqttscb_regack_received(
+ unsigned char topicID_1,
+ unsigned char topicID_2,
+ unsigned char returnCode)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"REGACK received\r\n",17);
+#endif
+
+ pub_p.flpTopicID[0] = topicID_1;
+ pub_p.flpTopicID[1] = topicID_2;
+
+}
+
+/**
+ * PUBLISH received from gw/broker */
+unsigned char mqttscb_publish_received(
+ unsigned char dup,
+ unsigned char qos,
+ unsigned char topicID_0, /* Topic ID[0] */
+ unsigned char topicID_1, /* Topic ID[1] */
+ unsigned char *data,
+ unsigned char data_len)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"PUBLISH received\r\n",18);
+#endif
+ return 0;
+}
+
+/**
+ * PUBACK received, only for PUBLISH with QoS 1 */
+void mqttscb_puback_received(
+ unsigned char topicId_0,
+ unsigned char topicId_1,
+ unsigned char returnCode)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"PUBACK received\r\n",17);
+#endif
+}
+
+/**
+ * PUBCOMP received, only for PUBLISH with QoS 2 */
+void mqttscb_pubcomp_received()
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"PUBCOMP received\r\n",18);
+#endif
+}
+
+/**
+ * SUBACK received */
+void mqttscb_suback_received(
+ unsigned char qos,
+ unsigned char topicID_1,
+ unsigned char topicID_2,
+ unsigned char returnCode)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"SUBACK received\r\n",17);
+#endif
+}
+
+/**
+ * UNSUBACK received */
+void mqttscb_unsuback_received()
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"UNSUBACK received\r\n",19);
+#endif
+}
+
+/**
+ * REGISTER received */
+void mqttscb_register_received(
+ unsigned char topicID_0, /* Topic ID[0] */
+ unsigned char topicID_1, /* Topic ID[1] */
+ unsigned char *topic,
+ unsigned char topic_len)
+{
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"REGISTER received\r\n",19);
+#endif
+}
+
+/**
+ * WILLTOPICRESP received */
+void mqttscb_willtopicresp_received() {
+
+}
+
+
+/**
+ * WILLMSGRESP received */
+void mqttscb_willmsgresp_received() {
+
+}
+
+/***********************************************
+ *
+ * END OF FILE
+ *
+ */
+
diff --git a/apps/MQTTSN-C-Client/src/mqttsn/gp_api.h b/apps/MQTTSN-C-Client/src/mqttsn/gp_api.h
new file mode 100644
index 0000000..edf0a32
--- /dev/null
+++ b/apps/MQTTSN-C-Client/src/mqttsn/gp_api.h
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+
+/**
+ *
+ *
+ * Description : Generic platform (gp) API header file
+ *
+ *
+ */
+
+
+
+
+#ifndef _MQTTS_GP_API_H
+#define _MQTTS_GP_API_H
+
+
+
+/*************************************************************************
+ * The following functions are called by the mqtts client and have to be
+ * implemented by the generic platform (gp):
+ * 1. Timer related functions:
+ * * gp_timer_new
+ * * gp_timer_start
+ * * gp_timer_stop
+ * * gp_timer_end
+ * 2. Messages related functions:
+ * * gp_network_msg_send
+ * * gp_network_msg_broadcast
+ * * gp_byte_get
+ * 3. Help/Utility functions (optional, need not be implemented)
+ * * gp_debug (e.g. to print debug info)
+ *
+ * There is only one callback function from gp, namely:
+ * gpcb_network_msg_received()
+ *************************************************************************/
+
+
+/**
+ * request gp to create a new timer
+ *
+ * Parameters:
+ * timeout_funccb callback-function when time-out happens
+ * Return:
+ * id of timer created
+ */
+unsigned char gp_timer_new(void (*timeout_funccb)(void));
+
+
+/**
+ * request gp to start indicated timer with the indicated timer value in seconds
+ * Parameters:
+ * id id of timer to be started
+ * msb most significant byte of timer value (in seconds)
+ * lsb least significant byte of timer value
+ * Return:
+ * none
+ */
+void gp_timer_start(unsigned char id,
+ unsigned char msb,
+ unsigned char lsb);
+
+
+/**
+ * request gp to stop indicated timer
+ *
+ * Parameters:
+ * id id of timer to be stopped
+ *
+ * Return:
+ * none
+ *
+ */
+void gp_timer_stop(unsigned char id);
+
+/**
+ * request gp to end indicated timer (id cannot be used anymore)
+ *
+ * Parameters: id id of timer to be ended
+ *
+ * Return:
+ * none
+ *
+ */
+void gp_timer_end(unsigned char id);
+
+/**
+ * request gp to send a message
+ *
+ * Parameters:
+ * *msg pointer to first byte to be sent
+ * (message's length is in first byte to send!)
+ * *dest pointer to destination address
+ * length length of destination address
+ *
+ * Return:
+ * none
+ *
+ */
+void gp_network_msg_send(unsigned char *msg,
+ unsigned char *dest,
+ unsigned char length);
+
+/**
+ * request gp to broadcast a message
+ *
+ * Parameters:
+ * *msg pointer to first byte to be broadcasted
+ * (message's length is in first byte to send!)
+ * radius broadcast radius (0 means all network broadcast)
+ *
+ * Return:
+ * none
+ *
+ */
+void gp_network_msg_broadcast(unsigned char *msg,
+ unsigned char radius);
+
+
+/**
+ * get a byte from a message just received
+ * only called within the handling of gpcb_network_msg_received()
+ *
+ * Parameters:
+ * *msg pointer to the mqtts message
+ * (as received in gpcb_network_msg_received())
+ * index index of the byte to get
+ * index=1 => mqtts msg length field!
+ *
+ * Return:
+ * requested byte
+ *
+ */
+unsigned char gp_byte_get(unsigned char *msg, unsigned char index);
+
+
+/**
+ * Optional function: print/display e.g. debug information
+ *
+ * Parameters:
+ * *s pointer to string or array to be displayed
+ * length length of string/array to be displayed
+ *
+ * Return:
+ * none
+ *
+ */
+#if MQTTS_DEBUG
+//void gp_debug(char *s, ...);
+void gp_debug(unsigned char *s, unsigned char length);
+#endif
+
+
+/*************************************************************************
+ * callback functions (implemented by mqtts, see mqtts-core.c)
+ *************************************************************************/
+
+/**
+ * indicate the reception of a mqtts message
+ * to be called by gp to give the msg to mqtts client
+ *
+ * Parameters:
+ * *msg pointer to message received
+ * *sender pointer to sender's address
+ * length length of sender's address
+ *
+ * Return:
+ *
+ * NOTE 1: use gp_byte_get(msg,i) to get msg's byte #i !
+ * NOTE 2: mqtts length field is in msg[1], not in msg[0] !
+ */
+void gpcb_network_msg_received(
+ unsigned char *msg,
+ unsigned char *sender,
+ unsigned char length);
+
+
+#endif
diff --git a/apps/MQTTSN-C-Client/src/mqttsn/mqtts-core.c b/apps/MQTTSN-C-Client/src/mqttsn/mqtts-core.c
new file mode 100644
index 0000000..dc1594c
--- /dev/null
+++ b/apps/MQTTSN-C-Client/src/mqttsn/mqtts-core.c
@@ -0,0 +1,1407 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+/**
+ *
+ * Description : MQTT-SN client core implementation
+ *
+ *
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mqtts_api.h"
+#include "gp_api.h"
+
+#include "mqtts-timer.h"
+
+
+
+/**
+ * MQTT-S Message types */
+#define ADVERTISE 0x00
+#define SEARCHGW 0x01
+#define GWINFO 0x02
+
+#define CONNECT 0x04
+#define CONNACK 0x05
+#define WILLTOPICREQ 0x06
+#define WILLTOPIC 0x07
+#define WILLMSGREQ 0x08
+#define WILLMSG 0x09
+#define REGISTER 0x0A
+#define REGACK 0x0B
+#define PUBLISH 0x0C
+#define PUBACK 0x0D
+#define PUBCOMP 0x0E
+#define PUBREC 0x0F
+#define PUBREL 0x10
+
+#define SUBSCRIBE 0x12
+#define SUBACK 0x13
+#define UNSUBSCRIBE 0x14
+#define UNSUBACK 0x15
+#define PINGREQ 0x16
+#define PINGRESP 0x17
+#define DISCONNECT 0x18
+
+#define WILLTOPICUPD 0x1A
+#define WILLTOPICRESP 0x1B
+#define WILLMSGUPD 0x1C
+#define WILLMSGRESP 0x1D
+
+
+/**
+ * Flags binary masks */
+#define EMPTY_MASK 0x00 /* binary : 0000 0000 */
+#define DUP_FLAG_MASK 0x80 /* binary : 1000 0000 */
+#define QOS_MIN1_FLAG_MASK 0x60 /* binary : 0110 0000 */
+#define QOS2_FLAG_MASK 0x40 /* binary : 0100 0000 */
+#define QOS1_FLAG_MASK 0x20 /* binary : 0010 0000 */
+#define QOS0_FLAG_MASK 0x00 /* binary : 0000 0000 */
+#define RETAIN_FLAG_MASK 0x10 /* binary : 0001 0000 */
+#define WILL_FLAG_MASK 0x08 /* binary : 0000 1000 */
+#define CLEANSS_FLAG_MASK 0x04 /* binary : 0000 0100 */
+#define TOPICSHORT_FLAG_MASK 0x02 /* binary : 0000 0010 */
+#define TOPICIDPRE_FLAG_MASK 0x01 /* binary : 0000 0001 */
+#define TOPICID_FLAG_MASK 0x00 /* binary : 0000 0000 */
+
+#define GET_DUP_FLAG_MASK 0x80 /* binary : 1000 0000 */
+#define GET_QOS_FLAG_MASK 0x60 /* binary : 0110 0000 */
+
+
+/**
+ * mqtts client's state */
+static unsigned char mqtts_state = MQTTS_STATE_NOT_ACTIVE;
+/**
+ * MsgIg: incremented after having sent a message */
+static unsigned char msgId0=0;
+static unsigned char msgId1=0;
+
+static unsigned char myGwAddr[MQTTS_MAX_NETWORK_ADDRESS_LENGTH]={NULL};
+static unsigned char myGwAddrLength=0;
+static unsigned char myGwId=0;
+
+static unsigned char isConnected=0;
+static unsigned char lostGw=0;
+
+static unsigned char broadcastRadius;
+/* backupMsg: contains msg which will be retransmitted in case of ACK time-out */
+static unsigned char backupMsg[MQTTS_MAX_MSG_SIZE];
+
+static mqtts_CONNECT_Parms* conn_parms;
+
+#define HEADER_LENGTH 2
+/*
+ * macros
+ */
+#define msg_new(size) unsigned char msg[(size)]
+#define msg_set_length(len) *((msg)+0)=(len) /*msg[0]=len*/
+#define msg_get_length(msg) *((msg)+0)
+#define msg_set_type(type) *((msg)+1)=(type) /*msg[1]=type*/
+
+
+/*************************
+ * functions prototypes
+ *************************/
+static void mqtts_connecting(void);
+static void mqtts_willtopic(void);
+static void mqtts_willmsg(void);
+static void mqtts_regack(unsigned char topicId_1, unsigned char topicId_2,
+ unsigned char msgId1, unsigned char msgId2, unsigned char retCode );
+static void mqtts_puback(unsigned char topicID_1, unsigned char topicID_2,
+ unsigned char msgID_1, unsigned char msgID_2, unsigned char retCode );
+static void mqtts_pingresp(void);
+static void mqtts_pubrel(unsigned char msgID_1, unsigned char msgID_2 );
+static void gwinfo_received(unsigned char *msg, unsigned char *sender,
+ unsigned char sender_len);
+
+/****************************************************
+ * stack internal functions
+ ****************************************************/
+
+/**
+ * called when we lose a gw, e.g. after multiple ack time-outs */
+void lost_gw(void) {
+ myGwAddrLength=0;
+ mqtts_timer_stop_keep_alive();
+
+ /* if we have sent a DISC to the gw then we could go state WAITING_CONNECT
+ * otherwise we have start searching for gw */
+ if (mqtts_state == MQTTS_STATE_DISCONNECTING) {
+ mqtts_state = MQTTS_STATE_WAITING_CONNECT;
+ } else {
+ lostGw= 1;
+ mqtts_state = MQTTS_STATE_SEARCHING_GW; /* start searching for a new gw */
+ mqtts_timer_start_wait_searchgw(); /* delay sending out SEARCHGW */
+ }
+ mqttscb_disconnected(MQTTS_LOST_GATEWAY);
+}
+
+/**
+ * ack received in state WAITING_ACK */
+void ack_rx(void) {
+ mqtts_timer_stop_ack();
+ mqtts_state=MQTTS_STATE_READY;
+ if (lostGw == 1) {
+ mqttscb_connected();
+ lostGw= 0;
+ }
+}
+
+/**
+ * backup msg for later retransmission */
+void backup_msg(unsigned char *msg) {
+ unsigned char i;
+ for (i=0;i<(msg_get_length(msg));i++) {
+ backupMsg[i]= msg[i];
+ }
+}
+/**
+ * send backup message */
+void send_backupMsg(void) {
+ mqtts_timer_start_keep_alive();
+ mqtts_timer_start_ack();
+ gp_network_msg_send(backupMsg,myGwAddr,myGwAddrLength);
+}
+
+/* Set the MsgId field of the message. The MsgId is simply incremented for any
+ * message sent
+ *
+ * Input:
+ * msgId pointer to first byte of the MsgId field in the msg
+ * Returns:
+ * none
+ **/
+static void set_msg_id(unsigned char* msgId) {
+ /* msgId0 is msb, and msgId1 is lsb */
+ if (msgId1==255) {
+ msgId1=0;
+ if (msgId0==255) msgId0=0;
+ else msgId0++;
+ } else msgId1++;
+ msgId[0]= msgId0;
+ msgId[1]= msgId1;
+}
+
+
+/*************************************************************************
+ * Handle messages received
+ * to avoid race conditions and simplify the client implementation
+ * the client will respond to all gw's requests without making any check!
+ *************************************************************************/
+
+static void handleSEARCHGW(void) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_SEARCHING_GW:
+ /* we are searching for a gw and receive a SEARCHGW before
+ * we send SEARCHGW => we re-schedule the sending of our SEARCHGW */
+ mqtts_timer_start_wait_searchgw();
+ break;
+ /*only reply with GWINFO if we are connected to a gw*/
+ case MQTTS_STATE_READY:
+ /* delay before sending GWINFO to give priority to gw */
+ mqtts_timer_start_wait_gwinfo();
+ break;
+ default:
+ break;
+ }
+}
+
+static void handleCONNACK(unsigned char* msg) {
+ switch (mqtts_state) {
+ /* only accept CNNACK if we are in CONNECTING_TO_GW*/
+ case MQTTS_STATE_CONNECTING_TO_GW:
+ if (gp_byte_get(msg,3) == MQTTS_RET_ACCEPTED) { /* check return code */
+ mqtts_timer_stop_ack();
+ mqtts_state=MQTTS_STATE_READY;
+ isConnected= 1;
+ lostGw= 0;
+ mqttscb_connected();
+ /* set flagCleanSession and flagWill to 0 so that in case we
+ * lose the gw we can re-connect without requesting the app
+ * to re-do the subscriptions and the will stuffs */
+ //conn_parms->flagCleanSession=0;
+ /* TODO the new Will feature is not yet supported by the broker */
+ //conn_parms->flagWill=0;
+ } else {
+ /* conn is rejected => either we look for another gw, or we give
+ * the rejection reason to the app and let it decide what to do
+ * current decision: let app decide */
+ mqtts_state = MQTTS_STATE_WAITING_CONNECT;
+ mqtts_timer_stop_ack();
+ mqtts_timer_stop_keep_alive();
+ mqttscb_disconnected(gp_byte_get(msg,3));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void handleWILLTOPICREQ(void) {
+ mqtts_timer_stop_ack();
+ mqtts_willtopic();
+}
+
+static void handleWILLMSGREQ(void) {
+ mqtts_timer_stop_ack();
+ mqtts_willmsg();
+}
+
+static void handleREGISTER(unsigned char* msg) {
+ unsigned char i;
+ unsigned char topic[MQTTS_MAX_MSG_SIZE];
+ unsigned char topic_len;
+ unsigned char msg_len;
+
+ msg_len = gp_byte_get(msg,1);
+ topic_len = 0;
+
+ /* ignore message if not sent by our gw */
+ /* gw = mqtts_conn_get_gw();
+ if (memcmp(sender,gw->address, gw->address_len)!=0) return; */
+
+ /* copy topic */
+ for (i=0;i<(msg_len-6);i++) {
+ topic[i] = gp_byte_get(msg,7+i);
+ topic_len++;
+ }
+
+ /* send regack to gw */
+ mqtts_regack(
+ gp_byte_get(msg,3), gp_byte_get(msg,4), /* topic id*/
+ gp_byte_get(msg,5), gp_byte_get(msg,6), /* msg id*/
+ MQTTS_RET_ACCEPTED); /*return code*/
+ /* inform app */
+ mqttscb_register_received(
+ gp_byte_get(msg,3), gp_byte_get(msg,4),
+ topic, topic_len);
+}
+
+static void handleREGACK(unsigned char* msg) {
+
+ /*gw = mqtts_conn_get_gw();*/
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /* check MsgId */
+ if ((gp_byte_get(msg,5)!=msgId0) || (gp_byte_get(msg,6)!=msgId1)) return;
+
+ ack_rx();
+ mqttscb_regack_received(
+ gp_byte_get(msg,3), gp_byte_get(msg,4), /* Topic ID */
+ gp_byte_get(msg,7)); /* Return code */
+
+ break;
+ default:
+ break;
+ }
+}
+
+static void handlePUBLISH(unsigned char* msg) {
+ unsigned char i;
+ unsigned char data[MQTTS_MAX_MSG_SIZE];
+ unsigned char data_len= 0;
+ unsigned char msg_len= gp_byte_get(msg,1);
+
+ /* ignore message if not sent by our gw */
+ /*gw = mqtts_conn_get_gw(); */
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+
+ /* copy data*/
+ for (i=0;i<(msg_len-7);i++) {
+ data[i]=gp_byte_get(msg,8+i);
+ data_len++;
+ }
+ /* i is now return code from app */
+ i= mqttscb_publish_received(
+ ((gp_byte_get(msg,3) & GET_DUP_FLAG_MASK) >> 7),
+ ((gp_byte_get(msg,3) & GET_QOS_FLAG_MASK) >> 5),
+ gp_byte_get(msg,4), gp_byte_get(msg,5), /* Topic id */
+ data, data_len);
+ /* send puback if QoS = 1 or retCode = MQTTS_RET_INVALID_TOPIC_ID */
+ if (((gp_byte_get(msg,3) & GET_QOS_FLAG_MASK)>> 5)==1 ||
+ (i == MQTTS_RET_INVALID_TOPIC_ID)) {
+ mqtts_puback(gp_byte_get(msg,4), gp_byte_get(msg,5), /* Topic ID */
+ gp_byte_get(msg,6), gp_byte_get(msg,7), /* Msg Id */
+ i); /* return code */
+ }
+ /* TODO QoS=2 not implemented yet */
+
+}
+
+static void handlePUBACK(unsigned char* msg) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /*gw = mqtts_conn_get_gw();*/
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+
+ // check msgId
+ if ((gp_byte_get(msg,5)!=msgId0) || (gp_byte_get(msg,6)!=msgId1)) return;
+
+ ack_rx();
+ // inform app
+ mqttscb_puback_received(gp_byte_get(msg,3), gp_byte_get(msg,4), /* topicId */
+ gp_byte_get(msg,7)); /* Return code */
+ break;
+ default:
+ /*inform app in any case if return code != MQTTS_RET_ACCEPTED*/
+ if (gp_byte_get(msg,7)!=MQTTS_RET_ACCEPTED){
+ mqttscb_puback_received(gp_byte_get(msg,3), gp_byte_get(msg,4), /* topicId */
+ gp_byte_get(msg,7)); /* Return code */
+ }
+ break;
+ }
+}
+
+static void handleSUBACK(unsigned char* msg) {
+
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /*gw = mqtts_conn_get_gw();*/
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+ if ((gp_byte_get(msg,6)!=msgId0) || (gp_byte_get(msg,7)!=msgId1)) return;
+
+ ack_rx();
+ mqttscb_suback_received(
+ ((gp_byte_get(msg,3) & GET_QOS_FLAG_MASK) >> 5),
+ gp_byte_get(msg,4), gp_byte_get(msg,5), /* Topic Id */
+ gp_byte_get(msg,6)); /* Return code */
+ break;
+ default:
+ break;
+ }
+}
+
+static void handleUNSUBACK(unsigned char* msg) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /*gw = mqtts_conn_get_gw();*/
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+
+ if ((gp_byte_get(msg,3)!=msgId0) || (gp_byte_get(msg,4)!=msgId1)) return;
+
+ ack_rx();
+ mqttscb_unsuback_received();
+ break;
+ default:
+ break;
+ }
+}
+
+/* received a PINGREQ from gw; answer it with PINGRESP */
+static void handlePINGREQ(void) {
+ mqtts_pingresp();
+}
+
+static void handlePINGRESP(void) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /*gw = mqtts_conn_get_gw();*/
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+ ack_rx();
+ break;
+ default:
+ break;
+ }
+}
+
+static void handleDISCONNECT(void) {
+ mqtts_timer_stop_ack();
+ mqtts_timer_stop_keep_alive();
+ isConnected= 0;
+ if (mqtts_state == MQTTS_STATE_DISCONNECTING) {
+ mqtts_state = MQTTS_STATE_WAITING_CONNECT;
+ mqttscb_disconnected(MQTTS_OK);
+ } else {
+ /* ops , gw does not know me any more, try to re-CONNECT */
+ mqtts_state = MQTTS_STATE_CONNECTING_TO_GW;
+ mqtts_connecting();
+ }
+}
+
+static void handlePUBREC(unsigned char* msg) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /*gw = mqtts_conn_get_gw();
+ if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+ mqtts_timer_stop_ack();
+ mqtts_pubrel(gp_byte_get(msg,3), gp_byte_get(msg,4)); /* Msg id */
+ /* WARNING: stack is not ready here because pubrel waits for pubcomp */
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void handlePUBCOMP(void) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ ack_rx();
+ mqttscb_pubcomp_received();
+ break;
+ default:
+ break;
+ }
+}
+
+static void handleWILLTOPICRESP(void) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /*gw = mqtts_conn_get_gw();*/
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+ ack_rx();
+ mqttscb_willtopicresp_received();
+ break;
+ default:
+ break;
+ }
+}
+
+static void handleWILLMSGRESP(void) {
+ switch (mqtts_state) {
+ case MQTTS_STATE_WAITING_ACK:
+ /*gw = mqtts_conn_get_gw();*/
+ /*if (memcmp(sender,gw->address, gw->address_len)!=0) return;*/
+ ack_rx();
+ mqttscb_willmsgresp_received();
+ break;
+ default:
+ break;
+ }
+}
+
+static void gwFound(void) {
+ mqtts_timer_stop_wait_searchgw();
+ if (isConnected == 0) {
+ mqtts_state = MQTTS_STATE_CONNECTING_TO_GW;
+ mqtts_connecting();
+ } else {
+ /* we have lost the gw and find now one again
+ * we resend the last message without reconnecting */
+ mqtts_state = MQTTS_STATE_WAITING_ACK;
+ send_backupMsg();
+ }
+}
+
+static void handleADVERTISE(unsigned char* msg, unsigned char* sender,
+ unsigned char sender_len) {
+
+ mqtts_timer_stop_wait_gwinfo(); /* cancel send gwinfo */
+ switch (mqtts_state) {
+ case MQTTS_STATE_SEARCHING_GW:
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"adv ",4);
+#endif
+ memcpy(myGwAddr,sender,sender_len);
+ myGwAddrLength= sender_len;
+ myGwId=gp_byte_get(msg,3);
+ gwFound();
+ break;
+ default:
+ /* ignore ADVERTISE if we are not searching for GW */
+ break;
+ }
+}
+
+static void handleGWINFO(unsigned char* msg, unsigned char* sender,
+ unsigned char sender_len) {
+
+ /* we receive a GWINFO before sending our GWINFO */
+ /* => we don't send our GWINFO */
+ mqtts_timer_stop_wait_gwinfo();
+
+ switch (mqtts_state) {
+ case MQTTS_STATE_SEARCHING_GW:
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"gwi ",4);
+#endif
+ gwinfo_received(msg,sender,sender_len);
+ gwFound();
+ break;
+ default:
+ /* ignore GWINFO if we are not searching for GW */
+ break;
+ }
+}
+
+/********************************************************************/
+
+/***
+ * send a SEARCHGW message */
+void mqtts_searchgw(void) {
+ unsigned char msg[3]= {3,SEARCHGW,MQTTS_SEARCHGW_BROADCAST_RADIUS};
+
+ /* broadcast message and restart timer */
+ mqtts_timer_start_wait_searchgw();
+ gp_network_msg_broadcast(msg,MQTTS_SEARCHGW_BROADCAST_RADIUS);
+#if MQTTS_DEBUG
+ gp_debug((unsigned char*)"s_gw ",5);
+#endif
+}
+
+/***
+ * send a GWINFO message */
+void mqtts_gwinfo(void) {
+ unsigned char msg[MQTTS_MAX_NETWORK_ADDRESS_LENGTH + HEADER_LENGTH + 1];
+ unsigned char i;
+
+ msg_set_type(GWINFO);
+ msg[HEADER_LENGTH]= myGwId;
+ msg_set_length (HEADER_LENGTH + 1 + myGwAddrLength);
+ for (i=0;i<myGwAddrLength;i++) {
+ msg[HEADER_LENGTH+1+i]=myGwAddr[i];
+ }
+
+ /* broadcast message */
+ gp_network_msg_broadcast(msg,broadcastRadius);
+ /* Note: GWINFO is broadcasted with the same radius as received in SEARCHGW
+ * while SEARCHGW itself is broacasted with radius=MQTTS_SEARCHGW_BROADCAST_RADIUS
+ */
+}
+
+
+
+/***
+ * send a PUBACK message */
+static void mqtts_puback(unsigned char topicID_1, unsigned char topicID_2,
+ unsigned char msgID_1, unsigned char msgID_2, unsigned char retCode ) {
+
+ unsigned char msg[HEADER_LENGTH+5];
+
+ msg_set_type(PUBACK);
+ /* (Header size) + 2 (Topic ID) + 2 (Message ID) + 1 (Return code) */
+ msg_set_length(HEADER_LENGTH+5);
+
+ /* Fill fixed length parameters */
+ msg[HEADER_LENGTH]=topicID_1;
+ msg[HEADER_LENGTH+1]=topicID_2;
+ msg[HEADER_LENGTH+2]=msgID_1;
+ msg[HEADER_LENGTH+3]=msgID_2;
+ msg[HEADER_LENGTH+4]=retCode;
+
+ /* start keep alive timer and send the message*/
+ mqtts_timer_start_keep_alive();
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+}
+
+/***
+ * send a REGACK message */
+static void mqtts_regack(unsigned char topicId_1, unsigned char topicId_2,
+ unsigned char msgId1, unsigned char msgId2, unsigned char retCode ) {
+
+ unsigned char msg[HEADER_LENGTH+5];
+
+ msg_set_type(REGACK);
+ /* (Header size) + 2 (topic id) + 2 (Message ID) + 1 (Return code) */
+ msg_set_length(HEADER_LENGTH+5);
+
+ /* Fill fixed length parameters */
+ msg[HEADER_LENGTH]=topicId_1;
+ msg[HEADER_LENGTH+1]=topicId_2;
+ msg[HEADER_LENGTH+2]=msgId1;
+ msg[HEADER_LENGTH+3]=msgId2;
+ msg[HEADER_LENGTH+4]=retCode;
+
+ /* start keep alive timer and send the message*/
+ mqtts_timer_start_keep_alive();
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+}
+
+
+/***
+ * send a PUBREL message */
+static void mqtts_pubrel(unsigned char msgID_1, unsigned char msgID_2 ) {
+
+ unsigned char msg[HEADER_LENGTH+2];
+
+ /* Fill the header */
+ msg_set_type(PUBREL);
+ /*(Header size) + 2 (Message ID) */
+ msg_set_length(HEADER_LENGTH+2);
+
+ /* Fill fixed length parameters */
+ msg[HEADER_LENGTH]=msgID_1;
+ msg[HEADER_LENGTH+1]=msgID_2;
+
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+
+ /* we are waiting for PUBCOMP */
+ /* TODO What happens if we do not rx a PUBCOMP ? Retransmit PUBREL? */
+ /* backup the message for the ack*/
+ backup_msg(msg);
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+}
+
+
+
+/***
+ * send an PINGRESP message */
+static void mqtts_pingresp(void) {
+ unsigned char msg[2]={2,PINGRESP};
+ mqtts_timer_start_keep_alive();
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+}
+
+/**
+ * send an PINGREQ message */
+void mqtts_pingreq(void) {
+ unsigned char msg[2]={2,PINGREQ};
+ /* backup the message for the ack*/
+ backup_msg(msg);
+ /* start timers */
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+}
+
+/**
+ send an WILLMSG message
+ */
+static void mqtts_willmsg(void) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ /* Fill the header */
+ msg_set_type(WILLMSG);
+
+ /* Length = Header size + WillMsg */
+ msg_set_length(HEADER_LENGTH + conn_parms->vlpWillMsg_length);
+
+ /* then the variable parameters */
+ for (i=0; i<conn_parms->vlpWillMsg_length; i++){
+ msg[HEADER_LENGTH+i]= conn_parms->vlpWillMsg[i];
+ }
+
+ /* backup the message for the ack*/
+ backup_msg(msg);
+
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+}
+
+/**
+ send an WILLTOPIC message
+ */
+static void mqtts_willtopic(void) {
+
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ /* Fill the header */
+ msg_set_type(WILLTOPIC);
+ /* Length = Header size + Flags + WillTopic */
+ msg_set_length(HEADER_LENGTH + 1 + conn_parms->vlpWillTopic_length);
+
+ /* First the flags */
+ msg[HEADER_LENGTH] = EMPTY_MASK;
+
+ switch (conn_parms->flagWillQOS) {
+ case 2:
+ msg[HEADER_LENGTH] |= QOS2_FLAG_MASK;
+ break;
+
+ case 1:
+ msg[HEADER_LENGTH] |= QOS1_FLAG_MASK;
+ break;
+
+ default:
+ msg[HEADER_LENGTH] |= QOS0_FLAG_MASK;
+ break;
+ }
+
+ switch (conn_parms->flagWillRetain) {
+ case 1:
+ msg[HEADER_LENGTH] |= RETAIN_FLAG_MASK;
+ break;
+
+ default:
+ break;
+ }
+
+ /* then the variable parameters */
+ for (i=0; i<conn_parms->vlpWillTopic_length; i++)
+ {
+ msg[HEADER_LENGTH+1+i]=conn_parms->vlpWillTopic[i];
+ }
+
+ /* backup the message for the ack*/
+ backup_msg(msg);
+
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+}
+
+/**
+ send CONNECT message
+ */
+
+static void mqtts_connecting(void) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ /* set the value of the keep_alive timer */
+ mqtts_timer_set_keep_alive_time(conn_parms->flpDuration);
+
+ /* Fill the header */
+ msg_set_type(CONNECT);
+ msg_set_length(HEADER_LENGTH + 4 + conn_parms->vlpClientID_length);
+
+ /* Fill the message parameters */
+
+ /* First the flags */
+ msg[HEADER_LENGTH] = EMPTY_MASK;
+
+ switch (conn_parms->flagWill) {
+ case 1:
+ msg[HEADER_LENGTH] |= WILL_FLAG_MASK;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (conn_parms->flagCleanSession)
+ {
+ case 1:
+ msg[HEADER_LENGTH] |= CLEANSS_FLAG_MASK;
+ break;
+
+ default:
+ break;
+ }
+
+ /* then the fixed parameters */
+ msg[HEADER_LENGTH+1] = conn_parms->flpProtocolID;
+ msg[HEADER_LENGTH+2] = conn_parms->flpDuration[0];
+ msg[HEADER_LENGTH+3] = conn_parms->flpDuration[1];
+
+
+ /* then the variable parameters */
+ for (i=0; i<conn_parms->vlpClientID_length; i++) {
+ msg[HEADER_LENGTH + 4 + i]= conn_parms->vlpClientID[i];
+ }
+
+
+ /* backup the message for the ack */
+ backup_msg(msg);
+
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+ /* inform app about CONNECT sent */
+ mqttscb_connect_sent();
+ return;
+}
+
+/*************************************************/
+/** **/
+/** application API Implementation **/
+/** **/
+/*************************************************/
+
+
+void mqtts_startStack (void) {
+ if (mqtts_state != MQTTS_STATE_NOT_ACTIVE) return;
+
+ mqtts_state = MQTTS_STATE_WAITING_CONNECT;
+ mqtts_timer_init();
+
+#if MQTTS_DEBUG
+ gp_debug((unsigned char *)"MQTT-S client v.",16);
+ gp_debug((unsigned char *)MQTTS_VERSION,4);
+ gp_debug((unsigned char *)", ",2);
+#endif
+}
+
+
+void mqtts_stopStack(void) {
+ /* reset all stack variables and stop/delete all timers */
+ mqtts_state = MQTTS_STATE_NOT_ACTIVE;
+ isConnected= 0;
+ lostGw= 0;
+ msgId0=msgId1= 0;
+ mqtts_timer_end();
+
+}
+
+
+unsigned char mqtts_connect(mqtts_CONNECT_Parms *pParms) {
+
+ if ((mqtts_state != MQTTS_STATE_WAITING_CONNECT)) {
+ return MQTTS_ERR_STACK_NOT_READY;
+ }
+
+ /* (Header size) + 4 ( 1 (Flags) + 1 (ProtocolId) + 2 (Duration)) */
+ if ( (pParms->vlpClientID_length) >
+ (MQTTS_MAX_MSG_SIZE - (HEADER_LENGTH + 4)) )
+ {
+ return MQTTS_ERR_DATA_TOO_LONG;
+ }
+
+ conn_parms = pParms;
+
+ if (myGwAddrLength == 0) { /* no gw available yet */
+ mqtts_state = MQTTS_STATE_SEARCHING_GW;
+ mqtts_timer_start_wait_searchgw();
+ } else {
+ mqtts_state = MQTTS_STATE_CONNECTING_TO_GW;
+ mqtts_connecting();
+ }
+
+ return MQTTS_OK;
+}
+
+
+unsigned char mqtts_disconnect(void) {
+ unsigned char msg[2]={2,DISCONNECT};
+
+ switch (mqtts_state) {
+ case MQTTS_STATE_NOT_ACTIVE:
+ case MQTTS_STATE_WAITING_CONNECT:
+ return MQTTS_ERR_STACK_NOT_READY;
+ case MQTTS_STATE_CONNECTING_TO_GW:
+ case MQTTS_STATE_SEARCHING_GW:
+ /* no need for sending a DISC since we are not connected */
+ mqtts_state = MQTTS_STATE_WAITING_CONNECT;
+ isConnected= 0;
+ mqtts_timer_stop_ack();
+ mqtts_timer_stop_keep_alive();
+ mqtts_timer_stop_wait_gwinfo();
+ mqtts_timer_stop_wait_searchgw();
+ mqttscb_disconnected(MQTTS_OK);
+ break;
+ case MQTTS_STATE_READY:
+ case MQTTS_STATE_WAITING_ACK:
+ /* send DISC to gw and wait for DISC */
+ backup_msg(msg);
+ mqtts_timer_start_ack();
+ mqtts_timer_stop_keep_alive();
+ mqtts_timer_stop_wait_gwinfo();
+ mqtts_timer_stop_wait_searchgw();
+ mqtts_state = MQTTS_STATE_DISCONNECTING;
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+ break;
+ default:
+ break;
+ }
+ return MQTTS_OK;
+}
+
+
+unsigned char mqtts_register(mqtts_REGISTER_Parms *pParms) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ if (mqtts_state != MQTTS_STATE_READY) return MQTTS_ERR_STACK_NOT_READY;
+
+ /* check topic length */
+ if ( (pParms->vlpTopic_length) >
+ (MQTTS_MAX_MSG_SIZE - (HEADER_LENGTH + 2)) )
+ {
+ return MQTTS_ERR_DATA_TOO_LONG;
+ }
+
+ msg_set_type(REGISTER);
+ msg_set_length(HEADER_LENGTH + 4 + pParms->vlpTopic_length);
+
+ /* TopicId field */
+ msg[HEADER_LENGTH] = 0x00;
+ msg[HEADER_LENGTH+1] = 0x00;
+ /* MsgId field */
+ set_msg_id(msg+HEADER_LENGTH+2);
+ /* TopicName Field */
+ for (i=0; i<pParms->vlpTopic_length; i++) {
+ msg[HEADER_LENGTH + 4 + i]=pParms->vlpTopic[i];
+ }
+
+ /* backup the message for the ack */
+ backup_msg(msg);
+ /* we waiting for REGACK */
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+
+ return MQTTS_OK;
+
+}
+
+unsigned char mqtts_publish(mqtts_PUBLISH_Parms *pParms) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ if (mqtts_state != MQTTS_STATE_READY) return MQTTS_ERR_STACK_NOT_READY;
+
+ /* Fill the header */
+ msg_set_type(PUBLISH);
+
+ /* Header size + 5 (1 (Flags) + 2 (Message ID) + 2 (Topic ID)) */
+
+ if ( (pParms->vlpData_length) > (MQTTS_MAX_MSG_SIZE - (HEADER_LENGTH+5)) )
+ {
+ return MQTTS_ERR_DATA_TOO_LONG;
+ }
+
+ msg_set_length(HEADER_LENGTH + 5 + pParms->vlpData_length);
+
+
+ /* Fill the message parameters */
+
+ /* First the flags */
+ msg[HEADER_LENGTH] = EMPTY_MASK;
+
+ switch (pParms->flagQOS) {
+ case 2:
+ msg[HEADER_LENGTH] |= QOS2_FLAG_MASK;
+ set_msg_id(msg+5);
+ break;
+
+ case 1:
+ msg[HEADER_LENGTH] |= QOS1_FLAG_MASK;
+ /* set the message id */
+ set_msg_id(msg+5);
+ break;
+
+ default:
+ msg[HEADER_LENGTH] |= QOS0_FLAG_MASK;
+ /* message id = 0x0000 in case of QoS level 0*/
+ msg[5]=0x00;
+ msg[6]=0x00;
+ break;
+ }
+
+ switch (pParms->flagRetain)
+ {
+ case 1:
+ msg[HEADER_LENGTH] |= RETAIN_FLAG_MASK;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (pParms->flagTopicIdType)
+ {
+ case 2:
+ msg[HEADER_LENGTH] |= TOPICSHORT_FLAG_MASK;
+ break;
+
+ case 1:
+ msg[HEADER_LENGTH] |= TOPICIDPRE_FLAG_MASK;
+ break;
+
+ default:
+ break;
+ }
+
+ /* then the fixed parameters */
+ msg[HEADER_LENGTH+1] = pParms->flpTopicID[0];
+ msg[HEADER_LENGTH+2] = pParms->flpTopicID[1];
+
+ /* then the variable parameters */
+ for (i=1; i<=pParms->vlpData_length; i++)
+ {
+ msg[(msg_get_length(msg)-i)]=pParms->vlpData[pParms->vlpData_length-i];
+ }
+
+ if (pParms->flagQOS!=0)
+ {
+ /* save the flag and set the DUP flag for the backup */
+ i = msg[2];
+ msg[2] |= DUP_FLAG_MASK;
+ /* backup the message for the ack or pubrec*/
+ backup_msg(msg);
+ /* reload the saved flag */
+ msg[2] = i;
+ /* start the ack or pubrec timer */
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+ }
+
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+
+ return MQTTS_OK;
+}
+
+
+unsigned char mqtts_subscribe(mqtts_SUBSCRIBE_Parms *pParms) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ if (mqtts_state != MQTTS_STATE_READY) return MQTTS_ERR_STACK_NOT_READY;
+
+ /* Fill the header */
+ msg_set_type(SUBSCRIBE);
+
+ /* Header size + 1 (Flags) + 2 (MsgId)*/
+
+ if ( (pParms->vlpTopic_length) > (MQTTS_MAX_MSG_SIZE - (HEADER_LENGTH+3)) )
+ {
+ return MQTTS_ERR_DATA_TOO_LONG;
+ }
+
+ msg_set_length((HEADER_LENGTH+3) + pParms->vlpTopic_length);
+
+ /* Fill the message parameters */
+ /* First the flags */
+ msg[HEADER_LENGTH] = EMPTY_MASK;
+
+ switch (pParms->flagQOS)
+ {
+ case 2:
+ msg[HEADER_LENGTH] |= QOS2_FLAG_MASK;
+ break;
+
+ case 1:
+ msg[HEADER_LENGTH] |= QOS1_FLAG_MASK;
+ break;
+
+ default:
+ msg[HEADER_LENGTH] |= QOS0_FLAG_MASK;
+ break;
+ }
+
+ switch (pParms->flagTopicIdType)
+ {
+ case 2:
+ msg[HEADER_LENGTH] |= TOPICSHORT_FLAG_MASK;
+ break;
+ case 1:
+ msg[HEADER_LENGTH] |= TOPICIDPRE_FLAG_MASK;
+ break;
+ default:
+ break;
+ }
+
+ /* MsgId field */
+ set_msg_id(msg+HEADER_LENGTH+1);
+
+ /* then the variable parameters */
+ for (i=0; i<pParms->vlpTopic_length; i++)
+ {
+ msg[HEADER_LENGTH + 3 + i]=pParms->vlpTopic[i];
+ }
+
+ /* save the flag and set the DUP flag for the backup */
+ i = msg[HEADER_LENGTH];
+ msg[HEADER_LENGTH] |= DUP_FLAG_MASK;
+ /* backup the message for the ack */
+ backup_msg(msg);
+ /* reload the saved flag */
+ msg[HEADER_LENGTH] = i;
+ /* we wait for SUBACK */
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+
+
+ return MQTTS_OK;
+}
+
+
+unsigned char mqtts_unsubscribe(mqtts_UNSUBSCRIBE_Parms *pParms) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ if (mqtts_state != MQTTS_STATE_READY) return MQTTS_ERR_STACK_NOT_READY;
+
+ /* Fill the header */
+ msg_set_type(UNSUBSCRIBE);
+ /* Header size + 3 (Flags+MsgId) + (TopicLength))*/
+ msg_set_length(HEADER_LENGTH + 3 + pParms->vlpTopic_length);
+
+ /* Fill the message parameters */
+
+ /* First the flags */
+ msg[HEADER_LENGTH] = EMPTY_MASK;
+
+ switch (pParms->flagTopicIdType)
+ {
+ case 2:
+ msg[HEADER_LENGTH] |= TOPICSHORT_FLAG_MASK;
+ break;
+ case 1:
+ msg[HEADER_LENGTH] |= TOPICIDPRE_FLAG_MASK;
+ break;
+ default:
+ break;
+ }
+
+ /* MsgId field */
+ set_msg_id(msg+HEADER_LENGTH+1);
+
+ /* then the variable parameters */
+ for (i=0; i<pParms->vlpTopic_length; i++)
+ {
+ msg[HEADER_LENGTH + 3 + i]=pParms->vlpTopic[i];
+ }
+
+ /* save the flag and set the DUP flag for the backup*/
+ i = msg[HEADER_LENGTH];
+ msg[HEADER_LENGTH] |= DUP_FLAG_MASK;
+ /* backup the message for the ack*/
+ backup_msg(msg);
+ /* reload the saved flag */
+ msg[HEADER_LENGTH] = i;
+ /* we wait for UNSUBACK */
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+
+
+ return MQTTS_OK;
+
+}
+
+
+unsigned char mqtts_willtopic_update(mqtts_WILLTOPICUPD_Parms *pParms) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ if (mqtts_state != MQTTS_STATE_READY) return MQTTS_ERR_STACK_NOT_READY;
+
+ /* Fill the header */
+ msg_set_type(WILLTOPICUPD);
+
+ if (pParms == NULL) { //send an empty WILLTOPICUPD to delete will topic and msg
+ msg_set_length(HEADER_LENGTH);
+ } else {
+ msg_set_length(HEADER_LENGTH + 1 + pParms->vlpWillTopic_length);
+ msg[HEADER_LENGTH] = EMPTY_MASK;
+ switch (pParms->flagWillQOS) {
+ case 2:
+ msg[HEADER_LENGTH] |= QOS2_FLAG_MASK;
+ break;
+ case 1:
+ msg[HEADER_LENGTH] |= QOS1_FLAG_MASK;
+ break;
+ default:
+ msg[HEADER_LENGTH] |= QOS0_FLAG_MASK;
+ break;
+ }
+ switch (pParms->flagWillRetain) {
+ case 1:
+ msg[HEADER_LENGTH] |= RETAIN_FLAG_MASK;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<pParms->vlpWillTopic_length; i++)
+ {
+ msg[HEADER_LENGTH+1+i]=pParms->vlpWillTopic[i];
+ }
+ }
+
+ /* backup the message for the ack*/
+ backup_msg(msg);
+ /* we wait for WILLTOPICRESP */
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+
+ return MQTTS_OK;
+}
+
+
+
+unsigned char mqtts_willmsg_update(mqtts_WILLMSGUPD_Parms *pParms) {
+ unsigned char msg[MQTTS_MAX_MSG_SIZE];
+ unsigned char i;
+
+ if (mqtts_state != MQTTS_STATE_READY) return MQTTS_ERR_STACK_NOT_READY;
+
+ /* Fill the header */
+ msg_set_type(WILLMSGUPD);
+
+ /* Length = Header size + WillMsg */
+ msg_set_length(HEADER_LENGTH + pParms->vlpWillMsg_length);
+
+ /* then the variable parameters */
+ for (i=0; i<pParms->vlpWillMsg_length; i++){
+ msg[HEADER_LENGTH+i]= pParms->vlpWillMsg[i];
+ }
+ /* backup the message for the ack*/
+ backup_msg(msg);
+ mqtts_state=MQTTS_STATE_WAITING_ACK;
+ mqtts_timer_start_ack();
+ mqtts_timer_start_keep_alive();
+
+ gp_network_msg_send(msg,myGwAddr,myGwAddrLength);
+
+ return MQTTS_OK;
+}
+
+
+
+
+static void gwinfo_received(unsigned char *msg, unsigned char *sender, unsigned char sender_len) {
+ unsigned char i;
+ unsigned char data[MQTTS_MAX_MSG_SIZE];
+ unsigned char data_len;
+ unsigned char msg_len;
+
+ msg_len = gp_byte_get(msg,1);
+ data_len = 0;
+
+ switch(msg_len) {
+ case 3:
+ /* GWINFO was sent by a gw */
+ memcpy(myGwAddr,sender,sender_len);
+ myGwAddrLength= sender_len;
+ myGwId= gp_byte_get(msg,3);
+ break;
+ default:
+ /* GWINFO was sent by a client */
+ for (i=0;i<(msg_len-3);i++) {
+ data[i]=gp_byte_get(msg,4+i);
+ data_len++;
+ }
+ memcpy(myGwAddr,data,data_len);
+ myGwAddrLength= data_len;
+ myGwId= gp_byte_get(msg,3);
+ break;
+ }
+
+}
+
+
+
+void gpcb_network_msg_received(unsigned char *msg,unsigned char *sender,unsigned char sender_len) {
+
+ unsigned char msg_type= gp_byte_get(msg,2);
+
+ if (mqtts_state == MQTTS_STATE_NOT_ACTIVE) {
+ /* stack not started, all msgs are ignored */
+ return;
+ }
+
+ switch (msg_type) {
+ case ADVERTISE:
+ handleADVERTISE(msg, sender, sender_len);
+ return;
+
+ case GWINFO:
+ handleGWINFO(msg, sender, sender_len);
+ return;
+
+ case SEARCHGW:
+ broadcastRadius= gp_byte_get(msg,3);
+ handleSEARCHGW();
+ return;
+
+ default:
+ /* ignore msg if not sent by my gw */
+ if (memcmp(sender,myGwAddr, myGwAddrLength)!=0) return;
+ }
+
+ switch (msg_type) {
+ case CONNACK:
+ handleCONNACK(msg);
+ break;
+
+ case WILLTOPICREQ:
+ handleWILLTOPICREQ();
+ break;
+
+ case WILLMSGREQ:
+ handleWILLMSGREQ();
+ break;
+
+ case REGISTER:
+ handleREGISTER(msg);
+ break;
+
+ case REGACK:
+ handleREGACK(msg);
+ break;
+
+ case PUBLISH:
+ handlePUBLISH(msg);
+ break;
+
+ case PUBACK:
+ handlePUBACK(msg);
+ break;
+
+ case PUBREC:
+ handlePUBREC(msg);
+ break;
+
+ case PUBCOMP:
+ handlePUBCOMP();
+ break;
+
+ case SUBACK:
+ handleSUBACK(msg);
+ break;
+
+ case UNSUBACK:
+ handleUNSUBACK(msg);
+ break;
+
+ case PINGREQ:
+ handlePINGREQ();
+ break;
+
+ case PINGRESP:
+ handlePINGRESP();
+ break;
+
+ case DISCONNECT:
+ handleDISCONNECT();
+ break;
+
+ case WILLTOPICRESP:
+ handleWILLTOPICRESP();
+ break;
+ case WILLMSGRESP:
+ handleWILLMSGRESP();
+ break;
+
+ default:
+ break;
+
+ } /* end switch (msg_type) */
+}
+
+unsigned char mqtts_get_state(void) {
+ return (mqtts_state);
+}
+
+
+/* END OF FILE */
+
+
diff --git a/apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.c b/apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.c
new file mode 100644
index 0000000..2b895e6
--- /dev/null
+++ b/apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.c
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+/**
+ *
+ * Description : MQTT-SN timer file
+ *
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mqtts-timer.h"
+#include "gp_api.h"
+#include "mqtts_api.h"
+
+
+/* Timer ids */
+static unsigned char timer_ack;
+static unsigned char timer_keep_alive;
+static unsigned char timer_wait_searchgw;
+static unsigned char timer_wait_gwinfo;
+
+static unsigned char gAckMissedCnt=0;
+
+/* Keep-alive timer value */
+static unsigned char gKeepAliveTime[2]={0,0};
+
+/* SEARCHGW procedure */
+/* simplified procedure
+ * SEARCHGW delay: double after each time-out acc. until it reaches 255 sec
+ */
+static unsigned char gSearchGwDelay = SEARCHGW_MIN_DELAY;
+
+/*callback functions when time-out */
+void timeoutcb_ack(void);
+void timeoutcb_keep_alive(void);
+void timeoutcb_wait_searchgw(void);
+void timeoutcb_wait_gwinfo(void);
+
+/* functions prototypes, see mqtts-core.c */
+void lost_gw(void);
+void mqtts_pingreq(void);
+void mqtts_searchgw(void);
+void mqtts_gwinfo(void);
+void send_backupMsg(void);
+
+/**
+ * init timer component */
+void mqtts_timer_init(void) {
+ /* ask gp to create timers */
+ timer_ack = gp_timer_new(timeoutcb_ack);
+ timer_keep_alive = gp_timer_new(timeoutcb_keep_alive);
+ timer_wait_searchgw = gp_timer_new(timeoutcb_wait_searchgw);
+ timer_wait_gwinfo = gp_timer_new(timeoutcb_wait_gwinfo);
+}
+
+/**
+ * set the keep alive timer value, value in sec */
+void mqtts_timer_set_keep_alive_time(unsigned char *time) {
+ gKeepAliveTime[0] = time[0]; /*Most significant byte*/
+ gKeepAliveTime[1] = time[1]; /*Least significant byte */
+}
+
+/**
+ * stop and release all timers */
+void mqtts_timer_end(void) {
+ gp_timer_end(timer_ack);
+ gp_timer_end(timer_keep_alive);
+ gp_timer_end(timer_wait_searchgw);
+ gp_timer_end(timer_wait_gwinfo);
+ gAckMissedCnt=0;
+ gSearchGwDelay=SEARCHGW_MIN_DELAY;
+}
+
+/**
+ * start ACK timer */
+void mqtts_timer_start_ack(void) {
+ gp_timer_start(timer_ack, 0, ACK_TIME);
+}
+
+
+/**
+ * start keep alive timer */
+void mqtts_timer_start_keep_alive(void) {
+ gp_timer_start(timer_keep_alive, gKeepAliveTime[0], gKeepAliveTime[1]);
+}
+
+
+/**
+ * start timer for SEARCHGW */
+void mqtts_timer_start_wait_searchgw() {
+ gp_timer_start(timer_wait_searchgw,0,gSearchGwDelay);
+
+ /* douple time delay for SEARCHGW after every time-out
+ * until it reaches 255 sec */
+ if ((gSearchGwDelay==0x80) || (gSearchGwDelay==0xFF)) {
+ gSearchGwDelay = 0xFF;
+ } else {
+ gSearchGwDelay = gSearchGwDelay << 1;
+ }
+}
+
+/**
+ * start timer for GWINFO */
+void mqtts_timer_start_wait_gwinfo() {
+ gp_timer_start(timer_wait_gwinfo,0,GWINFO_MIN_DELAY);
+}
+
+/**
+ * stop ack timer and reset gAckMissedCnt */
+void mqtts_timer_stop_ack(void) {
+ gp_timer_stop(timer_ack);
+ gAckMissedCnt=0;
+}
+/**
+ * stop keep alive timer */
+void mqtts_timer_stop_keep_alive(void) {
+ gp_timer_stop(timer_keep_alive);
+}
+/**
+ * stop wait GWINFO timer */
+void mqtts_timer_stop_wait_gwinfo(void) {
+ gp_timer_stop(timer_wait_gwinfo);
+}
+/**
+ * stop wait SEARCHGW timer */
+void mqtts_timer_stop_wait_searchgw(void) {
+ gp_timer_stop(timer_wait_searchgw);
+ gSearchGwDelay = 0x01;
+}
+
+/**
+ * ACK time-out */
+void timeoutcb_ack(void) {
+ /* increment counter and stop timer */
+ gAckMissedCnt++;
+ /*no need for stop, timer already stopped when times out*/
+ /*gp_timer_stop(timer_ack);*/
+
+ if (gAckMissedCnt > MAX_ACK_MISSED) {
+ /* too many ACKs missed */
+ lost_gw();
+ gAckMissedCnt=0;
+ } else {
+ /* send backup message */
+ send_backupMsg();
+ }
+}
+
+/**
+ * Keep alive time out: send a PINGREQ to gw */
+void timeoutcb_keep_alive(void) {
+ mqtts_pingreq();
+}
+
+/**
+ * Wait GWINFO time out => send GWINFO */
+void timeoutcb_wait_gwinfo(void) {
+ mqtts_gwinfo();
+}
+/**
+ * Wait SEARCHGW time out => send SERACHGW */
+void timeoutcb_wait_searchgw(void) {
+ mqtts_searchgw();
+}
+
diff --git a/apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.h b/apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.h
new file mode 100644
index 0000000..78d5931
--- /dev/null
+++ b/apps/MQTTSN-C-Client/src/mqttsn/mqtts-timer.h
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+/**
+ *
+ *
+ * Description : MQTT-SN timer header file
+ *
+ *
+ */
+
+
+/**
+ * Initialize mqtts-timer component */
+void mqtts_timer_init();
+/**
+ * set value of keep alive timer */
+void mqtts_timer_set_keep_alive_time(unsigned char *time);
+/**
+ * end and delete all timers */
+void mqtts_timer_end(void);
+/**
+ * stack ACK timer */
+void mqtts_timer_start_ack(void);
+/**
+ * start keep alive timer */
+void mqtts_timer_start_keep_alive(void);
+/**
+ * start wait timer before sending SEARCHGW */
+void mqtts_timer_start_wait_searchgw(void);
+/**
+ * start wait timer before sending GWINFO */
+void mqtts_timer_start_wait_gwinfo(void);
+/**
+ * stop ACK timer */
+void mqtts_timer_stop_ack(void);
+/**
+ * stop keep alive timer */
+void mqtts_timer_stop_keep_alive(void);
+/**
+ * stop GWINFO wait timer */
+void mqtts_timer_stop_wait_gwinfo(void);
+/**
+ * stop SEARCHGW wait timer */
+void mqtts_timer_stop_wait_searchgw(void);
+
+
diff --git a/apps/MQTTSN-C-Client/src/mqttsn/mqtts_api.h b/apps/MQTTSN-C-Client/src/mqttsn/mqtts_api.h
new file mode 100644
index 0000000..cc6a7cc
--- /dev/null
+++ b/apps/MQTTSN-C-Client/src/mqttsn/mqtts_api.h
@@ -0,0 +1,426 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+/**
+ *
+ *
+ * Description : MQTT-S client API header file
+ *
+ *
+ *
+ *
+ *
+ */
+
+
+
+#ifndef _MQTTS_APPLICATION_API_H
+#define _MQTTS_APPLICATION_API_H
+
+/**
+ * ************** MQTT-S specific parameters **/
+#define MQTTS_VERSION "1.03"
+/**
+ * Maximum length of network address, e.g. 4 for ZigBee, 16 for IPv6, etc.
+ * Note: it just defines a max value, i.e. 16 can also be used for ZigBee */
+#define MQTTS_MAX_NETWORK_ADDRESS_LENGTH 4
+/**
+ * Maximum size for a mqtts message */
+#define MQTTS_MAX_MSG_SIZE 60
+/**
+ * Default value of timers, delay periods, etc.
+ * All time values are in seconds */
+/**
+ * max number of ACKs missed before gw is declared to be lost */
+#define MAX_ACK_MISSED 4
+/**
+ * ack waiting time */
+#define ACK_TIME 10
+/**
+ * waiting time before sending a SEARCHGW */
+#define SEARCHGW_MIN_DELAY 2
+/**
+ * waiting time before sending a GWINFO */
+#define GWINFO_MIN_DELAY 2
+/**
+ * Broadcast radius for SEARCHGW messages */
+#define MQTTS_SEARCHGW_BROADCAST_RADIUS 1
+
+
+
+/**
+ * ********************* Return codes **************/
+/**
+ * protocol return codes (received from gw) */
+#define MQTTS_RET_ACCEPTED 0x00
+#define MQTTS_RET_CONGESTION 0x01
+#define MQTTS_RET_INVALID_TOPIC_ID 0x02
+
+/* local return codes */
+#define MQTTS_OK 0xF0
+#define MQTTS_ERR_STACK_NOT_READY 0xF1
+#define MQTTS_ERR_DATA_TOO_LONG 0xF2
+#define MQTTS_LOST_GATEWAY 0xF3
+
+
+/**
+ ******************** MQTTS client's states ***************/
+/**
+ * Client not active, needs be started with mqtts_startStack() */
+#define MQTTS_STATE_NOT_ACTIVE 0x00
+/* Client is active, but waits for mqtts_connect() to setup a connection */
+#define MQTTS_STATE_WAITING_CONNECT 0x01
+/* Client is searching for a gateway (or forwarder) */
+#define MQTTS_STATE_SEARCHING_GW 0x02
+/* Client has sent a CONNECT to a gw and is waiting for its response */
+#define MQTTS_STATE_CONNECTING_TO_GW 0x03
+/* Client is ready for sending request to gw */
+#define MQTTS_STATE_READY 0x04
+/* Client has sent a request to the gw and is waiting for an acknowledgment
+ * Note that client can only have one outstanding request at a time and
+ * therefore does not accept any further app's request in this state */
+#define MQTTS_STATE_WAITING_ACK 0x05
+/* Client has sent a DISCONNECT to gw and is waiting for its response
+ * Client will return to state WAITING_CONNECT afterwards */
+#define MQTTS_STATE_DISCONNECTING 0x06
+
+
+/**
+ ********************* Definition of structures **************/
+/* CONNECT parameters structure */
+typedef struct {
+ /* flags */
+ unsigned char flagCleanSession;
+ unsigned char flagWill;
+ unsigned char flagWillQOS;
+ unsigned char flagWillRetain;
+
+ /* fixed length parameters */
+ unsigned char flpProtocolID;
+ unsigned char flpDuration[2]; /* Keep Alive timer value */
+
+ /* variable length parameters */
+ unsigned char *vlpClientID;
+ unsigned char vlpClientID_length;
+ unsigned char *vlpWillMsg;
+ unsigned char vlpWillMsg_length;
+ unsigned char *vlpWillTopic;
+ unsigned char vlpWillTopic_length;
+
+} mqtts_CONNECT_Parms;
+
+/* WILLTOPICUPD parameters structure */
+typedef struct {
+ /* flags */
+ unsigned char flagWillQOS;
+ unsigned char flagWillRetain;
+
+ /* variable length parameters */
+ unsigned char *vlpWillTopic;
+ unsigned char vlpWillTopic_length;
+
+} mqtts_WILLTOPICUPD_Parms;
+
+/* WILLMSGUPD parameters structure */
+typedef struct {
+ unsigned char *vlpWillMsg;
+ unsigned char vlpWillMsg_length;
+} mqtts_WILLMSGUPD_Parms;
+
+/* REGISTER parameters structure */
+typedef struct {
+ /* variable length parameters */
+ unsigned char *vlpTopic;
+ unsigned char vlpTopic_length;
+} mqtts_REGISTER_Parms;
+
+/* PUBLISH parameters structure */
+typedef struct {
+ /* flags */
+ /* DUP is set by mqtts when retransmitting the message */
+ unsigned char flagQOS;
+ unsigned char flagRetain;
+ unsigned char flagTopicIdType;
+ /* fixed length parameters */
+ unsigned char flpTopicID[2];
+ /* variable length parameters */
+ unsigned char *vlpData;
+ unsigned char vlpData_length;
+} mqtts_PUBLISH_Parms;
+
+/* SUBSCRIBE parameters structure */
+typedef struct {
+ /* flags */
+ unsigned char flagQOS;
+ unsigned char flagTopicIdType;
+ /* variable length parameters: TopicName or TopicId */
+ unsigned char *vlpTopic;
+ unsigned char vlpTopic_length;
+} mqtts_SUBSCRIBE_Parms;
+
+/* UNSUBSCRIBE parameters structure */
+typedef struct {
+ /* flags */
+ unsigned char flagTopicIdType;
+ /* variable length parameters: TopicName or TopicId */
+ unsigned char *vlpTopic;
+ unsigned char vlpTopic_length;
+} mqtts_UNSUBSCRIBE_Parms;
+
+
+/*************************************************************
+ *
+ * Functions provided by the mqtts client
+ *
+ * Functions that trigger a request to be sent to the gw/broker and
+ * required a reply from the gw/broker are non-blocking, i.e. the client
+ * with return immediately after having sent the request to the gw/broker.
+ * The gw/broker's response will then be indicated by the corresponding
+ * call-back function.
+ *
+ *************************************************************/
+
+/**
+ start the mqtts client: client will go to state WAITING_CONNECT
+ and begin to process ADVERTISE and GWINFO, but it will wait for
+ mqtts_connect() to initialize a connection to a gw
+
+ Parameters : none
+
+ Returns : none
+
+ */
+void mqtts_startStack(void);
+
+
+/**
+ stop the mqtts client:
+ client will then ignore all messages and go to state "NOT_ACTIVE";
+ app needs to re-issue mqtts_startStack()
+
+ Parameters : none
+
+ Returns : none
+
+ */
+void mqtts_stopStack(void);
+
+
+/**
+ request client to setup a connection to a gw
+ client stack has to be already started (with mqtts_startStack() )
+
+ Parameters :
+ pParms - pointer to a mqtts_CONNECT_Parms
+ Returns :
+ MQTTS_ERR_STACK_NOT_READY
+ MQTTS_ERR_DATA_TOO_LONG
+ MQTTS_OK
+
+ */
+unsigned char mqtts_connect(mqtts_CONNECT_Parms *pParms);
+
+
+/**
+ request client to disconnect
+ client will wait again for mqtts_connect() to setup a connection
+
+ Parameters : none
+
+ Returns :
+ MQTTS_ERR_STACK_NOT_READY
+ MQTTS_OK
+
+ */
+unsigned char mqtts_disconnect(void);
+
+
+/**
+ request client to send a REGISTER message
+ only accepted if client state = READY
+
+ Parameters :
+ pParms - pointer to a REGISTER parameter
+
+ Returns :
+ MQTTS_ERR_STACK_NOT_READY
+ MQTTS_OK
+ *
+ */
+unsigned char mqtts_register(mqtts_REGISTER_Parms *pParms);
+
+
+
+/**
+ request client to send a PUBLISH message
+ only accepted if client state = READY
+
+ Parameters :
+ pParms - pointer to a PUBLISH parameter
+
+ Returns :
+ MQTTS_ERR_STACK_NOT_READY
+ MQTTS_OK
+
+ */
+unsigned char mqtts_publish(mqtts_PUBLISH_Parms *pParms);
+
+
+/**
+ request client to send a SUBSCRIBE message
+ only accepted if client state = READY
+
+ Parameters :
+ pParms - pointer to a SUBSCRIBE parameter
+
+ Returns :
+ MQTTS_ERR_STACK_NOT_READY
+ MQTTS_OK
+
+ */
+unsigned char mqtts_subscribe(mqtts_SUBSCRIBE_Parms *pParms);
+
+
+/**
+ request client to send an UNSUBSCRIBE message
+ only accepted if client state = READY
+
+ Parameters :
+ pParms - pointer to a UNSUBSCRIBE parameter
+
+ Returns :
+ MQTTS_ERR_STACK_NOT_READY
+ MQTTS_OK
+
+ */
+unsigned char mqtts_unsubscribe(mqtts_UNSUBSCRIBE_Parms *pParms);
+
+/**
+ * request client to send a WILLTOPICUPD message to update the Will topic
+ * only accepted if client state = READY
+ *
+ * Parameters:
+ * pParms - pointer to a WILLTOPIC parameter
+ * NULL to send an empty WILLTOPICUPD message (delete Will)
+ *
+ * Returns :
+ * MQTTS_ERR_STACK_NOT_READY
+ * MQTTS_OK
+ *
+ *
+ */
+unsigned char mqtts_willtopic_update(mqtts_WILLTOPICUPD_Parms *pParms);
+
+/**
+ * request client to send a WILLMSGUPD message to update the Will message
+ * only accepted if client state = READY
+ *
+ * Parameters:
+ * pParms - pointer to WILLMSGUPD parameter
+ *
+ * Returns :
+ * MQTTS_ERR_STACK_NOT_READY
+ * MQTTS_OK
+ *
+ *
+ */
+unsigned char mqtts_willmsg_update(mqtts_WILLMSGUPD_Parms *pParms);
+
+
+/**
+ * Request for client state
+ *
+ * Inputs: none
+ *
+ * Returns: client state
+ *
+ *
+ */
+unsigned char mqtts_get_state(void);
+
+
+
+/***************************************************
+ * callback functions (to be implemented by the app)
+ ****************************************************
+ */
+
+/* CONNECT sent to gw, client is waiting for gw's answer */
+void mqttscb_connect_sent(void);
+
+/* client is connected to a gw, app can now start publishing, ... */
+void mqttscb_connected(void);
+
+/* client is disconnected
+ * reason: reason of disconnection */
+void mqttscb_disconnected(unsigned char reason);
+
+/* REGACK received, app can now use the indicated topicID for publishing */
+void mqttscb_regack_received(
+ unsigned char topicID_0,
+ unsigned char topicID_1,
+ unsigned char returnCode);
+
+/* PUBLISH received from gw/broker
+ * app should return immediately either with
+ * MQTTS_RET_ACCEPTED or MQTTS_RET_INVALID_TOPIC_ID
+ * before calling any other mqtts function */
+unsigned char mqttscb_publish_received(
+ unsigned char dup,
+ unsigned char qos,
+ unsigned char topicID_0, /* Topic ID[0] */
+ unsigned char topicID_1, /* Topic ID[1] */
+ unsigned char *data,
+ unsigned char data_len);
+
+/* PUBACK received */
+void mqttscb_puback_received(
+ unsigned char topicID_0, /* Topic ID[0] */
+ unsigned char topicID_1, /* Topic ID[1] */
+ unsigned char returnCode);
+
+/* TODO QoS Level 2 not supported yet */
+/* we only need to inform app with PUBCOMP */
+/* PUBREC received (QoS 2) */
+/* void mqttscb_pubrec_received(void); */
+/* PUBCOMP received (QoS 2) */
+void mqttscb_pubcomp_received(void);
+
+/* SUBACK received */
+void mqttscb_suback_received(
+ unsigned char qos,
+ unsigned char topicID_0,
+ unsigned char topicID_1,
+ unsigned char returnCode);
+
+/* UNSUBACK received */
+void mqttscb_unsuback_received(void);
+
+/* REGISTER received from gw */
+void mqttscb_register_received(
+ unsigned char topicID_0, /* Topic ID[0] */
+ unsigned char topicID_1, /* Topic ID[1] */
+ unsigned char *topic,
+ unsigned char topic_len);
+
+/* WILLTOPICRESP received from gw */
+void mqttscb_willtopicresp_received(void);
+
+/* WILLMSGRESP received from gw */
+void mqttscb_willmsgresp_received(void);
+
+#endif
+

Back to the top