Minimal project to send AT-commands from the USB serialport to the BG96.
Fork of Nucleo_NbIotBG96_A2_cloud_IBM by
Diff: main.cpp
- Revision:
- 0:ae6c6727b545
- Child:
- 1:a622606a49fd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Nov 17 17:23:30 2017 +0100 @@ -0,0 +1,440 @@ +/* BG96 NetworkSocketAPI Example Program + * Copyright (c) 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 "mbed.h" +#include "BG96Interface.h" +#include "TCPSocket.h" +#include "MQTTClient.h" +#include "MQTT_GSM.h" +#include <ctype.h> +//#include "x_nucleo_iks01a1.h" +#include "XNucleoIKS01A2.h" + +#include "BG96.h" + +//------------------------------------ +// Hyperterminal default configuration +// 9600 bauds, 8-bit data, no parity +//------------------------------------ +Serial pc(SERIAL_TX, SERIAL_RX); +DigitalOut myled(LED1); +bool quickstartMode = true; + +#define MQTT_MAX_PACKET_SIZE 300 +#define MQTT_MAX_PAYLOAD_SIZE 500 + + +#define ORG_QUICKSTART // comment to connect to play.internetofthings.ibmcloud.com +//#define SUBSCRIBE // uncomment to subscribe to broker msgs (not to be used with IBM broker) + + // Configuration values needed to connect to IBM IoT Cloud +#define BROKER_URL ".messaging.internetofthings.ibmcloud.com"; +#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 "iotsample-mbed-Nucleo" + #define TOPIC "iot-2/evt/status/fmt/json" +#else // not def ORG_QUICKSTART + #define ORG "pvko17" // connect to play.internetofthings.ibmcloud.com/ For a registered connection, replace with your org + #define ID "testtype_112233445566" // For a registered connection, replace with your id + #define AUTH_TOKEN "testtype_112233445566" // For a registered connection, replace with your auth-token + #define DEFAULT_TYPE_NAME "TestType" + #define TOPIC "iot-2/type/TestType/id/testtype_112233445566/evt/status/fmt/json" +#endif + +// network credential +//#define APN "web.omnitel.it" //VODAFONE apn definition's +#define APN "internet.wind" //WIND apn definition's +#define PASSW "" +#define USNAME "" + +#define TYPE DEFAULT_TYPE_NAME // For a registered connection, replace with your type +#define MQTT_PORT 1883 +#define MQTT_TLS_PORT 8883 +#define IBM_IOT_PORT MQTT_PORT + +char id[30] = ID; // mac without colons +char org[12] = ORG; +int connack_rc = 0; // MQTT connack return code +//const char* ip_addr = "11.12.13.14"; +//char* host_addr = "11.12.13.14"; +char sensor_id[50]; +char type[30] = TYPE; +char auth_token[30] = AUTH_TOKEN; // Auth_token is only used in non-quickstart mode +bool netConnecting = false; +int connectTimeout = 1000; +bool mqttConnecting = false; +bool netConnected = false; +bool connected = false; +int retryAttempt = 0; +char subscription_url[MQTT_MAX_PAYLOAD_SIZE]; + +#define SENSOR_ENABLED 1 +#define SENSOR_MODEL 2 + +#define FW_REV "1.0a" + +PressureSensor *pressure_sensor; +HumiditySensor *humidity_sensor; +TempSensor *temp_sensor1; + +MQTT::Message message; +MQTTString TopicName={TOPIC}; +MQTT::MessageData MsgData(TopicName, message); + + +//#if SENSOR_ENABLED + //#if SENSOR_MODEL == 2 + + /* Instantiate the expansion board */ + static XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(D14, D15, D4, D5); + + /* Retrieve the composing elements of the expansion board */ + static LSM303AGRMagSensor *magnetometer = mems_expansion_board->magnetometer; + static HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor; + static LPS22HBSensor *press_temp = mems_expansion_board->pt_sensor; + static LSM6DSLSensor *acc_gyro = mems_expansion_board->acc_gyro; + static LSM303AGRAccSensor *accelerometer = mems_expansion_board->accelerometer; + //#endif +//#endif + +void subscribe_cb(MQTT::MessageData & msgMQTT) { + char msg[MQTT_MAX_PAYLOAD_SIZE]; + msg[0]='\0'; + strncat (msg, (char*)msgMQTT.message.payload, msgMQTT.message.payloadlen); + printf ("--->>> subscribe_cb msg: %s\n\r", msg); +} + +int subscribe(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack) +{ + char* pubTopic = TOPIC; + return client->subscribe(pubTopic, MQTT::QOS1, subscribe_cb); +} + +int connect(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack) +{ + const char* iot_ibm = 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]; + + #ifdef ORG_QUICKSTART + sprintf(clientId, "d:%s:%s:%s", org, type, id); //@@ + #else + sprintf(clientId, "g:%s:%s:%s", org, type, id); //@@ + #endif + + sprintf(subscription_url, "%s.%s/#/device/%s/sensor/", org, "internetofthings.ibmcloud.com",id); + + netConnecting = true; + ipstack->open(&ipstack->getGSM()); + int rc = ipstack->connect(hostname, IBM_IOT_PORT, connectTimeout); + if (rc != 0) + { + //WARN("IP Stack connect returned: %d\n", rc); + return rc; + } + pc.printf ("--->TCP Connected\n\r"); + netConnected = true; + netConnecting = false; + + // MQTT Connect + mqttConnecting = true; + MQTTPacket_connectData data = MQTTPacket_connectData_initializer; + data.MQTTVersion = 3; + data.struct_version=0; + data.clientID.cstring = clientId; + + if (!quickstartMode) + { + data.username.cstring = "use-token-auth"; + data.password.cstring = auth_token; + } + if ((rc = client->connect(data)) == 0) + { + connected = true; + pc.printf ("--->MQTT Connected\n\r"); + #ifdef SUBSCRIBE + if (!subscribe(client, ipstack)) printf ("--->>>MQTT subscribed to: %s\n\r",TOPIC); + #endif + } + else { + //WARN("MQTT connect returned %d\n", rc); + } + if (rc >= 0) + connack_rc = rc; + mqttConnecting = false; + 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<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack) +{ + connected = false; + + while (connect(client, ipstack) != MQTT_CONNECTION_ACCEPTED) + { + if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) { + printf ("File: %s, Line: %d Error: %d\n\r",__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){ + pc.printf ("\n\n\rFAIL!! system reset!!\n\n\r"); + NVIC_SystemReset(); + } + else + wait(timeout); + } +} +float hum_global = 50.0; +uint32_t n_msg = 0; + +int publish(MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_GSM* ipstack) +{ + MQTT::Message message; + char* pubTopic = TOPIC; + + char buf[MQTT_MAX_PAYLOAD_SIZE]; + float temp, temp1, temp2, press, hum; + + #if SENSOR_ENABLED + pc.printf("reading sensors..."); + #if SENSOR_MODEL == 1 + temp_sensor1->GetTemperature(&temp); + pressure_sensor->GetPressure(&press); + humidity_sensor->GetHumidity(&hum); + #endif + + #if SENSOR_MODEL == 2 + hum_temp->get_temperature(&temp1); + hum_temp->get_humidity(&hum); + + press_temp->get_temperature(&temp2); + press_temp->get_pressure(&press); + temp = (temp1+temp2)/2; + #endif + + pc.printf(" DONE\r\n"); + #else + temp=25.5; + hum_global +=0.1; + if (hum_global>99.0) + hum_global = 50.0; + hum=hum_global; + press=999; + #endif + + #ifdef ORG_QUICKSTART + sprintf(buf, + "{\"d\":{\"ST\":\"Nucleo-IoT-mbed\",\"Temp\":%0.4f,\"Pressure\":%0.4f,\"Humidity\":%0.4f}}", + temp, press, hum); + #else + sprintf (buf, + "{\"%s\": {\"temp\":%0.4f,\"humidity\":%0.4f,\"pressure\":%0.4f,\"ambient\":0,\"uv\":0,\"accel_X\":0,\"accel_Y\":0,\"accel_Z\":0}}", + sensor_id, temp, hum, press); + #endif + + message.qos = MQTT::QOS0; + message.retained = false; + message.dup = false; + message.payload = (void*)buf; + message.payloadlen = strlen(buf); + + //LOG("Publishing %s\n\r", buf); + n_msg++; + pc.printf("Publishing V%s #%d %s\n\r", FW_REV, n_msg, buf); + return client->publish(pubTopic, message); +} + + +int loop_count = 0; +void test_sens(void); + +int main() +{ + const char * apn = APN; // Network must be visible otherwise it can't connect + const char * username = USNAME; + const char * password = PASSW; + BG96Interface bg96_if(D8, D2, false); + //sprintf(sensor_id,"%s",bg96_if.get_mac_address()); + //Timer tyeld; + + //change serial baud to 115200 + pc.baud(115200); + wait(0.1); + + myled=1; + //wait(0.5); + pc.printf("\r\n*************************************************"); + wait( 0.1 ); + pc.printf("\r\nAvnet Silica NbIotBG96 mbed-os application\r\n"); + wait( 0.1 ); + pc.printf("MBED online version %s\r\n", FW_REV); + wait( 0.1 ); + //pc.printf("\r\nwait for APN ready ...\r\n"); + //wait( 0.1 ); + + #if SENSOR_ENABLED + #if SENSOR_MODEL == 1 + DevI2C *i2c = new DevI2C(I2C_SDA, I2C_SCL); + i2c->frequency(400000); + + X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(i2c); + pressure_sensor = mems_expansion_board->pt_sensor; + temp_sensor1 = mems_expansion_board->ht_sensor; + humidity_sensor = mems_expansion_board->ht_sensor; + #endif + + #if SENSOR_MODEL == 2 + /* Enable all sensors */ + hum_temp->enable(); + press_temp->enable(); + //magnetometer->enable(); + //accelerometer->enable(); + //acc_gyro->enable_x(); + //acc_gyro->enable_g(); + #endif + #endif + + + quickstartMode=false; + if (strcmp(org, "quickstart") == 0){quickstartMode = true;} + MQTT_GSM ipstack(bg96_if, apn, username, password); + MQTT::Client<MQTT_GSM, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack); + if (quickstartMode){ + char mac[50]; // remove all : from mac + char *digit=NULL; + sprintf (id,"%s", ""); + sprintf (mac,"%s",ipstack.getGSM().get_mac_address()); + digit = strtok (mac,":"); + while (digit != NULL) + { + strcat (id, digit); + digit = strtok (NULL, ":"); + } + } + attemptConnect(&client, &ipstack); + if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) + { + while (true) + wait(1.0); // Permanent failures - don't retry + } + myled=0; + sprintf(sensor_id,"%s",bg96_if.get_mac_address()); + + while (true) + { + if (++loop_count == 60) + { + // Publish a message every 30 second + pc.printf("\n"); + myled=1; + if (publish(&client, &ipstack) != 0) { + myled=0; + attemptConnect(&client, &ipstack); // if we have lost the connection + } + //else + myled=0; + loop_count = 0; + } +// int start = tyeld.read_ms(); + client.yield(500); // allow the MQTT client to receive messages + pc.printf ("loop %d\r", (loop_count+1)); //: %d\n\r",tyeld.read_ms()-start); + + } + +} + + + + +/* Helper function for printing floats & doubles */ +static char *print_double(char* str, double v, int decimalDigits=2) +{ + int i = 1; + int intPart, fractPart; + int len; + char *ptr; + + /* prepare decimal digits multiplicator */ + for (;decimalDigits!=0; i*=10, decimalDigits--); + + /* calculate integer & fractinal parts */ + intPart = (int)v; + fractPart = (int)((v-(double)(int)v)*i); + + /* fill in integer part */ + sprintf(str, "%i.", intPart); + + /* prepare fill in of fractional part */ + len = strlen(str); + ptr = &str[len]; + + /* fill in leading fractional zeros */ + for (i/=10;i>1; i/=10, ptr++) { + if (fractPart >= i) { + break; + } + *ptr = '0'; + } + + /* fill in (rest of) fractional part */ + sprintf(ptr, "%i", fractPart); + + return str; +} + + + //for testing sensor board ... +void test_sens(void) +{ + while(1) + { + + float value1, value2; + char buffer1[32], buffer2[32]; + printf("\r\n"); + + hum_temp->get_temperature(&value1); + hum_temp->get_humidity(&value2); + printf("HTS221: [temp] %7s C, [hum] %s%%\r\n", print_double(buffer1, value1), print_double(buffer2, value2)); + + press_temp->get_temperature(&value1); + press_temp->get_pressure(&value2); + printf("LPS22HB: [temp] %7s C, [press] %s mbar\r\n", print_double(buffer1, value1), print_double(buffer2, value2)); + + wait(2); + + } +} +