u-blox / Mbed 2 deprecated IBMIoTClientEthernetExample

Dependencies:   C12832 EthernetInterface LM75B MMA7660 MQTT mbed-rtos 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 "LM75B.h"
00025 #include "MMA7660.h"
00026 #include "MQTTClient.h"
00027 #include "MQTTEthernet.h"
00028 #include "C12832.h"
00029 #include "Arial12x12.h"
00030 #include "rtos.h"
00031 
00032 // Update this to the next number *before* a commit
00033 #define __APP_SW_REVISION__ "10"
00034 
00035 // Configuration values needed to connect to IBM IoT Cloud
00036 #define ORG "quickstart"             // For a registered connection, replace with your org
00037 #define ID ""                        // For a registered connection, replace with your id
00038 #define AUTH_TOKEN ""                // For a registered connection, replace with your auth-token
00039 #define TYPE DEFAULT_TYPE_NAME       // For a registered connection, replace with your type
00040 
00041 #define MQTT_PORT 1883
00042 #define MQTT_TLS_PORT 8883
00043 #define IBM_IOT_PORT MQTT_PORT
00044 
00045 #define MQTT_MAX_PACKET_SIZE 250
00046 
00047 #if defined(TARGET_UBLOX_C027)
00048 #warning "Compiling for mbed C027"
00049 #include "C027.h"
00050 #elif defined(TARGET_LPC1768)
00051 #warning "Compiling for mbed LPC1768"
00052 #include "LPC1768.h"
00053 #elif defined(TARGET_K64F)
00054 #warning "Compiling for mbed K64F"
00055 #include "K64F.h"
00056 #endif
00057 
00058 bool quickstartMode = true;
00059 char org[11] = ORG;  
00060 char type[30] = TYPE;
00061 char id[30] = ID;                 // mac without colons
00062 char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
00063 
00064 bool connected = false;
00065 char* joystickPos = "CENTRE";
00066 int blink_interval = 0;
00067 
00068 
00069 void off()
00070 {
00071     r = g = b = 1.0;    // 1 is off, 0 is full brightness
00072 }
00073 
00074 void red()
00075 {
00076     r = 0.7; g = 1.0; b = 1.0;    // 1 is off, 0 is full brightness
00077 }
00078 
00079 void yellow()
00080 {
00081     r = 0.7; g = 0.7; b = 1.0;    // 1 is off, 0 is full brightness
00082 }
00083 
00084 void green()
00085 {
00086     r = 1.0; g = 0.7; b = 1.0;    // 1 is off, 0 is full brightness
00087 }
00088 
00089 
00090 void flashing_yellow(void const *args)
00091 {
00092     bool on = false;
00093     while (!connected)    // flashing yellow only while connecting 
00094     {
00095         on = !on; 
00096         if (on)
00097             yellow();
00098         else
00099             off();   
00100         wait(0.5);
00101     }
00102 }
00103 
00104 
00105 void flashing_red(void const *args)  // to be used when the connection is lost
00106 {
00107     bool on = false;
00108     while (!connected)
00109     {
00110         on = !on;
00111         if (on)
00112             red();
00113         else
00114             off();
00115         wait(2.0);
00116     }
00117 }
00118 
00119 
00120 void printMenu(int menuItem) 
00121 {
00122     lcd.cls();
00123     lcd.locate(0,0);
00124     switch (menuItem)
00125     {
00126         case 0:
00127             lcd.printf("IBM IoT Cloud");
00128             lcd.locate(0,16);
00129             lcd.printf("Scroll with joystick");
00130             break;
00131         case 1:
00132             lcd.printf("Go to:");
00133             lcd.locate(0,16);
00134             lcd.printf("http://ibm.biz/iotqstart");
00135             break;
00136         case 2:
00137             lcd.printf("Device Identity:");
00138             lcd.locate(0,16);
00139             lcd.printf("%s", id);
00140             break;
00141         case 3:
00142             lcd.printf("Status:");
00143             lcd.locate(0,16);
00144             lcd.printf(connected ? "Connected" : "Disconnected");
00145             break;
00146         case 4:
00147             lcd.printf("App version:");
00148             lcd.locate(0,16);
00149             lcd.printf("%s",__APP_SW_REVISION__);
00150             break;
00151     }
00152 }
00153 
00154 
00155 void setMenu()
00156 {
00157     static int menuItem = 0;
00158     if (Down)
00159     {
00160         joystickPos = "DOWN";
00161         if (menuItem >= 0 && menuItem < 4)
00162             printMenu(++menuItem);
00163     } 
00164     else if (Left)
00165         joystickPos = "LEFT";
00166     else if (Click)
00167         joystickPos = "CLICK";
00168     else if (Up)
00169     {
00170         joystickPos = "UP";
00171         if (menuItem <= 4 && menuItem > 0)
00172             printMenu(--menuItem);
00173     }
00174     else if (Right)
00175         joystickPos = "RIGHT";
00176     else
00177         joystickPos = "CENTRE";
00178 }
00179 
00180 
00181 /**
00182  * Display a message on the LCD screen prefixed with IBM IoT Cloud
00183  */
00184 void displayMessage(char* message)
00185 {
00186     lcd.cls();
00187     lcd.locate(0,0);        
00188     lcd.printf("IBM IoT Cloud");
00189     lcd.locate(0,16);
00190     lcd.printf(message);
00191 }
00192 
00193 
00194 int connect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00195 {   
00196     const char* iot_ibm = ".messaging.internetofthings.ibmcloud.com";
00197     
00198     char hostname[strlen(org) + strlen(iot_ibm) + 1];
00199     sprintf(hostname, "%s%s", org, iot_ibm);
00200     DEBUG("hostname is %s\n", hostname);
00201     int rc = ipstack->connect(hostname, IBM_IOT_PORT);
00202     if (rc != 0)
00203         return rc;
00204      
00205     // Construct clientId - d:org:type:id
00206     char clientId[strlen(org) + strlen(type) + strlen(id) + 5];
00207     sprintf(clientId, "d:%s:%s:%s", org, type, id);
00208     DEBUG("clientid is %s\n", clientId);
00209     
00210     // MQTT Connect
00211     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
00212     data.MQTTVersion = 3;
00213     data.clientID.cstring = clientId;
00214     
00215     if (!quickstartMode) 
00216     {        
00217         data.username.cstring = "use-token-auth";
00218         data.password.cstring = auth_token;
00219     }
00220     
00221     if ((rc = client->connect(data)) == 0) 
00222     {       
00223         connected = true;
00224         green();    
00225         displayMessage("Connected");
00226         wait(2);
00227         displayMessage("Scroll with joystick");
00228     }
00229     return rc;
00230 }
00231 
00232 
00233 int getConnTimeout(int attemptNumber)
00234 {  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
00235    // after 20 attempts, retry every 10 minutes
00236     return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
00237 }
00238 
00239 
00240 void attemptConnect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00241 {
00242     int retryAttempt = 0;
00243     connected = false;
00244     
00245     // make sure a cable is connected before starting to connect
00246     while (!linkStatus()) {
00247         wait(1.0f);
00248         WARN("Ethernet link not present. Check cable connection\n");
00249     }
00250         
00251     while (connect(client, ipstack) != 0) 
00252     {    
00253 #if defined(TARGET_K64F)
00254         red();
00255 #else
00256         Thread red_thread(flashing_red);
00257 #endif
00258         int timeout = getConnTimeout(++retryAttempt);
00259         WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
00260         
00261         // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
00262         //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)
00263         
00264         // this works - reset the system when the retry count gets to a threshold
00265         if (retryAttempt == 5)
00266             NVIC_SystemReset();
00267         else
00268             wait(timeout);
00269     }
00270 }
00271 
00272 
00273 int publish(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00274 {
00275     MQTT::Message message;
00276     char* pubTopic = "iot-2/evt/status/fmt/json";
00277             
00278     char buf[250];
00279     sprintf(buf,
00280      "{\"d\":{\"myName\":\"IoT mbed\",\"accelX\":%0.4f,\"accelY\":%0.4f,\"accelZ\":%0.4f,\"temp\":%0.4f,\"joystick\":\"%s\",\"potentiometer1\":%0.4f,\"potentiometer2\":%0.4f}}",
00281             MMA.x(), MMA.y(), MMA.z(), sensor.temp(), joystickPos, ain1.read(), ain2.read());
00282     message.qos = MQTT::QOS0;
00283     message.retained = false;
00284     message.dup = false;
00285     message.payload = (void*)buf;
00286     message.payloadlen = strlen(buf);
00287     
00288     LOG("Publishing %s\n", buf);
00289     return client->publish(pubTopic, message);
00290 }
00291 
00292 
00293 #if defined(TARGET_K64F)
00294 int getUUID48(char* buf, int buflen) 
00295 {
00296     unsigned int UUID_LOC_WORD0 = 0x40048060;
00297     unsigned int UUID_LOC_WORD1 = 0x4004805C;
00298  
00299     // Fetch word 0
00300     uint32_t word0 = *(uint32_t *)UUID_LOC_WORD0;
00301  
00302     // Fetch word 1
00303     // we only want bottom 16 bits of word1 (MAC bits 32-47)
00304     // and bit 9 forced to 1, bit 8 forced to 0
00305     // Locally administered MAC, reduced conflicts
00306     // http://en.wikipedia.org/wiki/MAC_address
00307     uint32_t word1 = *(uint32_t *)UUID_LOC_WORD1;
00308     word1 |= 0x00000200;
00309     word1 &= 0x0000FEFF;
00310  
00311     int rc = snprintf(buf, buflen, "%4x%08x", word1, word0);   // Device id must be in lower case
00312     
00313     return rc;
00314 }
00315 #else
00316 char* getMac(EthernetInterface& eth, char* buf, int buflen)    // Obtain MAC address
00317 {   
00318     strncpy(buf, eth.getMACAddress(), buflen);
00319 
00320     char* pos;                                                 // Remove colons from mac address
00321     while ((pos = strchr(buf, ':')) != NULL)
00322         memmove(pos, pos + 1, strlen(pos) + 1);
00323     return buf;
00324 }
00325 #endif
00326 
00327 
00328 void messageArrived(MQTT::MessageData& md)
00329 {
00330     MQTT::Message &message = md.message;
00331     char topic[md.topicName.lenstring.len + 1];
00332     
00333     sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data);
00334     
00335     LOG("Message arrived on topic %s: %.*s\n",  topic, message.payloadlen, message.payload);
00336           
00337     // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/
00338     char* start = strstr(topic, "/cmd/") + 5;
00339     int len = strstr(topic, "/fmt/") - start;
00340     
00341     if (memcmp(start, "blink", len) == 0)
00342     {
00343         char payload[message.payloadlen + 1];
00344         sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload);
00345     
00346         char* pos = strchr(payload, '}');
00347         if (pos != NULL)
00348         {
00349             *pos = '\0';
00350             if ((pos = strchr(payload, ':')) != NULL)
00351             {
00352                 int blink_rate = atoi(pos + 1);       
00353                 blink_interval = (blink_rate <= 0) ? 0 : (blink_rate > 50 ? 1 : 50/blink_rate);
00354             }
00355         }
00356     }
00357     else
00358         WARN("Unsupported command: %.*s\n", len, start);
00359 }
00360 
00361 
00362 int main()
00363 {    
00364     quickstartMode = (strcmp(org, "quickstart") == 0);
00365 
00366     lcd.set_font((unsigned char*) Arial12x12);  // Set a nice font for the LCD screen
00367     
00368     led2 = LED2_OFF; // K64F: turn off the main board LED 
00369     
00370     displayMessage("Connecting");
00371 #if defined(TARGET_K64F)
00372     yellow();  // Don't flash on the K64F, because starting a thread causes the EthernetInterface init call to hang
00373 #else
00374     Thread yellow_thread(flashing_yellow);  
00375 #endif
00376     
00377     MQTTEthernet ipstack;
00378     MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
00379     
00380     if (quickstartMode)
00381     {
00382 #if defined(TARGET_K64F)
00383         getUUID48(id, sizeof(id));  // getMac doesn't work on the K64F
00384 #else
00385         getMac(ipstack.getEth(), id, sizeof(id));
00386 #endif
00387     }
00388     
00389     attemptConnect(&client, &ipstack);
00390     
00391     if (!quickstartMode) 
00392     {
00393         int rc = 0;
00394         if ((rc = client.subscribe("iot-2/cmd/+/fmt/json", MQTT::QOS1, messageArrived)) != 0)
00395             WARN("rc from MQTT subscribe is %d\n", rc); 
00396     }
00397     
00398     blink_interval = 0;
00399     int count = 0;
00400     while (true)
00401     {
00402         if (++count == 100)
00403         {               // Publish a message every second
00404             if (publish(&client, &ipstack) != 0) 
00405                 attemptConnect(&client, &ipstack);   // if we have lost the connection
00406             count = 0;
00407         }
00408         
00409         if (blink_interval == 0)
00410             led2 = LED2_OFF;
00411         else if (count % blink_interval == 0)
00412             led2 = !led2;
00413         if (count % 20 == 0)
00414             setMenu();
00415         client.yield(10);  // allow the MQTT client to receive messages
00416     }
00417 }