Peter Ferland / Mbed OS mDot-IKS01A2

Dependencies:   MTS_X_NUCLEO_IKS01A2 libmDot-mbed5

Fork of mDot-IKS01A1 by Peter Ferland

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "mDot.h"
00003 #include "ChannelPlan.h"
00004 #include "XNucleoIKS01A2.h"
00005 #include "dot_util.h"
00006 #include "RadioEvent.h"
00007 #include <cmath>
00008 
00009 #define TTN
00010 
00011 #if !defined(CHANNEL_PLAN)
00012 #define CHANNEL_PLAN CP_US915
00013 #endif
00014 
00015 // mDot UDK board demo with X-NUCLEO-IKS01A1 sensor card
00016 // For more examples see the Dot-Examples project:
00017 // https://developer.mbed.org/teams/MultiTech/code/Dot-Examples/
00018 
00019 // This triggers an I2C issue in mbed-os 5.1.5
00020 // Use any other revision to compile. (Tested with libmDot-dev/mbed-os 5.2.2
00021 //#define ACTILITY
00022 #ifdef ACTILITY
00023 // Network Id for Senet public network
00024 static uint8_t network_id[] = {0xF0, 0x3D, 0x29,0xAC,0x71,0x00,0x00, 0x00};
00025 static uint8_t network_key[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
00026 static uint8_t frequency_sub_band = 0;
00027 static bool public_network = true;
00028 #elif defined(SENET)
00029 // Network Id for Senet public network
00030 static uint8_t network_id[] = {0x00,0x25,0x0C,0x00,0x00,0x01,0x00,0x01};
00031 // Register at or Sign in to http://portal.senetco.com/ and register your NodeId to receive your AppId
00032 // 
00033 static uint8_t network_key[] =  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
00034 // 1 For Senet, configurable on your Conduit
00035 static uint8_t frequency_sub_band = 1;
00036 // True for Senet, false for your Conduit.
00037 static bool public_network = true;
00038 #elif defined(TTN)
00039 // Network Id for TheThingsNetwork public network
00040 static uint8_t network_id[] = {0x70,0xB3,0xD5,0x7E,0xD0,0x00,0x98,0xE6}; 
00041 // Network Key is known as "App Key" in TTN console
00042 static uint8_t network_key[] =  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
00043 // FSB if supported by region
00044 static uint8_t frequency_sub_band = 1;
00045 
00046 static bool public_network = true;
00047 
00048 #else
00049 //Replace with settings on your Conduit
00050 static std::string network_name = "TestTest";
00051 static std::string network_passphrase = "TestTest"; 
00052 // 1 For Senet, configurable on your Conduit
00053 static uint8_t frequency_sub_band = 1;
00054 // True for Senet, false for your Conduit.
00055 static bool public_network = false;
00056 #endif
00057 static uint8_t ack = 0;
00058 static uint8_t tx_datarate = lora::DR_3;
00059 
00060 // deepsleep consumes slightly less current than sleep
00061 // in sleep mode, IO state is maintained, RAM is retained, and application will resume after waking up
00062 // in deepsleep mode, IOs float, RAM is lost, and application will start from beginning after waking up
00063 // if deep_sleep == true, device will enter deepsleep mode
00064 static bool deep_sleep = false;
00065 
00066 mDot *dot = NULL;
00067 lora::ChannelPlan* plan = NULL;
00068 
00069 int main()
00070 {
00071     Serial pc(USBTX, USBRX);
00072     
00073     /* Instantiate the expansion board */
00074     XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(I2C_SDA, I2C_SCL, PC_1);
00075     
00076     /* Retrieve the composing elements of the expansion board */
00077     /* Retrieve the composing elements of the expansion board */
00078 //    LSM303AGRMagSensor *magnetometer = mems_expansion_board->magnetometer;
00079 //    HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor;
00080 //    LPS22HBSensor *press_temp = mems_expansion_board->pt_sensor;
00081 //    LSM6DSLSensor *acc_gyro = mems_expansion_board->acc_gyro;
00082 //    LSM303AGRAccSensor *accelerometer = mems_expansion_board->accelerometer;
00083     GyroSensor *gyroscope = mems_expansion_board->acc_gyro;
00084     mems_expansion_board->acc_gyro->enable_g();
00085     MotionSensor *accelerometer = mems_expansion_board->accelerometer;
00086     mems_expansion_board->accelerometer->enable();
00087     MagneticSensor *magnetometer = mems_expansion_board->magnetometer;
00088     mems_expansion_board->magnetometer->enable();
00089     HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor;
00090     mems_expansion_board->ht_sensor->enable();
00091     PressureSensor *pressure_sensor = mems_expansion_board->pt_sensor;
00092     mems_expansion_board->pt_sensor->enable();
00093     TempSensor *temp_sensor1 = mems_expansion_board->ht_sensor;
00094     TempSensor *temp_sensor2 = mems_expansion_board->pt_sensor;
00095     
00096     // Custom event handler for automatically displaying RX data
00097     RadioEvent events;
00098     pc.baud(115200);
00099 #if CHANNEL_PLAN == CP_US915
00100     plan = new lora::ChannelPlan_US915();
00101 #elif CHANNEL_PLAN == CP_AU915
00102     plan = new lora::ChannelPlan_AU915();
00103 #elif CHANNEL_PLAN == CP_EU868
00104     plan = new lora::ChannelPlan_EU868();
00105 #elif CHANNEL_PLAN == CP_KR920
00106     plan = new lora::ChannelPlan_KR920();
00107 #elif CHANNEL_PLAN == CP_AS923
00108     plan = new lora::ChannelPlan_AS923();
00109 #elif CHANNEL_PLAN == CP_AS923_JAPAN
00110     plan = new lora::ChannelPlan_AS923_Japan();
00111 #elif CHANNEL_PLAN == CP_IN865
00112     plan = new lora::ChannelPlan_IN865();
00113 #endif
00114     /* Initialize mDot */
00115     dot = mDot::getInstance(plan);
00116 
00117     //dot->setAdr(true);
00118     mts::MTSLog::setLogLevel(mts::MTSLog::INFO_LEVEL);
00119     dot->setEvents(&events);
00120     
00121 
00122     if (!dot->getStandbyFlag()) {
00123         logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);
00124         // start from a well-known state
00125         logInfo("defaulting Dot configuration");
00126         dot->resetConfig();
00127         dot->resetNetworkSession();
00128         
00129         // update configuration if necessary
00130         // in AUTO_OTA mode the session is automatically saved, so saveNetworkSession and restoreNetworkSession are not needed
00131         if (dot->getJoinMode() != mDot::AUTO_OTA) {
00132             logInfo("changing network join mode to AUTO_OTA");
00133             if (dot->setJoinMode(mDot::AUTO_OTA) != mDot::MDOT_OK) {
00134                 logError("failed to set network join mode to AUTO_OTA");
00135             }
00136         }
00137         
00138         uint32_t current_tx_datarate = dot->getTxDataRate();
00139         if (current_tx_datarate != tx_datarate) {
00140             logInfo("changing TX datarate from %u to %u", current_tx_datarate, tx_datarate);
00141             if (dot->setTxDataRate(tx_datarate) != mDot::MDOT_OK) {
00142                 logError("failed to set TX datarate to %u", tx_datarate);
00143             }
00144         }
00145         // in OTA and AUTO_OTA join modes, the credentials can be passed to the library as a name and passphrase or an ID and KEY
00146         // only one method or the other should be used!
00147         // network ID = crc64(network name)
00148 #if defined(SENET) || defined(ACTILITY) || defined(TTN)
00149         // network KEY = cmac(network passphrase)
00150         update_ota_config_id_key(network_id, network_key, frequency_sub_band, public_network, ack);
00151 #else
00152         update_ota_config_name_phrase(network_name, network_passphrase, frequency_sub_band, public_network, ack);
00153 #endif
00154         
00155         // configure network link checks
00156         // network link checks are a good alternative to requiring the gateway to ACK every packet and should allow a single gateway to handle more Dots
00157         // check the link every count packets
00158         // declare the Dot disconnected after threshold failed link checks
00159         // for count = 3 and threshold = 5, the Dot will be considered disconnected after 15 missed packets in a row
00160         update_network_link_check_config(3, 5);
00161         
00162         // save changes to configuration
00163         logInfo("saving configuration");
00164         if (!dot->saveConfig()) {
00165             logError("failed to save configuration");
00166         }
00167     
00168         // display configuration
00169         display_config();
00170     }  else {
00171         // restore the saved session if the dot woke from deepsleep mode
00172         // useful to use with deepsleep because session info is otherwise lost when the dot enters deepsleep
00173         logInfo("restoring network session from NVM");
00174         dot->restoreNetworkSession();
00175     }
00176 
00177 
00178     
00179     while (true) {
00180         std::vector<uint8_t> tx_data;
00181 
00182         // join network if not joined
00183         if (!dot->getNetworkJoinStatus()) {
00184             join_network();
00185         }
00186 
00187         // Payload structure for mydevices cayenne:
00188         // 1 byte Data1 ID
00189         // 1 Byte Data1 Type
00190         // N Bytes Data1 
00191         // 1 byte data 2 ID
00192         // 1 byte data 2 type
00193         // n Bytes data 2
00194         // ... 
00195         
00196         // formats:
00197         // Temperature sensor:
00198         /*
00199          * IPSO: 3303
00200          * LPP 103
00201          * HEX: 67
00202          * Data size: 2
00203          * Resolution: 0.1 degrees C
00204          
00205          * Humidity sensor
00206          * IPSO: 3304
00207          * LPP: 104
00208          * Hex: 68
00209          * Datasize: 1
00210          * Resolution: 0.5% unsigned
00211          
00212          * Barometer/pressure sensor
00213          * IPSO: 3315
00214          * LPP: 115
00215          * Hex: 73
00216          * Datasize: 2
00217          * Resolution 0.1hPa unsigned MSB
00218          
00219          * Accelerometer
00220          * IPSO: 3313
00221          * LPP: 113
00222          * Hex: 71
00223          * Data size: 6
00224          * Resolution: 0.001G signed MSB per axis
00225          
00226          * Gyrometer
00227          * IPSO: 3334
00228          * LPP: 134
00229          * Hex: 86
00230          * Data size: 6
00231          * Resolution: 0.01 degrees/s signed msb per axis
00232         */
00233         
00234         //temp floats
00235         float value1, value2;
00236         
00237         // HTS221 Humidity sensor
00238         temp_sensor1->get_temperature(&value1);
00239         humidity_sensor->get_humidity(&value2);
00240         
00241         //serialize data and append to packet
00242         // Cayenne data: temperature; tag is 0x67, 2 bytes signed, 0.1 C/bit
00243         tx_data.push_back(uint8_t(1)); // data id
00244         tx_data.push_back(uint8_t(0x67)); // data type - temp
00245         int16_t temp = floor(value1*10 + 0.5f);
00246         logInfo("Temp payload: %d", temp);
00247         tx_data.push_back(uint8_t( 0xFF & (temp >> 8)));
00248         tx_data.push_back(uint8_t(0xFF & temp));
00249         
00250         
00251         tx_data.push_back(uint8_t(2)); // data id
00252         tx_data.push_back(uint8_t(0x68)); // data type - humidity
00253         temp = floor(value2 * 2.0f + 0.5f);
00254         tx_data.push_back(uint8_t(0xFF & temp ));
00255 
00256         logInfo("Temperature data %f", value1);
00257         logInfo("Humidity data: %f", value2);
00258         
00259         pressure_sensor->get_pressure(&value1);
00260         logInfo("Pressure data: %f", value1);
00261         // pressure is reported in mbar, cayenne wants it in 0.1 hPa
00262         // 1mbar = 1 hPa
00263         temp = floor(value1 * 100.0f + 0.5f);
00264         tx_data.push_back(uint8_t(3)); // data id
00265         tx_data.push_back(uint8_t(0x73)); // data type - pressure
00266         temp = floor(value1 / 0.1f + 0.5f);
00267         tx_data.push_back(uint8_t(0xFF & (temp >> 8)));
00268         tx_data.push_back(uint8_t(0xFF & temp));
00269         
00270         
00271         // Get accelerometer data
00272         int32_t accel_vector[3];
00273         // returns in mG
00274         accelerometer->get_x_axes(accel_vector);
00275         logInfo("Acclerometer Z axis: %d", accel_vector[2]);
00276         
00277         tx_data.push_back(uint8_t(4)); // data id
00278         tx_data.push_back(uint8_t(0x71)); // data type - accelerometer
00279         for(int i=0; i<3; i++){
00280             tx_data.push_back(uint8_t(0xFF & accel_vector[i]) >> 8);
00281             tx_data.push_back(uint8_t(0xFF & accel_vector[i]));
00282         }
00283         
00284         // Get gyro data
00285         gyroscope->get_g_axes
00286         (accel_vector);
00287         // gyro reports in milidegrees/sec, cayenne wants centidegrees/sec
00288         tx_data.push_back(uint8_t(5)); //data id
00289         tx_data.push_back(uint8_t(0x86)); // data type - gyrometer
00290         for(int i=0; i<3; i++){
00291             accel_vector[i] /= 10;
00292             tx_data.push_back(uint8_t(0xFF & (accel_vector[i] >> 8)));
00293             tx_data.push_back(uint8_t(0xFF & accel_vector[i]));
00294         }
00295         
00296         
00297         send_data(tx_data);
00298         
00299         if(deep_sleep){
00300         // if going into deepsleep mode, save the session so we don't need to join again after waking up
00301         // not necessary if going into sleep mode since RAM is retained
00302             logInfo("saving network session to NVM");
00303             dot->saveNetworkSession();
00304         }
00305         
00306 
00307         // ONLY ONE of the three functions below should be uncommented depending on the desired wakeup method
00308         sleep_wake_rtc_only(deep_sleep);
00309         //sleep_wake_interrupt_only(deep_sleep);
00310         //sleep_wake_rtc_or_interrupt(deep_sleep);
00311         
00312     }
00313 
00314     return 0;    
00315 }