source: rtos_arduino/trunk/arduino_lib/libraries/Milkcocoa_Arduino_SDK/Adafruit_MQTT.cpp@ 144

Last change on this file since 144 was 144, checked in by ertl-honda, 8 years ago

Milkcocoa用のMQTTライブラリの追加と,ESP8266用ライブラリの名称変更.

File size: 12.6 KB
RevLine 
[144]1// The MIT License (MIT)
2//
3// Copyright (c) 2015 Adafruit Industries
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22#include "include/Adafruit/Adafruit_MQTT.h"
23
24#if defined(ARDUINO_ARCH_AVR)
25#define strncasecmp strncasecmp_P
26#define strncpy strncpy_P
27#else
28#include "avr/dtostrf.h"
29#endif
30
31void printBuffer(uint8_t *buffer, uint8_t len) {
32 for (uint8_t i=0; i<len; i++) {
33 if (isprint(buffer[i]))
34 DEBUG_PRINTER.write(buffer[i]);
35 else
36 DEBUG_PRINTER.print(" ");
37 DEBUG_PRINTER.print(F(" [0x"));
38 if (buffer[i] < 0x10)
39 DEBUG_PRINTER.print("0");
40 DEBUG_PRINTER.print(buffer[i],HEX);
41 DEBUG_PRINTER.print("], ");
42 if (i % 8 == 7) DEBUG_PRINTER.println();
43 }
44 DEBUG_PRINTER.println();
45}
46
47/* Not used now, but might be useful in the future
48static uint8_t *stringprint(uint8_t *p, char *s) {
49 uint16_t len = strlen(s);
50 p[0] = len >> 8; p++;
51 p[0] = len & 0xFF; p++;
52 memcpy(p, s, len);
53 return p+len;
54}
55*/
56
57static uint8_t *stringprint_P(uint8_t *p, const char *s, uint16_t maxlen=0) {
58 // If maxlen is specified (has a non-zero value) then use it as the maximum
59 // length of the source string to write to the buffer. Otherwise write
60 // the entire source string.
61 uint16_t len = strlen_P(s);
62 if (maxlen > 0 && len > maxlen) {
63 len = maxlen;
64 }
65 /*
66 for (uint8_t i=0; i<len; i++) {
67 Serial.write(pgm_read_byte(s+i));
68 }
69 */
70 p[0] = len >> 8; p++;
71 p[0] = len & 0xFF; p++;
72 strncpy((char *)p, s, len);
73 return p+len;
74}
75
76
77// Adafruit_MQTT Definition ////////////////////////////////////////////////////
78
79Adafruit_MQTT::Adafruit_MQTT(const char *server, uint16_t port, const char *cid,
80 const char *user, const char *pass) {
81 servername = server;
82 portnum = port;
83 clientid = cid;
84 username = user;
85 password = pass;
86
87 for (uint8_t i=0; i<MAXSUBSCRIPTIONS; i++) {
88 subscriptions[i] = 0;
89 }
90}
91
92Adafruit_MQTT::Adafruit_MQTT(const __FlashStringHelper *server, uint16_t port, const __FlashStringHelper *cid,
93 const __FlashStringHelper *user, const __FlashStringHelper *pass) {
94 servername = (const char *)server;
95 portnum = port;
96 clientid = (const char *)cid;
97 username = (const char *)user;
98 password = (const char *)pass;
99
100 for (uint8_t i=0; i<MAXSUBSCRIPTIONS; i++) {
101 subscriptions[i] = 0;
102 }
103}
104
105
106/*
107Adafruit_MQTT::Adafruit_MQTT(char *server, uint16_t port, char *cid, char *user, char *pass) {
108 strncpy(servername, server, SERVERNAME_SIZE);
109 servername[SERVERNAME_SIZE-1] = 0;
110 portnum = port;
111 serverip = 0;
112
113 strncpy(clientid, cid, CLIENTID_SIZE);
114 clientid[CLIENTID_SIZE-1] = 0;
115
116 strncpy(username, user, USERNAME_SIZE);
117 username[USERNAME_SIZE-1] = 0;
118
119 strncpy(password, pass, PASSWORD_SIZE);
120 password[PASSWORD_SIZE-1] = 0;
121}
122*/
123
124int8_t Adafruit_MQTT::connect() {
125 // Connect to the server.
126 if (!connectServer())
127 return -1;
128
129 // Construct and send connect packet.
130 uint8_t len = connectPacket(buffer);
131 if (!sendPacket(buffer, len))
132 return -1;
133
134 // Read connect response packet and verify it
135 len = readPacket(buffer, 4, CONNECT_TIMEOUT_MS);
136 if (len != 4)
137 return -1;
138 if ((buffer[0] != (MQTT_CTRL_CONNECTACK << 4)))
139 return -1;
140 if (buffer[3] != 0)
141 return buffer[3];
142
143 // Setup subscriptions once connected.
144 for (uint8_t i=0; i<MAXSUBSCRIPTIONS; i++) {
145 // Ignore subscriptions that aren't defined.
146 if (subscriptions[i] == 0) continue;
147
148 // Construct and send subscription packet.
149 uint8_t len = subscribePacket(buffer, subscriptions[i]->topic, subscriptions[i]->qos);
150 if (!sendPacket(buffer, len))
151 return -1;
152
153 // Get SUBACK
154 len = readPacket(buffer, 5, CONNECT_TIMEOUT_MS);
155 // DEBUG_PRINT(F("SUBACK:\t"));
156 // DEBUG_PRINTBUFFER(buffer, len);
157 // if (false) {
158 // return 6; // failure to subscribe
159 // }
160 }
161
162 return 0;
163}
164
165const __FlashStringHelper* Adafruit_MQTT::connectErrorString(int8_t code) {
166 switch (code) {
167 case 1: return F("Wrong protocol");
168 case 2: return F("ID rejected");
169 case 3: return F("Server unavail");
170 case 4: return F("Bad user/pass");
171 case 5: return F("Not authed");
172 case 6: return F("Failed to subscribe");
173 case -1: return F("Connection failed");
174 default: return F("Unknown error");
175 }
176}
177
178bool Adafruit_MQTT::publish(const char *topic, const char *data, uint8_t qos) {
179 // Construct and send publish packet.
180 uint8_t len = publishPacket(buffer, topic, data, qos);
181 if (!sendPacket(buffer, len))
182 return false;
183
184 // If QOS level is high enough verify the response packet.
185 if (qos > 0) {
186 len = readPacket(buffer, 4, PUBLISH_TIMEOUT_MS);
187 DEBUG_PRINT(F("Publish QOS1+ reply:\t"));
188 DEBUG_PRINTBUFFER(buffer, len);
189 //TODO: Verify response packet?
190 }
191
192 return true;
193}
194
195bool Adafruit_MQTT::subscribe(Adafruit_MQTT_Subscribe *sub) {
196 uint8_t i;
197 // see if we are already subscribed
198 for (i=0; i<MAXSUBSCRIPTIONS; i++) {
199 if (subscriptions[i] == sub) {
200 DEBUG_PRINTLN(F("Already subscribed"));
201 return true;
202 }
203 }
204 if (i==MAXSUBSCRIPTIONS) { // add to subscriptionlist
205 for (i=0; i<MAXSUBSCRIPTIONS; i++) {
206 if (subscriptions[i] == 0) {
207 DEBUG_PRINT(F("Added sub ")); DEBUG_PRINTLN(i);
208 subscriptions[i] = sub;
209 return true;
210 }
211 }
212 }
213
214 DEBUG_PRINTLN(F("no more subscription space :("));
215 return false;
216}
217
218Adafruit_MQTT_Subscribe *Adafruit_MQTT::readSubscription(int16_t timeout) {
219 uint8_t i, topiclen, datalen;
220
221 // Check if data is available to read.
222 uint16_t len = readPacket(buffer, MAXBUFFERSIZE, timeout, true); // return one full packet
223 if (!len)
224 return NULL; // No data available, just quit.
225 DEBUG_PRINTBUFFER(buffer, len);
226
227 // Parse out length of packet.
228 topiclen = buffer[3];
229 DEBUG_PRINT(F("Looking for subscription len ")); DEBUG_PRINTLN(topiclen);
230
231 // Find subscription associated with this packet.
232 for (i=0; i<MAXSUBSCRIPTIONS; i++) {
233 if (subscriptions[i]) {
234 // Skip this subscription if its name length isn't the same as the
235 // received topic name.
236 if (strlen_P(subscriptions[i]->topic) != topiclen)
237 continue;
238 // Stop if the subscription topic matches the received topic. Be careful
239 // to make comparison case insensitive.
240 if (strncasecmp((char*)buffer+4, subscriptions[i]->topic, topiclen) == 0) {
241 DEBUG_PRINT(F("Found sub #")); DEBUG_PRINTLN(i);
242 break;
243 }
244 }
245 }
246 if (i==MAXSUBSCRIPTIONS) return NULL; // matching sub not found ???
247
248 // zero out the old data
249 memset(subscriptions[i]->lastread, 0, SUBSCRIPTIONDATALEN);
250
251 datalen = len - topiclen - 4;
252 // if (datalen > SUBSCRIPTIONDATALEN) {
253 // datalen = SUBSCRIPTIONDATALEN-1; // cut it off
254 // }
255 // extract out just the data, into the subscription object itself
256 memcpy(subscriptions[i]->lastread, buffer+4+topiclen, datalen);
257 subscriptions[i]->datalen = datalen;
258 DEBUG_PRINT(F("Data len: ")); DEBUG_PRINTLN(datalen);
259 DEBUG_PRINT(F("Data: ")); DEBUG_PRINTLN((char *)subscriptions[i]->lastread);
260
261 // return the valid matching subscription
262 return subscriptions[i];
263}
264
265bool Adafruit_MQTT::ping(uint8_t times) {
266 while (times) {
267 // Construct and send ping packet.
268 uint8_t len = pingPacket(buffer);
269 if (!sendPacket(buffer, len))
270 return false;
271
272 // Process ping reply.
273 len = readPacket(buffer, 2, PING_TIMEOUT_MS);
274 if (buffer[0] == (MQTT_CTRL_PINGRESP << 4))
275 return true;
276 }
277 return false;
278}
279
280// Packet Generation Functions /////////////////////////////////////////////////
281
282// The current MQTT spec is 3.1.1 and available here:
283// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028
284// However this connect packet and code follows the MQTT 3.1 spec here (some
285// small differences in the protocol):
286// http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connect
287uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) {
288 uint8_t *p = packet;
289 uint16_t len;
290
291 // fixed header, connection messsage no flags
292 p[0] = (MQTT_CTRL_CONNECT << 4) | 0x0;
293 p+=2;
294 // fill in packet[1] last
295
296 p = stringprint_P(p, PSTR("MQTT"));
297
298 p[0] = MQTT_PROTOCOL_LEVEL;
299 p++;
300
301 p[0] = MQTT_CONN_CLEANSESSION;
302 if (pgm_read_byte(username) != 0)
303 p[0] |= MQTT_CONN_USERNAMEFLAG;
304 if (pgm_read_byte(password) != 0)
305 p[0] |= MQTT_CONN_PASSWORDFLAG;
306 p++;
307 // TODO: add WILL support?
308
309 p[0] = MQTT_CONN_KEEPALIVE >> 8;
310 p++;
311 p[0] = MQTT_CONN_KEEPALIVE & 0xFF;
312 p++;
313
314 p = stringprint_P(p, clientid, 23); // Limit client ID to first 23 characters.
315
316 if (pgm_read_byte(username) != 0) {
317 p = stringprint_P(p, username);
318 }
319 if (pgm_read_byte(password) != 0) {
320 p = stringprint_P(p, password);
321 }
322
323 len = p - packet;
324
325 packet[1] = len-2; // don't include the 2 bytes of fixed header data
326 DEBUG_PRINTLN(F("MQTT connect packet:"));
327 DEBUG_PRINTBUFFER(buffer, len);
328 return len;
329}
330
331uint8_t Adafruit_MQTT::publishPacket(uint8_t *packet, const char *topic,
332 const char *data, uint8_t qos) {
333 uint8_t *p = packet;
334 uint16_t len;
335
336 p[0] = MQTT_CTRL_PUBLISH << 4 | qos << 1;
337 // fill in packet[1] last
338 p+=2;
339
340 p = stringprint_P(p, topic);
341
342 memcpy(p, data, strlen(data));
343 p+=strlen(data);
344 len = p - packet;
345 packet[1] = len-2; // don't include the 2 bytes of fixed header data
346 DEBUG_PRINTLN(F("MQTT publish packet:"));
347 DEBUG_PRINTBUFFER(buffer, len);
348 return len;
349}
350
351uint8_t Adafruit_MQTT::subscribePacket(uint8_t *packet, const char *topic,
352 uint8_t qos) {
353 uint8_t *p = packet;
354 uint16_t len;
355
356 p[0] = MQTT_CTRL_SUBSCRIBE << 4 | MQTT_QOS_1 << 1;
357 // fill in packet[1] last
358 p+=2;
359
360 // put in a message id,
361 p[0] = 0xAD;
362 p[1] = 0xAF;
363 p+=2;
364
365 p = stringprint_P(p, topic);
366
367 p[0] = qos;
368 p++;
369
370 len = p - packet;
371 packet[1] = len-2; // don't include the 2 bytes of fixed header data
372 DEBUG_PRINTLN(F("MQTT subscription packet:"));
373 DEBUG_PRINTBUFFER(buffer, len);
374 return len;
375}
376
377uint8_t Adafruit_MQTT::pingPacket(uint8_t *packet) {
378 packet[0] = MQTT_CTRL_PINGREQ << 4;
379 packet[1] = 0;
380 DEBUG_PRINTLN(F("MQTT ping packet:"));
381 DEBUG_PRINTBUFFER(buffer, 2);
382 return 2;
383}
384
385
386// Adafruit_MQTT_Publish Definition ////////////////////////////////////////////
387
388Adafruit_MQTT_Publish::Adafruit_MQTT_Publish(Adafruit_MQTT *mqttserver,
389 const char *feed, uint8_t q) {
390 mqtt = mqttserver;
391 topic = feed;
392 qos = q;
393}
394
395Adafruit_MQTT_Publish::Adafruit_MQTT_Publish(Adafruit_MQTT *mqttserver,
396 const __FlashStringHelper *feed, uint8_t q) {
397 mqtt = mqttserver;
398 topic = (const char *)feed;
399 qos = q;
400}
401
402bool Adafruit_MQTT_Publish::publish(int32_t i) {
403 char payload[18];
404 itoa(i, payload, 10);
405 return mqtt->publish(topic, payload, qos);
406}
407
408bool Adafruit_MQTT_Publish::publish(double f, uint8_t precision) {
409 char payload[40]; // Need to technically hold float max, 39 digits and minus sign.
410 dtostrf(f, 0, precision, payload);
411 return mqtt->publish(topic, payload, qos);
412}
413
414bool Adafruit_MQTT_Publish::publish(uint32_t i) {
415 char payload[18];
416 itoa(i, payload, 10);
417 return mqtt->publish(topic, payload, qos);
418}
419
420bool Adafruit_MQTT_Publish::publish(const char *payload) {
421 return mqtt->publish(topic, payload, qos);
422}
423
424
425// Adafruit_MQTT_Subscribe Definition //////////////////////////////////////////
426
427Adafruit_MQTT_Subscribe::Adafruit_MQTT_Subscribe(Adafruit_MQTT *mqttserver,
428 const char *feed, uint8_t q) {
429 mqtt = mqttserver;
430 topic = feed;
431 qos = q;
432}
433
434Adafruit_MQTT_Subscribe::Adafruit_MQTT_Subscribe(Adafruit_MQTT *mqttserver,
435 const __FlashStringHelper *feed, uint8_t q) {
436 mqtt = mqttserver;
437 topic = (const char *)feed;
438 qos = q;
439}
Note: See TracBrowser for help on using the repository browser.