IBM IoT Client WiFi example using Murata Type-YD WiFi module

Dependencies:   C12832_fix LM75B MMA7660 MQTT PowerControl SNICInterface mbed-rtos mbed

Fork of IBMIoTClientEthernetExample by Toyomasa Watarai

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