UDK + Shield

Dependencies:   DOGS102 ISL29011 MMA845x MPL3115A2 NCP5623B libmDot_1012-hotifx mbed-rtos mbed-src Senet_Packet X_NUCLEO_IKS01A1

Fork of MTDOT-EVBDemo_Senet by Dave Kjendal

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

Go to the documentation of this file.
00001 /**
00002  * @file    main.cpp
00003  * @brief   Main application for mDot-EVB demo
00004  * @author  Tim Barr  MultiTech Systems Inc.
00005  * @version 1.03
00006  * @see
00007  *
00008  * Copyright (c) 2015
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License");
00011  * you may not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  *     http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS,
00018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  *
00022  * 1.01 TAB 7/6/15 Removed NULL pointer from evbAmbientLight creation call.
00023  *
00024  * 1.02 TAB 7/8/15 Send logo to LCD before attempting connection to LoRa network. Added
00025  *                  information on setting up for public LoRa network. Moved SW setup to
00026  *                  beginning of main. Removed printf call from ISR functions. Added
00027  *                  additional checks for exit_program.
00028  *
00029  * 1.03 TAB 7/15/15 Added threads for push button switch debounce.
00030  *
00031  */
00032 
00033 #include "mbed.h"
00034 #include "senet_packet.h"
00035 
00036 #if !defined(MTDOT_EVB) && !defined(MTDOT_UDK)
00037 #define MTDOT_UDK
00038 #define REFLECT_FAST_TX
00039 #endif
00040 
00041 // EVB Sensors
00042 #ifdef MTDOT_EVB
00043 
00044 #include "MMA845x.h"
00045 #include "MPL3115A2.h"
00046 #include "ISL29011.h"
00047 #include "NCP5623B.h"
00048 #include "DOGS102.h"
00049 #include "font_6x8.h"
00050 #include "MultiTech_Logo.h"
00051 
00052 // Added period delay 
00053 #define PERIOD_DELAY 0
00054 
00055 // Fast send period 
00056 #define FAST_SEND_PERIOD pckt_time
00057 
00058 // Send frame period 
00059 #define SEND_PERIOD 100 
00060 
00061 #elif defined(MTDOT_UDK)
00062 
00063 #include "x_nucleo_iks01a1.h"
00064 
00065 // Added period delay  
00066 #define PERIOD_DELAY 3000 
00067 
00068 // Fast send period 
00069 #define FAST_SEND_PERIOD 1  
00070 
00071 // Send frame period 
00072 #define SEND_PERIOD 10  
00073 
00074 #endif
00075 
00076 #include "mDot.h"
00077 #include "rtos.h"
00078 #include <string>
00079 #include <vector>
00080 
00081 /* 
00082  * Board sensor data
00083  */
00084 struct BoardSensorData
00085 {
00086     float temperature;
00087     float pressure;
00088     int32_t accel_x;
00089     int32_t accel_y;
00090     int32_t accel_z;
00091 
00092     inline void init()
00093     {
00094         temperature= 0;
00095         pressure = 0;
00096         accel_x = 0;
00097         accel_y = 0;
00098         accel_z = 0;
00099     }
00100 
00101     BoardSensorData() { init(); }
00102 };
00103 
00104 #ifdef MTDOT_EVB
00105 
00106 //DigitalIn mDot02(PA_2);  //  GPIO/UART_TX
00107 //DigitalOut mDot03(PA_3); //  GPIO/UART_RX
00108 //DigitalIn mDot04(PA_6);  //  GPIO/SPI_MISO
00109 //DigitalIn mDot06(PA_8);  //  GPIO/I2C_SCL
00110 //DigitalIn mDot07(PC_9);  //  GPIO/I2C_SDA
00111 
00112 InterruptIn mDot08(PA_12);  //  GPIO/USB       PB S1 on EVB
00113 InterruptIn mDot09(PA_11);  //  GPIO/USB       PB S2 on EVB
00114 
00115 //DigitalIn mDot11(PA_7);   //  GPIO/SPI_MOSI
00116 
00117 InterruptIn mDot12(PA_0);    //  GPIO/UART_CTS  PRESSURE_INT2 on EVB
00118 DigitalOut  mDot13(PC_13,1); //  GPIO           LCD_C/D
00119 InterruptIn mDot15(PC_1);    //  GPIO           LIGHT_PROX_INT on EVB
00120 InterruptIn mDot16(PA_1);    //  GPIO/UART_RTS  ACCEL_INT2 on EVB
00121 DigitalOut mDot17(PA_4,1);   //  GPIO/SPI_NCS   LCD_CS on EVB
00122 
00123 //DigitalIn mDot18(PA_5);    //  GPIO/SPI_SCK
00124 
00125 //DigitalInOut mDot19(PB_0,PIN_INPUT,PullNone,0); // GPIO         PushPull LED Low=Red High=Green set MODE=INPUT to turn off
00126 AnalogIn mDot20(PB_1);         //  GPIO          Current Sense Analog in on EVB
00127 Serial debugUART(PA_9, PA_10); // mDot debug UART
00128 //Serial mDotUART(PA_2, PA_3); // mDot external UART mDot02 and mDot03
00129 I2C mDoti2c(PC_9,PA_8); // mDot External I2C mDot6 and mDot7
00130 
00131 SPI mDotspi(PA_7,PA_6,PA_5); // mDot external SPI mDot11, mDot4, and mDot18
00132 #elif defined(MTDOT_UDK)
00133 
00134 Serial debugUART(USBTX, USBRX); // mDot debug UART
00135 
00136 #endif
00137 
00138 /* 
00139  * LoRaWAN Configuration 
00140  */
00141  
00142  // Senet Developer Portal Application EUI
00143 static uint8_t app_id[8]   = {0x00,0x25,0x0C,0x00,0x00,0x01,0x00,0x01};
00144 
00145 // Get Application Key from Senet Developer Portal Device Edit page
00146 static uint8_t app_key[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};
00147 
00148 static std::vector<uint8_t> config_app_id(app_id,app_id+sizeof(app_id)/sizeof(uint8_t));
00149 static std::vector<uint8_t> config_app_key(app_key,app_key+sizeof(app_key)/sizeof(uint8_t));
00150 static uint8_t config_frequency_sub_band = 0;
00151 static bool    config_adr_on = true;
00152 
00153 bool     position_changed = true;
00154 uint32_t sample_period    = 0;
00155 
00156 #ifdef  MTDOT_EVB
00157 MMA845x_DATA accel_data;
00158 MPL3115A2_DATA baro_data;
00159 uint16_t  lux_data;
00160 MMA845x* evbAccel;     
00161 MPL3115A2* evbBaro;
00162 ISL29011* evbAmbLight;
00163 NCP5623B* evbBackLight;
00164 DOGS102* evbLCD;
00165 
00166 /* 
00167  * EVB Application state 
00168  */
00169 uint8_t position_value   = 0xFF; // 00 unknown, 01 is flat, 02 is vertical
00170 uint8_t reflected_value  = 0xFE;
00171 
00172 unsigned char test;
00173 char     txtstr[17];
00174 int32_t  num_whole;
00175 uint32_t pressure;
00176 int16_t  num_frac;
00177 uint8_t  result, pckt_time=100;
00178 char     data;
00179 // flags for pushbutton debounce code
00180 bool pb1_low = false;
00181 bool pb2_low = false;
00182 
00183 void pb1ISR(void);
00184 void pb2ISR(void);
00185 void pb1_debounce(void const *args);
00186 void pb2_debounce(void const *args);
00187 Thread* thread_3;
00188 
00189 void config_pkt_xmit (void const *args);
00190 
00191 #elif defined(MTDOT_UDK)
00192 
00193 uint16_t position_value  = 0;
00194 uint16_t reflected_value = 0;
00195 
00196 static X_NUCLEO_IKS01A1 *mems_shield; 
00197 
00198 #endif 
00199 
00200 mDot* mdot_radio;
00201 bool  exit_program = false;
00202 Ticker joinTicker;
00203 DigitalOut APP_LED(PA_0);
00204 
00205 // join status
00206 #define JOIN_LED APP_LED
00207 
00208 // server sync status 
00209 #define SYNC_LED APP_LED
00210 
00211 #define SYNC_LED_OK  0 // synced
00212 #define SYNC_LED_OOS 1 // out of sync
00213 
00214 
00215 /* 
00216  * Process downlink
00217  */
00218 static void ReceiveData(std::vector<uint8_t> frame);
00219 
00220 static bool checkForExit(bool exit);
00221 
00222 /*
00223  *  prints of mDot error 
00224  */
00225 void log_error(mDot* dot, const char* msg, int32_t retval)
00226 {
00227     printf("%s - %ld:%s, %s\r\n", msg, retval, mDot::getReturnCodeString(retval).c_str(), dot->getLastError().c_str());
00228 }
00229 
00230 /*
00231  * Send frame
00232  */
00233 void SendFrame(std::vector<uint8_t> frame)
00234 {
00235     int32_t mdot_ret;
00236 
00237     if ((mdot_ret = mdot_radio->send(frame)) != mDot::MDOT_OK) {
00238         log_error(mdot_radio, "failed to send", mdot_ret);
00239     } 
00240     else {
00241         printf("successfully sent data\r\n");
00242         frame.clear();
00243         if ((mdot_ret = mdot_radio->recv(frame)) == mDot::MDOT_OK) {
00244             printf("recv data: ");
00245             for(uint32_t i = 0;i < frame.size();i++)
00246                 printf("%02X",frame[i]);
00247             printf("\r\n");
00248 
00249             ReceiveData(frame);
00250         }
00251         position_changed = false;
00252     }
00253 }
00254 
00255 #ifdef MTDOT_EVB
00256 
00257 void ReceiveData(std::vector<uint8_t> frame)
00258 {
00259     reflected_value = frame[0];
00260 
00261     if(reflected_value == position_value)
00262     {
00263         evbBackLight->setLEDCurrent(16);
00264         // Set LED to indicate server in agreement 
00265         SYNC_LED=SYNC_LED_OK;
00266     }
00267     else 
00268     {
00269         evbBackLight->setLEDCurrent(0);
00270     }
00271 }
00272 
00273 void BoardInit()
00274 {
00275     static Thread thread_1(pb1_debounce);    // threads for de-bouncing pushbutton switches
00276     static Thread thread_2(pb2_debounce);
00277 
00278     debugUART.baud(115200);
00279     // mDotUART.baud(9600);    // mdot UART unused but available on external connector
00280 
00281     thread_3 = new Thread(config_pkt_xmit); // start thread that sends LoRa packet when SW2 pressed
00282 
00283     evbAccel = new MMA845x(mDoti2c,MMA845x::SA0_VSS); // setup Accelerometer
00284     evbBaro = new MPL3115A2(mDoti2c); // setup Barometric sensor
00285     evbAmbLight = new ISL29011(mDoti2c); // Setup Ambient Light Sensor
00286     evbBackLight = new NCP5623B(mDoti2c); // setup backlight and LED 2 driver chip
00287     evbLCD = new DOGS102(mDotspi, mDot17, mDot13); // setup LCD
00288 
00289     /*
00290      *  Setup SW1 as program stop function
00291      */
00292     mDot08.disable_irq();
00293     mDot08.fall(&pb1ISR);
00294 
00295     /*
00296      *  need to call this function after rise or fall because rise/fall sets
00297      *  mode to PullNone
00298      */
00299     mDot08.mode(PullUp);
00300 
00301     mDot08.enable_irq();
00302 
00303     /*
00304      *  Setup SW2 as packet time change
00305      */
00306     mDot09.disable_irq();
00307     mDot09.fall(&pb2ISR);
00308 
00309     /*
00310      *  need to call this function after rise or fall because rise/fall sets
00311      *  mode to PullNone
00312      */
00313     mDot09.mode(PullUp);
00314  
00315     mDot09.enable_irq();
00316 
00317     /*
00318     * Setting other InterruptIn pins with Pull Ups
00319     */
00320     mDot12.mode(PullUp);
00321     mDot15.mode(PullUp);
00322     mDot16.mode(PullUp);
00323 
00324     printf("font table address %p\n\r",&font_6x8);
00325     printf("bitmap address %p\n\r",&MultiTech_Logo);
00326 
00327 // Setup and display logo on LCD
00328     evbLCD->startUpdate();
00329 
00330     evbLCD->writeBitmap(0,0,MultiTech_Logo);
00331 
00332     sprintf(txtstr,"MTDOT");
00333     evbLCD->writeText(24,3,font_6x8,txtstr,strlen(txtstr));
00334     sprintf(txtstr,"Evaluation");
00335     evbLCD->writeText(24,4,font_6x8,txtstr,strlen(txtstr));
00336     sprintf(txtstr,"Board");
00337     evbLCD->writeText(24,5,font_6x8,txtstr,strlen(txtstr));
00338 
00339     evbLCD->endUpdate();
00340 
00341     pckt_time = 10;
00342 }
00343 
00344 void PostJoinInit()
00345 {
00346     osDelay(200);
00347     evbBackLight->setPWM(NCP5623B::LED_3,16); // enable LED2 on EVB and set to 50% PWM
00348 
00349     // sets LED2 to 50% max current
00350     evbBackLight->setLEDCurrent(16);
00351 
00352     printf("Start of Test\n\r");
00353 
00354     osDelay (500); // allows other threads to process
00355     printf("shutdown LED:\n\r");
00356     evbBackLight->shutdown();
00357 
00358     osDelay (500); // allows other threads to process
00359     printf("Turn on LED2\n\r");
00360     evbBackLight->setLEDCurrent(16);
00361 
00362     data = evbAccel->getWhoAmI();
00363     printf("Accelerometer who_am_i value = %x \n\r", data);
00364 
00365     result = evbAccel->getStatus();
00366     printf("status byte = %x \n\r", result);
00367 
00368     printf("Barometer who_am_i check = %s \n\r", evbBaro->testWhoAmI() ? "TRUE" : "FALSE");
00369 
00370     result = evbBaro->getStatus();
00371     printf("status byte = %x \n\r", result);
00372 
00373     /*
00374      *  Setup the Accelerometer for 8g range, 14 bit resolution, Noise reduction off, sample rate 1.56 Hz
00375      *  normal oversample mode, High pass filter off
00376      */
00377     evbAccel->setCommonParameters(MMA845x::RANGE_8g,MMA845x::RES_MAX,MMA845x::LN_OFF,
00378                                   MMA845x::DR_1_56,MMA845x::OS_NORMAL,MMA845x::HPF_OFF );
00379 
00380     /*
00381      * Setup the Barometric sensor for post processed Ambient pressure, 4 samples per data acquisition.
00382      * and a sample taken every second when in active mode
00383      */
00384     evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16,
00385                            MPL3115A2::AT_1);
00386     /*
00387      * Setup the Ambient Light Sensor for continuous Ambient Light Sensing, 16 bit resolution,
00388      * and 16000 lux range
00389      */
00390 
00391     evbAmbLight->setMode(ISL29011::ALS_CONT);
00392     evbAmbLight->setResolution(ISL29011::ADC_16BIT);
00393     evbAmbLight->setRange(ISL29011::RNG_16000);
00394 
00395     /*
00396      * Set the accelerometer for active mode
00397      */
00398     evbAccel->activeMode();
00399 
00400     /*
00401      * Clear the min-max registers in the Barometric Sensor
00402      */
00403     evbBaro->clearMinMaxRegs();
00404 
00405     evbBackLight->setLEDCurrent(0);
00406 
00407     /*
00408      * Check for PB1 press during network join attempt
00409      */
00410     if (exit_program) {
00411         printf("Exiting program\n\r");
00412         evbLCD->clearBuffer();
00413         sprintf(txtstr,"Exiting Program");
00414         evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr));
00415         exit(1);
00416     }
00417 }
00418 
00419 void ReadSensors(BoardSensorData &sensorData)
00420 {
00421     MMA845x_DATA accel_data;
00422     /*
00423      * Test Accelerometer XYZ data ready bit to see if acquisition complete
00424      */
00425     do {
00426         osDelay(100); // allows other threads to process
00427         result = evbAccel->getStatus();
00428     } while ((result & MMA845x::XYZDR) == 0 );
00429 
00430     /*
00431      * Retrieve and print out accelerometer data
00432      */
00433     accel_data = evbAccel->getXYZ();
00434 
00435     sprintf(txtstr,"Accelerometer");
00436     evbLCD->writeText(0,0,font_6x8,txtstr,strlen(txtstr));
00437     sprintf(txtstr, "x = %d", accel_data._x);
00438     evbLCD->writeText(20,1,font_6x8,txtstr,strlen(txtstr));
00439     sprintf(txtstr, "y = %d", accel_data._y);
00440     evbLCD->writeText(20,2,font_6x8,txtstr,strlen(txtstr));
00441     sprintf(txtstr, "z = %d", accel_data._z );
00442     evbLCD->writeText(20,3,font_6x8,txtstr,strlen(txtstr));
00443 
00444     sensorData.accel_x = accel_data._x;
00445     sensorData.accel_y = accel_data._y;
00446     sensorData.accel_z = accel_data._z;
00447 
00448     // Update accelerometer state
00449     evbLCD->startUpdate();
00450     evbLCD->clearBuffer();
00451     
00452     // convert to simple position value for use in send/recv
00453     if((accel_data._x > 500)&&(accel_data._z < 500))
00454     {
00455         if(position_value != 0x02)
00456             position_changed = true;
00457         position_value = 0x02;
00458     }
00459     else if((accel_data._x < 500)&&(accel_data._z > 500))
00460     {
00461         if(position_value != 0x01)
00462             position_changed = true;
00463         position_value = 0x01;
00464     }
00465     else
00466     {
00467         if(position_value != 0x00)
00468             position_changed = true;
00469         position_value= 0x00;
00470     }
00471 
00472     if(position_changed){
00473         evbBackLight->setLEDCurrent(0);
00474         // Turn LED off to indicate server not in agreement 
00475         SYNC_LED=SYNC_LED_OOS;
00476         // Set reflected_value to an out of range value to stay
00477         // in fast transmit mode until server responds
00478         reflected_value = 0;
00479     }
00480 
00481     /*
00482      * Trigger a Pressure reading
00483      */
00484     evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16,
00485                            MPL3115A2::AT_1);
00486     evbBaro->triggerOneShot();
00487 
00488     /*
00489      * Test barometer device status to see if acquisition is complete
00490      */
00491     do {
00492         osDelay(100);           // allows other threads to process
00493         result = evbBaro->getStatus();
00494     } while ((result & MPL3115A2::PTDR) == 0 );
00495 
00496     /*
00497      * Retrieve and print out barometric pressure
00498      */
00499     pressure = evbBaro->getBaroData() >> 12; // convert 32 bit signed to 20 bit unsigned value
00500     num_whole = pressure >> 2;          // 18 bit integer significant
00501     num_frac = (pressure & 0x3) * 25;       // 2 bit fractional  0.25 per bit
00502     sensorData.pressure = pressure + (.25 * num_frac);
00503 
00504     sprintf(txtstr,"Press=%ld.%02d Pa", num_whole, num_frac);
00505     evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr));
00506 
00507     /*
00508      * Trigger a Altitude reading
00509      */
00510     evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_ALTIMETER, MPL3115A2::OR_16,
00511                            MPL3115A2::AT_1);
00512     evbBaro->triggerOneShot();
00513 
00514     /*
00515      * Test barometer device status to see if acquisition is complete
00516      */
00517     do {
00518         osDelay(100);           // allows other threads to process
00519         result = evbBaro->getStatus();
00520     } while ((result & MPL3115A2::PTDR) == 0 );
00521 
00522     /*
00523      * Retrieve and print out altitude and temperature
00524      */
00525     baro_data = evbBaro->getAllData(false);
00526     baro_data._baro /= 4096;                // convert 32 bit signed to 20 bit signed value
00527     num_whole = baro_data._baro / 16;       //  18 bit signed significant integer
00528     num_frac = (baro_data._baro & 0xF) * 625 / 100;     // 4 bit fractional .0625 per bit
00529     sprintf(txtstr,"Alti=%ld.%03d m", num_whole, num_frac);
00530     evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr));
00531     num_whole = baro_data._temp / 16;       // 8 bit signed significant integer
00532     num_frac = (baro_data._temp & 0x0F) * 625 / 100;        // 4 bit fractional .0625 per bit
00533     sensorData.temperature = num_whole  + ((float)num_frac / 100);
00534     sprintf(txtstr,"Temp=%ld.%03d C", num_whole, num_frac);
00535     evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr));
00536 
00537     /*
00538      * retrieve and print out Ambient Light level
00539      */
00540     lux_data = evbAmbLight->getData();
00541     num_whole = lux_data * 24 / 100;        // 16000 lux full scale .24 lux per bit
00542     num_frac = lux_data * 24 % 100;
00543     sprintf(txtstr, "Light=%ld.%02d lux", num_whole, num_frac );
00544     evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr));
00545 
00546     evbLCD->endUpdate();
00547 }
00548 
00549 uint32_t PrepareFrame(std::vector<uint8_t> &frame, BoardSensorData &data)
00550 {
00551     frame.clear();
00552 
00553 #ifdef REFLECT_FAST_TX
00554     if((reflected_value != position_value)|| position_changed || ( ( sample_period % SEND_PERIOD ) == 0 ) )
00555 #else
00556     if( position_changed || ( ( sample_period % SEND_PERIOD ) == 0 ) )
00557 #endif
00558     {
00559         // we will send a simple byte descriptor of the current position of the device: 01 is laying flat, 02 is vertically oriented
00560         frame.push_back(0x00);
00561         frame.push_back(position_value);
00562     }
00563 
00564     return frame.size();
00565 }
00566 
00567 bool checkForExit(bool _exit)
00568 {
00569     // Check for PB1 press during network join attempt
00570     if (exit_program) {
00571       printf("Exiting program\n\r"); 
00572       evbLCD->clearBuffer();
00573       sprintf(txtstr,"Exiting Program");
00574       evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr));
00575       if(_exit)
00576           exit(1);
00577     } 
00578 
00579     return false;
00580 }
00581 
00582 void ExitingProgram()
00583 {
00584     evbBaro->triggerOneShot();
00585     do {
00586         osDelay(200);           // allows other threads to process
00587         result = evbBaro->getStatus();
00588     } while ((result & MPL3115A2::PTDR) == 0 );
00589 
00590     baro_data = evbBaro->getAllData(true);
00591     printf ("minBaro=%ld maxBaro=%ld minTemp=%d maxTemp=%d\n\r", baro_data._minbaro, baro_data._maxbaro,
00592             baro_data._mintemp, baro_data._maxtemp);
00593     evbLCD->clearBuffer();
00594     sprintf(txtstr,"Exiting Program");
00595     evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr));
00596     printf("End of Test\n\r");
00597 }
00598 
00599 
00600 /*
00601  * Sets pb1_low flag. Slag is cleared in pb1_debounce thread
00602  */
00603 void pb1ISR(void)
00604 {
00605     if (!pb1_low)
00606         pb1_low = true;
00607 }
00608 
00609 /*
00610  * Debounces pb1. Also exits program if pushbutton 1 is pressed
00611  */
00612 void pb1_debounce(void const *args)
00613 { 
00614     static uint8_t count = 0;
00615 
00616     while (true) { 
00617         if (pb1_low && (mDot08 == 0))
00618             count++;
00619         else {
00620             count = 0;
00621             pb1_low = false;
00622         } 
00623 
00624         if (count == 5) 
00625             exit_program = true; 
00626 
00627         Thread::wait(5);
00628     }
00629 }
00630 
00631 /*
00632  * Sets pb2_low flag. Flag is cleared in pb2_debounce thread
00633  */
00634 void pb2ISR(void)
00635 {
00636     if (!pb2_low)
00637         pb2_low = true;
00638 }
00639 
00640 /*
00641  * Debounces pb2. Also changes packet transmit time to every other,
00642  * every fifth, or every tenth sample when SW2 pushed
00643  * Also triggers a thread to transmit a configuration packet
00644  */
00645 void pb2_debounce(void const *args)
00646 {
00647     static uint8_t count = 0;
00648 
00649     while (true) {
00650 
00651         if (pb2_low && (mDot09 == 0))
00652             count++;
00653         else {
00654             count = 0;
00655             pb2_low = false;
00656         }
00657         
00658         if (count == 5){ 
00659             if (pckt_time >= 5)
00660                 pckt_time /= 2;
00661             else 
00662                 pckt_time = 20; 
00663             
00664             //thread_3->signal_set(0x10);       // signal config_pkt_xmit to send packet
00665             position_changed = true;
00666         } 
00667         Thread::wait(5);
00668     }
00669  }
00670 
00671 /*
00672  * Thread that is triggered by SW2 ISR. Sends a packet to the LoRa server with the new Packet Transmission time setting
00673  */
00674 void config_pkt_xmit (void const *args)
00675 {
00676     int32_t mdot_ret;
00677 
00678     std::vector<uint8_t> data;
00679 
00680     while (true) {
00681         Thread::signal_wait(0x10);      // wait for pb2ISR to signal send
00682         data.clear();
00683         data.push_back(0x0F);           // key for Configuration data (packet transmission timer)
00684         data.push_back(pckt_time);
00685 
00686         if ((mdot_ret = mdot_radio->send(data)) != mDot::MDOT_OK) {
00687             log_error(mdot_radio, "failed to send config data", mdot_ret);
00688         } else {
00689             printf("sent config data to gateway\r\n");
00690         }
00691     }
00692 }
00693 
00694 #elif defined(MTDOT_UDK)
00695 
00696 void ReceiveData(std::vector<uint8_t> frame)
00697 {
00698     uint16_t value;
00699 
00700     if(frame.size() >= 2)
00701     {
00702         value = frame[0] << 8 | frame[1];
00703         if(value == position_value)
00704         {
00705             reflected_value = value;
00706             // Turn LED on to indicate server in agreement 
00707             SYNC_LED=SYNC_LED_OK;
00708         }
00709     }
00710 }
00711 
00712 void BoardInit()
00713 { 
00714     debugUART.baud(115200); 
00715 
00716     // ST X-NUCLEO-IKS01A1 MEMS Shield
00717     mems_shield = X_NUCLEO_IKS01A1::Instance(NULL, NC); 
00718     // mems_shield = X_NUCLEO_IKS01A1::Instance(); 
00719 }
00720 
00721 void PostJoinInit() { }
00722 
00723 
00724 void ReadSensors(BoardSensorData &data)
00725 {
00726     uint32_t ret = 0;
00727     int32_t  accel_data[3];
00728     
00729    // Temperature
00730    ret |= (!CALL_METH(mems_shield->pt_sensor, GetTemperature, &data.temperature, 0.0f) ? 0x0 : 0x1);
00731 
00732    // Pressure
00733    ret |= (!CALL_METH(mems_shield->pt_sensor, GetPressure, &data.pressure, 0.0f) ? 0x0 : 0x1);
00734 
00735    // Accelerometer
00736    MotionSensor *motionSensor = mems_shield->GetAccelerometer();
00737    if( motionSensor != NULL)
00738    {
00739        motionSensor->Get_X_Axes(accel_data);
00740 
00741        data.accel_x = accel_data[0];
00742        data.accel_y = accel_data[1];
00743        data.accel_z = accel_data[2];
00744        /*  z-axis : > 0 = rightside up, < 0 upside down
00745         *  x-axis: com LED to the left x < 0, x > 0 on the right
00746         *  y-axis: y > 0 COM LED down, y < 0  COM LED up 
00747         */
00748        bool up         = false;
00749        bool down       = false;
00750        bool right      = false;
00751        bool left       = false;
00752        bool horizontal = false;
00753        bool upsidedown = false;
00754        uint16_t next_value = 0; 
00755        
00756        // rightside up
00757        if(data.accel_z >= 750)
00758        {
00759            horizontal  = true;
00760        }
00761        // upside down
00762        else if(data.accel_z <= -750)
00763        {
00764            horizontal  = true;
00765            upsidedown  = true;
00766            position_value = (2 << 12) | (1 << 8);
00767        }
00768        // vertical down
00769        else if(data.accel_y >= 900 )
00770        {
00771            down = true;
00772        }
00773        // vertical up
00774        else if(data.accel_y <= -900 )
00775        {
00776            up = true;
00777        }
00778        // side right
00779        else if(data.accel_x > 900)
00780        {
00781            right = true;
00782        }
00783        // side left
00784        else
00785        {
00786            left = true;
00787        }
00788 
00789        if(horizontal)
00790        {
00791            next_value = (2 << 12) | (upsidedown << 8); 
00792        }
00793        else
00794        {
00795            next_value = (up << 12) | (left << 8) | (down << 4) | right;
00796        }
00797 
00798        if(next_value != position_value)
00799        {
00800            position_value = next_value;
00801            position_changed = true;
00802            
00803            // Set reflected_value to an out of range value to stay
00804            // in fast transmit mode until server responds
00805            reflected_value = 0;
00806 
00807             // Turn LED off to indicate server is not in agreement 
00808             SYNC_LED=SYNC_LED_OOS;
00809        }
00810    }
00811 
00812    printf("%s: position_value=%04x, reflected_value=%04x\r\n",__func__, position_value, reflected_value);
00813 }
00814 
00815 uint32_t PrepareFrame(std::vector<uint8_t> &frame, BoardSensorData &data)
00816 {
00817     static uint8_t buffer[64];
00818 
00819     frame.clear();
00820 
00821     // Sensor packet type serialized to the LMIC frame buffer
00822     SensorPacket packet(buffer, sizeof(buffer));
00823 
00824 #ifdef REFLECT_FAST_TX
00825     if( position_changed  || (reflected_value != position_value) || ( ( sample_period % SEND_PERIOD ) == 0 ) )
00826 #else
00827     if( position_changed  || ( ( sample_period % SEND_PERIOD ) == 0 ) )
00828 #endif
00829     {
00830         packet.setPrimarySensor(position_value);
00831         packet.setTemperature(data.temperature);
00832         packet.setPressure(data.pressure);
00833                 
00834         // Serialize  packet 
00835         packet.serialize();
00836 
00837         frame.assign(packet.payload(), packet.payload() + packet.length());
00838     }
00839 
00840     return frame.size();
00841 }
00842 
00843 bool checkForExit(bool _exit) { return false;}
00844 
00845 
00846 void ExitingProgram()
00847 {
00848     printf("Exiting\n\r");
00849 }
00850 
00851 #else
00852 #error Board type not defined!
00853 #endif
00854 
00855 void joinLedToggle()
00856 {
00857     JOIN_LED = !JOIN_LED;
00858 }
00859 
00860 void mDotConfigureAndJoin()
00861 { 
00862     bool    ok;
00863     int32_t mdot_ret;
00864 
00865     printf("Configuring mDot\r\n");
00866     
00867     // get mDot handle
00868     mdot_radio = mDot::getInstance();
00869     if(mdot_radio == NULL)
00870     { 
00871         while(1) {
00872             printf("radio setup failed\n\r");
00873             osDelay(1000);
00874         }
00875     }
00876 
00877     do{
00878         ok = true; 
00879 
00880         printf("\n\r setup mdot\n\r"); 
00881         
00882         // reset to default config so we know what state we're in
00883         mdot_radio->resetConfig();
00884         //mdot_radio->setLogLevel(6);
00885 
00886         mdot_radio->setAntennaGain(-3);
00887 
00888         // Setting up LED1 as activity LED
00889 #ifdef MTDOT_EVB
00890         mdot_radio->setActivityLedPin(PB_0);
00891         mdot_radio->setActivityLedEnable(true);
00892 #endif
00893 
00894         // Read node ID
00895         std::vector<uint8_t> mdot_EUI;
00896         mdot_EUI = mdot_radio->getDeviceId();
00897         printf("mDot EUI = ");
00898 
00899         for (uint8_t i=0; i<mdot_EUI.size(); i++) {
00900             printf("%02x ", mdot_EUI[i]);
00901         }
00902         printf("\n\r"); 
00903         
00904 
00905       /*
00906        * This call sets up private or public mode on the MTDOT. Set the function to true if
00907        * connecting to a public network
00908        */
00909        printf("setting Public Network Mode\r\n");
00910        if ((mdot_ret = mdot_radio->setPublicNetwork(true)) != mDot::MDOT_OK) {
00911            log_error(mdot_radio, "failed to set Public Network Mode", mdot_ret);
00912        }
00913        mdot_radio->setTxDataRate(mDot::DR0);
00914        mdot_radio->setTxPower(14);
00915        mdot_radio->setJoinRetries(1);
00916        mdot_radio->setJoinMode(mDot::OTA); 
00917 
00918       /*
00919        * Frequency sub-band is valid for NAM only and for Private networks should be set to a value
00920        * between 1-8 that matches the the LoRa gateway setting. Public networks use sub-band 0 only.
00921        * This function can be commented out for EU networks
00922        */
00923        printf("setting frequency sub band\r\n");
00924        if ((mdot_ret = mdot_radio->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
00925             log_error(mdot_radio, "failed to set frequency sub band", mdot_ret);
00926             ok = false;
00927         }
00928         
00929         printf("setting ADR\r\n");
00930         if ((mdot_ret = mdot_radio->setAdr(config_adr_on)) != mDot::MDOT_OK) {
00931             log_error(mdot_radio, "failed to set ADR", mdot_ret);
00932             ok = false;
00933         }
00934 
00935        /*
00936         * setNetworkName is used for private networks.
00937         * Use setNetworkID(AppID) for public networks
00938         */ 
00939         printf("setting network name\r\n");
00940         if ((mdot_ret = mdot_radio->setNetworkId(config_app_id)) != mDot::MDOT_OK) {
00941             log_error(mdot_radio, "failed to set network name", mdot_ret);
00942             ok = false;
00943         }
00944 
00945        /*
00946         * setNetworkPassphrase is used for private networks
00947         * Use setNetworkKey for public networks
00948         */ 
00949         printf("setting network key\r\n");
00950         if ((mdot_ret = mdot_radio->setNetworkKey(config_app_key)) != mDot::MDOT_OK) {
00951             log_error(mdot_radio, "failed to set network password", mdot_ret);
00952             ok = false;
00953         } 
00954 
00955         checkForExit(true);
00956 
00957     }while(ok == false);
00958 
00959     joinTicker.attach(joinLedToggle,1); 
00960     
00961     // attempt to join the network
00962     printf("joining network\r\n");
00963     while ((mdot_ret = mdot_radio->joinNetwork()) != mDot::MDOT_OK) { 
00964         log_error(mdot_radio,"failed to join network:", mdot_ret);
00965         if (mdot_radio->getFrequencyBand() == mDot::FB_868){
00966             mdot_ret = mdot_radio->getNextTxMs();
00967         }
00968         else {
00969             mdot_ret = 0;
00970         } 
00971         checkForExit(true);
00972         printf("delay = %lu\n\r",mdot_ret);
00973         osDelay(mdot_ret + 10000);
00974     } 
00975     printf("network joined\r\n");
00976 
00977     joinTicker.detach(); 
00978     JOIN_LED=1;
00979 }
00980 
00981 
00982 int main()
00983 {
00984     BoardSensorData sensorData;
00985     std::vector<uint8_t> frame;
00986     
00987     // Board specific initialization
00988     BoardInit(); 
00989 
00990     // Configure mDot and join
00991     mDotConfigureAndJoin();
00992 
00993     // Do board specific post join configuration
00994     PostJoinInit();
00995 
00996     /*
00997      * Main data acquisition loop
00998      */
00999     while(!checkForExit(false))
01000     {
01001         if( PERIOD_DELAY  > 0 )
01002             osDelay( PERIOD_DELAY ); 
01003 
01004         // Minimum delay between sampling
01005         if( ( sample_period % FAST_SEND_PERIOD ) == 0 )
01006         {
01007             // Acquire sensor values
01008             ReadSensors(sensorData);
01009 
01010             // Generate frame if send conditions are satisified
01011             if( PrepareFrame(frame, sensorData) > 0 )
01012             {
01013                 // Send sensor packets
01014                 SendFrame( frame );
01015             }
01016         }
01017         sample_period++;
01018     } 
01019 
01020     ExitingProgram();
01021 }