Code sample to be used with Bluemix for education purpose

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, 2015 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  *    James Sutton - Mac fix and extra debug
00019  *    Ian Craggs - add not authorized messages
00020  *
00021  * To do :
00022  *    Add magnetometer sensor output to IoT data stream
00023  *
00024  *******************************************************************************/
00025 
00026 #include "LM75B.h"
00027 #include "MMA7660.h"
00028 #include "MQTTClient.h"
00029 #include "MQTTEthernet.h"
00030 #include "C12832.h"
00031 #include "Arial12x12.h"
00032 #include "rtos.h"
00033 
00034 // Update this to the next number *before* a commit
00035 #define __APP_SW_REVISION__ "18"
00036 
00037 // Configuration values needed to connect to IBM IoT Cloud
00038 #define ORG "!!!!!!"             // For a registered connection, replace with your org
00039 #define ID  "!!!!!!"              // For a registered connection, replace with your id
00040 #define AUTH_TOKEN "!!!!!!"                // For a registered connection, replace with your auth-token
00041 #define TYPE "!!!!!!"      // For a registered connection, replace with your type
00042 #define DEVICE_NAME "!!!!!!!"     // Replace with your own name
00043 
00044 #define MQTT_PORT 1883
00045 #define MQTT_TLS_PORT 8883
00046 #define IBM_IOT_PORT MQTT_PORT
00047 
00048 #define MQTT_MAX_PACKET_SIZE 250
00049 
00050 #if defined(TARGET_UBLOX_C027)
00051 #warning "Compiling for mbed C027"
00052 #include "C027.h"
00053 #elif defined(TARGET_LPC1768)
00054 #warning "Compiling for mbed LPC1768"
00055 #include "LPC1768.h"
00056 #elif defined(TARGET_K64F)
00057 #warning "Compiling for mbed K64F"
00058 #include "K64F.h"
00059 #endif
00060 
00061 
00062 bool quickstartMode = false;
00063 char org[11] = ORG;  
00064 char type[30] = TYPE;
00065 char id[30] = ID;                 // mac without colons
00066 char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
00067 
00068 bool connected = false;
00069 bool mqttConnecting = false;
00070 bool netConnected = false;
00071 bool netConnecting = false;
00072 bool ethernetInitialising = true;
00073 int connack_rc = 0; // MQTT connack return code
00074 int retryAttempt = 0;
00075 int menuItem = 0;
00076 
00077 char* joystickPos = "CENTRE";
00078 int blink_interval = 0;
00079 
00080 char* ip_addr = "";
00081 char* gateway_addr = "";
00082 char* host_addr = "";
00083 int connectTimeout = 1000;
00084 
00085 // If we wanted to manually set the MAC address,
00086 // this is how to do it. In this example, we take
00087 // the original Mbed Set MAC address and combine it
00088 // with a prefix of our choosing.
00089  /*
00090 extern "C" void $Super$$mbed_mac_address(char *s);
00091 extern "C" void $Sub$$mbed_mac_address(char *s) 
00092 {
00093     char originalMAC[6] = "";
00094     $Super$$mbed_mac_address(originalMAC);
00095     
00096     char mac[6];
00097     mac[0] = 0x00;
00098     mac[1] = 0x08;
00099     mac[2] = 0xdc;
00100     mac[3] = originalMAC[3];
00101     mac[4] = originalMAC[4];
00102     mac[5] = originalMAC[5];
00103     memcpy(s, mac, 6);
00104 }
00105 */
00106 
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 && connack_rc != MQTT_NOT_AUTHORIZED && connack_rc != MQTT_BAD_USERNAME_OR_PASSWORD)    // 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 void printMenu(int menuItem) 
00160 {
00161     static char last_line1[30] = "", last_line2[30] = "";
00162     char line1[30] = "", line2[30] = "";
00163         
00164     switch (menuItem)
00165     {
00166         case 0:
00167             sprintf(line1, "IBM IoT Cloud");
00168             sprintf(line2, "Scroll with joystick");
00169             break;
00170         case 1:
00171             sprintf(line1, "Go to:");
00172             sprintf(line2, "http://ibm.biz/iotqstart");
00173             break;
00174         case 2:
00175             sprintf(line1, "Device Identity:");
00176             sprintf(line2, "%s", id);
00177             break;
00178         case 3:
00179             sprintf(line1, "MQTT Status:");
00180             if (mqttConnecting)
00181                 sprintf(line2, "Connecting... %d/5", retryAttempt);
00182             else
00183             {
00184                 if (connected)
00185                     sprintf(line2, "Connected");
00186                 else
00187                 {
00188                     switch (connack_rc)
00189                     {
00190                         case MQTT_CLIENTID_REJECTED:
00191                             sprintf(line2, "Clientid rejected");
00192                             break;
00193                         case MQTT_BAD_USERNAME_OR_PASSWORD:
00194                             sprintf(line2, "Invalid username or password");
00195                             break;
00196                         case MQTT_NOT_AUTHORIZED:
00197                             sprintf(line2, "Not authorized");
00198                             break;
00199                         default:
00200                             sprintf(line2, "Disconnected");
00201                     }
00202                 }
00203             }
00204             break;
00205         case 4:
00206             sprintf(line1, "Ethernet State:");
00207             sprintf(line2, ethernetInitialising ? "Initializing..." : "Initialized");
00208             break;
00209         case 5:
00210             sprintf(line1, "Socket State:");
00211             if (netConnecting)
00212                 sprintf(line2, "Connecting... %d/5", retryAttempt);
00213             else
00214                 sprintf(line2, netConnected ? "Connected" : "Disconnected");
00215             break;
00216         case 6:
00217             sprintf(line1, "IP Address:");
00218             sprintf(line2, "%s", ip_addr);
00219             break;
00220         case 7:
00221             sprintf(line1, "Gateway:");
00222             sprintf(line2, "%s", gateway_addr);
00223             break;
00224         case 8:
00225             sprintf(line1, "App version:");
00226             sprintf(line2, "%s", __APP_SW_REVISION__);
00227             break;
00228         case 9:
00229             sprintf(line1, "Current Timeout:");
00230             sprintf(line2, "%d ms", connectTimeout);
00231             break;
00232     }
00233     
00234     if (strcmp(line1, last_line1) != 0 || strcmp(line2, last_line2) != 0)
00235     {
00236         lcd.cls(); 
00237         lcd.locate(0, 0);
00238         lcd.printf(line1);
00239         strncpy(last_line1, line1, sizeof(last_line1));
00240 
00241         lcd.locate(0,16);
00242         lcd.printf(line2);
00243         strncpy(last_line2, line2, sizeof(last_line2));
00244     }
00245 }
00246 
00247 
00248 void setMenu()
00249 {
00250     
00251     if (Down)
00252     {
00253         joystickPos = "DOWN";
00254         if (menuItem >= 0 && menuItem < 9)
00255             printMenu(++menuItem);
00256     } 
00257     else if (Left)
00258         joystickPos = "LEFT";
00259     else if (Click)
00260         joystickPos = "CLICK";
00261     else if (Up)
00262     {
00263         joystickPos = "UP";
00264         if (menuItem <= 9 && menuItem > 0)
00265             printMenu(--menuItem);
00266     }
00267     else if (Right)
00268         joystickPos = "RIGHT";
00269     else
00270         joystickPos = "CENTRE";
00271 }
00272 
00273 void menu_loop(void const *args)
00274 {
00275     int count = 0;
00276     while(true)
00277     {
00278         setMenu();
00279         if (++count % 10 == 0)
00280             printMenu(menuItem);
00281         Thread::wait(100);
00282     }
00283 }
00284 
00285 
00286 /**
00287  * Display a message on the LCD screen prefixed with IBM IoT Cloud
00288  */
00289 void displayMessage(char* message)
00290 {
00291     lcd.cls();
00292     lcd.locate(0,0);        
00293     lcd.printf("IBM IoT Cloud");
00294     lcd.locate(0,16);
00295     lcd.printf(message);
00296 }
00297 
00298 
00299 int connect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00300 {   
00301     const char* iot_ibm = ".messaging.internetofthings.ibmcloud.com";
00302     
00303     char hostname[strlen(org) + strlen(iot_ibm) + 1];
00304     sprintf(hostname, "%s%s", org, iot_ibm);
00305     EthernetInterface& eth = ipstack->getEth();
00306     ip_addr = eth.getIPAddress();
00307     gateway_addr = eth.getGateway();
00308     
00309     // Construct clientId - d:org:type:id
00310     char clientId[strlen(org) + strlen(type) + strlen(id) + 5];
00311     sprintf(clientId, "d:%s:%s:%s", org, type, id);
00312     
00313     // Network debug statements 
00314     LOG("=====================================\n");
00315     LOG("Connecting Ethernet.\n");
00316     LOG("IP ADDRESS: %s\n", eth.getIPAddress());
00317     LOG("MAC ADDRESS: %s\n", eth.getMACAddress());
00318     LOG("Gateway: %s\n", eth.getGateway());
00319     LOG("Network Mask: %s\n", eth.getNetworkMask());
00320     LOG("Server Hostname: %s\n", hostname);
00321     LOG("Client ID: %s\n", clientId);
00322     LOG("=====================================\n");
00323     
00324     netConnecting = true;
00325     int rc = ipstack->connect(hostname, IBM_IOT_PORT, connectTimeout);
00326     if (rc != 0)
00327     {
00328         WARN("IP Stack connect returned: %d\n", rc);    
00329         return rc;
00330     }
00331     netConnected = true;
00332     netConnecting = false;
00333 
00334     // MQTT Connect
00335     mqttConnecting = true;
00336     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
00337     data.MQTTVersion = 3;
00338     data.clientID.cstring = clientId;
00339     
00340     if (!quickstartMode) 
00341     {        
00342         data.username.cstring = "use-token-auth";
00343         data.password.cstring = auth_token;
00344     }
00345     
00346     if ((rc = client->connect(data)) == 0) 
00347     {       
00348         connected = true;
00349         green();    
00350         displayMessage("Connected");
00351         wait(1);
00352         displayMessage("Scroll with joystick");
00353     }
00354     else
00355         WARN("MQTT connect returned %d\n", rc);
00356     if (rc >= 0)
00357         connack_rc = rc;
00358     mqttConnecting = false;
00359     return rc;
00360 }
00361 
00362 
00363 int getConnTimeout(int attemptNumber)
00364 {  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
00365    // after 20 attempts, retry every 10 minutes
00366     return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
00367 }
00368 
00369 
00370 void attemptConnect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00371 {
00372     connected = false;
00373    
00374     // make sure a cable is connected before starting to connect
00375     while (!linkStatus()) 
00376     {
00377         wait(1.0f);
00378         WARN("Ethernet link not present. Check cable connection\n");
00379     }
00380         
00381     while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED) 
00382     {    
00383         if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)
00384             return; // don't reattempt to connect if credentials are wrong
00385             
00386         Thread red_thread(flashing_red);
00387 
00388         int timeout = getConnTimeout(++retryAttempt);
00389         WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
00390         
00391         // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
00392         //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)
00393         
00394         // this works - reset the system when the retry count gets to a threshold
00395         if (retryAttempt == 5)
00396             NVIC_SystemReset();
00397         else
00398             wait(timeout);
00399     }
00400 }
00401 
00402 
00403 int publish(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00404 {
00405     MQTT::Message message;
00406     char* pubTopic = "iot-2/evt/status/fmt/json";
00407             
00408     char buf[250];
00409     sprintf(buf,
00410      "{\"d\":{\"myName\":\"IoT mbed\",\"accelX\":%0.4f,\"accelY\":%0.4f,\"accelZ\":%0.4f,\"temp\":%0.4f,\"joystick\":\"%s\",\"potentiometer1\":%0.4f,\"potentiometer2\":%0.4f,\"Latitude\":43.7,\"Longitude\":7.25,\"Rfid\":12345}}",
00411             MMA.x(), MMA.y(), MMA.z(), sensor.temp(), joystickPos, ain1.read(), ain2.read());
00412      
00413     message.qos = MQTT::QOS0;
00414     message.retained = false;
00415     message.dup = false;
00416     message.payload = (void*)buf;
00417     message.payloadlen = strlen(buf);
00418     
00419     LOG("Publishing %s\n", buf);
00420     return client->publish(pubTopic, message);
00421 }
00422 
00423 
00424 char* getMac(EthernetInterface& eth, char* buf, int buflen)    // Obtain MAC address
00425 {   
00426     strncpy(buf, eth.getMACAddress(), buflen);
00427 
00428     char* pos;                                                 // Remove colons from mac address
00429     while ((pos = strchr(buf, ':')) != NULL)
00430         memmove(pos, pos + 1, strlen(pos) + 1);
00431     return buf;
00432 }
00433 
00434 
00435 void messageArrived(MQTT::MessageData& md)
00436 {
00437     MQTT::Message &message = md.message;
00438     char topic[md.topicName.lenstring.len + 1];
00439     
00440     sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data);
00441     
00442     LOG("Message arrived on topic %s: %.*s\n",  topic, message.payloadlen, message.payload);
00443           
00444     // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/
00445     char* start = strstr(topic, "/cmd/") + 5;
00446     int len = strstr(topic, "/fmt/") - start;
00447     
00448     if (memcmp(start, "blink", len) == 0)
00449     {
00450         char payload[message.payloadlen + 1];
00451         sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload);
00452     
00453         char* pos = strchr(payload, '}');
00454         if (pos != NULL)
00455         {
00456             *pos = '\0';
00457             if ((pos = strchr(payload, ':')) != NULL)
00458             {
00459                 int blink_rate = atoi(pos + 1);       
00460                 blink_interval = (blink_rate <= 0) ? 0 : (blink_rate > 50 ? 1 : 50/blink_rate);
00461             }
00462         }
00463     }
00464     else
00465         WARN("Unsupported command: %.*s\n", len, start);
00466 }
00467 
00468 
00469 int main()
00470 {    
00471     quickstartMode = (strcmp(org, "quickstart") == 0);
00472 
00473     lcd.set_font((unsigned char*) Arial12x12);  // Set a nice font for the LCD screen
00474     
00475     led2 = LED2_OFF; // K64F: turn off the main board LED 
00476     
00477     displayMessage("Connecting");
00478     Thread yellow_thread(flashing_yellow);
00479     Thread menu_thread(menu_loop);  
00480     
00481     LOG("***** IBM IoT Client Ethernet Example *****\n");
00482     MQTTEthernet ipstack;
00483     ethernetInitialising = false;
00484     MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
00485     LOG("Ethernet Initialized\n"); 
00486     
00487     if (quickstartMode)
00488         getMac(ipstack.getEth(), id, sizeof(id));
00489         
00490     attemptConnect(&client, &ipstack);
00491     
00492     if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)    
00493     {
00494         red();
00495         while (true)
00496             wait(1.0); // Permanent failures - don't retry
00497     }
00498     
00499     if (!quickstartMode) 
00500     {
00501         int rc = 0;
00502         if ((rc = client.subscribe("iot-2/cmd/+/fmt/json", MQTT::QOS1, messageArrived)) != 0)
00503             WARN("rc from MQTT subscribe is %d\n", rc); 
00504     }
00505     
00506     blink_interval = 0;
00507     int count = 0;
00508     while (true)
00509     {
00510         if (++count == 2500)  // Here is the count to change the number of publish/second
00511         {               // Publish a message every second
00512             if (publish(&client, &ipstack) != 0) 
00513                 attemptConnect(&client, &ipstack);   // if we have lost the connection
00514             count = 0;
00515         }
00516         
00517         if (blink_interval == 0)
00518             led2 = LED2_OFF;
00519         else if (count % blink_interval == 0)
00520             led2 = !led2;
00521         client.yield(10);  // allow the MQTT client to receive messages
00522     }
00523 }