This software setup a central node of a star topology network

Dependencies:   MQTT target_st_bluenrg

Fork of ble-star-mbed by Lorenzo Invidia

Revision:
4:4af40af2530e
Parent:
3:3f35e80ed848
--- a/source/main.cpp	Tue Mar 13 16:31:07 2018 +0000
+++ b/source/main.cpp	Sat Mar 31 15:10:54 2018 +0000
@@ -1,19 +1,3 @@
-/* mbed Microcontroller Library
- * Copyright (c) 2006-2015 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
 #include <events/mbed_events.h>
 #include <mbed.h>
 #include "ble/BLE.h"
@@ -22,13 +6,278 @@
 #include <UUID.h>
 #include <BleMasterService.h>
 #include <BleSlaveService.h>
+#include <string.h>
+#include "easy-connect.h"
+#include "MQTTClient.h"
+#include "MQTTmbed.h"
+#include "MQTTNetwork.h"
+
+/*----------------------------------------------------------------------------*/
+
+/* Enable/Disable WiFi (1 = WiFi Enabled, 0 = WiFi Disabled) */
+#define ENABLE_WIFI 1
+
+/****  System configuration define   ****/
+#define ORG_QUICKSTART           // comment to connect to play.internetofthings.ibmcloud.com
+#ifndef ORG_QUICKSTART
+//#define TLS_EN                   // uncomment to add TLS to NON quickstart connections
+#endif
+
+#ifdef TLS_EN     // Digicert Root Certificate in PEM format (from IBM website)
+const char SSL_CA_PEM[] ="-----BEGIN CERTIFICATE-----\n"
+"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"
+"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
+"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"
+"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
+"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"
+"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"
+"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"
+"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"
+"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"
+"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"
+"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"
+"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"
+"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"
+"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"
+"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"
+"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"
+"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"
+"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"
+"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"
+"-----END CERTIFICATE-----\n";
+#endif
+
+
+
+static bool quickstartMode = true;      // set to false to connect with authentication tocken
+
+#define MQTT_MAX_PACKET_SIZE 400
+#define MQTT_MAX_PAYLOAD_SIZE 300
+
+
+
+// Configuration values needed to connect to IBM IoT Cloud
+#ifdef  ORG_QUICKSTART
+#define ORG "quickstart"     // connect to quickstart.internetofthings.ibmcloud.com/ For a registered connection, replace with your org
+#define ID ""
+#define AUTH_TOKEN ""
+#define DEFAULT_TYPE_NAME "sensor"
+#define DEFAULT_PORT  MQTT_PORT
+
+#else   // not def ORG_QUICKSTART
+#define ORG MQTT_ORG_ID            // connect to ORG.internetofthings.ibmcloud.com/ For a registered connection, replace with your org
+#define ID MQTT_DEVICE_ID          // For a registered connection is your device id
+#define AUTH_TOKEN  MQTT_DEVICE_PASSWORD  // For a registered connection is a device auth-token
+#define DEFAULT_TYPE_NAME  MQTT_DEVICE_TYPE  // For a registered connection is device type
+
+#ifdef  TLS_EN
+#define DEFAULT_PORT  MQTT_TLS_PORT
+#else
+#define DEFAULT_PORT  MQTT_PORT
+
+#endif
+#endif
+
+
+
+#define TYPE DEFAULT_TYPE_NAME       // For a registered connection, replace with your type
+#define IBM_IOT_PORT  DEFAULT_PORT
+
+#define MAXLEN_MBED_CONF_APP_WIFI_SSID       32  // same as WIFI_SSID_MAX_LEN in easy_connect
+#define MAXLEN_MBED_CONF_APP_WIFI_PASSWORD   64  // same as WIFI_PASSWORD_MAX_LEN
+
+static char     id[30] = ID;                 // mac without colons
+static char     org[12] = ORG;
+static int      connack_rc = 0; // MQTT connack return code
+static char     type[30] = TYPE;
+static char     auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode
+static bool     netConnecting = false;
+static bool     mqttConnecting = false;
+static bool     netConnected = false;
+static bool     connected = false;
+static int      retryAttempt = 0;
+static char     subscription_url[MQTT_MAX_PAYLOAD_SIZE];
+static char     ssid[MAXLEN_MBED_CONF_APP_WIFI_SSID];     // Network must be visible otherwise it can't connect
+static char     seckey[MAXLEN_MBED_CONF_APP_WIFI_PASSWORD];
+
+MQTT::Client<MQTTNetwork, Countdown, MQTT_MAX_PACKET_SIZE> *pClient;
 
 const char NAME_BLESTAR1[] =    "BleStar1";
 
+uint8_t wifi_status;
+
+uint8_t wifi_data[256];
+uint8_t new_data = 0;
+uint8_t *data;
+uint8_t wifi_present;
+uint8_t start_bnrg;
+extern  PeripheralDevices_t perDevs;
+uint8_t json_buffer[512];
+
+/*----------------------------------------------------------------------------*/
+
+
+
+/* Prepare JSON packet with sensors data */
+void prepare_json_pkt (uint8_t * buffer){
+  char tempbuff[256];
+
+  strcpy((char *)buffer,"{\"d\":{\"ST\":\"BLEStar\"");     
+  sprintf(tempbuff, ",%s", data);
+  strcat((char *)buffer,tempbuff); 
+  strcat((char *)buffer,"}}");
+  
+  return;
+}
 /*----------------------------------------------------------------------------*/
 
 
 
+/* Connect the broker - return the CONNACK*/
+int connect(MQTT::Client<MQTTNetwork, Countdown, MQTT_MAX_PACKET_SIZE> * client, MQTTNetwork *mqttNetwork, NetworkInterface* network)
+{
+    const char* iot_ibm = MQTT_BROKER_URL;
+    char hostname[strlen(org) + strlen(iot_ibm) + 1];
+
+    sprintf(hostname, "%s%s", org, iot_ibm);
+    // Construct clientId - d:org:type:id
+    char clientId[strlen(org) + strlen(type) + strlen(id) + 5];
+    sprintf(clientId, "d:%s:%s:%s", org, type, id);
+    sprintf(subscription_url, "%s.%s/#/device/%s/%s/", org, "internetofthings.ibmcloud.com", id, TYPE);
+
+    // Network debug statements
+    printf("\r\n=====================================");
+    printf("\r\nNucleo IP ADDRESS: %s\n", network->get_ip_address());
+    printf("\r\nNucleo MAC ADDRESS: %s\n", network->get_mac_address());
+    printf("\r\nServer Hostname: %s port: %d\n", hostname, IBM_IOT_PORT);
+    printf("\r\nClient ID: %s\n", clientId);
+    printf("\r\nTopic: %s\n",MQTT_TOPIC);
+    printf("\r\nSubscription URL: %s", subscription_url);
+    printf("\r\n=====================================\r\n");
+    netConnecting = true;
+
+
+
+#ifdef ORG_QUICKSTART
+    int tls = TLS_OFF;
+    const char * cert = NULL;
+    unsigned int sizeof_cert = 0;
+    
+#else  // if !QUICKSTART possible to connect with TLS or not
+#ifdef TLS_EN
+    int tls = TLS_ON;
+    const char * cert = SSL_CA_PEM;
+    unsigned int sizeof_cert = sizeof(SSL_CA_PEM);
+
+#else
+    int tls = TLS_OFF;
+    const char * cert = 0;
+    unsigned int sizeof_cert = 0;
+
+#endif
+#endif
+
+
+    //Return code
+    int rc = mqttNetwork->connect(hostname, IBM_IOT_PORT, tls, cert, sizeof_cert);
+    if (rc != 0)
+    {
+        printf("\r\nrc from TCP connect is %d\n", rc);
+        return rc;
+    }
+    netConnected = true;
+    netConnecting = false;
+
+
+    // MQTT Connect
+    mqttConnecting = true;
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+    data.MQTTVersion = 4;
+    data.struct_version=0;
+    data.clientID.cstring = clientId;
+    data.keepAliveInterval = 0; //MQTT_KEEPALIVE;  // in Sec
+    if (!quickstartMode){
+        data.username.cstring = "use-token-auth";
+        data.password.cstring = auth_token;
+        printf ("\r\nAutToken: %s\n", auth_token);
+    }
+    if ((rc = client->connect(data)) != MQTT::SUCCESS) {
+        printf("\r\nrc from MQTT connect is %d\n", rc);
+        connack_rc = rc;
+        return rc;
+    }
+    connected = true;
+    printf ("\r\n--->MQTT Connected\n");
+
+    mqttConnecting = false;
+    connack_rc = rc;
+    return rc;
+}
+/*----------------------------------------------------------------------------*/
+
+
+
+int getConnTimeout(int attemptNumber)
+{  // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
+   // after 20 attempts, retry every 10 minutes
+    return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
+}
+/*----------------------------------------------------------------------------*/
+
+
+
+void attemptConnect(MQTT::Client<MQTTNetwork, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTTNetwork *mqttNetwork, NetworkInterface* network)
+{
+    connected = false;
+
+    while (connect(client, mqttNetwork, network) != MQTT_CONNECTION_ACCEPTED)
+    {
+        if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) {
+            printf ("\r\nError MQTT_BAD_USERNAME_OR_PASSWORDFile: %s, Line: %d Error: %d \n",__FILE__,__LINE__, connack_rc);
+            return; // don't reattempt to connect if credentials are wrong
+        }
+        int timeout = getConnTimeout(++retryAttempt);
+        WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);
+
+        // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
+        //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)
+        // this works - reset the system when the retry count gets to a threshold
+        if (retryAttempt == 5)
+            NVIC_SystemReset();
+        else
+            wait(timeout);
+    }
+}
+/*----------------------------------------------------------------------------*/
+
+
+/* Method to publish data to client (sending data to broker) */
+int publish(MQTT::Client<MQTTNetwork, Countdown, MQTT_MAX_PACKET_SIZE>* client){
+    //printf("\r\npublish");//DEBUG
+
+    MQTT::Message message;
+    const char* pubTopic = MQTT_TOPIC;
+
+
+    if (!client->isConnected()){ 
+        printf ("\r\npublish failed: MQTT disconnected\n"); 
+        return MQTT::FAILURE; 
+    }
+    
+            
+    message.qos = MQTT::QOS0;               // quality of service 0 default
+    message.retained = false;               // (false) new clients will not receive past data
+    message.dup = false;                    // (false) no duplicated message
+    message.payload = (void*)json_buffer;   // DATA to be sent
+    message.payloadlen = strlen((const char *)(json_buffer));
+
+
+    return client->publish(pubTopic, message);
+}
+/*----------------------------------------------------------------------------*/
+
+
 
 /* scheduleBleEventsProcessing */
 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
@@ -36,6 +285,10 @@
     eventQ.call(Callback<void()>(&ble, &BLE::processEvents));
 }
 /*----------------------------------------------------------------------------*/
+
+
+
+
 /* Complete the initialization of ble module */
 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params){
   
@@ -59,12 +312,6 @@
         return;
     }
     
-    printf("\r\nBLE Init Completed\n");
-    
-    
-    /* notification */
-    //ble.gattServer().onUpdatesEnabled(onUpdatesEnabledCallback);
-    //ble.gattServer().onUpdatesDisabled(onUpdatesDisabledCallback);
     
     /* notification + attr writing */
     ble.gattServer().onDataWritten(AttributeModified_CB);
@@ -80,7 +327,7 @@
     ble.gap().onDisconnection(disconnectionCallback);    
     /* connection */
     ble.gap().onConnection(connectionCallback);
-    ble.gap().setScanParams(400, 200);    //(scanInterval,scanWindow)ms
+    ble.gap().setScanParams(200, 200);    //(scanInterval,scanWindow)ms
     ble.gap().setScanTimeout(0x0004);     //stop scanning after N sec
     ble.gap().onTimeout(onStopScan);      //callback when scan stops
     
@@ -102,20 +349,48 @@
     
     addAllServices();
     printMacAddress();
-    
-    
-    /* Start connection, service/chars discovery and enable notification */
-    connectionProcess();
-    
-    /* Start advertising from this point */
-    //setSlaveDiscoverable();//DEBUG_ONLY
 
 }
 /*----------------------------------------------------------------------------*/
 
 
 
-void onBleInitError(BLE &ble, ble_error_t error) {}
+void onBleInitError(BLE &ble, ble_error_t error){}
+/*----------------------------------------------------------------------------*/
+
+
+
+void mainFunc(void){
+    
+    if ((wifi_present) && (perDevs.status != NOTIFICATIONS_DATA_READ)){
+        
+        if((new_data)){
+            prepare_json_pkt(json_buffer);
+        }//if-new_data
+        start_bnrg = 1;
+        
+    }else{
+        start_bnrg = 1;
+        if (perDevs.status != NOTIFICATIONS_DATA_READ) {
+            HAL_Delay(1000);
+        }
+    }//if-else
+    
+    
+    if (start_bnrg){
+        eventQ.call(connectionProcess);
+    }
+}
+/*----------------------------------------------------------------------------*/
+
+
+void MQTTpublish(){
+    
+    if((new_data)){
+        /* publish every 5 seconds */
+        publish(pClient);            
+    }//if-new_data    
+}
 /*----------------------------------------------------------------------------*/
 
 
@@ -124,20 +399,73 @@
 {
     printf("\r\n\n/*******************************************************\n");
     printf("\r*                                                      *\n");
-    printf("\r*      FP-NET-BLESTAR1 (MBED) Expansion Software       *\n");
+    printf("\r*           BLESTAR1 MBED Expansion Software           *\n");
     printf("\r*                                                      *\n");
     printf("\r*******************************************************/\n\n\n");
   
+  
+#if ENABLE_WIFI
+    wifi_present = ENABLE_WIFI;
+    printf("\r\nWi-Fi Enabled!\n");
+    printf("\rTo edit SSID and/or Password please refer to mbed_app.json file\n");
+
+    /* QUICK START MODE */
+    quickstartMode=false;
+    if (strcmp(org, "quickstart") == 0){
+        quickstartMode = true;
+    }
+    
+    /* Connect network */
+    printf("\r\nConnecting to Access Point...\n\n");
+    NetworkInterface * network = easy_connect(true); // SSID and pw in .jason
+    if (!network){
+        printf("\r\nError easy_connect\n");
+    }
+            
+    /* MQTT CONFIG*/
+    printf("\r\nConfiguring MQTT network...\n");
+    MQTTNetwork mqttNetwork(network);
+    MQTT::Client<MQTTNetwork, Countdown, MQTT_MAX_PACKET_SIZE> client(mqttNetwork);
+    pClient = &client;
+    
+    
+    if (quickstartMode){
+        char mac[50];  // remove all : from mac
+        char *digit=NULL;
+        sprintf (id,"%s", "");
+        sprintf (mac,"%s",network->get_mac_address());
+        digit = strtok (mac,":");
+        while (digit != NULL)
+        {
+            strcat (id, digit);
+            digit = strtok (NULL, ":");
+        }
+    }//if-quickstart
+            
+    /* Connect MQTT broker  */
+    printf("\r\nConnecting MQTT broker...\n");
+    attemptConnect(&client, &mqttNetwork, network);
+    
+#else
+    printf("\r\nWi-Fi Disabled!\n");    
+
+#endif  
+  
+    printf("\r\n\nStarting the BLE module...\n");
+  
     /* Create the ble instance */
     BLE &ble = BLE::Instance();
     
     ble.onEventsToProcess(scheduleBleEventsProcessing);
     
-    /* Uncommenting to debug the status*/
+    /* Uncomment to debug the status*/
     //eventQ.call_every(20000, checkStatus);
     
     ble.init(bleInitComplete);   
     
+    /* Start main method */
+    eventQ.call_every(100, mainFunc);
+    eventQ.call_every(1000, MQTTpublish);
     
     //dispatch events
     eventQ.dispatch_forever();