A program for IoT demonstration with mbed, EnOcean and MQTT.

Dependencies:   IBMIoTClientEthernetExample C12832 EthernetInterface MQTT USB400Serial USBHost mbed

Fork of IBMIoTClientEthernetExample by IBM Watson IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*******************************************************************************
00002  * Copyright (c) 2014 IBM Corp.
00003  *
00004  * All rights reserved. This program and the accompanying materials
00005  * are made available under the terms of the Eclipse Public License v1.0
00006  * and Eclipse Distribution License v1.0 which accompany this distribution.
00007  *
00008  * The Eclipse Public License is available at
00009  *    http://www.eclipse.org/legal/epl-v10.html
00010  * and the Eclipse Distribution License is available at
00011  *   http://www.eclipse.org/org/documents/edl-v10.php.
00012  *
00013  * Contributors:
00014  *    Sam Danbury - initial implementation
00015  *    Ian Craggs - refactoring to remove STL and other changes
00016  *    Sam Grove  - added check for Ethernet cable.
00017  *    Chris Styles - Added additional menu screen for software revision
00018  *
00019  * To do :
00020  *    Add magnetometer sensor output to IoT data stream
00021  *
00022  *******************************************************************************/
00023 
00024 #include "MQTTClient.h"
00025 #include "MQTTEthernet.h"
00026 #include "USB400Serial.h"
00027 #include "C12832.h"
00028 #include "Arial12x12.h"
00029 #include "rtos.h"
00030 
00031 // Update this to the next number *before* a commit
00032 #define __APP_SW_REVISION__ "10"
00033 
00034 // Configuration values needed to connect to IBM IoT Cloud
00035 #define ORG "CHANGE_THIS"               // For a registered connection, replace with your org
00036 #define ID "CHANGE_THIS"                // For a registered connection, replace with your id
00037 #define AUTH_TOKEN "CHANGE_THIS"        // For a registered connection, replace with your auth-token
00038 #define TYPE "CHANGE_THIS"              // For a registered connection, replace with your type
00039 
00040 #define MQTT_PORT 1883
00041 #define MQTT_TLS_PORT 8883
00042 #define IBM_IOT_PORT MQTT_PORT
00043 
00044 #define MQTT_MAX_PACKET_SIZE 250
00045 
00046 #if defined(TARGET_UBLOX_C027)
00047 #warning "Compiling for mbed C027"
00048 #include "C027.h"
00049 #elif defined(TARGET_LPC1768)
00050 #warning "Compiling for mbed LPC1768"
00051 #include "LPC1768.h"
00052 #elif defined(TARGET_K64F)
00053 #warning "Compiling for mbed K64F"
00054 #include "K64F.h"
00055 #endif
00056 
00057 bool quickstartMode = false;
00058 char org[11] = ORG;  
00059 char type[30] = TYPE;
00060 char id[30] = ID;                 // mac without colons
00061 char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
00062 
00063 bool connected = false;
00064 char* joystickPos = "CENTRE";
00065 int blink_interval = 0;
00066 
00067 int sensor = 0;
00068 int humidity = 0;
00069 int temperature = 0;
00070 
00071 uint8_t u8CRC8Table[256] = {
00072     0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
00073     0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
00074     0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
00075     0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
00076     0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
00077     0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
00078     0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
00079     0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
00080     0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
00081     0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
00082     0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
00083     0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
00084     0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
00085     0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
00086     0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
00087     0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
00088     0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
00089     0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
00090     0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
00091     0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
00092     0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
00093     0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
00094     0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
00095     0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
00096     0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
00097     0x76, 0x71, 0x78, 0x7f, 0x6A, 0x6d, 0x64, 0x63,
00098     0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
00099     0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
00100     0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
00101     0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83,
00102     0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
00103     0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
00104 };
00105 
00106 #define proccrc8(u8CRC, u8Data) (u8CRC8Table[u8CRC ^ u8Data])
00107 
00108 void off()
00109 {
00110     r = g = b = 1.0;    // 1 is off, 0 is full brightness
00111 }
00112 
00113 void red()
00114 {
00115     r = 0.7; g = 1.0; b = 1.0;    // 1 is off, 0 is full brightness
00116 }
00117 
00118 void yellow()
00119 {
00120     r = 0.7; g = 0.7; b = 1.0;    // 1 is off, 0 is full brightness
00121 }
00122 
00123 void green()
00124 {
00125     r = 1.0; g = 0.7; b = 1.0;    // 1 is off, 0 is full brightness
00126 }
00127 
00128 
00129 void flashing_yellow(void const *args)
00130 {
00131     bool on = false;
00132     while (!connected)    // flashing yellow only while connecting 
00133     {
00134         on = !on; 
00135         if (on)
00136             yellow();
00137         else
00138             off();   
00139         wait(0.5);
00140     }
00141 }
00142 
00143 
00144 void flashing_red(void const *args)  // to be used when the connection is lost
00145 {
00146     bool on = false;
00147     while (!connected)
00148     {
00149         on = !on;
00150         if (on)
00151             red();
00152         else
00153             off();
00154         wait(2.0);
00155     }
00156 }
00157 
00158 /**
00159  * Display a message on the LCD screen prefixed with IBM IoT Cloud
00160  */
00161 void displayMessage(char* message)
00162 {
00163     lcd.cls();
00164     lcd.locate(0,0);        
00165     lcd.printf("IBM IoT Cloud");
00166     lcd.locate(0,16);
00167     lcd.printf(message);
00168 }
00169 
00170 
00171 int connect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00172 {   
00173     const char* iot_ibm = ".messaging.internetofthings.ibmcloud.com";
00174     
00175     char hostname[strlen(org) + strlen(iot_ibm) + 1];
00176     sprintf(hostname, "%s%s", org, iot_ibm);
00177 //    DEBUG("hostname is %s\n", hostname);
00178     int rc = ipstack->connect(hostname, IBM_IOT_PORT);
00179     if (rc != 0)
00180         return rc;
00181      
00182     // Construct clientId - d:org:type:id
00183     char clientId[strlen(org) + strlen(type) + strlen(id) + 5];
00184     sprintf(clientId, "d:%s:%s:%s", org, type, id);
00185 //    DEBUG("clientid is %s\n", clientId);
00186     
00187     // MQTT Connect
00188     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
00189     data.MQTTVersion = 3;
00190     data.clientID.cstring = clientId;
00191     
00192     if (!quickstartMode) 
00193     {        
00194         data.username.cstring = "use-token-auth";
00195         data.password.cstring = auth_token;
00196     }
00197     
00198     if ((rc = client->connect(data)) == 0) 
00199     {       
00200         connected = true;
00201         green();    
00202         displayMessage("Connected");
00203   }
00204     return rc;
00205 }
00206 
00207 
00208 int getConnTimeout(int attemptNumber)
00209 {  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
00210    // after 20 attempts, retry every 10 minutes
00211     return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
00212 }
00213 
00214 
00215 void attemptConnect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00216 {
00217     int retryAttempt = 0;
00218     connected = false;
00219     
00220     // make sure a cable is connected before starting to connect
00221     while (!linkStatus()) {
00222         wait(1.0f);
00223         WARN("Ethernet link not present. Check cable connection\n");
00224     }
00225     
00226     while (connect(client, ipstack) != 0) 
00227     {    
00228 #if defined(TARGET_K64F)
00229         red();
00230 #else
00231         Thread red_thread(flashing_red);
00232 #endif
00233         int timeout = getConnTimeout(++retryAttempt);
00234         WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
00235         
00236         // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
00237         //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)
00238         
00239         // this works - reset the system when the retry count gets to a threshold
00240         if (retryAttempt == 5)
00241             NVIC_SystemReset();
00242         else
00243             wait(timeout);
00244     }
00245 }
00246 
00247 
00248 int publish(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00249 {
00250     MQTT::Message message;
00251     char* pubTopic = "iot-2/evt/status/fmt/json";
00252             
00253     char buf[250];
00254 //    sprintf(buf,
00255 //     "{\"d\":{\"myName\":\"IoT mbed\",\"accelX\":%0.4f,\"accelY\":%0.4f,\"accelZ\":%0.4f,\"temp\":%0.4f,\"joystick\":\"%s\",\"potentiometer1\":%0.4f,\"potentiometer2\":%0.4f}}",
00256 //            MMA.x(), MMA.y(), MMA.z(), sensor.temp(), joystickPos, ain1.read(), ain2.read());
00257     sprintf(buf,
00258      "{\"d\":{\"sensor\":\"%02X\",\"hum\":%3.1f,\"temp\":%2.2f}}",
00259             sensor, humidity*0.4, temperature*0.16);
00260     message.qos = MQTT::QOS0;
00261     message.retained = false;
00262     message.dup = false;
00263     message.payload = (void*)buf;
00264     message.payloadlen = strlen(buf);
00265     
00266     LOG("Publishing %s\n", buf);
00267     return client->publish(pubTopic, message);
00268 }
00269 
00270 void messageArrived(MQTT::MessageData& md)
00271 {
00272     MQTT::Message &message = md.message;
00273     char topic[md.topicName.lenstring.len + 1];
00274     
00275     sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data);
00276     
00277     LOG("Message arrived on topic %s: %.*s\n",  topic, message.payloadlen, message.payload);
00278           
00279     // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/
00280     char* start = strstr(topic, "/cmd/") + 5;
00281     int len = strstr(topic, "/fmt/") - start;
00282     
00283     if (memcmp(start, "blink", len) == 0)
00284     {
00285         char payload[message.payloadlen + 1];
00286         sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload);
00287     
00288         char* pos = strchr(payload, '}');
00289         if (pos != NULL)
00290         {
00291             *pos = '\0';
00292             if ((pos = strchr(payload, ':')) != NULL)
00293             {
00294                 int blink_rate = atoi(pos + 1);       
00295                 blink_interval = (blink_rate <= 0) ? 0 : (blink_rate > 50 ? 1 : 50/blink_rate);
00296             }
00297         }
00298     }
00299     else
00300         WARN("Unsupported command: %.*s\n", len, start);
00301 }
00302 
00303 int main()
00304 {
00305 //    quickstartMode = (strcmp(org, "quickstart") == 0);
00306     lcd.set_font((unsigned char*) Arial12x12);  // Set a nice font for the LCD screen
00307     led2 = LED2_OFF; // K64F: turn off the main board LED 
00308     displayMessage("Connecting");
00309 
00310 #if defined(TARGET_K64F)
00311     yellow();  // Don't flash on the K64F, because starting a thread causes the EthernetInterface init call to hang
00312 #else
00313     Thread yellow_thread(flashing_yellow);  
00314 #endif
00315     
00316     MQTTEthernet ipstack;
00317     MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
00318 /*
00319     if (quickstartMode)
00320     {
00321 #if defined(TARGET_K64F)
00322         getUUID48(id, sizeof(id));  // getMac doesn't work on the K64F
00323 #else
00324         getMac(ipstack.getEth(), id, sizeof(id));
00325 #endif
00326     }
00327 */    
00328     attemptConnect(&client, &ipstack);
00329 
00330 //    if (!quickstartMode) 
00331 //    {
00332         int rc = 0;
00333         if ((rc = client.subscribe("iot-2/cmd/+/fmt/json", MQTT::QOS1, messageArrived)) != 0)
00334             WARN("rc from MQTT subscribe is %d\n", rc); 
00335 //    }
00336 
00337     USB400Serial usb400;
00338     int i;
00339     int dataLength;
00340     int optionalLength;
00341     uint8_t c;
00342     uint8_t crc;
00343     
00344     while(1) {
00345 
00346         while(!usb400.connect())
00347             wait(0.5);
00348 
00349         while (1) {
00350             if (!usb400.connected())
00351                 break;
00352 
00353             if (usb400.available()) {
00354                 c = usb400.getc();
00355 
00356                 if (c == 0x55) {
00357                     crc = 0;
00358 
00359                     c = usb400.getc();
00360                     crc = proccrc8(crc, c);
00361                     dataLength = c;
00362 
00363                     c = usb400.getc();
00364                     crc = proccrc8(crc, c);
00365                     dataLength = (dataLength << 8) | c;
00366 
00367                     c = usb400.getc();
00368                     crc = proccrc8(crc, c);
00369                     optionalLength = c;
00370 
00371                     c = usb400.getc();
00372                     crc = proccrc8(crc, c); // packet type
00373 
00374                     c = usb400.getc();
00375                     crc = proccrc8(crc, c); // CRC
00376 
00377                     if (crc == 0) {
00378                         crc = 0;
00379 
00380                         for (i = 0; i < dataLength; i++) {
00381                             c = usb400.getc();
00382                             crc = proccrc8(crc, c);
00383 
00384                             if (i == 4) {
00385 //                                printf("Sensor: %02X ", c);
00386                                 sensor = c;
00387                             }
00388                             //A5-04-01
00389                             if (i == 6) {
00390                                 humidity = c;
00391                             }
00392                             if (i == 7) {
00393                                 temperature = c;
00394                             }
00395                         }
00396 //                        printf("hum:%3.1f%% temp:%2.2fC\r\n", humidity*0.4, temperature*0.16);
00397                         
00398                         if (publish(&client, &ipstack) != 0) 
00399                         attemptConnect(&client, &ipstack);   // if we have lost the connection
00400 
00401                         for (i = 0; i < optionalLength; i++) {
00402                             c = usb400.getc();
00403                             crc = proccrc8(crc, c);
00404                         }
00405 
00406                         c = usb400.getc();
00407                         crc = proccrc8(crc, c);
00408 
00409                     }
00410                 }
00411             }
00412         }
00413     }    
00414 }