BG96 Module MQTT client example using X-NUCLEO-IKS01A2

Dependencies:   mbed X_NUCLEO_IKS01A2 NetworkSocketAPI MQTT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* BG96 NetworkSocketAPI Example Program
00002  * Copyright (c) 2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "BG96Interface.h"
00019 #include "TCPSocket.h"
00020 #include "MQTTClient.h"
00021 #include "MQTT_GSM.h"
00022 #include <ctype.h>
00023 //#include "x_nucleo_iks01a1.h"
00024 #include "XNucleoIKS01A2.h"
00025 
00026 #include "BG96.h"
00027 
00028 #include "SLG46824Interface.h"
00029 #include "SLG46824_driver.h"
00030 
00031 //------------------------------------
00032 // Hyperterminal default configuration
00033 // 9600 bauds, 8-bit data, no parity
00034 //------------------------------------
00035 Serial pc(SERIAL_TX, SERIAL_RX); 
00036 DigitalOut myled(LED1);
00037 bool quickstartMode = true;    
00038 
00039 #define MQTT_MAX_PACKET_SIZE 300   
00040 #define MQTT_MAX_PAYLOAD_SIZE 500 
00041 
00042 
00043 #define ORG_QUICKSTART                                  // comment to connect to play.internetofthings.ibmcloud.com
00044 //#define SUBSCRIBE                                         // uncomment to subscribe to broker msgs (not to be used with IBM broker) 
00045 
00046  // Configuration values needed to connect to IBM IoT Cloud
00047 #define BROKER_URL ".messaging.internetofthings.ibmcloud.com";     
00048 #ifdef ORG_QUICKSTART
00049     #define ORG "quickstart"                                    // connect to quickstart.internetofthings.ibmcloud.com/ For a registered connection, replace with your org 
00050     #define ID ""
00051     #define AUTH_TOKEN ""
00052     #define DEFAULT_TYPE_NAME "iotsample-mbed-Nucleo"
00053     #define TOPIC  "iot-2/evt/status/fmt/json" 
00054 #else   // not def ORG_QUICKSTART
00055     #define ORG "pvko17"                                    // connect to play.internetofthings.ibmcloud.com/ For a registered connection, replace with your org
00056     #define ID "testtype_112233445566"              // For a registered connection, replace with your id
00057     #define AUTH_TOKEN "testtype_112233445566"  // For a registered connection, replace with your auth-token
00058     #define DEFAULT_TYPE_NAME "TestType"
00059     #define TOPIC   "iot-2/type/TestType/id/testtype_112233445566/evt/status/fmt/json" 
00060 #endif
00061 
00062 // network credential
00063 #define APN   "web.omnitel.it"  //VODAFONE apn definition's
00064 //#define APN           "internet.wind"     //WIND apn definition's
00065 #define PASSW  ""
00066 #define USNAME ""
00067 
00068 #define TYPE DEFAULT_TYPE_NAME       // For a registered connection, replace with your type
00069 #define MQTT_PORT 1883
00070 #define MQTT_TLS_PORT 8883
00071 #define IBM_IOT_PORT MQTT_PORT
00072     
00073 char id[30] = ID;                 // mac without colons  
00074 char org[12] = ORG;        
00075 int connack_rc = 0; // MQTT connack return code
00076 //const char* ip_addr = "11.12.13.14";
00077 //char* host_addr = "11.12.13.14";
00078 char sensor_id[50];
00079 char type[30] = TYPE;
00080 char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
00081 bool netConnecting = false;
00082 int connectTimeout = 1000;
00083 bool mqttConnecting = false;
00084 bool netConnected = false;
00085 bool connected = false;
00086 int retryAttempt = 0;
00087 char subscription_url[MQTT_MAX_PAYLOAD_SIZE];
00088 
00089 #define SENSOR_ENABLED      1
00090 #define SENSOR_MODEL            2
00091 
00092 #define FW_REV                      "1.0a"
00093 
00094 PressureSensor *pressure_sensor;
00095 HumiditySensor *humidity_sensor;
00096 TempSensor *temp_sensor1;
00097 
00098 MQTT::Message message;
00099 MQTTString TopicName={TOPIC};
00100 MQTT::MessageData MsgData(TopicName, message);
00101 
00102 /* Instantiate the expansion board */
00103 static XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(D14, D15, D4, D5);
00104 
00105 /* Retrieve the composing elements of the expansion board */
00106 static LSM303AGRMagSensor *magnetometer = mems_expansion_board->magnetometer;
00107 static HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor;
00108 static LPS22HBSensor *press_temp = mems_expansion_board->pt_sensor;
00109 static LSM6DSLSensor *acc_gyro = mems_expansion_board->acc_gyro;
00110 static LSM303AGRAccSensor *accelerometer = mems_expansion_board->accelerometer;
00111 
00112 void subscribe_cb(MQTT::MessageData & msgMQTT) {
00113     char msg[MQTT_MAX_PAYLOAD_SIZE];
00114     msg[0]='\0';
00115     strncat (msg, (char*)msgMQTT.message.payload, msgMQTT.message.payloadlen);
00116     printf ("--->>> subscribe_cb msg: %s\n\r", msg);
00117 }
00118 
00119 int subscribe(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
00120 {
00121     char* pubTopic = TOPIC;    
00122     return client->subscribe(pubTopic, MQTT::QOS1, subscribe_cb);
00123 }
00124 
00125 int connect(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
00126 { 
00127     const char* iot_ibm = BROKER_URL; 
00128 
00129     
00130     char hostname[strlen(org) + strlen(iot_ibm) + 1];
00131     sprintf(hostname, "%s%s", org, iot_ibm);
00132     
00133 
00134     // Construct clientId - d:org:type:id
00135     char clientId[strlen(org) + strlen(type) + strlen(id) + 5];  
00136     
00137         #ifdef ORG_QUICKSTART
00138     sprintf(clientId, "d:%s:%s:%s", org, type, id);  //@@
00139         #else
00140         sprintf(clientId, "g:%s:%s:%s", org, type, id);  //@@
00141         #endif
00142     
00143     sprintf(subscription_url, "%s.%s/#/device/%s/sensor/", org, "internetofthings.ibmcloud.com",id);
00144         
00145     netConnecting = true;
00146     ipstack->open(&ipstack->getGSM());
00147     int rc = ipstack->connect(hostname, IBM_IOT_PORT, connectTimeout);    
00148     if (rc != 0)
00149     {
00150         //WARN("IP Stack connect returned: %d\n", rc);    
00151         return rc;
00152     }
00153     pc.printf ("--->TCP Connected\n\r");
00154     netConnected = true;
00155     netConnecting = false;
00156 
00157     // MQTT Connect
00158     mqttConnecting = true;
00159     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
00160     data.MQTTVersion = 3;
00161     data.struct_version=0;
00162     data.clientID.cstring = clientId;
00163  
00164     if (!quickstartMode) 
00165     {        
00166         data.username.cstring = "use-token-auth";
00167         data.password.cstring = auth_token;
00168     }   
00169     if ((rc = client->connect(data)) == 0) 
00170     {       
00171         connected = true;
00172         pc.printf ("--->MQTT Connected\n\r");
00173     #ifdef SUBSCRIBE
00174         if (!subscribe(client, ipstack)) printf ("--->>>MQTT subscribed to: %s\n\r",TOPIC);
00175     #endif           
00176     }
00177     else {
00178         //WARN("MQTT connect returned %d\n", rc);        
00179     }
00180     if (rc >= 0)
00181         connack_rc = rc;
00182     mqttConnecting = false;
00183     return rc;
00184 }
00185 
00186 int getConnTimeout(int attemptNumber)
00187 {  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
00188    // after 20 attempts, retry every 10 minutes
00189     return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
00190 }
00191 
00192 void attemptConnect(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
00193 {
00194     connected = false;
00195            
00196     while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED) 
00197     {    
00198         if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) {
00199             printf ("File: %s, Line: %d Error: %d\n\r",__FILE__,__LINE__, connack_rc);        
00200             return; // don't reattempt to connect if credentials are wrong
00201         } 
00202         int timeout = getConnTimeout(++retryAttempt);
00203         //WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
00204         
00205         // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
00206         //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)        
00207         // this works - reset the system when the retry count gets to a threshold
00208         if (retryAttempt == 5){
00209                         pc.printf ("\n\n\rFAIL!! system reset!!\n\n\r");
00210             NVIC_SystemReset();
00211                 }
00212         else
00213             wait(timeout);
00214     }
00215 }
00216 float hum_global = 50.0;
00217 uint32_t n_msg = 0;
00218 
00219 int publish(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack)
00220 {
00221     MQTT::Message message;
00222     char* pubTopic = TOPIC;
00223             
00224     char buf[MQTT_MAX_PAYLOAD_SIZE];
00225     float temp, temp1, temp2, press, hum;
00226     
00227     #if SENSOR_ENABLED
00228         pc.printf("A02 reading sensors...");
00229 
00230         hum_temp->get_temperature(&temp1);
00231             hum_temp->get_humidity(&hum);
00232    
00233             press_temp->get_temperature(&temp2);
00234             press_temp->get_pressure(&press);
00235             temp = (temp1+temp2)/2;
00236         
00237     pc.printf(" DONE\r\n");
00238     #else
00239         temp=25.5;
00240         hum_global +=0.1;
00241         if (hum_global>99.0)
00242             hum_global = 50.0;
00243         hum=hum_global;
00244         press=999;
00245     #endif
00246         
00247     #ifdef ORG_QUICKSTART
00248     sprintf(buf,
00249      "{\"d\":{\"ST\":\"Nucleo-IoT-mbed\",\"Temp\":%0.4f,\"Pressure\":%0.4f,\"Humidity\":%0.4f}}",
00250               temp, press, hum);
00251     #else
00252         sprintf (buf, 
00253         "{\"%s\": {\"temp\":%0.4f,\"humidity\":%0.4f,\"pressure\":%0.4f,\"ambient\":0,\"uv\":0,\"accel_X\":0,\"accel_Y\":0,\"accel_Z\":0}}", 
00254                 sensor_id, temp, hum, press);
00255     #endif
00256         
00257         message.qos = MQTT::QOS0;
00258     message.retained = false;
00259     message.dup = false;
00260     message.payload = (void*)buf;
00261     message.payloadlen = strlen(buf);
00262     
00263         //LOG("Publishing %s\n\r", buf);
00264         n_msg++;
00265     pc.printf("Publishing V%s #%d %s\n\r", FW_REV, n_msg, buf);
00266     return client->publish(pubTopic, message);
00267 } 
00268     
00269 
00270 int loop_count = 0;  
00271 void test_sens(void);
00272 bool slg_active =  false;
00273 
00274 int main()
00275 {
00276         uint8_t SL46824_I2C_addr = 0;
00277     const char * apn = APN; // Network must be visible otherwise it can't connect
00278     const char * username = USNAME;
00279         const char * password = PASSW;
00280         SLG46824Interface sl_if(A4, A5);
00281     BG96Interface bg96_if(D8, D2, false);
00282         //sprintf(sensor_id,"%s",bg96_if.get_mac_address()); 
00283         //Timer tyeld;
00284     
00285         //change serial baud to 115200
00286         pc.baud(115200);
00287         //wait(0.1);
00288     
00289         wait(0.5);
00290 
00291       slg_active = sl_if.get_i2c_address(&SL46824_I2C_addr);
00292         
00293         if(slg_active == true)
00294         {
00295             //sl_if.startup();      //only for debug..
00296             sl_if.hw_set();             //not needed if SLG46824 already programmed
00297 
00298         }
00299 
00300     myled=1;
00301         //wait(0.5);
00302     pc.printf("\r\n*************************************************");
00303       wait( 0.1 ); 
00304         pc.printf("\r\nAvnet Silica NbIotBG96 A02 mbed-os application\r\n");  
00305     wait( 0.1 );   
00306     pc.printf("MBED online version %s\r\n", FW_REV);     
00307     wait( 0.1 );
00308     //pc.printf("\r\nwait for APN ready ...\r\n");  
00309     //wait( 0.1 );     
00310     
00311      #if SENSOR_ENABLED
00312                 /* Enable all sensors */
00313                 hum_temp->enable();
00314                 press_temp->enable();
00315                 //magnetometer->enable();
00316                 //accelerometer->enable();
00317                 //acc_gyro->enable_x();
00318                 //acc_gyro->enable_g();
00319      #endif
00320 
00321 
00322    quickstartMode=false;
00323    if (strcmp(org, "quickstart") == 0){quickstartMode = true;}
00324    MQTT_GSM ipstack(bg96_if, apn, username, password);
00325    MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
00326    if (quickstartMode){
00327         char mac[50];  // remove all : from mac
00328         char *digit=NULL;
00329         sprintf (id,"%s", "");                
00330         sprintf (mac,"%s",ipstack.getGSM().get_mac_address()); 
00331         digit = strtok (mac,":");
00332         while (digit != NULL)
00333         {
00334             strcat (id, digit);
00335             digit = strtok (NULL, ":");
00336         }     
00337    }
00338    attemptConnect(&client, &ipstack);
00339    if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD)    
00340    {
00341       while (true)
00342       wait(1.0); // Permanent failures - don't retry
00343    }
00344         myled=0;      
00345         sprintf(sensor_id,"%s",bg96_if.get_mac_address()); 
00346 
00347     while (true)
00348     {
00349         if (++loop_count == 60)
00350         {   
00351                         // Publish a message every 30 second
00352                         pc.printf("\n");
00353                         myled=1;
00354             if (publish(&client, &ipstack) != 0) { 
00355                 myled=0;
00356                 attemptConnect(&client, &ipstack);   // if we have lost the connection                
00357             } 
00358                         //else 
00359                         myled=0;
00360             loop_count = 0;
00361         }        
00362 //      int start = tyeld.read_ms();
00363         client.yield(500);  // allow the MQTT client to receive messages
00364                 pc.printf ("loop %d\r", (loop_count+1));        //: %d\n\r",tyeld.read_ms()-start);
00365 
00366     }
00367 
00368 }
00369 
00370 
00371 
00372 
00373 /* Helper function for printing floats & doubles */
00374 static char *print_double(char* str, double v, int decimalDigits=2)
00375 {
00376   int i = 1;
00377   int intPart, fractPart;
00378   int len;
00379   char *ptr;
00380 
00381   /* prepare decimal digits multiplicator */
00382   for (;decimalDigits!=0; i*=10, decimalDigits--);
00383 
00384   /* calculate integer & fractinal parts */
00385   intPart = (int)v;
00386   fractPart = (int)((v-(double)(int)v)*i);
00387 
00388   /* fill in integer part */
00389   sprintf(str, "%i.", intPart);
00390 
00391   /* prepare fill in of fractional part */
00392   len = strlen(str);
00393   ptr = &str[len];
00394 
00395   /* fill in leading fractional zeros */
00396   for (i/=10;i>1; i/=10, ptr++) {
00397     if (fractPart >= i) {
00398       break;
00399     }
00400     *ptr = '0';
00401   }
00402 
00403   /* fill in (rest of) fractional part */
00404   sprintf(ptr, "%i", fractPart);
00405 
00406   return str;
00407 }
00408 
00409 
00410         //for testing sensor board ...
00411 void test_sens(void)
00412 {   
00413         while(1)
00414         {
00415             
00416               float value1, value2;
00417               char buffer1[32], buffer2[32];
00418               printf("\r\n");
00419 
00420               hum_temp->get_temperature(&value1);
00421                 hum_temp->get_humidity(&value2);
00422                 printf("HTS221: [temp] %7s C,   [hum] %s%%\r\n", print_double(buffer1, value1), print_double(buffer2, value2));
00423     
00424                 press_temp->get_temperature(&value1);
00425                 press_temp->get_pressure(&value2);
00426                 printf("LPS22HB: [temp] %7s C, [press] %s mbar\r\n", print_double(buffer1, value1), print_double(buffer2, value2));
00427                 
00428                 wait(2);
00429             
00430         }
00431 }
00432