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

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

ESP8266のライブラリの更新に伴う変更

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