├── .gitignore ├── README.md ├── SConscript ├── dlList.c ├── dlList.h ├── mqtt.c ├── mqtt.h ├── mqtt_client.c ├── mqtt_conf.h ├── mqtt_finsh.c ├── mqtt_handlers.c ├── mqtt_net.c ├── mqtt_send.c ├── mqtt_thread.c ├── mqtt_utf8.c └── mqtt_utf8.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | 5 | # Libraries 6 | *.lib 7 | *.a 8 | 9 | # Shared objects (inc. Windows DLLs) 10 | *.dll 11 | *.so 12 | *.so.* 13 | *.dylib 14 | 15 | # Executables 16 | *.exe 17 | *.out 18 | *.app 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MQTT 2 | ==== 3 | 4 | LWIP implementation of MQTT stack 5 | 6 | This is a work in progress but does work. I plan on doing alot of work to harden 7 | the code. Right now I am using RT-THREAD to run the stack so right now it might 8 | be OS dependent. I will be making it OS independent by using LWIP's OS ports 9 | -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | Import('RTT_ROOT') 2 | Import('rtconfig') 3 | from building import * 4 | 5 | src = Glob('*.c') 6 | CPPPATH = [RTT_ROOT + '/components/MQTT'] 7 | group = DefineGroup('mqtt', src, depend = ['RT_USING_MQTT'], CPPPATH = CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /dlList.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dlList.c 3 | * 4 | * Created on: Nov 17, 2013 5 | * Author: poppe 6 | */ 7 | #include 8 | #include 9 | #include 10 | 11 | #define DLL_ASSERT(x) RT_ASSERT(x) 12 | 13 | /** 14 | * @brief Initilize Double Linked List with know list type 15 | * @param[in] list to initilize 16 | * @param[in] type of list 17 | * @return Error code 18 | **/ 19 | int dllist_initList(List_t *list, int type) 20 | { 21 | DLL_ASSERT(list); 22 | //set list memory all to zero 23 | memset(list, '\0', sizeof(struct List)); 24 | list->type = type; 25 | return 0; 26 | } 27 | 28 | /** 29 | * @brief Allocates memory for a new Node 30 | * @param[out] list to initilize 31 | * @return Error code 32 | **/ 33 | int dllist_newNode(Node_t **node) 34 | { 35 | DLL_ASSERT(node); 36 | 37 | *node = DLL_MALLOC(sizeof(struct Node)); 38 | 39 | if(!*node) 40 | return -1; 41 | 42 | memset(*node, '\0', sizeof(struct Node)); 43 | 44 | return 0; 45 | } 46 | 47 | int dllist_destroyNode(Node_t *node) 48 | { 49 | DLL_ASSERT(node); 50 | 51 | DLL_FREE(node); 52 | return 0; 53 | } 54 | 55 | Node_t *dllist_findNodeWithData(List_t *list, void *data) 56 | { 57 | DLL_ASSERT(list); 58 | DLL_ASSERT(data); 59 | 60 | Node_t *tempNode = list->first; 61 | while(tempNode) 62 | { 63 | if(data == tempNode->data) 64 | return tempNode; 65 | 66 | tempNode = tempNode->next; 67 | } 68 | return NULL; 69 | } 70 | 71 | Node_t *dllist_getNodeAt(List_t *list, int pos) 72 | { 73 | DLL_ASSERT(list); 74 | 75 | Node_t *tempNode; 76 | 77 | if(pos > list->len) 78 | return NULL; 79 | 80 | tempNode = list->first; 81 | pos--; 82 | while(pos && tempNode) 83 | { 84 | tempNode = tempNode->next; 85 | pos--; 86 | } 87 | 88 | return tempNode; 89 | } 90 | 91 | void *dllist_getDataAt(List_t *list, int pos) 92 | { 93 | DLL_ASSERT(list); 94 | void *data; 95 | Node_t *tempNode = dllist_getNodeAt(list, pos); 96 | 97 | if(tempNode == NULL) 98 | return NULL; 99 | data = tempNode->data; 100 | 101 | return data; 102 | } 103 | 104 | Node_t *dllist_addData(List_t *list, void *data) 105 | { 106 | DLL_ASSERT(list); 107 | DLL_ASSERT(data); 108 | 109 | Node_t *newNode; 110 | dllist_newNode(&newNode); 111 | 112 | newNode->data = data; 113 | 114 | dllist_addNode(list, newNode); 115 | 116 | return newNode; 117 | 118 | } 119 | 120 | int dllist_addNode(List_t *list, Node_t *node) 121 | { 122 | DLL_ASSERT(list); 123 | DLL_ASSERT(node); 124 | 125 | if(list->type == DLL_FIFO) 126 | return dllist_addNodeToEnd(list, node); 127 | 128 | return dllist_addNodeToFront(list, node); 129 | } 130 | 131 | 132 | int dllist_insertBefore(List_t *list, Node_t *node, Node_t *newNode) 133 | { 134 | DLL_ASSERT(list); 135 | DLL_ASSERT(node); 136 | DLL_ASSERT(newNode); 137 | 138 | Node_t *tempNode; 139 | 140 | tempNode = node->prev; 141 | tempNode->next = newNode; 142 | newNode->prev = tempNode; 143 | node->prev = newNode; 144 | newNode->next = node; 145 | 146 | list->len++; 147 | return 0; 148 | } 149 | 150 | int dllist_addNodeToEnd(List_t *list, Node_t *node) 151 | { 152 | DLL_ASSERT(list); 153 | DLL_ASSERT(node); 154 | 155 | Node_t *tempNode; 156 | if(list->len == 0) 157 | { 158 | list->first = node; 159 | list->last = node; 160 | list->len++; 161 | return 0; 162 | } 163 | tempNode = list->last; 164 | tempNode->next = node; 165 | 166 | node->prev = tempNode; 167 | 168 | list->last = node; 169 | list->len++; 170 | 171 | return 0; 172 | } 173 | 174 | int dllist_addNodeToFront(List_t *list, Node_t *node) 175 | { 176 | DLL_ASSERT(list); 177 | DLL_ASSERT(node); 178 | 179 | Node_t *tempNode; 180 | 181 | if(list->len == 0) 182 | { 183 | list->first = node; 184 | list->last = node; 185 | list->len++; 186 | return 0; 187 | } 188 | tempNode = list->first; 189 | tempNode->prev = node; 190 | 191 | node->next = tempNode; 192 | 193 | list->first = node; 194 | list->len++; 195 | 196 | return 0; 197 | } 198 | 199 | int dllist_removeNode(List_t *list, Node_t *node, int freeNode) 200 | { 201 | DLL_ASSERT(list); 202 | DLL_ASSERT(node); 203 | 204 | Node_t *tempNode; 205 | 206 | if(!(dllist_NodeExsist(list, node))) 207 | return -1; 208 | 209 | tempNode = node->prev; 210 | if(tempNode) 211 | { 212 | tempNode->next = node->next; 213 | if(node->next) 214 | node->next->prev = tempNode; 215 | } 216 | list->len--; 217 | 218 | if(list->first == node) 219 | list->first = node->next; 220 | 221 | if(list->last == node) 222 | list->last = node->prev; 223 | 224 | if(freeNode) 225 | dllist_destroyNode(node); 226 | 227 | return 0; 228 | } 229 | 230 | int dllist_removeNodeWithData(List_t *list, void *data, int freeNode) 231 | { 232 | DLL_ASSERT(list); 233 | DLL_ASSERT(data); 234 | 235 | Node_t *tempNode = dllist_findNodeWithData(list, data); 236 | 237 | if(tempNode) 238 | dllist_removeNode(list, tempNode, freeNode); 239 | //TODO: I have no inditcaton if we don't find the node... need to fix 240 | return 0; 241 | } 242 | int dllist_listLen(List_t *list) 243 | { 244 | DLL_ASSERT(list); 245 | 246 | return list->len; 247 | } 248 | 249 | void dllist_foreachNode(List_t *list, void(*prototype)(Node_t *node, void *arg), void *arg) 250 | { 251 | DLL_ASSERT(list); 252 | DLL_ASSERT(prototype); 253 | 254 | int len = list->len; 255 | Node_t *tempNode = list->first; 256 | Node_t *nextTempNode; 257 | while(tempNode) 258 | { 259 | nextTempNode = tempNode->next; 260 | prototype(tempNode, arg); 261 | tempNode = nextTempNode; 262 | } 263 | } 264 | 265 | void dllist_foreachData(List_t *list, void(*prototype)(void *data, void *arg), void *arg) 266 | { 267 | DLL_ASSERT(list); 268 | DLL_ASSERT(prototype); 269 | 270 | int len = list->len; 271 | Node_t *tempNode = list->first; 272 | Node_t *nextTempNode; 273 | while(tempNode) 274 | { 275 | /* 276 | * I keep the next temp node so if the prototype deletes the node we can still move on the list 277 | * I am not sure that I need this but it can't hurt 278 | */ 279 | nextTempNode = tempNode->next; 280 | prototype(tempNode->data, arg); 281 | tempNode = nextTempNode; 282 | } 283 | } 284 | 285 | void dllist_foreachNodeWithBreak(List_t *list, int(*prototype(void*, void*)), void *arg) 286 | { 287 | DLL_ASSERT(list); 288 | DLL_ASSERT(prototype); 289 | 290 | int len = list->len, loopBreak = 0; 291 | Node_t *tempNode = list->first; 292 | 293 | while(tempNode && !loopBreak) 294 | { 295 | loopBreak = prototype(tempNode->data, arg); 296 | tempNode = tempNode->next; 297 | } 298 | } 299 | 300 | void *dllist_searchWithinData(List_t * list, int(*prototype(void *, void*)), void *arg) 301 | { 302 | DLL_ASSERT(list); 303 | DLL_ASSERT(prototype); 304 | 305 | int len = list->len, loopBreak = 0; 306 | Node_t *tempNode = list->first; 307 | 308 | while(tempNode) 309 | { 310 | loopBreak = prototype(tempNode->data, arg); 311 | 312 | if(loopBreak) 313 | return tempNode->data; 314 | 315 | tempNode = tempNode->next; 316 | } 317 | 318 | return NULL; 319 | } 320 | 321 | int dllist_swapData(Node_t *f, Node_t *s) 322 | { 323 | DLL_ASSERT(f); 324 | DLL_ASSERT(s); 325 | 326 | void *tempData = f->data; 327 | f->data = s->data; 328 | s->data = tempData; 329 | 330 | return 0; 331 | } 332 | 333 | 334 | 335 | int dllist_NodeExsist(List_t *list, Node_t *node) 336 | { 337 | DLL_ASSERT(list); 338 | DLL_ASSERT(node); 339 | int len = list->len; 340 | Node_t *tempNode = list->first; 341 | 342 | while(len && tempNode) 343 | { 344 | if(tempNode == node) 345 | return -1; 346 | 347 | len--; 348 | } 349 | 350 | return 0; 351 | } 352 | -------------------------------------------------------------------------------- /dlList.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dlList.h 3 | * 4 | * Created on: Nov 17, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #ifndef DLLIST_H_ 9 | #define DLLIST_H_ 10 | #include "rtthread.h" 11 | 12 | /*** STUCTURES ENUMS and UNIONS ***/ 13 | enum dllTypes 14 | { 15 | DLL_FIFO, 16 | DLL_FIL0, 17 | }; 18 | 19 | struct Node 20 | { 21 | struct Node *next; 22 | struct Node *prev; 23 | void * data; 24 | }; 25 | 26 | struct List 27 | { 28 | int type; 29 | int len; 30 | struct Node *current; 31 | struct Node *first; 32 | struct Node *last; 33 | }; 34 | 35 | /*** TYPEDEFS ***/ 36 | typedef struct Node Node_t; 37 | typedef struct List List_t; 38 | 39 | /*** DEFINES ***/ 40 | #define DLL_MALLOC(size) rt_malloc(size); 41 | #define DLL_FREE(data) rt_free(data); 42 | 43 | /*** PROTOTYPES ***/ 44 | int dllist_initList(List_t *list, int type); 45 | int dllist_newNode(Node_t **node); 46 | int dllist_destryNode(Node_t *node); 47 | Node_t * dllist_getNodeAt(List_t *list, int pos); 48 | void * dllist_getDataAt(List_t *list, int pos); 49 | Node_t *dllist_addData(List_t *list, void *data); 50 | int dllist_addNode(List_t *list, Node_t *node); 51 | int dllist_insertBefore(List_t *list, Node_t *node, Node_t *newNode); 52 | int dllist_addNodeToEnd(List_t *list, Node_t *node); 53 | int dllist_addNodeToFront(List_t *list, Node_t *node); 54 | int dllist_removeNode(List_t *list, Node_t *node, int freeNode); 55 | int dllist_listLen(List_t *list); 56 | //void dllist_foreachNode(List_t *list, int (*prototype(void *, void *)), void *arg) 57 | int dllist_findData(List_t list, void *data, int (*prototype(void *first, void *second))); 58 | int dllist_NodeExsist(List_t *list, Node_t *node); 59 | void *dllist_searchWithinData(List_t * list, int(*prototype(void *, void*)), void *arg); 60 | void dllist_foreachNode(List_t *list, void(*prototype)(Node_t *node, void *arg), void *arg); 61 | #endif /* DLLIST_H_ */ 62 | -------------------------------------------------------------------------------- /mqtt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt.c 3 | * 4 | * Created on: Oct 20, 2013 5 | * Author: poppe 6 | */ 7 | #include "mqtt.h" 8 | #include "lwip/sys.h" 9 | 10 | uint8_t user_flag = 0; 11 | uint8_t pass_flag = 0; 12 | 13 | uint8_t username_string[10]; 14 | uint8_t password_string[10]; 15 | 16 | uint8_t client_id[23] = DEFALUT_CLIENT_ID; 17 | 18 | 19 | 20 | mqtt_utf_t username = { 21 | 0, 22 | username_string, 23 | }; 24 | mqtt_utf_t password = { 25 | 0, 26 | password_string 27 | }; 28 | 29 | mqtt_err_t mqtt_sendConnect(mqtt_client_t *client) 30 | { 31 | 32 | mqtt_msg_t *msg = mqtt_createMsg(80);//FIXME: Fix the length to be correct based on values 33 | uint8_t *buf; 34 | printf("sending Connect for:%s\n", client->name); 35 | 36 | buf = msg->pkt; 37 | 38 | msg->fHdr.bits.msg_type = CONNECT; 39 | msg->fHdr.bits.dup_flag = 0; 40 | msg->fHdr.bits.qos = 0; 41 | msg->fHdr.bits.retain = 0; 42 | *buf++ = msg->fHdr.firstByte; 43 | 44 | //printf("Fixed Header first byte: 0x%X for %s\n", msg->fHdr.firstByte, client->name); 45 | //TODO: fix to a dynamic len right now it has to have a constant client ID len 46 | msg->fHdr.pkt_len = (44); //client id + variable header + client id len 47 | *buf++ = msg->fHdr.pkt_len; 48 | if(user_flag) 49 | { 50 | msg->vHdr.bits.user_flag = 1; 51 | //TODO: add username and password code 52 | if(pass_flag) 53 | { 54 | msg->vHdr.bits.pass_flag = 1; 55 | } 56 | } 57 | 58 | /******************************************* 59 | * Variable Header 60 | ******************************************/ 61 | 62 | /* Protocol */ 63 | buf += mqtt_stringToUtf("MQIsdp", buf); 64 | 65 | /* Version */ 66 | *buf++ = 3; 67 | 68 | //TODO: change clean session to be selectable 69 | msg->vHdr.bits.pass_flag = 0; 70 | msg->vHdr.bits.user_flag = 0; 71 | if(client->will) 72 | { 73 | msg->vHdr.bits.will_flag = 1; 74 | msg->vHdr.bits.will_qos = client->will->qos; 75 | msg->vHdr.bits.will_retain = 0; 76 | } 77 | else 78 | { 79 | msg->vHdr.bits.will_flag = 0; 80 | msg->vHdr.bits.will_qos = 0; 81 | msg->vHdr.bits.will_retain = 0; 82 | } 83 | 84 | msg->vHdr.bits.clean_session = 1; 85 | *buf++ = msg->vHdr.firstbyte; 86 | 87 | /* Keep Alive */ 88 | uint32_t toSec = client->keepalive / 1000; 89 | *buf++ = (uint8_t)(0xff & (toSec >> 8)); 90 | *buf++ = 0xff & toSec; 91 | 92 | /* order the variable header must be in 93 | * client ID 94 | * will topic 95 | * will message 96 | * username 97 | * password */ 98 | 99 | //TODO Add user authentication 100 | buf += mqtt_stringToUtf(client_id, buf);//FIXME and variable client ID 101 | 102 | if(client->will) 103 | { 104 | buf += mqtt_stringToUtf(client->will->topic, buf); 105 | buf += mqtt_stringToUtf(client->will->message, buf); 106 | } 107 | msg->len = buf - msg->pkt; 108 | 109 | mqtt_send(client, msg); 110 | 111 | /* wait for connack for 5s */ 112 | if(mqtt_waitForConnAck(client, 10000)) 113 | { 114 | printf("mqtt: server timeout\n"); 115 | } 116 | 117 | //TODO: Add error code handler after we attempt to connect 118 | 119 | //TODO: I might start the thread here 120 | return mqtt_errSuccess; 121 | } 122 | 123 | mqtt_err_t mqtt_publish(mqtt_client_t *client, mqtt_topic_t topic, 124 | mqtt_payload_t payload, uint8_t qos, uint8_t retain) 125 | { 126 | 127 | uint32_t neededLen = (strlen(topic)+2)+(strlen(payload)); 128 | if(qos >= 1) 129 | neededLen += 2; 130 | /* 131 | * Add 2 to the length to allow room for the fixed header: 132 | * TODO: I need to fix this if the length of the body is longer that 127 133 | */ 134 | mqtt_msg_t *msg = mqtt_createMsg(neededLen+2); 135 | uint8_t *ptr = msg->pkt; 136 | 137 | msg->fHdr.pkt_len = neededLen; 138 | msg->fHdr.bits.retain = retain; 139 | msg->fHdr.bits.msg_type = PUBLISH; 140 | msg->fHdr.bits.qos = qos; 141 | 142 | /* Fixed Header */ 143 | *ptr++ = msg->fHdr.firstByte; 144 | ptr += mqtt_lenEncode(ptr, msg->fHdr.pkt_len); 145 | 146 | /* Variable Header */ 147 | /* Topic */ 148 | ptr += mqtt_stringToUtf(topic, ptr); 149 | 150 | /* Message ID */ 151 | if(qos >=1 ) 152 | { 153 | msg->msgID = mqtt_makeMsgID(); 154 | *ptr++ = (0xff & (msg->msgID >> 8)); 155 | *ptr++ = 0xff & msg->msgID; 156 | } 157 | 158 | /* Payload */ 159 | memcpy(ptr, payload, strlen(payload)); 160 | 161 | ptr += strlen(payload); 162 | /* Msg Len */ 163 | msg->len = ptr - msg->pkt; 164 | //TODO: I want to create a queue of outgoing messages 165 | mqtt_send(client, msg); 166 | 167 | return mqtt_errSuccess; 168 | } 169 | 170 | mqtt_err_t mqtt_subscribe(mqtt_client_t *client, mqtt_topic_t topic, uint8_t qos) 171 | { 172 | mqtt_msg_t *msg = mqtt_createMsg(40); 173 | uint8_t *ptr = msg->pkt; 174 | //TODO: I created a subPub msg for subscription us it 175 | msg->fHdr.pkt_len = (1+strlen(topic)+2);//1 for QOS 2 for string len plus message ID len of 2 plus string len 176 | msg->fHdr.bits.retain = 0; 177 | msg->fHdr.bits.msg_type = SUBSCRIBE; 178 | msg->fHdr.bits.qos = qos; 179 | msg->fHdr.bits.dup_flag = 0; 180 | 181 | if(msg->fHdr.bits.qos >= 0) 182 | { 183 | msg->fHdr.pkt_len += 2; 184 | msg->msgID = mqtt_makeMsgID(); 185 | } 186 | /* Fixed Header */ 187 | *ptr++ = msg->fHdr.firstByte; 188 | ptr += mqtt_lenEncode(ptr, msg->fHdr.pkt_len); 189 | 190 | //MSG ID 191 | if(msg->fHdr.bits.qos >= 0) 192 | { 193 | 194 | *ptr++ = (0xff & (msg->msgID >> 8)); 195 | *ptr++ = 0xff & msg->msgID; 196 | } 197 | /* Variable Header */ 198 | /* Topic */ 199 | ptr += mqtt_stringToUtf(topic, ptr); 200 | 201 | /* Requested QOS */ 202 | *ptr++ = msg->fHdr.bits.qos; 203 | 204 | /* Msg Len */ 205 | msg->len = ptr - msg->pkt; 206 | 207 | mqtt_send(client, msg); 208 | printf("MQTT: sending Sub: with len: %i buf size: %i\n", msg->fHdr.pkt_len, msg->len); 209 | printf("MQTT: subscribe to topic: %s\n", topic); 210 | 211 | //TODO: The spec allows for multible subscriptions to be made at once... this is not impletemented 212 | return 0; 213 | } 214 | 215 | mqtt_err_t mqtt_disconnect(mqtt_client_t *client) 216 | { 217 | //TODO: add disconnect to MQTT code 218 | 219 | closesocket(client->socket); 220 | 221 | //session = NULL; 222 | 223 | return mqtt_errSuccess; 224 | 225 | } 226 | 227 | mqtt_err_t mqtt_check_keepalive(mqtt_client_t *client) 228 | { 229 | LWIP_ASSERT("Client != NULL",client != NULL); 230 | 231 | uint32_t currentTime = sys_now(), timeOut; 232 | timeOut = client->timeLastSent + client->keepalive; 233 | 234 | if(timeOut <= currentTime) 235 | { 236 | mqtt_sendPing(client); 237 | } 238 | return mqtt_errSuccess; 239 | } 240 | 241 | void mqtt_registerMsgCB(mqtt_client_t *client, pubMsgCallback cb) 242 | { 243 | RT_ASSERT(client); 244 | RT_ASSERT(cb); 245 | 246 | client->msgCB = cb; 247 | } 248 | -------------------------------------------------------------------------------- /mqtt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt.h 3 | * 4 | * Created on: Oct 15, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #ifndef MQTT_H_ 9 | #define MQTT_H_ 10 | 11 | #include "mqtt_utf8.h" 12 | #include "mqtt_conf.h" 13 | #include "stdint.h" 14 | #include "rtthread.h" 15 | #include 16 | #include 17 | #include "lwip/ip_addr.h" 18 | #include "dlList.h" 19 | 20 | #define PROTOCOL_NAME "MQTTClient" 21 | #define PROTOCOL_VERSION_MAJOR 3 22 | #define PROTOCOL_VERSION_MINOR 1 23 | #define CODE_VERSION_MAJOR 0 24 | #define CODE_VERSION_MINOR 2 25 | #define MAX_TX_FIFO_SIZE 8 26 | #define MQTT_RETRIES 4 27 | #define MQTT_DEFAULT_TIMEOUT_MS 5000 28 | 29 | /* Message types */ 30 | #define CONNECT 1 31 | #define CONNACK 2 32 | #define PUBLISH 3 33 | #define PUBACK 4 34 | #define PUBREC 5 35 | #define PUBREL 6 36 | #define PUBCOMP 7 37 | #define SUBSCRIBE 8 38 | #define SUBACK 9 39 | #define UNSUBSCRIBE 10 40 | #define UNSUBACK 11 41 | #define PINGREQ 12 42 | #define PINGRESP 13 43 | #define DISCONNECT 14 44 | 45 | #define CONNACK_ACCEPTED 0 46 | #define CONNACK_REFUSED_PROTOCOL_VERSION 1 47 | #define CONNACK_REFUSED_IDENTIFIER_REJECTED 2 48 | #define CONNACK_REFUSED_SERVER_UNAVAILABLE 3 49 | #define CONNACK_REFUSED_BAD_USERNAME_PASSWORD 4 50 | #define CONNACK_REFUSED_NOT_AUTHORIZED 5 51 | 52 | #define MQTT_MAX_PAYLOAD 268435455 53 | 54 | #define MQTT_UPDATE_DELAY 500 //MS delay.... 55 | 56 | #ifndef NULL 57 | #define NULL (void *)0 58 | #endif /* NULL */ 59 | 60 | #define MQTT_MALLOC(size) rt_malloc(size); 61 | #define MQTT_FREE(data) rt_free(data); 62 | 63 | extern uint8_t user_flag; 64 | extern uint8_t pass_flag; 65 | extern uint8_t username_string[10]; 66 | extern uint8_t password_string[10]; 67 | 68 | extern uint8_t client_id[]; 69 | 70 | 71 | typedef enum mqtt_err { 72 | mqtt_errSuccess, 73 | outOfMem, 74 | badSocket, 75 | mqtt_timeout, 76 | 77 | }mqtt_err_t; 78 | 79 | enum sendStatus{ 80 | MSG_UNSENT, 81 | MSG_SENT, 82 | MSG_WAITING_FOR_ACK, 83 | MSG_WAITING_FOR_COMP, 84 | MSG_WAITING_FOR_PUBREL, 85 | MSG_WAITING_FOR_PUBACK, 86 | MSG_HOLD_IN_MEMORY, 87 | MSG_SEND_ERROR, 88 | MSG_COMPLETE, 89 | }; 90 | 91 | enum connectStatus { 92 | CONNECTION_ACCEPTED, 93 | CONNECTION_BAD_VERSION, 94 | CONNECTION_IDENTITY_REJECTED, 95 | CONNECTION_SERVER_UNAVAIL, 96 | CONNECTION_NOT_AUTHORIZED 97 | }; 98 | 99 | typedef struct mqtt_fixedHdr { 100 | union{ 101 | uint8_t firstByte; 102 | 103 | struct { 104 | uint8_t retain : 1; 105 | uint8_t qos : 2 ; 106 | uint8_t dup_flag : 1; 107 | uint8_t msg_type : 4; 108 | }bits; 109 | }; 110 | uint32_t pkt_len; 111 | }mqtt_fixedHdr_t; 112 | 113 | typedef union mqtt_varHdr { 114 | uint8_t firstbyte; 115 | 116 | struct { 117 | uint8_t reserved : 1; 118 | uint8_t clean_session : 1; 119 | uint8_t will_flag : 1; 120 | uint8_t will_qos : 2; 121 | uint8_t will_retain : 1; 122 | uint8_t pass_flag : 1; 123 | uint8_t user_flag : 1; 124 | }bits; 125 | }mqtt_varHdr_t; 126 | #if 0 127 | struct { 128 | uint8_t user_flag : 1; 129 | uint8_t pass_flag : 1; 130 | uint8_t will_retain : 1; 131 | uint8_t will_qos : 2; 132 | uint8_t will_flag : 1; 133 | uint8_t clean_session : 1; 134 | uint8_t reserved : 1; 135 | }bits; 136 | #endif 137 | 138 | typedef struct mqtt_msg { 139 | mqtt_fixedHdr_t fHdr; 140 | mqtt_varHdr_t vHdr; 141 | size_t len; 142 | uint32_t timesent; 143 | uint16_t msgID; 144 | enum sendStatus status; 145 | uint8_t retries; 146 | uint8_t pkt[]; 147 | 148 | }mqtt_msg_t; 149 | 150 | typedef struct mqtt_will { 151 | char * topic;//Not a big fan of having the will here may look into moving 152 | uint8_t * message; 153 | uint8_t qos; 154 | }mqtt_will_t; 155 | 156 | typedef struct mqtt_pubSubMsg { 157 | uint8_t *topic; 158 | uint8_t *payload; 159 | uint32_t payLen; 160 | uint16_t msgID;//I don't know if I want this value here 161 | uint8_t qos; 162 | }mqtt_pubSubMsg_t; 163 | 164 | typedef void (*pubMsgCallback)(struct mqtt_client *, mqtt_pubSubMsg_t *); 165 | 166 | typedef struct mqtt_client { 167 | int socket; 168 | char name[16]; 169 | char * server; 170 | uint16_t port; 171 | uint32_t keepalive; 172 | uint32_t timeLastSent; 173 | uint32_t timeout; 174 | mqtt_will_t * will; 175 | List_t * txList; 176 | List_t * subList; 177 | pubMsgCallback msgCB; 178 | void (*subMsgHook)(struct mqtt_client *, mqtt_msg_t *); 179 | struct sockaddr_in serverAddr; 180 | sys_sem_t pingResp; 181 | sys_sem_t pubAck; 182 | sys_sem_t connAck; 183 | sys_mutex_t txOK; 184 | uint32_t connected; 185 | }mqtt_client_t; 186 | 187 | typedef char * mqtt_topic_t; 188 | typedef char * mqtt_payload_t; 189 | 190 | 191 | 192 | /*** PROTOTYPES ***/ 193 | /* mqtt.c */ 194 | mqtt_err_t mqtt_check_keepalive(mqtt_client_t *client); 195 | mqtt_err_t mqtt_createClient(mqtt_client_t *client, char *server, uint16_t port, uint32_t keepAlive, const char *name); 196 | mqtt_err_t mqtt_sendConnect(mqtt_client_t *client); 197 | mqtt_err_t mqtt_publish(mqtt_client_t *client, mqtt_topic_t topic, 198 | mqtt_payload_t payload, uint8_t qos, uint8_t retain); 199 | mqtt_err_t mqtt_subscribe(mqtt_client_t *client, mqtt_topic_t topic, uint8_t qos); 200 | void mqtt_registerMsgCB(mqtt_client_t *client, pubMsgCallback cb); 201 | 202 | /* mqtt_thread.c */ 203 | void mqtt_clientThread(void *arg); 204 | void mqtt_writeData(Node_t *node, mqtt_client_t *client); 205 | 206 | void mqtt_sendPing(mqtt_client_t *client); 207 | void mqtt_dnsCallback(const char *name, ip_addr_t *ipaddr, void *callback_arg); 208 | 209 | size_t mqtt_lenEncode(uint8_t *buf, uint32_t pktLen); 210 | mqtt_err_t mqtt_waitForConnAck(mqtt_client_t *client, uint32_t timeout); 211 | 212 | /* mqtt_send.c */ 213 | mqtt_msg_t *mqtt_findPubWithID(mqtt_client_t *client, uint16_t msgID); 214 | #endif /* MQTT_H_ */ 215 | -------------------------------------------------------------------------------- /mqtt_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_client.c 3 | * 4 | * Created on: Oct 15, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | /** 22 | * Move to mqtt.c 23 | */ 24 | mqtt_err_t mqtt_createClient(mqtt_client_t *client, char *server, uint16_t port, uint32_t keepAlive, const char *name) 25 | { 26 | RT_ASSERT(client); 27 | struct sockaddr_in serverAddr; 28 | struct in_addr addr; 29 | uint32_t serveraddr; 30 | int err; 31 | 32 | // memset(client, 0, sizeof(mqtt_client_t)); 33 | 34 | memcpy(client->name, name, strlen(name)); 35 | client->keepalive = keepAlive; 36 | client->timeout = MQTT_DEFAULT_TIMEOUT_MS; 37 | 38 | serveraddr = inet_addr(server); 39 | 40 | if(serveraddr != INADDR_NONE) 41 | { 42 | client->serverAddr.sin_addr.s_addr = ipaddr_addr(server); 43 | } 44 | else 45 | { 46 | LWIP_DEBUGF(MQTT_DEBUG, ("Waiting to find IP\n")); 47 | err = dns_gethostbyname(server, &client->serverAddr.sin_addr.s_addr, mqtt_dnsCallback, client); 48 | if(err == ERR_INPROGRESS) 49 | { 50 | if(mqtt_waitForDNS(5000)) 51 | { 52 | LWIP_DEBUG(MQTT_DEBUG, ("MQTT: no IP found\n")); 53 | return badSocket; 54 | } 55 | LWIP_DEBUGF(MQTT_DEBUG, ("IP found:\n")); 56 | } 57 | } 58 | 59 | client->serverAddr.sin_port = htons(port); 60 | client->serverAddr.sin_family = AF_INET; 61 | 62 | sys_sem_new(&client->pingResp, 0); 63 | sys_sem_new(&client->connAck, 0); 64 | sys_sem_new(&client->pubAck, 0); 65 | sys_mutex_new(&client->txOK); 66 | 67 | client->txList = MQTT_MALLOC(sizeof(List_t)); 68 | dllist_initList(client->txList, DLL_FIFO); 69 | 70 | client->socket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); 71 | 72 | LWIP_DEBUGF(MQTT_DEBUG, ("client %s socket number: %i\n", client->name, client->socket)); 73 | if(client->socket < 0 || client->socket > 100) 74 | { 75 | rt_kprintf( "MQTT: SOCKET FAILED\n" ); 76 | return badSocket; 77 | } 78 | /* set socket option */ 79 | int sock_opt = 5000; /* 5 seconds */ 80 | lwip_setsockopt(client->socket, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt)); 81 | 82 | err = connect(client->socket, (struct sockaddr *)&client->serverAddr, sizeof(struct sockaddr_in)); 83 | if(err) 84 | { 85 | LWIP_DEBUGF(MQTT_DEBUG, ("MQTT: did not connect to socket: %i\n", client->socket)); 86 | return badSocket; 87 | } 88 | sys_thread_t t = sys_thread_new("MQTTRecv", mqtt_clientThread, client, 8192, 5); 89 | 90 | LWIP_DEBUGF(MQTT_DEBUG, ("Created client: %s:\n", client->name)); 91 | 92 | mqtt_sendConnect(client);//FIXME: I don't want to in the future auto connect 93 | 94 | return mqtt_errSuccess; 95 | 96 | } 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /mqtt_conf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_conf.h 3 | * 4 | * Created on: Oct 20, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #ifndef MQTT_CONF_H_ 9 | #define MQTT_CONF_H_ 10 | 11 | #include "lwip/debug.h" 12 | 13 | #define DEFALUT_CLIENT_ID "POPPEtest1234" 14 | #define DEFAULT_SERVER_IP "192.168.34.45" 15 | 16 | #define MQTT_MAX_PKT_SIZE 128 17 | 18 | //TODO: Make more eligant place and setup for wills 19 | #define MQTT_DEFAULT_WILL_TOPIC "matt/will" 20 | #define MQTT_DEFAULT_WILL_MSG "dead" 21 | #define MQTT_DEFAULT_WILL_QOS 1 22 | 23 | #define MQTT_DEBUG LWIP_DBG_ON 24 | #endif /* MQTT_CONF_H_ */ 25 | -------------------------------------------------------------------------------- /mqtt_finsh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_finsh.c 3 | * 4 | * Created on: Oct 15, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #include 9 | #include "mqtt.h" 10 | #include 11 | 12 | static mqtt_client_t myClient; 13 | static char willTopic[] = MQTT_DEFAULT_WILL_TOPIC; 14 | static uint8_t willMsg[] = MQTT_DEFAULT_WILL_MSG; 15 | 16 | 17 | static mqtt_will_t myWill = { 18 | .topic = willTopic, 19 | .message = willMsg, 20 | .qos = MQTT_DEFAULT_WILL_QOS, 21 | }; 22 | 23 | void mqttConnect(void) 24 | { 25 | myClient.will = &myWill; 26 | //mqtt_client_t *secondClient = (mqtt_client_t *)malloc(sizeof(mqtt_client_t)); 27 | //mqtt_createClient(&myClient, "85.119.83.194", 1883, 10000, "MyClient"); 28 | mqtt_createClient(&myClient, "192.168.34.127", 1883, 100000, "MyClient"); 29 | //mqtt_createClient(secondClient, "192.168.34.127", 1883, 10000, "MyClient"); 30 | } 31 | FINSH_FUNCTION_EXPORT(mqttConnect, connect to mosquitto server); 32 | 33 | void mqttSub(uint8_t qos) 34 | { 35 | mqtt_subscribe(&myClient, "matt/pizza", qos); 36 | } 37 | FINSH_FUNCTION_EXPORT(mqttSub, subscribe to message); 38 | void mqttPub(void) 39 | { 40 | mqtt_publish(&myClient, "matt/pizza", "pepperoni", 2, 0); 41 | } 42 | FINSH_FUNCTION_EXPORT(mqttPub, publish a message); 43 | //FINSH_FUNCTION_EXPORT_ALIAS() 44 | -------------------------------------------------------------------------------- /mqtt_handlers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_handlers.c 3 | * 4 | * Created on: Dec 27, 2013 5 | * Author: poppe 6 | */ 7 | #include "mqtt.h" 8 | 9 | static int connAckCode = 0; 10 | 11 | 12 | /* 13 | * Prototypes 14 | */ 15 | //Handlers 16 | mqtt_err_t mqtt_pubHandler(mqtt_client_t *client, mqtt_msg_t *msg, uint8_t *buf); 17 | mqtt_err_t mqtt_connAckHandler(mqtt_client_t *client, uint8_t *buf); 18 | mqtt_err_t mqtt_pingRespHandler(mqtt_client_t *client, uint8_t *buf); 19 | mqtt_err_t mqtt_pubRecHandler(mqtt_client_t *client, mqtt_msg_t *msg, uint8_t *buf); 20 | mqtt_err_t mqtt_pubackHandler(mqtt_client_t *client, uint8_t *buf); 21 | mqtt_err_t mqtt_subackHandler(mqtt_client_t *client, uint8_t *buf); 22 | mqtt_err_t mqtt_pubcompHandler(mqtt_client_t *client, uint8_t *buf); 23 | 24 | /************************************************************************************************** 25 | * 26 | * Message Handlers 27 | * 28 | *************************************************************************************************/ 29 | void mqtt_handler(mqtt_client_t *client, uint8_t *buf, size_t size) 30 | { 31 | static mqtt_msg_t msg; 32 | 33 | while(size > 0) 34 | { 35 | msg.fHdr.firstByte = *buf++; 36 | buf += mqtt_lenDecode(buf, &msg.fHdr.pkt_len); 37 | 38 | switch(msg.fHdr.bits.msg_type) 39 | { 40 | case CONNACK: 41 | if(msg.fHdr.pkt_len == 2) 42 | mqtt_connAckHandler(client, buf); 43 | else 44 | printf("Connack has wrong len\n"); 45 | break; 46 | 47 | case PUBLISH: 48 | printf("PUBLISH Receive\n"); 49 | //TODO: I need to reformat all the type handlers to have the msg as well 50 | mqtt_pubHandler(client, &msg, buf); 51 | break; 52 | case PUBACK: 53 | printf("PUBACK Received\n"); 54 | mqtt_pubackHandler(client, buf); 55 | 56 | break; 57 | case PUBREC: 58 | mqtt_pubRecHandler(client, &msg, buf); 59 | printf("PUBREC Received\n"); 60 | break; 61 | 62 | case PUBREL: 63 | printf("PUBREL Received\n"); 64 | break; 65 | 66 | case PUBCOMP: 67 | mqtt_pubcompHandler(client, buf); 68 | printf("PUBCOMP Received\n"); 69 | break; 70 | 71 | case SUBACK: 72 | printf("SUBACK Received\n"); 73 | break; 74 | 75 | case UNSUBACK: 76 | printf("UNSUBACK Received\n"); 77 | break; 78 | case PINGRESP: 79 | mqtt_pingRespHandler(client, buf); 80 | break; 81 | default: 82 | 83 | printf("Unknown Message Type\n"); 84 | return; 85 | } 86 | buf += (msg.fHdr.pkt_len + 2); 87 | size -= (msg.fHdr.pkt_len + 2); 88 | } 89 | } 90 | 91 | mqtt_err_t mqtt_pingRespHandler(mqtt_client_t *client, uint8_t *buf) 92 | { 93 | mqtt_msg_t *msg; 94 | 95 | printf("MQTT: GOT PING RESPONCE\n"); 96 | sys_sem_signal(&client->pingResp); 97 | 98 | msg = mqtt_findMsg(client, PINGREQ); 99 | 100 | if(msg) 101 | msg->status = MSG_COMPLETE; 102 | 103 | client->timeLastSent = sys_now(); 104 | return mqtt_errSuccess; 105 | } 106 | 107 | mqtt_err_t mqtt_subackHandler(mqtt_client_t *client, uint8_t *buf) 108 | { 109 | RT_ASSERT(client); 110 | mqtt_msg_t *msg = NULL; 111 | uint16_t msgID; 112 | uint8_t grantedQOS; 113 | 114 | msgID = *buf++; 115 | msgID <<= 8; 116 | msgID = *buf++; 117 | 118 | grantedQOS = *buf++; 119 | 120 | msg = mqtt_findSubWithID(client, msgID); 121 | 122 | if(msg) 123 | { 124 | printf("Sub ack with msgID: %i is found and acked", msgID); 125 | msg->status = MSG_COMPLETE; 126 | 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | mqtt_err_t mqtt_pubRespHandler(mqtt_client_t *client, uint8_t *buf) 133 | { 134 | mqtt_msg_t *msg; 135 | 136 | printf("MQTT: GOT PUB RESPONCE\n"); 137 | 138 | msg = mqtt_findMsg(client, PUBLISH); 139 | 140 | if(msg) 141 | msg->status = MSG_COMPLETE; 142 | 143 | client->timeLastSent = sys_now(); 144 | return mqtt_errSuccess; 145 | } 146 | 147 | mqtt_err_t mqtt_pubHandler(mqtt_client_t *client, mqtt_msg_t *msg, uint8_t *buf) 148 | { 149 | RT_ASSERT(client); 150 | RT_ASSERT(msg); 151 | 152 | uint32_t bufferLeft = msg->fHdr.pkt_len; 153 | mqtt_pubSubMsg_t PSMsg; 154 | uint32_t strLen; 155 | 156 | PSMsg.qos = msg->fHdr.bits.qos; 157 | 158 | strLen = (uint32_t)((*buf++) << 8); 159 | strLen = (uint32_t)(*buf++); 160 | 161 | //Determine the length left for the payload 2 for the utf str len and also actual str len 162 | bufferLeft -= 2; 163 | bufferLeft -= strLen; 164 | PSMsg.topic = (uint8_t *)MQTT_MALLOC(strLen+1); 165 | 166 | memcpy(PSMsg.topic, buf, strLen); 167 | PSMsg.topic[strLen] = '\0'; 168 | buf += strLen; 169 | 170 | /* 171 | * MSG ID 172 | * If there is a QOS greater than 0 we need the msg ID 173 | */ 174 | if(PSMsg.qos > 0) 175 | { 176 | PSMsg.msgID = (uint32_t)((*buf++) << 8); 177 | PSMsg.msgID = (uint32_t)(*buf++); 178 | } 179 | 180 | //** PAYLOAD **// 181 | PSMsg.payload = (uint8_t *)MQTT_MALLOC(bufferLeft+1); 182 | PSMsg.payLen = bufferLeft; 183 | 184 | memcpy(PSMsg.payload, buf, bufferLeft); 185 | PSMsg.payload[bufferLeft] = '\0'; 186 | buf += strLen; 187 | 188 | LWIP_DEBUGF(MQTT_DEBUG, ("Topic len:%i Payload len: %i\n", strLen, bufferLeft)); 189 | 190 | 191 | LWIP_DEBUGF(MQTT_DEBUG, ("------ Received Pub MSG: -------\n")); 192 | 193 | if(PSMsg.qos > 0) 194 | LWIP_DEBUGF(MQTT_DEBUG, ("MSG ID: %i", PSMsg.msgID)); 195 | 196 | LWIP_DEBUGF(MQTT_DEBUG, (" Topic: %s\n", PSMsg.topic)); 197 | /* FIXME This need to be changed in case the payload is not ascii */ 198 | LWIP_DEBUGF(MQTT_DEBUG, (" Payload: %s\n", PSMsg.payload)); 199 | 200 | if(PSMsg.qos == 1) 201 | { 202 | mqtt_pubAck(client, PSMsg.msgID); 203 | } else if ( PSMsg.qos == 2) 204 | { 205 | mqtt_pubRec(client, PSMsg.msgID); 206 | } 207 | 208 | 209 | /** 210 | * I am going to add a hook here to bridge coap to mqtt 211 | * currently this is very weak and needs to be improved 212 | */ 213 | #if defined(MQTT_SEND_TO_HOOK) 214 | coap_outsideDataInput(PSMsg.payload, bufferLeft); 215 | #endif 216 | 217 | if(client->msgCB) 218 | { 219 | client->msgCB(client, &PSMsg); 220 | } 221 | 222 | //FOR NOW I AM FREEING THE BUFFERS MAYNEED TO CHANGE 223 | MQTT_FREE(PSMsg.payload); 224 | MQTT_FREE(PSMsg.topic); 225 | /* 226 | * TODO: I have alot to do in here I hate it all I don't like the malloc calls 227 | * and I would like to get rid of that also I am not sure what method I am going to 228 | * using in calling the application to give it indication that we have a published 229 | * MSG. I still don't know how or when I want to free both the MSG and the PSMsg 230 | */ 231 | 232 | return 0; 233 | 234 | } 235 | 236 | mqtt_err_t mqtt_pubRecHandler(mqtt_client_t *client, mqtt_msg_t *msg, uint8_t *buf) 237 | { 238 | RT_ASSERT(client); 239 | RT_ASSERT(msg); 240 | 241 | uint16_t msgID; 242 | uint8_t dup = 0; 243 | 244 | msgID = *buf++; 245 | msgID <<= 8; 246 | 247 | msgID = *buf++; 248 | 249 | printf("pubRec: with msg ID: %i\n", msgID); 250 | //TODO: I need to update the msg status to keep a tally on where the msg is. 251 | 252 | msg = mqtt_findPubWithID(client, msgID); 253 | 254 | if(msg) 255 | msg->status = MSG_WAITING_FOR_COMP; 256 | else 257 | dup = 1; 258 | 259 | mqtt_pubrel(client, dup, msgID); 260 | return 0; 261 | 262 | } 263 | 264 | mqtt_err_t mqtt_pubackHandler(mqtt_client_t *client, uint8_t *buf) 265 | { 266 | RT_ASSERT(client); 267 | mqtt_msg_t *msg = NULL; 268 | uint16_t msgID; 269 | 270 | msgID = *buf++; 271 | msgID <<= 8; 272 | 273 | msgID = *buf++; 274 | 275 | printf("pubRec: with msg ID: %i\n", msgID); 276 | //TODO: I need to update the msg status to keep a tally on where the msg is. 277 | 278 | msg = mqtt_findPubWithID(client, msgID); 279 | 280 | if(msg) 281 | { 282 | msg->status = MSG_COMPLETE; 283 | } 284 | 285 | return 0; 286 | } 287 | 288 | mqtt_err_t mqtt_pubcompHandler(mqtt_client_t *client, uint8_t *buf) 289 | { 290 | RT_ASSERT(client); 291 | mqtt_msg_t *msg; 292 | 293 | uint16_t msgID; 294 | 295 | msgID = *buf++; 296 | msgID <<= 8; 297 | 298 | msgID = *buf++; 299 | 300 | msg = mqtt_findPubWithID(client, msgID); 301 | 302 | if(msg) 303 | { 304 | msg->status = MSG_COMPLETE; 305 | } 306 | 307 | 308 | return 0; 309 | } 310 | 311 | mqtt_err_t mqtt_connAckHandler(mqtt_client_t *client, uint8_t *buf) 312 | { 313 | mqtt_msg_t *msg = 0; 314 | if(buf[0] == 0) 315 | connAckCode = buf[1]; 316 | 317 | msg = mqtt_findMsg(client, CONNECT); 318 | 319 | if(msg) 320 | msg->status = MSG_COMPLETE; 321 | 322 | client->timeLastSent = sys_now(); 323 | client->connected = -1; 324 | 325 | printf("MQTT: GOT CONNACK for %s\n", client->name); 326 | sys_sem_signal(&client->connAck); 327 | 328 | return 0; 329 | } 330 | 331 | 332 | -------------------------------------------------------------------------------- /mqtt_net.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_net.c 3 | * 4 | * Created on: Oct 15, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #include "stm32f4xx.h" 9 | #include 10 | #include 11 | 12 | #include "mqtt.h" 13 | #include "lwip/ip_addr.h" 14 | 15 | /* LWIP mqtt Client */ 16 | static volatile int dnsDone = 0; 17 | 18 | 19 | 20 | 21 | //ALIGN(RT_ALIGN_SIZE) 22 | 23 | //static struct rt_data_queue TxQueue; 24 | static void rt_thread_entry_mqttThread(void* parameter) 25 | { 26 | //rt_data_queue_init(TxQueue, MAX_TXQUEUE_SIZE, ) 27 | } 28 | 29 | mqtt_err_t mqtt_netTx(mqtt_msg_t *msg, uint32_t timeout) 30 | { 31 | 32 | return 0; 33 | } 34 | 35 | mqtt_err_t mqtt_waitForDNS(uint32_t timeout) 36 | { 37 | rt_tick_t ticks = timeout * RT_TICK_PER_SECOND/1000; 38 | ticks += rt_tick_get(); 39 | 40 | while(!dnsDone){ 41 | if(rt_tick_get() > ticks) 42 | { 43 | dnsDone = 0; 44 | return mqtt_timeout; 45 | } 46 | } 47 | dnsDone = 0; 48 | return mqtt_errSuccess; 49 | } 50 | 51 | void mqtt_dnsCallback(const char *name, ip_addr_t *ipaddr, void *callback_arg) 52 | { 53 | mqtt_client_t *client = (mqtt_client_t *)callback_arg; 54 | 55 | client->serverAddr.sin_addr.s_addr = ipaddr; 56 | 57 | printf("IP ADDRESS FOUND: %s\n", ipaddr_ntoa(ipaddr)); 58 | 59 | dnsDone = 1; 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /mqtt_send.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_send.c 3 | * 4 | * Created on: Oct 15, 2013 5 | * Author: poppe 6 | */ 7 | #include "mqtt.h" 8 | #include "rtthread.h" 9 | #include 10 | #include "stdio.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "stm32f4xx_eth.h" 22 | 23 | 24 | 25 | 26 | 27 | uint16_t mqtt_makeMsgID(void); 28 | void mqtt_sendPing(mqtt_client_t *client); 29 | mqtt_err_t mqtt_waitForDNS(uint32_t timeout); 30 | mqtt_err_t mqtt_sendConnect(mqtt_client_t *client); 31 | static mqtt_err_t mqtt_waitForPingResp(mqtt_client_t *client, uint32_t timeout); 32 | mqtt_err_t mqtt_freeMsg(mqtt_msg_t *msg); 33 | int mqtt_dllFindMsgType(void *data, void *type); 34 | int mqtt_dllFindPubWithID(void *data, void *id); 35 | mqtt_msg_t *mqtt_findMsg(mqtt_client_t *client, uint8_t type); 36 | void mqtt_writeData(Node_t *node, mqtt_client_t *client); 37 | uint8_t mqtt_lenDecode(uint8_t *buf, uint32_t *sizeHolder); 38 | mqtt_err_t mqtt_pubrel(mqtt_client_t *client, uint8_t dup, uint16_t id); 39 | mqtt_err_t mqtt_send(mqtt_client_t *client, mqtt_msg_t *msg); 40 | 41 | 42 | 43 | static uint16_t runningMsgID = 100; 44 | 45 | 46 | void mqtt_writeData(Node_t *node, mqtt_client_t *client) 47 | { 48 | RT_ASSERT(client); 49 | RT_ASSERT(node); 50 | int msgLen; 51 | uint8_t *msgPtr; 52 | mqtt_msg_t *msg = (mqtt_msg_t *)node->data; 53 | 54 | switch(msg->status) 55 | { 56 | case MSG_UNSENT: 57 | msg->status = MSG_SENT;//TODO: Find a home for changing this status 58 | #if 0 59 | msgLen = msg->len; 60 | msgPtr = msg->pkt; 61 | 62 | while(msgLen) 63 | { 64 | printf("0x%x ", *msgPtr++); 65 | msgLen--; 66 | } 67 | printf("\n"); 68 | #endif 69 | send(client->socket, msg->pkt, msg->len, 0); 70 | msg->timesent = client->timeLastSent = sys_now();//TODO: This is reset a ton... Find a home for this too. 71 | //I put the time last set here to prevent sending two pings after timeout 72 | //TODO: I want some kind of way to prevent multible connects or pings I don't think this will be it. 73 | 74 | switch(msg->fHdr.bits.msg_type) 75 | { 76 | case CONNECT: 77 | break; 78 | case PUBLISH: 79 | switch(msg->fHdr.bits.qos) 80 | { 81 | case 0: 82 | msg->status = MSG_COMPLETE; 83 | break; 84 | case 1: 85 | msg->status = MSG_WAITING_FOR_PUBACK; 86 | break; 87 | case 2: 88 | msg->status = MSG_WAITING_FOR_PUBREL; 89 | break; 90 | } 91 | break; 92 | case PUBREC: 93 | break; 94 | case PUBREL: 95 | msg->status = MSG_COMPLETE; 96 | break; 97 | case SUBSCRIBE: 98 | switch(msg->fHdr.bits.qos) 99 | { 100 | case 0: 101 | msg->status = MSG_COMPLETE; 102 | break; 103 | case 1: 104 | case 2: 105 | msg->status = MSG_WAITING_FOR_ACK; 106 | break; 107 | } 108 | break; 109 | case PINGREQ: 110 | break; 111 | } 112 | 113 | printf("MQTT: sending packet for: %s size:%i at %i\n", client->name, msg->len, client->timeLastSent); 114 | break; 115 | 116 | case MSG_SENT: 117 | 118 | if((sys_now() - msg->timesent) > client->timeout) 119 | { 120 | /*FIXME no retries yet */ 121 | msg->status = MSG_SEND_ERROR; 122 | printf("temp:MSG ERROR\n"); 123 | client->connected = 0; 124 | //msg->status = MSG_COMPLETE; 125 | } 126 | break; 127 | 128 | case MSG_WAITING_FOR_PUBACK: 129 | 130 | if((sys_now() - msg->timesent) > client->timeout) 131 | { 132 | msg->retries++; 133 | 134 | if(msg->retries > MQTT_RETRIES) 135 | msg->status = MSG_SEND_ERROR; 136 | } 137 | 138 | break; 139 | 140 | case MSG_COMPLETE: 141 | printf("MSG: Complete\n"); 142 | dllist_removeNode(client->txList, node, 1);//This seems dangerous I need to come up with a better method 143 | } 144 | 145 | } 146 | 147 | 148 | mqtt_err_t mqtt_setKeepAlive(mqtt_client_t *client, size_t keepAlive) 149 | { 150 | return mqtt_errSuccess; 151 | } 152 | 153 | mqtt_msg_t * mqtt_createMsg(size_t size) 154 | { 155 | return(mqtt_msg_t *)MQTT_MALLOC(sizeof(mqtt_msg_t)+size); 156 | } 157 | 158 | mqtt_err_t mqtt_freeMsg(mqtt_msg_t *msg) 159 | { 160 | MQTT_FREE(msg); 161 | return mqtt_errSuccess; 162 | } 163 | /************************************************************************************************** 164 | * 165 | * MQTT Send Messages commands 166 | * 167 | *************************************************************************************************/ 168 | void mqtt_sendPing(mqtt_client_t *client) 169 | { 170 | mqtt_msg_t *msg = mqtt_createMsg(4); 171 | int err; 172 | 173 | RT_ASSERT(client); 174 | 175 | if(!msg) 176 | printf("MQTT: out of memory\n"); 177 | 178 | printf("Sending %s Ping\n", client->name); 179 | 180 | msg->fHdr.bits.msg_type = PINGREQ; 181 | msg->fHdr.bits.dup_flag =0; 182 | msg->fHdr.bits.qos = 0; 183 | msg->fHdr.bits.retain = 0; 184 | msg->pkt[0] = msg->fHdr.firstByte; 185 | msg->pkt[1] = 0; 186 | 187 | msg->len = 2; 188 | mqtt_send(client, msg); 189 | #if 0 190 | if(mqtt_waitForPingResp(client, 5000)) 191 | { 192 | printf("mqtt: server timeout\n"); 193 | } 194 | #endif 195 | } 196 | 197 | mqtt_err_t mqtt_pubAck(mqtt_client_t *client, uint16_t id) 198 | { 199 | mqtt_msg_t *msg = mqtt_createMsg(4); 200 | uint8_t *buf = msg->pkt; 201 | 202 | msg->fHdr.pkt_len = 2; 203 | msg->fHdr.bits.retain = 0; 204 | msg->fHdr.bits.msg_type = PUBACK; 205 | msg->fHdr.bits.qos = 0; 206 | msg->fHdr.bits.dup_flag = 0; 207 | 208 | *buf++ = msg->fHdr.firstByte; 209 | *buf++ = 2; 210 | *buf++ = (0xff & (id >> 8)); 211 | *buf++ = 0xff & id; 212 | 213 | msg->len = 4; 214 | mqtt_send(client, msg); 215 | return 0; 216 | 217 | } 218 | 219 | mqtt_err_t mqtt_pubRec(mqtt_client_t *client, uint16_t id) 220 | { 221 | mqtt_msg_t *msg = mqtt_createMsg(4); 222 | uint8_t *buf = msg->pkt; 223 | 224 | msg->fHdr.pkt_len = 2; 225 | msg->fHdr.bits.retain = 0; 226 | msg->fHdr.bits.msg_type = PUBREC; 227 | msg->fHdr.bits.qos = 0; 228 | msg->fHdr.bits.dup_flag = 0; 229 | 230 | *buf++ = msg->fHdr.firstByte; 231 | *buf++ = 2; 232 | *buf++ = (0xff & (id >> 8)); 233 | *buf++ = 0xff & id; 234 | 235 | msg->len = 4; 236 | mqtt_send(client, msg); 237 | return 0; 238 | 239 | } 240 | 241 | mqtt_err_t mqtt_pubrel(mqtt_client_t *client, uint8_t dup, uint16_t id) 242 | { 243 | mqtt_msg_t *msg = mqtt_createMsg(4); 244 | uint8_t *buf = msg->pkt; 245 | 246 | msg->fHdr.pkt_len = 2; 247 | msg->fHdr.bits.retain = 0; 248 | msg->fHdr.bits.msg_type = PUBREL; 249 | msg->fHdr.bits.qos = 1; 250 | msg->fHdr.bits.dup_flag = dup; 251 | 252 | *buf++ = msg->fHdr.firstByte; 253 | *buf++ = 2; 254 | *buf++ = (0xff & (id >> 8)); 255 | *buf++ = 0xff & id; 256 | 257 | msg->len = 4; 258 | mqtt_send(client, msg); 259 | return 0; 260 | } 261 | /************************************************************************************************** 262 | * 263 | * Message wait/blocking..... put into thread 264 | * 265 | *************************************************************************************************/ 266 | mqtt_err_t mqtt_waitForConnAck(mqtt_client_t *client, uint32_t timeout) 267 | { 268 | int err; 269 | err = sys_arch_sem_wait(&client->connAck, timeout); 270 | if(err == -1) 271 | { 272 | return mqtt_timeout; 273 | } 274 | return mqtt_errSuccess; 275 | } 276 | 277 | static mqtt_err_t mqtt_waitForPingResp(mqtt_client_t *client, uint32_t timeout) 278 | { 279 | int err; 280 | printf("waiting for ping for %s\n", client->name); 281 | err = sys_arch_sem_wait(&client->pingResp, timeout); 282 | printf("waited %ims for ping\n", err); 283 | if(err == timeout) 284 | { 285 | return mqtt_timeout; 286 | } 287 | return mqtt_errSuccess; 288 | } 289 | 290 | 291 | 292 | 293 | /************************************************************************************************** 294 | * 295 | * MQTT Misc. 296 | * 297 | *************************************************************************************************/ 298 | uint16_t mqtt_makeMsgID(void) 299 | { 300 | return runningMsgID++; 301 | } 302 | 303 | mqtt_msg_t *mqtt_findMsg(mqtt_client_t *client, uint8_t type) 304 | { 305 | mqtt_msg_t *msg; 306 | RT_ASSERT(client); 307 | 308 | msg = dllist_searchWithinData(client->txList, mqtt_dllFindMsgType, (void *)type); 309 | 310 | return msg; 311 | } 312 | 313 | mqtt_msg_t *mqtt_findPubWithID(mqtt_client_t *client, uint16_t msgID) 314 | { 315 | mqtt_msg_t *msg; 316 | RT_ASSERT(client); 317 | 318 | msg = dllist_searchWithinData(client->txList, mqtt_dllFindPubWithID, (void *)msgID); 319 | 320 | return msg; 321 | } 322 | 323 | //TODO: I pass a pointer and then cast them to an interger. THis works fine for a 32bit system but it may not for an 8bit 324 | int mqtt_dllFindMsgType(void *data, void *type) 325 | { 326 | mqtt_msg_t *msg = (mqtt_msg_t *)data; 327 | uint8_t msgType = type; 328 | 329 | if(msg->fHdr.bits.msg_type == msgType) 330 | return -1; 331 | 332 | return 0; 333 | } 334 | 335 | int mqtt_dllFindPubWithID(void *data, void *id) 336 | { 337 | mqtt_msg_t *msg = (mqtt_msg_t *)data; 338 | uint16_t msgID = (uint16_t)id; 339 | 340 | if(msg->msgID == msgID) 341 | return -1; 342 | 343 | return 0; 344 | } 345 | 346 | 347 | uint8_t mqtt_lenDecode(uint8_t *buf, uint32_t *sizeHolder) 348 | { 349 | uint32_t multiplier = 1; 350 | size_t value = 0; 351 | int cnt = 0; 352 | uint8_t digit; 353 | 354 | do { 355 | digit = *buf++; 356 | value += (digit & 0x7f) * multiplier; 357 | multiplier *= 128; 358 | cnt++; 359 | }while ((digit & 0x80) != 0); 360 | 361 | *sizeHolder = value; 362 | return cnt; 363 | } 364 | 365 | size_t mqtt_lenEncode(uint8_t *buf, uint32_t pktLen) 366 | { 367 | int digit, cnt = 0; 368 | do 369 | { 370 | digit = pktLen%128; 371 | pktLen /= 128; 372 | 373 | if ( pktLen > 0 ) 374 | { 375 | digit |= 0x80; 376 | } 377 | 378 | *buf++ = digit; 379 | cnt++; 380 | }while ( pktLen ); 381 | 382 | return cnt; 383 | } 384 | 385 | 386 | mqtt_err_t mqtt_send(mqtt_client_t *client, mqtt_msg_t *msg) 387 | { 388 | LWIP_ASSERT("Client is not active", client); 389 | int err; 390 | //sys_mutex_lock(&client->txOK); 391 | 392 | msg->status = MSG_UNSENT; 393 | dllist_addData(client->txList, msg); 394 | //sys_mutex_unlock(&client->txOK); 395 | 396 | return mqtt_errSuccess; 397 | } 398 | -------------------------------------------------------------------------------- /mqtt_thread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_thread.c 3 | * 4 | * Created on: Dec 27, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #include "mqtt.h" 9 | 10 | static char thread_mqttThread_stack[1024]; 11 | struct rt_thread thread_mqttThread; 12 | static uint8_t receiveBuf[2048]; 13 | 14 | 15 | /************************************************************************************************** 16 | * 17 | * Main Thread for the client 18 | * 19 | *************************************************************************************************/ 20 | void mqtt_clientThread(void *arg) 21 | { 22 | mqtt_client_t *client = (mqtt_client_t *)arg; 23 | mqtt_msg_t *msg; 24 | mqtt_setKeepAlive(client, client->keepalive); 25 | size_t bytesRead; 26 | uint32_t timeSpent; 27 | 28 | int err; 29 | /* set socket option */ 30 | int sock_opt = 500; /* 500 ms */ 31 | lwip_setsockopt(client->socket, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt)); 32 | 33 | while(1) 34 | { 35 | bytesRead = recv(client->socket, receiveBuf, 256, 0); 36 | if(bytesRead < 1500 && bytesRead != 0) 37 | { 38 | LWIP_DEBUGF(MQTT_DEBUG, ("MQTT received 0x%x bytes of data\n", bytesRead)); 39 | 40 | mqtt_handler(client, receiveBuf, bytesRead); 41 | #if 0 42 | int x = 0; 43 | while(bytesRead) 44 | { 45 | printf("0x%X ", receiveBuf[x]); 46 | x++; 47 | bytesRead--; 48 | } 49 | printf("\n"); 50 | #endif 51 | } 52 | 53 | dllist_foreachNode(client->txList, mqtt_writeData, client); 54 | 55 | if(client->connected) 56 | mqtt_check_keepalive(client); 57 | 58 | if(MQTT_UPDATE_DELAY) 59 | sys_msleep(MQTT_UPDATE_DELAY); 60 | } 61 | 62 | } 63 | 64 | 65 | mqtt_err_t mqtt_netInit(void) 66 | { 67 | 68 | /* init and start mqtt recv data thread */ 69 | rt_thread_init(&thread_mqttThread, 70 | "mqttRecv", 71 | thread_mqttThread_stack, 72 | RT_NULL, 73 | &thread_mqttThread_stack[0], 74 | sizeof(thread_mqttThread_stack),11,5); 75 | rt_thread_startup(&thread_mqttThread); 76 | 77 | return mqtt_errSuccess; 78 | 79 | } 80 | -------------------------------------------------------------------------------- /mqtt_utf8.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_utf8.c 3 | 4 | * 5 | * Created on: Oct 20, 2013 6 | * Author: poppe 7 | */ 8 | #include "mqtt.h" 9 | #include "string.h" 10 | 11 | uint32_t mqtt_stringToUtf(uint8_t *S, uint8_t *B) 12 | { 13 | uint32_t size = strlen(S); 14 | 15 | *B++ = ((size >> 8) & 0xff); 16 | *B++ = (size & 0xff); 17 | 18 | memcpy(B, S, size); 19 | 20 | return (size + 2); 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /mqtt_utf8.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_utf8.h 3 | * 4 | * Created on: Oct 20, 2013 5 | * Author: poppe 6 | */ 7 | 8 | #ifndef MQTT_UTF8_H_ 9 | #define MQTT_UTF8_H_ 10 | 11 | #include "stdint.h" 12 | 13 | typedef struct mqtt_utf { 14 | uint16_t len; //be very careful this is Big Endian 15 | uint8_t *string; 16 | }mqtt_utf_t; 17 | 18 | uint32_t mqtt_stringToUtf(uint8_t *S, uint8_t *B); 19 | 20 | #endif /* MQTT_UTF8_H_ */ 21 | --------------------------------------------------------------------------------