Peter Ferland / Mbed OS XDOT-Devicewise

Dependencies:   ISL29011 libxDot-mbed5

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*================================================================================
00002  *
00003  * CLASIFICATION:     **** PUBLIC RELEASE AS-IS APPLICATION EXAMPLE ****
00004  *
00005  * SOURCE FILE NAME:  main.cpp
00006  *
00007  * DESCRIPTIVE NAME:  MBED Source for MultiTech mDot, EVB, and MDOT-BOX Devices
00008  *
00009  * COPYRIGHT:         Copyright 2014-2017, Telit
00010  *
00011 ** WEB SITE:          www.telit.com
00012  *
00013  * WRITTEN BY:        John Keever
00014  *
00015  * DATE:              27 July, 2017
00016  *
00017  * VERSION:           1.00
00018  *
00019  * FUNCTION:          Provide working example for LoRa 'Sensor-to-Cloud'
00020  *                    Demonstration using MultiTech LoRa Starter Kit and
00021  *                    Telit Data and Cloud Platform Services Offerings
00022  *
00023  * SOURCE FILE TYPE:  MBED C++
00024  *
00025  * FUNCTIONS/ENTRY POINTS:  main
00026  *
00027  * INPUT  = None.
00028  * OUTPUT = None.
00029  *
00030  * EXIT-NORMAL = N/A
00031  * EXIT-ERROR  = N/A
00032  *
00033  * EXTERNAL REFERENCES = None.
00034  *
00035  * EXTERNAL FUNCTIONS = None.
00036  *
00037  * CONTROL BLOCKS = None.
00038  *
00039  *================================================================================*/
00040 /*                              LEGAL DISCLAIMER                                  */
00041 /*================================================================================
00042 
00043   Redistribution and use in source and binary forms, with or without
00044   modification, are permitted provided that the following conditions
00045   are met:
00046 
00047     Neither the name of ILS Technology nor Telit nor the names of its
00048     contributors may be used to endorse or promote products derived
00049     from this software without specific prior written permission.
00050 
00051   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00052   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00053   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00054   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00055   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00056   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00057   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00058   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00059   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00060   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00061   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00062 
00063  *================================================================================*/
00064 /*                                 CHANGE LOG                                     */
00065 /*================================================================================*/
00066 /*          |Changed |          |                                                 */
00067 /*  Date    |   by   |Version ID| Comments                                        */
00068 /*----------+--------+----------+-------------------------------------------------*/
00069 /*07-27-2017|JEK     |V1.00     |Original Version - xDot (Light Sensor, S2 Button)*/
00070 /*          |        |          |                                                 */
00071 /*================================================================================*/
00072 /*NOTE:  Please keep the change log up to date!!!                                 */
00073 /*================================================================================*/
00074 
00075 #include "mbed.h"
00076 #include "mDot.h"
00077 #include "rtos.h"
00078 #include "ChannelPlans.h"
00079 
00080 #include "ISL29011.h"
00081 
00082 #include <cmath>
00083 #include <string>
00084 #include <vector>
00085 #include <ctime>
00086 
00087 #ifndef CHANNEL_PLAN
00088 #define CHANNEL_PLAN CP_US915
00089 #endif
00090 
00091 static volatile bool timer_irq_triggered = false;
00092 static volatile bool ff_irq_triggered = false;
00093 
00094 //static std::string config_network_name = "MTCDT-19186797";
00095 //static std::string config_network_pass = "MTCDT-19186797";
00096 //static uint8_t config_frequency_sub_band = 1;
00097 
00098 static std::string config_network_name = "MTCDT-19186799";
00099 static std::string config_network_pass = "MTCDT-19186799";
00100 static uint8_t config_frequency_sub_band = 1;
00101 
00102 uint8_t result;
00103 uint8_t data;
00104 uint8_t sf_val = mDot::DR2;
00105 uint8_t pwr_val = 11; // dBm
00106 uint8_t swp_pwr;
00107 uint8_t swp_sf;
00108 
00109 int32_t mdot_ret;
00110 int32_t join_delay;
00111 
00112 osThreadId mainThreadID;
00113 
00114 // Physical I/O Instantiation
00115 DigitalOut led(LED1);
00116 DigitalIn s2(PA_0);
00117 
00118 I2C i2c(I2C_SDA, I2C_SCL);
00119 ISL29011 lux(i2c);
00120 // InterruptIn btn(PA_0); /* S2 - button */
00121 
00122 // flags for push button debounce code
00123 bool pb1_low = false;
00124 bool pb2_low = false;
00125 bool toggle_text = false;
00126 bool sw1_state = false;
00127 bool sw2_state = false;
00128 
00129 uint32_t num_whole;
00130 uint16_t num_frac;
00131 
00132 uint32_t pressure;
00133 double current;
00134 
00135 bool exit_program = false;
00136 
00137 mDot* mdot_radio;
00138 Mutex mdot_mutex;
00139 
00140 static Ticker ticker;
00141 
00142 void pb1ISR(void);
00143 void pb2ISR(void);
00144 void pb1_debounce(void const *args);
00145 void pb2_debounce(void const *args);
00146 
00147 //MPL3115A2* resetBaro(const MPL3115A2* oldBaro);
00148 void log_error(mDot* dot, const char* msg, int32_t retval);
00149 int32_t sendString(const std::string text);
00150 bool writeValueOrError();
00151 
00152 const int FAIL_MAX=15;
00153 int failtime=FAIL_MAX;
00154 int cycle_cnt = 0;
00155 
00156 char sensor_text[64];
00157 char lora_temp_string[16];
00158 char lora_alt_string[16];
00159 char lora_press_string[16];
00160 char lora_light_string[16];
00161 char lora_current_string[16];
00162 char lora_humid_string[16];
00163 
00164 bool bHasGPS = false;
00165 bool bHasACC = false;
00166 bool bHasLCD = false;
00167 
00168 //Helper Functions... Interrupt Handlers
00169 
00170 void rise() 
00171 {
00172     printf("\r\nS2 Button Interrupt... RISE (on)\r\n");
00173     //led.write(true);
00174     led = 1;
00175 }
00176 
00177 void fall() 
00178 {
00179     printf("\r\nS2 Button Interrupt... FALL (off)\r\n");
00180     //led.write(false);
00181     led = 0;
00182 }
00183 
00184 int xmitDataPayload( int, int, int );
00185 
00186 /*===================================================================================
00187 Main Program Logic - Entry
00188 ===================================================================================*/
00189 int main()
00190 {
00191     std::vector<uint8_t> mdot_data;
00192     std::vector<uint8_t> mdot_EUI;
00193     uint16_t i = 0;
00194     
00195     printf ("\r\nStarting xDot Demonstration Application...\r\n");
00196 
00197     mainThreadID = osThreadGetId();
00198 
00199     printf("Begin I2C/SPI Device Initialization...\r\n");
00200 
00201     printf("Initializing Light Sensor...\r\n");
00202 
00203     lux.setMode(ISL29011::ALS_CONT);
00204     lux.setResolution(ISL29011::ADC_16BIT);
00205     lux.setRange(ISL29011::RNG_64000);    
00206 
00207     printf("I2C/SPI Device Initialization Complete...\r\n");
00208 
00209     printf("Setup PushButton Interface Handlers...\r\n");
00210 
00211     //btn.rise(&rise);
00212     //btn.fall(&fall);
00213 
00214     printf("S2 IRQs Set...\r\n");
00215 
00216     printf("PushButton Interface Handlers Setup...\r\n");
00217  
00218     printf("\r\nSetup xDot Radio Communications...\r\n");
00219     
00220     #if CHANNEL_PLAN == CP_AS923
00221         lora::ChannelPlan* plan = new lora::ChannelPlan_AS923();
00222     #elif CHANNEL_PLAN == CP_US915
00223         lora::ChannelPlan* plan = new lora::ChannelPlan_US915();
00224     #elif CHANNEL_PLAN == CP_AU915
00225         lora::ChannelPlan* plan = new lora::ChannelPlan_AU915();
00226     #elif CHANNEL_PLAN == CP_EU868
00227         lora::ChannelPlan* plan = new lora::ChannelPlan_EU868();
00228     #elif CHANNEL_PLAN == CP_KR920
00229         lora::ChannelPlan* plan = new lora::ChannelPlan_KR920();
00230     #elif CHANNEL_PLAN == CP_IN865
00231         lora::ChannelPlan* plan = new lora::ChannelPlan_IN865();
00232     #elif CHANNEL_PLAN == CP_AS923_JAPAN
00233         lora::ChannelPlan* plan = new lora::ChannelPlan_AS923_Japan();
00234     #endif
00235 
00236     printf("xDot getInstance()...\r\n");
00237 
00238     // get an xDot handle
00239     mdot_radio = mDot::getInstance( plan ); 
00240     
00241     if (mdot_radio)
00242     {
00243         printf("xDot getInstance()... Successful!\r\n");  
00244 
00245         // reset to default config so we know what state we're in
00246         mdot_mutex.lock();  // lock mdot before setting configuration
00247         mdot_radio->resetConfig();
00248 
00249         // Setting up LED1 as activity LED
00250         mdot_radio->setActivityLedPin(LED1);
00251         mdot_radio->setActivityLedEnable(true);
00252 
00253         // Read node ID
00254         mdot_EUI = mdot_radio->getDeviceId();
00255         printf("mDot EUI = ");
00256 
00257         for(i=0; i<mdot_EUI.size(); i++) 
00258         {
00259             printf("%02x ", mdot_EUI[i]);
00260         }
00261         printf("\r\n");
00262 
00263         // Setting up the mDot with network information.
00264 
00265         // This call sets up private or public mode on the MTDOT. Set the function to true if
00266         // connecting to a public network
00267         printf("Setting Private Network Mode...\r\n");
00268         if ((mdot_ret = mdot_radio->setPublicNetwork(false)) != mDot::MDOT_OK) {
00269             log_error(mdot_radio, "ERROR: Failed to set Public Network Mode", mdot_ret);
00270         }
00271 
00272         // Frequency sub-band is valid for NAM only and for Private networks should be set to a value
00273         // between 1-8 that matches the the LoRa gateway setting. Public networks use sub-band 0 only.
00274         // This function can be commented out for EU networks
00275         printf("Setting Frequency Sub-Band...\r\n");
00276         if ((mdot_ret = mdot_radio->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
00277             log_error(mdot_radio, "ERROR: Failed to set Frequency Sub-Band", mdot_ret);
00278         }
00279 
00280         // Setting TX power for radio. Max allowed is +14dBm for EU and +20 dBm for NAM. Default is +11 dBm
00281         printf("Setting TX Power Level to %2d dBm...\r\n", pwr_val);
00282         if ((mdot_ret = mdot_radio->setTxPower(pwr_val)) != mDot::MDOT_OK) {
00283             log_error(mdot_radio, "ERROR: Failed to set TX Power Level", mdot_ret);
00284         }
00285 
00286         // Turning ADR off for the purposes of demonstrating TX data rates
00287         printf("Setting ADR to Off...\r\n");
00288         if((mdot_ret = mdot_radio->setAdr(false)) != mDot::MDOT_OK){
00289             log_error(mdot_radio, "ERROR: Failed to set ADR", mdot_ret);
00290         }
00291         
00292         // Setting TX data rate for radio. Max allowed is SF_12 for EU and SF10 dBm for NAM. Default is SF_10
00293         printf("Setting TX data rate to SF_7...\r\n");
00294         if ((mdot_ret = mdot_radio->setTxDataRate(sf_val)) != mDot::MDOT_OK) {
00295             log_error(mdot_radio, "ERROR: Failed to set TX Data Rate", mdot_ret);
00296         }
00297 
00298         // Setting Packet ACK to 1 try.
00299         printf("Setting Packet Retry to 1...\r\n");
00300         if ((mdot_ret = mdot_radio->setAck(1)) != mDot::MDOT_OK) {
00301             log_error(mdot_radio, "ERROR: Failed to set Packet Retry\r\n", mdot_ret);
00302         }
00303 
00304         // setNetworkName is used for private networks.
00305         // Use setNetworkID(AppID) for public networks
00306         // config_app_id.assign(app_id,app_id+7);
00307 
00308         printf("Setting Network Name...\r\n");
00309         if ((mdot_ret = mdot_radio->setNetworkName(config_network_name)) != mDot::MDOT_OK) {
00310         // if ((mdot_ret = mdot_radio->setNetworkID(config_app_id)) != mDot::MDOT_OK) {
00311             log_error(mdot_radio, "ERROR: Failed to set Network Name", mdot_ret);
00312         }
00313 
00314         // setNetworkPassphrase is used for private networks
00315         // Use setNetworkKey for public networks
00316         // config_app_key.assign(app_key,app_key+15);
00317 
00318         printf("Setting Network Password...\r\n");
00319         if ((mdot_ret = mdot_radio->setNetworkPassphrase(config_network_pass)) != mDot::MDOT_OK) {
00320         // if ((mdot_ret = mdot_radio->setNetworkKey(config_app_key)) != mDot::MDOT_OK) {
00321             log_error(mdot_radio, "ERROR: Failed to set Network Password", mdot_ret);
00322         }
00323 
00324         mdot_mutex.unlock();        // unlock mdot mutex before join attempt so SW1 can work
00325 
00326         // attempt to join the network
00327         printf("Joining LoRa Network...\r\n");
00328         do {
00329             mdot_mutex.lock();      // lock mdot mutex before join attempt
00330             mdot_ret = mdot_radio->joinNetwork();
00331             mdot_mutex.unlock();        // unlock mdot mutex after join attempt so SW1 can work
00332 
00333             if (mdot_ret != mDot::MDOT_OK)
00334             {
00335                 log_error(mdot_radio,"ERROR: Failed to Join Network:", mdot_ret);
00336 
00337                 join_delay = 100;
00338 
00339                 printf("Join Delay = %lu\r\n",join_delay);
00340                 osDelay(join_delay + 1);
00341                 toggle_text = !toggle_text;
00342             }
00343 
00344             /*
00345              * Setting TX power and Data Rate for radio just in case user requested by SW2
00346              */
00347             mdot_mutex.lock();      // lock mdot mutex before setting change
00348             mdot_radio->setTxPower(pwr_val);
00349             mdot_radio->setTxDataRate(sf_val);
00350             mdot_mutex.unlock();        // unlock mdot mutex after settings change so SW1 can work
00351 
00352         } while (mdot_ret != mDot::MDOT_OK);
00353 
00354         printf("Successfully Joined LoRa Network...\r\n");
00355     }
00356     else
00357     {
00358         printf("ERROR:  Unable to Join LoRa Network...\r\n");
00359         printf("getInstance... Radio Initialization Failed!\r\n");
00360 
00361         exit(1);
00362     }
00363 
00364     printf("Initialization/Configuration Completed...\r\n");
00365 
00366     osDelay(1500);
00367 
00368     // Enter Main Data Acquisition Loop...
00369     printf("Processing Data Acquisition Scan Loop...\r\n");
00370 
00371     i = 0;
00372     cycle_cnt = 100;
00373 
00374     bool s2_last = 0;
00375     int  lum_last = 0;
00376     int  lum_delta = 0;
00377 
00378     do
00379     {
00380             // Read Pushbutton #2 (S2) State...
00381             if( s2 > 0 )
00382             {
00383                 printf("S2 Pressed... State: %d\r\n", (int) s2);
00384             }         
00385 
00386             int delta = rand()%16;
00387             int temperature = 20 + delta;
00388             int luminosity = lux.getData();
00389             int current = s2;
00390 
00391             printf("Scan... Temperature: %d degC (delta=%d), Light: %d lux, Button: %d\r\n", temperature, delta, luminosity, current );
00392 
00393             lum_delta = abs( luminosity - lum_last );
00394 
00395             if( s2 != s2_last || lum_delta > 20 )
00396             {
00397                 printf("Data Change Event...\r\n");
00398 
00399                 xmitDataPayload( temperature, luminosity, current );
00400                 
00401                 cycle_cnt = 0;
00402             } 
00403            
00404             if( cycle_cnt > 30 )
00405             {   
00406                 printf("Transmitting Data... \r\n");
00407 
00408                 sprintf(sensor_text, "t:%d,l:%d,c:%d",
00409                     temperature,
00410                     luminosity,
00411                     current );
00412 
00413                 if((mdot_ret = sendString((const std::string)sensor_text)) != mDot::MDOT_OK) 
00414                 {
00415                     log_error(mdot_radio, "ERROR: Failed to Send Data", mdot_ret);
00416                 } 
00417                 else 
00418                 {
00419                     printf("Ok, Successfully Sent Data to Gateway...\r\n");
00420                 }
00421 
00422                 /*
00423                 //---------------------------------------------------------------------------
00424                 // Binary Encoded Format:  Most Data Payload, Not Human Readible
00425                 //---------------------------------------------------------------------------
00426                 mdot_data.clear();
00427                 mdot_data.push_back(0x0E);              // key for Current Acceleration 3-Axis Value
00428                 converts.f_s = accel_data._x *4;        // shift data 2 bits while retaining sign
00429                 mdot_data.push_back(converts.t_u[1]);   // get 8 MSB of 14 bit value
00430                 converts.f_s = accel_data._y * 4;       // shift data 2 bits while retaining sign
00431                 mdot_data.push_back(converts.t_u[1]);   // get 8 MSB of 14 bit value
00432                 converts.f_s = accel_data._z * 4;       // shift data 2 bits while retaining sign
00433                 mdot_data.push_back(converts.t_u[1]);   // get 8 MSB of 14 bit value
00434                 mdot_data.push_back(0x08);              // key for Current Pressure Value
00435                 convertl.f_u = pressure;                // pressure data is 20 bits unsigned
00436                 mdot_data.push_back(convertl.t_u[2]);
00437                 mdot_data.push_back(convertl.t_u[1]);
00438                 mdot_data.push_back(convertl.t_u[0]);
00439                 mdot_data.push_back(0x05);              // key for Current Ambient Light Value
00440                 converts.f_u = lux_data;                // data is 16 bits unsigned
00441                 mdot_data.push_back(converts.t_u[1]);
00442                 mdot_data.push_back(converts.t_u[0]);
00443                 mdot_data.push_back(0x0B);              // key for Current Temperature Value
00444                 converts.f_s = baro_data._temp;         // temperature is signed 12 bit
00445                 mdot_data.push_back(converts.t_u[1]);
00446                 mdot_data.push_back(converts.t_u[0]);
00447 
00448                 if ((mdot_ret = mdot_radio->send(mdot_data)) != mDot::MDOT_OK) 
00449                 {
00450                     log_error(mdot_radio, "ERROR: Failed to Send Data", mdot_ret);
00451                 } 
00452                 else 
00453                 {
00454                     printf("Ok, Successfully Sent Data to Gateway...\r\n");
00455                 }
00456                 */
00457             
00458                 osDelay(500);
00459 
00460                 printf("Scanning...     \r\n");
00461                 cycle_cnt = 0;
00462             }
00463 
00464         s2_last = s2;
00465         lum_last = luminosity;
00466 
00467         osDelay(1000);
00468         cycle_cnt++;
00469                 
00470         // Put Thread to Sleep for 30 Seconds...
00471         // osDelay(30000);
00472 
00473     } while(i < 86400);
00474 
00475     printf("End of Data Collection Cycle (24 Hours) - Ending Application, GoodBye...\r\n");
00476 }
00477 
00478 /*===================================================================================
00479 Send String Payload to Conduit Gateway
00480 ===================================================================================*/
00481 int32_t sendString(const std::string text)
00482 {
00483     int32_t ret;
00484     if (mdot_radio->getNextTxMs() != 0)
00485     {
00486         printf("Sending in %lu ms...\r\n", mdot_radio->getNextTxMs());
00487         return false;
00488     }
00489 
00490     printf("Sending: '%s'\r\n", text.c_str());
00491     std::vector<uint8_t> data(text.begin(), text.end());
00492     if ((ret = mdot_radio->send(data, 1)) != mDot::MDOT_OK)
00493     {
00494         log_error(mdot_radio, "ERROR: Failed to Send Data", ret);
00495     }
00496 
00497     led = 0;
00498 
00499     return ret;
00500 }
00501 
00502 /*===================================================================================
00503 Transmit Data Payload to Cloud Platform
00504 ===================================================================================*/
00505 int32_t xmitDataPayload( int temperature, int luminosity, int current )
00506 {
00507     int32_t mdot_ret;
00508 
00509     printf("Transmitting Data... \r\n");
00510 
00511     sprintf(sensor_text, "t:%d,l:%d,c:%d", temperature, luminosity, current );
00512 
00513     if((mdot_ret = sendString((const std::string)sensor_text)) != mDot::MDOT_OK) 
00514     {
00515         log_error(mdot_radio, "ERROR: Failed to Send Data", mdot_ret);
00516     } 
00517     else 
00518     {
00519         printf("Ok, Successfully Sent Data to Gateway...\r\n");
00520     }
00521 
00522     return mdot_ret;
00523 }
00524 
00525 /*===================================================================================
00526 Print clear text verion of mDot/EVB errors
00527 ===================================================================================*/
00528 void log_error(mDot* dot, const char* msg, int32_t retval)
00529 {
00530     printf("%s - %ld:%s, %s\r\n", msg, retval, mDot::getReturnCodeString(retval).c_str(), dot->getLastError().c_str());
00531 }