a modified code based on the IoTClientEthernet code

Dependencies:   C12832 EthernetInterface LM75B MMA7660 MQTT mbed-rtos mbed

Fork of IoTClientEthernet by Zhengguo Sheng

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 "quickstart"             // 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 DEFAULT_TYPE_NAME       // For a registered connection, replace with your type
00042 
00043 #define MQTT_PORT 1883
00044 #define MQTT_TLS_PORT 8883
00045 #define IBM_IOT_PORT MQTT_PORT
00046 
00047 #define MQTT_MAX_PACKET_SIZE 250
00048 
00049 #if defined(TARGET_UBLOX_C027)
00050 #warning "Compiling for mbed C027"
00051 #include "C027.h"
00052 #elif defined(TARGET_LPC1768)
00053 #warning "Compiling for mbed LPC1768"
00054 #include "LPC1768.h"
00055 #elif defined(TARGET_K64F)
00056 #warning "Compiling for mbed K64F"
00057 #include "K64F.h"
00058 #endif
00059 
00060 
00061 bool quickstartMode = true;
00062 char org[11] = ORG;  
00063 char type[30] = TYPE;
00064 char id[30] = ID;                 // mac without colons
00065 char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
00066 bool connected = false;
00067 bool mqttConnecting = false;
00068 bool netConnected = false;
00069 bool netConnecting = false;
00070 bool ethernetInitialising = true;
00071 int connack_rc = 0; // MQTT connack return code
00072 int retryAttempt = 0;
00073 int menuItem = 0;
00074 char* joystickPos = "CENTRE";
00075 int blink_interval = 0;
00076 char* ip_addr = "";
00077 char* gateway_addr = "";
00078 char* host_addr = "";
00079 int connectTimeout = 1000;
00080 // If we wanted to manually set the MAC address,
00081 // this is how to do it. In this example, we take
00082 // the original Mbed Set MAC address and combine it
00083 // with a prefix of our choosing. 
00084 extern "C" void $Super$$mbed_mac_address(char *s);
00085 extern "C" void $Sub$$mbed_mac_address(char *s) 
00086 {   
00087 // define your own MAC Address
00088   s[0] = 0x68;  
00089   s[1] = 0xf7;  
00090   s[2] = 0x28;  
00091   s[3] = 0x06;  
00092   s[4] = 0x02;  
00093   s[5] = 0x63;           
00094 }
00095 
00096 
00097 //---------------------------functions to flash the LED in different colours----------
00098 void off()
00099 {
00100     r = g = b = 1.0;    // 1 is off, 0 is full brightness
00101 }
00102 
00103 void red()
00104 {
00105     r = 0.7; g = 1.0; b = 1.0;    // 1 is off, 0 is full brightness
00106 }
00107 
00108 void yellow()
00109 {
00110     r = 0.7; g = 0.7; b = 1.0;    // 1 is off, 0 is full brightness
00111 }
00112 
00113 void green()
00114 {
00115     r = 1.0; g = 0.7; b = 1.0;    // 1 is off, 0 is full brightness
00116 }
00117 
00118 //----------------------------------------------------------------------------------------
00119 void flashing_yellow(void const *args) 
00120 { bool on = false;
00121 // flashing yellow only while connecting 
00122   while (!connected && connack_rc != MQTT_NOT_AUTHORIZED && connack_rc != MQTT_BAD_USERNAME_OR_PASSWORD)    
00123    {
00124         on = !on; 
00125         if (on)
00126             yellow();
00127         else
00128            off();   
00129         wait(0.5);
00130     }
00131 }
00132 
00133 
00134 void flashing_red(void const *args)  // to be used when the connection is lost
00135 {
00136     bool on = false;
00137     while (!connected)
00138     {
00139         on = !on;
00140         if (on)
00141             red();
00142         else
00143             off();
00144         wait(2.0);
00145     }
00146 }
00147 
00148 
00149 void printMenu(int menuItem) 
00150 {
00151     static char last_line1[60] = "", last_line2[60] = "";
00152     char line1[60] = "", line2[60] = "";
00153         
00154     switch (menuItem)
00155     {
00156         case 0:
00157             sprintf(line1, "IBM IoT Cloud");
00158             sprintf(line2, "Scroll with joystick");
00159             break;
00160         case 1:
00161             sprintf(line1, "Go to:");
00162             sprintf(line2, "http://ibm.biz/iotqstart");
00163             break;
00164         case 2:
00165             sprintf(line1, "Device Identity:");
00166             sprintf(line2, "%s", id);
00167             break;
00168         case 3:
00169             sprintf(line1, "MQTT Status:");
00170             if (mqttConnecting)
00171                 sprintf(line2, "Connecting... %d/5", retryAttempt);
00172             else
00173             {
00174                 if (connected)
00175                     sprintf(line2, "Connected");
00176                 else
00177                 {
00178                     switch (connack_rc)
00179                     {
00180                         case MQTT_CLIENTID_REJECTED:
00181                             sprintf(line2, "Clientid rejected");
00182                             break;
00183                         case MQTT_BAD_USERNAME_OR_PASSWORD:
00184                             sprintf(line2, "Invalid username or password");
00185                             break;
00186                         case MQTT_NOT_AUTHORIZED:
00187                             sprintf(line2, "Not authorized");
00188                             break;
00189                         default:
00190                             sprintf(line2, "Disconnected");
00191                     }
00192                 }
00193             }
00194             break;
00195         case 4:
00196             sprintf(line1, "Ethernet State:");
00197             sprintf(line2, ethernetInitialising ? "Initializing..." : "Initialized");
00198             break;
00199         case 5:
00200             sprintf(line1, "Socket State:");
00201             if (netConnecting)
00202                 sprintf(line2, "Connecting... %d/5", retryAttempt);
00203             else
00204                 sprintf(line2, netConnected ? "Connected" : "Disconnected");
00205             break;
00206         case 6:
00207             sprintf(line1, "IP Address:");
00208             sprintf(line2, "%s", ip_addr);
00209             break;
00210         case 7:
00211             sprintf(line1, "Gateway:");
00212             sprintf(line2, "%s", gateway_addr);
00213             break;
00214         case 8:
00215             sprintf(line1, "App version:");
00216             sprintf(line2, "%s", __APP_SW_REVISION__);
00217             break;
00218         case 9:
00219             sprintf(line1, "Current Timeout:");
00220             sprintf(line2, "%d ms", connectTimeout);
00221             break;
00222         case 10: //prints out the temperature on the LCD, after the joystick is scrolled down 10 times
00223             sprintf(line1, "Temperature");
00224             sprintf(line2, "%0.4f degrees C", sensor.temp());
00225             break;
00226        case 11: //prints out the accelerometer output on the LCD, after the joystick is scrolled down 11 times
00227             sprintf(line1, "accelX  accelY  accelZ");
00228             sprintf(line2, "%0.4f,  %0.4f,  %0.4f", MMA.x(), MMA.y(), MMA.z());
00229             break;
00230        case 12: //prints out the potentiometer values on the LCD, after the joystick is scrolled down 12 times
00231             sprintf(line1, "Pot1     Pot2");
00232             sprintf(line2, "%0.4f,  %0.4f", ain1.read(), ain2.read());
00233             break;
00234     }
00235     
00236     if (strcmp(line1, last_line1) != 0 || strcmp(line2, last_line2) != 0)
00237     {
00238         lcd.cls(); 
00239         lcd.locate(0, 0);
00240         lcd.printf(line1);
00241         strncpy(last_line1, line1, sizeof(last_line1));
00242 
00243         lcd.locate(0,16);
00244         lcd.printf(line2);
00245         strncpy(last_line2, line2, sizeof(last_line2));
00246     }
00247 }
00248 void setMenu()
00249 {
00250     
00251     if (Down)
00252     {
00253         joystickPos = "DOWN";
00254         if (menuItem >= 0 && menuItem < 12)
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 <= 12 && 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  /* Display a message on the LCD screen prefixed with IBM IoT Cloud*/
00285 void displayMessage(char* message)
00286 {
00287     lcd.cls();
00288     lcd.locate(0,0);        
00289     lcd.printf("IBM IoT Cloud");
00290     lcd.locate(0,16);
00291     lcd.printf(message);
00292 }
00293 int connect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00294 {   
00295     const char* iot_ibm = ".messaging.internetofthings.ibmcloud.com";
00296     
00297     char hostname[strlen(org) + strlen(iot_ibm) + 1];
00298     sprintf(hostname, "%s%s", org, iot_ibm);
00299     EthernetInterface& eth = ipstack->getEth();
00300     ip_addr = eth.getIPAddress();
00301     gateway_addr = eth.getGateway();
00302     
00303     // Construct clientId - d:org:type:id
00304     char clientId[strlen(org) + strlen(type) + strlen(id) + 5];
00305     sprintf(clientId, "d:%s:%s:%s", org, type, id);
00306     
00307     // Network debug statements 
00308     LOG("=====================================\n");
00309     LOG("Connecting Ethernet.\n");
00310     LOG("IP ADDRESS: %s\n", eth.getIPAddress());
00311     LOG("MAC ADDRESS: %s\n", eth.getMACAddress());
00312     LOG("Gateway: %s\n", eth.getGateway());
00313     LOG("Network Mask: %s\n", eth.getNetworkMask());
00314     LOG("Server Hostname: %s\n", hostname);
00315     LOG("Client ID: %s\n", clientId);
00316     LOG("=====================================\n");
00317     
00318     netConnecting = true;
00319     int rc = ipstack->connect(hostname, IBM_IOT_PORT, connectTimeout);
00320     if (rc != 0)
00321     {
00322         WARN("IP Stack connect returned: %d\n", rc);    
00323         return rc;
00324     }
00325     netConnected = true;
00326     netConnecting = false;
00327 
00328     // MQTT Connect
00329     mqttConnecting = true;
00330     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
00331     data.MQTTVersion = 3;
00332     data.clientID.cstring = clientId;
00333     
00334     if (!quickstartMode) 
00335     {        
00336         data.username.cstring = "use-token-auth";
00337         data.password.cstring = auth_token;
00338     }
00339     
00340     if ((rc = client->connect(data)) == 0) 
00341     {       
00342         connected = true;
00343         green();    
00344         displayMessage("Connected");
00345         wait(1);
00346         displayMessage("Scroll with joystick");
00347     }
00348     else
00349         WARN("MQTT connect returned %d\n", rc);
00350     if (rc >= 0)
00351         connack_rc = rc;
00352     mqttConnecting = false;
00353     return rc;
00354 }
00355 
00356 
00357 int getConnTimeout(int attemptNumber)
00358 {  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
00359    // after 20 attempts, retry every 10 minutes
00360     return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
00361 }
00362 
00363 
00364 void attemptConnect(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00365 {
00366     connected = false;
00367    
00368     // make sure a cable is connected before starting to connect
00369     while (!linkStatus()) 
00370     {
00371         wait(1.0f);
00372         WARN("Ethernet link not present. Check cable connection\n");
00373     }
00374         
00375     while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED) 
00376     {    
00377         if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)
00378             return; // don't reattempt to connect if credentials are wrong
00379             
00380         Thread red_thread(flashing_red);
00381 
00382         int timeout = getConnTimeout(++retryAttempt);
00383         WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
00384         
00385         // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
00386         //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)
00387         
00388         // this works - reset the system when the retry count gets to a threshold
00389         if (retryAttempt == 5)
00390             NVIC_SystemReset();
00391         else
00392             wait(timeout);
00393     }
00394 }
00395 
00396 
00397 int publish(MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTEthernet* ipstack)
00398 {
00399     MQTT::Message message;
00400     char* pubTopic = "iot-2/evt/status/fmt/json";
00401             
00402     char buf[250];
00403     //sends data from accelerator, temperature sensor,
00404     // joystick and potentiometers to the IBM quickstart page
00405     sprintf(buf,
00406      "{\"d\":{\"myName\":\"IoT mbed\",\"accelX\":%0.4f,\"accelY\":%0.4f,\"accelZ\":%0.4f,\"temp\
00407      ":%0.4f,\"joystick\":\"%s\",\"potentiometer1\":%0.4f,\"potentiometer2\":%0.4f}}",
00408             MMA.x(), MMA.y(), MMA.z(), sensor.temp(), joystickPos, ain1.read(), ain2.read());
00409     message.qos = MQTT::QOS0;
00410     message.retained = false;
00411     message.dup = false;
00412     message.payload = (void*)buf;
00413     message.payloadlen = strlen(buf);
00414     
00415     LOG("Publishing %s\n", buf);
00416     return client->publish(pubTopic, message);
00417 }
00418 
00419 
00420 char* getMac(EthernetInterface& eth, char* buf, int buflen)    // Obtain MAC address
00421 {   
00422     strncpy(buf, eth.getMACAddress(), buflen);
00423 
00424     char* pos;                                                 // Remove colons from mac address
00425     while ((pos = strchr(buf, ':')) != NULL)
00426         memmove(pos, pos + 1, strlen(pos) + 1);
00427     return buf;
00428 }
00429 
00430 
00431 void messageArrived(MQTT::MessageData& md)
00432 {
00433     MQTT::Message &message = md.message;
00434     char topic[md.topicName.lenstring.len + 1];
00435     
00436     sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data);
00437     
00438     LOG("Message arrived on topic %s: %.*s\n",  topic, message.payloadlen, message.payload);
00439           
00440     // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/
00441     char* start = strstr(topic, "/cmd/") + 5;
00442     int len = strstr(topic, "/fmt/") - start;
00443     
00444     if (memcmp(start, "blink", len) == 0)
00445     {
00446         char payload[message.payloadlen + 1];
00447         sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload);
00448     
00449         char* pos = strchr(payload, '}');
00450         if (pos != NULL)
00451         {
00452             *pos = '\0';
00453             if ((pos = strchr(payload, ':')) != NULL)
00454             {
00455                 int blink_rate = atoi(pos + 1);       
00456                 blink_interval = (blink_rate <= 0) ? 0 : (blink_rate > 50 ? 1 : 50/blink_rate);
00457             }
00458         }
00459     }
00460     else
00461         WARN("Unsupported command: %.*s\n", len, start);
00462 }
00463 
00464 PwmOut spkr(D6); //defines D6 as a PWM pin
00465 DigitalOut redled(LED_RED); //defines LED_RED as digital output pin
00466 DigitalOut greenled(LED_GREEN); //defines LED_GREEN as digital output pin
00467 int main()
00468 {    //if temperature is not within the set threshld, the the speaker gives 
00469   //alarm, which is set by PWM, also red LED of FRDM board turns on 
00470     if (sensor.temp()>23 || sensor.temp()<20) //sets temperature threshold
00471      {spkr.period(0.010); // set PWM period to 10 ms
00472       spkr=0.5; // set duty cycle to 50%
00473       greenled=!greenled; //turns green LED off and red LED on
00474      }
00475      // if temperature is within the threshold set, the the speaker will be turned
00476      //off and will not give an alarm, also the green LED of the FRDM board will turn on
00477      if (sensor.temp()<23 && sensor.temp()>20)
00478      {
00479       spkr=0.0; // set duty cycle to 50%
00480       redled=!redled; //turns red LED off and green LED on
00481      }
00482     quickstartMode = (strcmp(org, "quickstart") == 0);
00483 
00484     lcd.set_font((unsigned char*) Arial12x12);  // Set a nice font for the LCD screen
00485     
00486     led2 = LED2_OFF; // K64F: turn off the main board LED 
00487     displayMessage("Connecting");
00488     Thread yellow_thread(flashing_yellow);
00489     Thread menu_thread(menu_loop);  
00490     
00491     LOG("***** IBM IoT Client Ethernet Example *****\n");
00492     MQTTEthernet ipstack;
00493     ethernetInitialising = false;
00494     MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
00495     LOG("Ethernet Initialized\n"); 
00496     
00497     if (quickstartMode)
00498         getMac(ipstack.getEth(), id, sizeof(id));
00499         
00500     attemptConnect(&client, &ipstack);
00501     
00502     if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)    
00503     {
00504         red();
00505         while (true)
00506             wait(1.0); // Permanent failures - don't retry
00507     }
00508     
00509     if (!quickstartMode) 
00510     {
00511         int rc = 0;
00512         if ((rc = client.subscribe("iot-2/cmd/+/fmt/json", MQTT::QOS1, messageArrived)) != 0)
00513             WARN("rc from MQTT subscribe is %d\n", rc); 
00514     }
00515     
00516     blink_interval = 0;
00517     int count = 0;
00518     while (true)
00519     {
00520         if (++count == 100)
00521         {               // Publish a message every second
00522             if (publish(&client, &ipstack) != 0) 
00523                 attemptConnect(&client, &ipstack);   // if we have lost the connection
00524             count = 0;
00525         }
00526         
00527         if (blink_interval == 0)
00528             led2 = LED2_OFF;
00529         else if (count % blink_interval == 0)
00530             led2 = !led2;
00531         client.yield(10);  // allow the MQTT client to receive messages
00532     }
00533     } 
00534