Provide working example for LoRa 'Sensor-to-Cloud' demonstration using MultiTech LoRa Starter Kit and Telit Data and Cloud Platform Services Offerings
Dependencies: DOGS102 GpsParser ISL29011 MMA845x MPL3115A2 MTS-Serial NCP5623B mDot_X_NUCLEO_IKS01A1 libmDot-mbed5
Diff: main_mems.cpp
- Revision:
- 0:e516bb631931
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main_mems.cpp Thu Jul 13 19:03:50 2017 +0000 @@ -0,0 +1,1496 @@ +/*================================================================================ + * + * CLASIFICATION: **** PUBLIC RELEASE AS-IS APPLICATION EXAMPLE **** + * + * SOURCE FILE NAME: main.cpp + * + * DESCRIPTIVE NAME: MBED Source for MultiTech mDot, EVB, and MDOT-BOX Devices + * + * COPYRIGHT: Copyright 2014-2017, Telit + * + * LICENSED MATERIAL - PROGRAM PROPERTY OF TELIT + * REFER TO TELIT COPYRIGHT INSTRUCTION + * +** WEB SITE: www.telit.com + * + * WRITTEN BY: Eliott Fersko and John Keever + * + * DATE: April 17, 2017 + * + * VERSION: 1.04 + * + * FUNCTION: Provide working example for LoRa 'Sensor-to-Cloud' + * Demonstration using MultiTech LoRa Starter Kit and + * Telit Data and Cloud Platform Services Offerings + * + * SOURCE FILE TYPE: MBED C++ + * + * FUNCTIONS/ENTRY POINTS: main + * + * INPUT = None. + * OUTPUT = None. + * + * EXIT-NORMAL = N/A + * EXIT-ERROR = N/A + * + * EXTERNAL REFERENCES = None. + * + * EXTERNAL FUNCTIONS = None. + * + * CONTROL BLOCKS = None. + * + *================================================================================*/ +/* LEGAL DISCLAIMER */ +/*================================================================================ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Neither the name of ILS Technology nor Telit nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + *================================================================================*/ +/* CHANGE LOG */ +/*================================================================================*/ +/* |Changed | | */ +/* Date | by |Version ID| Comments */ +/*----------+--------+----------+-------------------------------------------------*/ +/*04-12-2017|JEK |V1.00 |Original Version - mDot, EVB, MDOT-BOX */ +/*04-14-2017|JEK |V1.01 |Added IRQ Handlers - SW1/SW2 (Threads?) */ +/*04-17-2017|JEK |V1.02 |Added Binary LoRa Payload Message Framing Type */ +/*04-24-2017|EMF |V1.03 |Updated Libraries */ +/*05-10-2017|EMF |V1.04 |Added support for ST-Micro MEMS Sensor Shield */ +/*05-30-2017|EMF |V1.05 |Added GPS support for MDOT-BOX */ +/*================================================================================*/ +/*NOTE: Please keep the change log up to date!!! */ +/*================================================================================*/ + +#include "mbed.h" +#include "MMA845x.h" +#include "MPL3115A2.h" +#include "ISL29011.h" +#include "NCP5623B.h" +#include "DOGS102.h" +#include "font_6x8.h" +#include "MultiTech_Logo.h" +#include "mDot.h" +#include "rtos.h" +#include "GPSPARSER.h" +#include "MTSSerial.h" +#include "x_nucleo_iks01a1.h" + +#include <cmath> +#include <string> +#include <vector> +#include <ctime> +#include <Ticker.h> + +#define CALL_METH(obj, meth, param, ret) ((obj == NULL) ? \ + ((*(param) = (ret)), 0) : \ + ((obj)->meth(param)) \ + ) + +//Length of time between data publishes +const int CYCLE_TIME = 5000; + +enum LED1_COLOR { + RED = 0, + GREEN = 1 +}; + +namespace { + const int MS_INTERVALS = 1000; +} + +/* + * union for converting from 32-bit to 4 8-bit values + */ +union convert32 { + int32_t f_s; // convert from signed 32 bit int + uint32_t f_u; // convert from unsigned 32 bit int + uint8_t t_u[4]; // convert to 8 bit unsigned array +}; + +typedef struct { + int32_t AXIS_X; + int32_t AXIS_Y; + int32_t AXIS_Z; +} AxesRaw_TypeDef; + + +/* + * union for converting from 16- bit to 2 8-bit values + */ +union convert16 { + int16_t f_s; // convert from signed 16 bit int + uint16_t f_u; // convert from unsigned 16 bit int + uint8_t t_u[2]; // convert to 8 bit unsigned array +}; + +//DigitalIn mDot02(PA_2); // GPIO/UART_TX +//DigitalOut mDot03(PA_3); // GPIO/UART_RX +//DigitalIn mDot04(PA_6); // GPIO/SPI_MISO +//DigitalIn mDot06(PA_8); // GPIO/I2C_SCL +//DigitalIn mDot07(PC_9); // GPIO/I2C_SDA + +InterruptIn mDot08(PA_12); // GPIO/USB PB S1 on EVB +InterruptIn mDot09(PA_11); // GPIO/USB PB S2 on EVB + +//DigitalIn mDot11(PA_7); // GPIO/SPI_MOSI + +InterruptIn mDot12(PA_0); // GPIO/UART_CTS PRESSURE_INT2 on EVB +DigitalOut mDot13(PC_13,1); // GPIO LCD_C/D +InterruptIn mDot15(PC_1); // GPIO LIGHT_PROX_INT on EVB +InterruptIn mDot16(PA_1); // GPIO/UART_RTS ACCEL_INT2 on EVB +DigitalOut mDot17(PA_4,1); // GPIO/SPI_NCS LCD_CS on EVB + +// DigitalIn mDot18(PA_5); // GPIO/SPI_SCK +// DigitalInOut mDot19(PB_0,PIN_INPUT,PullNone,0); // GPIO PushPull LED Low=Red High=Green set MODE=INPUT to turn off +// AnalogIn mDot20(PB_1); // GPIO Current Sense Analog in on EVB + +Serial debugUART(PA_9, PA_10); // mDot debug UART +MTSSerial mDotUART(PA_2,PA_3); // mDot external UART mDot02 and mDot03 +I2C mDoti2c(PC_9,PA_8); // mDot External I2C mDot6 and mDot7 +SPI mDotspi(PA_7,PA_6,PA_5); // mDot external SPI mDot11, mDot4, and mDot18 +AnalogIn current_sensor(PB_1); // EVB - GPIO - Current Sensor Analog Input + +/* **** replace these values with the proper public or private network settings **** + * config_network_nameand config_network_pass are for private networks. + */ + +//static std::string config_network_name = "telitlora"; +//static std::string config_network_pass = "telitpass"; +//static uint8_t config_frequency_sub_band = 7; + + + +static volatile bool timer_irq_triggered = false; +static volatile bool ff_irq_triggered = false; + + +static std::string config_network_name = "MTCDT-19020718"; +static std::string config_network_pass = "MTCDT-19020718"; +static uint8_t config_frequency_sub_band = 1; + + +/* +static std::string config_network_name = "MTCDT-19186804"; +static std::string config_network_pass = "MTCDT-19186804"; +static uint8_t config_frequency_sub_band = 1; +*/ + +/* config_app_id and config_app_key are for public networks. +static uint8_t app_id[8] = {0x00,0x01,0x02,0x03,0x0A,0x0B,0x0C,0x0D}; +std::vector<uint8_t> config_app_id; +static uint8_t app_key[16] = {0x00,0x01,0x02,0x03,0x0A,0x0B,0x0C,0x0D}; +std::vector<uint8_t> config_app_key; +*/ + +uint8_t result; +uint8_t data; +uint8_t sf_val = mDot::SF_7; +uint8_t pwr_val = 11; // dBm +uint8_t swp_pwr; +uint8_t swp_sf; + +// max size of text string for 6x8 font. Set to 12 if using 8x8 font +char txtstr[17]; + +int32_t mdot_ret; +int32_t join_delay; + +osThreadId mainThreadID; + +// flags for push button debounce code +bool pb1_low = false; +bool pb2_low = false; +bool toggle_text = false; +bool sw1_state = false; +bool sw2_state = false; + +uint32_t num_whole; +uint16_t num_frac; + +uint32_t pressure; +double current; + +bool exit_program = false; + +//EVB sensor variables +MMA845x_DATA accel_data; +MPL3115A2_DATA baro_data; +uint16_t lux_data; +MMA845x* evbAccel; +MPL3115A2* evbBaro; +ISL29011* evbAmbLight; +NCP5623B* evbBackLight; +DOGS102* evbLCD; + +//MEMS sensor variables +X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(I2C_SDA, I2C_SCL, PC_1); +static Ticker ticker; +GyroSensor *memsGyro; +MotionSensor *memsAccel; +MagneticSensor *memsMag; +HumiditySensor *memsHumidity; +PressureSensor *memsPressure; +TempSensor *memsTemp1; +TempSensor *memsTemp2; +unsigned int ret = 0; +char buffer1[32]; +char buffer2[32]; +char buffer3[32]; +char buffer4[32]; +float temp_value, humid_value, pressure_value; +int16_t int_temp_value, int_humid_value, int_pressure_value; +int32_t accel_vector[3]; +int32_t mag_vector[3]; +int32_t gyro_vector[3]; + +//MDOT-BOX sensor variables +GPSPARSER::latitude lat_data; +GPSPARSER::longitude lng_data; +NCP5623B* led_cont; +MTSSerial gps_serial(XBEE_DOUT, XBEE_DIN, 256, 2048); +GPSPARSER* mdot_gps; +float lat = 0; +float lng = 0; +bool sat_lock = 0; + +mDot* mdot_radio; +Mutex mdot_mutex; + + + + + + + + + + +convert32 convertl; +convert16 converts; + +void pb1ISR(void); +void pb2ISR(void); +void pb1_debounce(void const *args); +void pb2_debounce(void const *args); + +MPL3115A2* resetBaro(const MPL3115A2* oldBaro); +void log_error(mDot* dot, const char* msg, int32_t retval); +int32_t sendString(const std::string text); +bool writeValueOrError(); + +const int FAIL_MAX=15; +int failtime=FAIL_MAX; +int cycle_cnt = 0; + +char sensor_text[64]; +char lora_temp_string[16]; +char lora_alt_string[16]; +char lora_press_string[16]; +char lora_light_string[16]; +char lora_current_string[16]; +char lora_humid_string[16]; +char lora_lat_string[16]; +char lora_lng_string[16]; + +bool bHasGPS = false; +bool bHasACC = false; +bool bHasLCD = false; + +/*** Helper Functions ------------------------------------------------------------ ***/ +/* print floats & doubles */ +static char *printDouble(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; +} +/*=================================================================================== +Main Program Logic - Entry +===================================================================================*/ +int main() +{ + std::vector<uint8_t> mdot_data; + std::vector<uint8_t> mdot_EUI; + uint16_t i = 0; + uint8_t id1 = 0; + + debugUART.baud(9600); + + printf ("Starting Application...\r\n"); + + mainThreadID = osThreadGetId(); + + printf("Begin I2C/SPI Device Initialization...\r\n"); + + + // Use Magnetometer As MEMS sensor shield Enumeration... + + memsMag = mems_expansion_board->magnetometer; + CALL_METH(memsMag, ReadID, &id1, 0x0); + printf("Magnetometer ID value = %i \n\r", id1); + + //chcek for default magnetomter ID 61... + if(id1 == 61) + { + printf("Magnetometer Found - MEMS sensor shield detected...\r\n"); + bHasACC = true; + + // Initialize Integrated Sensors... + printf("Instantiate Magnetometer...\r\n"); + memsMag = mems_expansion_board->magnetometer; + + printf("Instantiate Accelerometer...\r\n"); + memsAccel = mems_expansion_board->GetAccelerometer(); + + printf("Instantiate Gyroscope...\r\n"); + memsGyro = mems_expansion_board->GetGyroscope(); + + printf("Instantiate Barometric Pressure Sensor...\r\n"); + memsPressure = mems_expansion_board->pt_sensor; + + printf("Instantiate Temperature Pressure Sensor...\r\n"); + memsTemp1 = mems_expansion_board->ht_sensor; + memsTemp2 = mems_expansion_board->pt_sensor; + + printf("Instantiate Humidity Sensor...\r\n"); + memsHumidity = mems_expansion_board->ht_sensor; + + } + + + else + { + printf("No Magnetometer Found...\r\n"); + // Use Accelerometer As MDOT-BOX/EVB Enumeration... + printf("Instantiate Accelerometer...\r\n"); + evbAccel = new MMA845x(mDoti2c,MMA845x::SA0_VSS); + + printf("Accelerometer Status = %d\r\n", evbAccel->getStatus()); + printf("Accelerometer who_am_i value = %x \n\r", evbAccel->getWhoAmI()); + + if( (evbAccel->getStatus() == 1) && (evbAccel->getWhoAmI() == 0) ) + { + printf("No Accelerometer Found - Basic mDot, Not MDOT-BOX or EVB...\r\n"); + } + + else + { + printf("Accelerometer Found - Either MDOT-BOX or EVB...\r\n"); + bHasACC = true; + + // Initialize Integrated Sensors... + printf("Instantiate Barometric Pressure Sensor...\r\n"); + evbBaro = new MPL3115A2(mDoti2c); // Setup Barometric Sensor + printf("Barometric Sensor Status = %d\r\n", evbBaro->getStatus()); + printf("Barometer who_am_i check = %d\r\n", evbBaro->testWhoAmI()); + printf("Barometer who_am_i check = %s\r\n", evbBaro->testWhoAmI() ? "TRUE" : "FALSE"); + + if( evbBaro->getStatus() == 0 ) printf("No Barometric Sensor...\r\n"); + + printf("Instantiate Ambient Light Sensor...\r\n"); + evbAmbLight = new ISL29011(mDoti2c); // Setup Ambient Light Sensor + + // Setup the Accelerometer for 8g range, 14 bit resolution, Noise reduction off, sample rate 1.56 Hz + // Normal oversample mode, High pass filter off + evbAccel->setCommonParameters(MMA845x::RANGE_8g,MMA845x::RES_MAX,MMA845x::LN_OFF, MMA845x::DR_1_56,MMA845x::OS_NORMAL,MMA845x::HPF_OFF ); + + // Setup the Barometric sensor for post processed Ambient pressure, 4 samples per data acquisition. + // and a sample taken every second when in active mode + evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16, MPL3115A2::AT_1); + + // Setup the Ambient Light Sensor for continuous Ambient Light Sensing, 16 bit resolution, and 16000 lux range + evbAmbLight->setMode(ISL29011::ALS_CONT); + evbAmbLight->setResolution(ISL29011::ADC_16BIT); + evbAmbLight->setRange(ISL29011::RNG_16000); + + // Set the accelerometer for active mode + evbAccel->activeMode(); + + // Clear the min-max registers in the Barometric Sensor + evbBaro->clearMinMaxRegs(); + + // Support Integrated LCD Display + bHasLCD = true; + + printf("Instantiate BackLight and LCD Display...\r\n"); + evbBackLight = new NCP5623B(mDoti2c); // setup backlight and LED 2 driver chip + + evbLCD = new DOGS102(mDotspi, mDot17, mDot13); // setup LCD Display + + printf("Font Table Address: %p\r\n",&font_6x8); + printf("Bitmap Logo Address: %p\r\n",&MultiTech_Logo); + + // Setup and display logo on LCD + evbLCD->startUpdate(); + evbLCD->writeBitmap(0,0,MultiTech_Logo); + + sprintf(txtstr,"MTDOT-EVB"); + evbLCD->writeText(24,3,font_6x8,txtstr,strlen(txtstr)); + sprintf(txtstr,"Sensor Demo"); + evbLCD->writeText(18,4,font_6x8,txtstr,strlen(txtstr)); + + evbLCD->endUpdate(); + + printf("Setup PushButton Interface Handlers...\r\n"); + + printf("Launching Debounce Threads...\r\n"); + Thread thread_1(pb1_debounce); + Thread thread_2(pb2_debounce); + printf("Debounce Threads Launched...\r\n"); + + printf("Set SW1/SW2 IRQs...\r\n"); + // Setup SW1 as Data rate and power out select + mDot08.disable_irq(); + mDot08.fall(&pb1ISR); + + // need to call this function after rise or fall because rise/fall sets mode to PullNone + mDot08.mode(PullUp); + mDot08.enable_irq(); + + // Setup SW2 as send PING + mDot09.disable_irq(); + mDot09.fall(&pb2ISR); + + // need to call this function after rise or fall because rise/fall sets mode to PullNone + mDot09.mode(PullUp); + mDot09.enable_irq(); + + // Setting other InterruptIn pins with Pull Ups + mDot12.mode(PullUp); + mDot15.mode(PullUp); + mDot16.mode(PullUp); + + printf("SW1/SW2 IRQs Set...\r\n"); + } + } + + printf("I2C/SPI Device Initialization Complete...\r\n"); + + printf("\r\nSetup mDot Radio Communications...\r\n"); + + // get a mDot handle + mdot_radio = mDot::getInstance(); + + if (mdot_radio) + { + // reset to default config so we know what state we're in + mdot_mutex.lock(); // lock mdot before setting configuration + mdot_radio->resetConfig(); + + // Setting up LED1 as activity LED + mdot_radio->setActivityLedPin(PB_0); + mdot_radio->setActivityLedEnable(true); + + // Read node ID + mdot_EUI = mdot_radio->getDeviceId(); + printf("mDot EUI = "); + + for(i=0; i<mdot_EUI.size(); i++) { + printf("%02x ", mdot_EUI[i]); + } + printf("\r\n"); + + // Setting up the mDot with network information. + + // This call sets up private or public mode on the MTDOT. Set the function to true if + // connecting to a public network + printf("Setting Private Network Mode...\r\n"); + if ((mdot_ret = mdot_radio->setPublicNetwork(false)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to set Public Network Mode", mdot_ret); + } + + // Frequency sub-band is valid for NAM only and for Private networks should be set to a value + // between 1-8 that matches the the LoRa gateway setting. Public networks use sub-band 0 only. + // This function can be commented out for EU networks + printf("Setting Frequency Sub-Band...\r\n"); + if ((mdot_ret = mdot_radio->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to set Frequency Sub-Band", mdot_ret); + } + + // Setting TX power for radio. Max allowed is +14dBm for EU and +20 dBm for NAM. Default is +11 dBm + printf("Setting TX Power Level to %2d dBm...\r\n", pwr_val); + if ((mdot_ret = mdot_radio->setTxPower(pwr_val)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to set TX Power Level", mdot_ret); + } + + // Setting TX data rate for radio. Max allowed is SF_12 for EU and SF10 dBm for NAM. Default is SF_10 + printf("Setting TX data rate to SF_7...\r\n"); + if ((mdot_ret = mdot_radio->setTxDataRate(sf_val)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to set TX Data Rate", mdot_ret); + } + + // Configure Pushbutton Display Labels... + sprintf(txtstr,"SF=%2d PWR=%2d",sf_val,pwr_val); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + printf("%s\r\n",txtstr); + + + // Setting Packet ACK to 1 try. + + printf("Setting Packet Retry to 1...\r\n"); + if ((mdot_ret = mdot_radio->setAck(1)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to set Packet Retry\r\n", mdot_ret); + } + + + // setNetworkName is used for private networks. + // Use setNetworkID(AppID) for public networks + + // config_app_id.assign(app_id,app_id+7); + + printf("Setting Network Name...\r\n"); + if ((mdot_ret = mdot_radio->setNetworkName(config_network_name)) != mDot::MDOT_OK) { + // if ((mdot_ret = mdot_radio->setNetworkID(config_app_id)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to set Network Name", mdot_ret); + } + + // setNetworkPassphrase is used for private networks + // Use setNetworkKey for public networks + + // config_app_key.assign(app_key,app_key+15); + + printf("Setting Network Password...\r\n"); + if ((mdot_ret = mdot_radio->setNetworkPassphrase(config_network_pass)) != mDot::MDOT_OK) { + // if ((mdot_ret = mdot_radio->setNetworkKey(config_app_key)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to set Network Password", mdot_ret); + } + + mdot_mutex.unlock(); // unlock mdot mutex before join attempt so SW1 can work + + // attempt to join the network + printf("Joining LoRa Network...\r\n"); + do { + mdot_mutex.lock(); // lock mdot mutex before join attempt + mdot_ret = mdot_radio->joinNetwork(); + mdot_mutex.unlock(); // unlock mdot mutex after join attempt so SW1 can work + + if (mdot_ret != mDot::MDOT_OK) + { + log_error(mdot_radio,"ERROR: Failed to Join Network:", mdot_ret); + + if (toggle_text) + sprintf(txtstr," > Join Failed <"); + else + sprintf(txtstr," < Join Failed >"); + + if( bHasLCD ) evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); + + if (mdot_radio->getFrequencyBand() == mDot::FB_868) + { + join_delay = mdot_radio->getNextTxMs(); + } + else + { + join_delay = 10; + } + printf("Join Delay = %lu\r\n",join_delay); + osDelay(join_delay + 1); + toggle_text = !toggle_text; + } + + /* + * Setting TX power and Data Rate for radio just in case user requested by SW2 + */ + mdot_mutex.lock(); // lock mdot mutex before setting change + mdot_radio->setTxPower(pwr_val); + mdot_radio->setTxDataRate(sf_val); + mdot_mutex.unlock(); // unlock mdot mutex after settings change so SW1 can work + + } while (mdot_ret != mDot::MDOT_OK); + + printf("Successfully Joined LoRa Network...\r\n"); + + sprintf(txtstr,"*Network Joined*"); + if( bHasLCD ) evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); + + } + else + { + printf("ERROR: Unable to Join LoRa Network...\r\n"); + sprintf(txtstr,"Radio Init Failed!"); + if( bHasLCD ) evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); + printf("%s\r\n",txtstr); + exit(1); + } + + // Check for MDOT-BOX Configuration (GPS) + + if( bHasACC && bHasLCD ) + { + printf("Instantiate GPS...\r\n"); + mdot_gps = new GPSPARSER(&gps_serial, led_cont); + osDelay(1000); + if(!mdot_gps->gpsDetected()) + { + printf(">>>> No GPS Detected... Not an MDOT-BOX, EVB Identified\r\n"); + + sprintf(txtstr,"*No GPS Detected*"); + if( bHasLCD ) evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); + } + else + { + // main_single = main_sweep = false; + printf(">>>> GPS Detected... MDOT-BOX Identified\r\n"); + sprintf(txtstr,"*GPS Detected*"); + if( bHasLCD ) evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); + bHasGPS = true; + } + } + + printf("Initialization/Configuration Completed...\r\n"); + + osDelay(1500); + if( bHasLCD ) evbBackLight->setPWM(NCP5623B::LED_3,16); // enable LED2 on EVB and set to 50% PWM + + // sets LED2 to 50% max current + if( bHasLCD ) evbBackLight->setLEDCurrent(16); + + + // Check for PB1 press during network join attempt + /* + if (exit_program) + { + printf("PB1 Pressed, Exiting Program...\r\n"); + if( bHasLCD ) evbLCD->clearBuffer(); + sprintf(txtstr,"Exiting Program"); + if( bHasLCD ) evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); + exit(1); + } + */ + + // Enter Main Data Acquisition Loop... + printf("Processing Data Acquisition Scan Loop...\r\n"); + + i = 0; + cycle_cnt = 100; + + if( bHasLCD ) evbLCD->clearBuffer(); + + do + { + //BOX + if(bHasGPS) + { + //GPS code + if (mdot_gps->getLockStatus()) + { + + //Retrieve and print out Latitude data + lat_data = mdot_gps->getLatitude(); + sat_lock = 1; + //Conversion from DMS to decimal + if(lat_data.degrees>0) + { + lat = (lat_data.degrees + lat_data.minutes/60.0 + lat_data.seconds/600000.0); + } + else + { + lat = (lat_data.degrees - lat_data.minutes/60.0 - lat_data.seconds/600000.0); + } + sprintf(txtstr, "Lat = %.7f",lat); + sprintf(lora_lat_string,"%.7f",lat); + evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); + + //Retrieve and print out Longitude data + lng_data = mdot_gps->getLongitude(); + //Conversion from DMS to decimal + if(lng_data.degrees>0) + { + lng = (lng_data.degrees + lng_data.minutes/60.0 + lng_data.seconds/600000.0); + } + else + { + lng = (lng_data.degrees - lng_data.minutes/60.0 - lng_data.seconds/600000.0); + } + sprintf(txtstr, "Lng = %.7f",lng); + sprintf(lora_lng_string,"%.7f",lng); + evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); + } + else + { + //reset sat_lock, lat, and lng while device doesn't have lock + sprintf(txtstr," > no GPS lock < "); + evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); + evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); + printf("%s \r\n",txtstr); + sat_lock = 0; + lat = 0; + lng = 0; + sprintf(lora_lat_string, "%f",lat); + sprintf(lora_lng_string, "%f",lng); + + + } + + // Check Accelerometer XYZ data ready bit to see if acquisition complete + failtime = FAIL_MAX; + do + { + osDelay(100); // allows other threads to process + result = evbAccel->getStatus(); + failtime--; + } while ((result & MMA845x::XYZDR) == 0 && failtime > 0); + + if (failtime==0) + { + evbBaro=resetBaro(evbBaro); + continue; + } + + // Retrieve and print out accelerometer data + + accel_data = evbAccel->getXYZ(); + sprintf(txtstr, "Accel-X = %d", accel_data._x); + evbLCD->writeText(0,0,font_6x8,txtstr,strlen(txtstr)); + sprintf(txtstr, "Accel-Y = %d", accel_data._y); + evbLCD->writeText(0,1,font_6x8,txtstr,strlen(txtstr)); + sprintf(txtstr, "Accel-Z = %d", accel_data._z ); + evbLCD->writeText(0,2,font_6x8,txtstr,strlen(txtstr)); + + // Trigger a Barometric Pressure Reading + evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16, MPL3115A2::AT_1); + evbBaro->triggerOneShot(); + + // Test Barometer Device, Check to see if acquisition is complete + failtime=FAIL_MAX; + do + { + osDelay(100); // allows other threads to process + result = evbBaro->getStatus(); + failtime--; + } while ((result & MPL3115A2::PTDR) == 0 && failtime > 0 ); + + if(failtime==0) + { + evbBaro=resetBaro(evbBaro); + continue; + } + + // Retrieve and Display Barometric Pressure + pressure = evbBaro->getBaroData() >> 12; // convert 32 bit signed to 20 bit unsigned value + num_whole = pressure >> 2; // 18 bit integer significant + num_frac = (pressure & 0x3) * 25; // 2 bit fractional 0.25 per bit + + // If failtime reached 0 , indicates that the result might be junk. + sprintf(txtstr,"Press=%ld.%01d Pa", num_whole, num_frac/10); + + pressure = evbBaro->getBaroData() >> 12; // convert 32 bit signed to 20 bit unsigned value + num_whole = pressure >> 2; // 18 bit integer significant + num_frac = (pressure & 0x3) * 25; // 2 bit fractional 0.25 per bit + + writeValueOrError(); // will write to lorapresstring and txtstr + + // Trigger a Altitude reading + // evbBaro->setAltitudeCalib(101); + evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_ALTIMETER, MPL3115A2::OR_16, MPL3115A2::AT_1); + // evbBaro->setAltitudeCalib(101); + evbBaro->triggerOneShot(); + + // Test barometer device status to see if acquisition is complete + failtime=FAIL_MAX; + do + { + osDelay(100); // allows other threads to process + result = evbBaro->getStatus(); + failtime--; + } while ((result & MPL3115A2::PTDR) == 0 && failtime > 0 ); + + if (failtime==0) + { + evbBaro=resetBaro(evbBaro); + continue; + } + + // Retrieve and Display Altimeter Reading + baro_data = evbBaro->getAllData(false); + baro_data._baro /= 4096; // convert 32 bit signed to 20 bit signed value + num_whole = baro_data._baro / 16; // 18 bit signed significant integer (JEK Added 60 as SWAG Offset for Boca) + num_frac = (baro_data._baro & 0xF) * 625 / 100; // 4 bit fractional .0625 per bit + sprintf(txtstr,"Alti=%ld.%03d m", num_whole, num_frac); + sprintf(lora_alt_string,"%ld.%03d", num_whole, num_frac); + evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); + + // Retrieve and Display Temperature Reading + num_whole = baro_data._temp / 16; // 8 bit signed significant integer + num_frac = (baro_data._temp & 0x0F) * 625 / 100; // 4 bit fractional .0625 per bit + sprintf(txtstr,"Temp=%ld.%03d C", num_whole, num_frac); + sprintf(lora_temp_string,"%ld.%03d", num_whole, num_frac); + //evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); + + // Retrieve and Display Ambient Light Level + lux_data = evbAmbLight->getData(); + num_whole = lux_data * 24 / 100; // 16000 lux full scale .24 lux per bit + num_frac = lux_data * 24 % 100; + sprintf(txtstr, "Light=%ld.%02d lux", num_whole, num_frac ); + sprintf(lora_light_string, "%ld.%02d", num_whole, num_frac ); + //evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); + + // Retrieve and Display Current Sensor Level (EVB Analog Input) + current = (double) current_sensor * 65535.0; + sprintf(lora_current_string, "%d", (int) current); + + // Handle Pushbutton #1 (SW1) - This should be handled by the 'pb1_debounce' thread. + if( pb1_low ) + { + sw1_state = !sw1_state; + if( bHasLCD ) evbBackLight->setPWM(NCP5623B::LED_3,0); // enable LED2 on EVB and set to 0% PWM + + sprintf(txtstr,"PB1 Press-SW1: %d", sw1_state); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + printf("%s \r\n",txtstr); + + pb1_low = false; + } + + // Handle Pushbutton #2 (SW2) - This should be handled by the 'pb2_debounce' thread. + if( pb2_low ) + { + sw2_state = !sw2_state; + if( bHasLCD ) evbBackLight->setPWM(NCP5623B::LED_3,16); // enable LED2 on EVB and set to 50% PWM + + sprintf(txtstr,"PB2 Press-SW2: %d", sw2_state); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + printf("%s \r\n",txtstr); + + pb2_low = false; + } + } + + //EVB + else if( bHasACC && bHasLCD ) + { + // Check Accelerometer XYZ data ready bit to see if acquisition complete + failtime = FAIL_MAX; + do + { + osDelay(100); // allows other threads to process + result = evbAccel->getStatus(); + failtime--; + } while ((result & MMA845x::XYZDR) == 0 && failtime > 0); + + if (failtime==0) + { + evbBaro=resetBaro(evbBaro); + continue; + } + + // Retrieve and print out accelerometer data + accel_data = evbAccel->getXYZ(); + sprintf(txtstr, "Accel-X = %d", accel_data._x); + evbLCD->writeText(0,0,font_6x8,txtstr,strlen(txtstr)); + sprintf(txtstr, "Accel-Y = %d", accel_data._y); + evbLCD->writeText(0,1,font_6x8,txtstr,strlen(txtstr)); + sprintf(txtstr, "Accel-Z = %d", accel_data._z ); + evbLCD->writeText(0,2,font_6x8,txtstr,strlen(txtstr)); + + // Trigger a Barometric Pressure Reading + evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16, MPL3115A2::AT_1); + evbBaro->triggerOneShot(); + + // Test Barometer Device, Check to see if acquisition is complete + failtime=FAIL_MAX; + do + { + osDelay(100); // allows other threads to process + result = evbBaro->getStatus(); + failtime--; + } while ((result & MPL3115A2::PTDR) == 0 && failtime > 0 ); + + if(failtime==0) + { + evbBaro=resetBaro(evbBaro); + continue; + } + + // Retrieve and Display Barometric Pressure + pressure = evbBaro->getBaroData() >> 12; // convert 32 bit signed to 20 bit unsigned value + num_whole = pressure >> 2; // 18 bit integer significant + num_frac = (pressure & 0x3) * 25; // 2 bit fractional 0.25 per bit + + // If failtime reached 0 , indicates that the result might be junk. + sprintf(txtstr,"Press=%ld.%01d Pa", num_whole, num_frac/10); + + pressure = evbBaro->getBaroData() >> 12; // convert 32 bit signed to 20 bit unsigned value + num_whole = pressure >> 2; // 18 bit integer significant + num_frac = (pressure & 0x3) * 25; // 2 bit fractional 0.25 per bit + + writeValueOrError(); // will write to lorapresstring and txtstr + + // Trigger an Altitude reading + // evbBaro->setAltitudeCalib(101); + evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_ALTIMETER, MPL3115A2::OR_16, MPL3115A2::AT_1); + // evbBaro->setAltitudeCalib(101); + evbBaro->triggerOneShot(); + + // Test barometer device status to see if acquisition is complete + failtime=FAIL_MAX; + do + { + osDelay(100); // allows other threads to process + result = evbBaro->getStatus(); + failtime--; + } while ((result & MPL3115A2::PTDR) == 0 && failtime > 0 ); + + if (failtime==0) + { + evbBaro=resetBaro(evbBaro); + continue; + } + + // Retrieve and Display Altimeter Reading + baro_data = evbBaro->getAllData(false); + baro_data._baro /= 4096; // convert 32 bit signed to 20 bit signed value + num_whole = baro_data._baro / 16; // 18 bit signed significant integer (JEK Added 60 as SWAG Offset for Boca) + num_frac = (baro_data._baro & 0xF) * 625 / 100; // 4 bit fractional .0625 per bit + sprintf(txtstr,"Alti=%ld.%03d m", num_whole, num_frac); + sprintf(lora_alt_string,"%ld.%03d", num_whole, num_frac); + evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); + + // Retrieve and Display Temperature Reading + num_whole = baro_data._temp / 16; // 8 bit signed significant integer + num_frac = (baro_data._temp & 0x0F) * 625 / 100; // 4 bit fractional .0625 per bit + sprintf(txtstr,"Temp=%ld.%03d C", num_whole, num_frac); + sprintf(lora_temp_string,"%ld.%03d", num_whole, num_frac); + evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); + + // Retrieve and Display Ambient Light Level + lux_data = evbAmbLight->getData(); + num_whole = lux_data * 24 / 100; // 16000 lux full scale .24 lux per bit + num_frac = lux_data * 24 % 100; + sprintf(txtstr, "Light=%ld.%02d lux", num_whole, num_frac ); + sprintf(lora_light_string, "%ld.%02d", num_whole, num_frac ); + evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); + + // Retrieve and Display Current Sensor Level (EVB Analog Input) + current = (double) current_sensor * 65535.0; + sprintf(lora_current_string, "%d", (int) current); + + // Handle Pushbutton #1 (SW1) - This should be handled by the 'pb1_debounce' thread. + if( pb1_low ) + { + sw1_state = !sw1_state; + if( bHasLCD ) evbBackLight->setPWM(NCP5623B::LED_3,0); // enable LED2 on EVB and set to 0% PWM + + sprintf(txtstr,"PB1 Press-SW1: %d", sw1_state); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + printf("%s \r\n",txtstr); + + pb1_low = false; + } + + // Handle Pushbutton #2 (SW2) - This should be handled by the 'pb2_debounce' thread. + if( pb2_low ) + { + sw2_state = !sw2_state; + if( bHasLCD ) evbBackLight->setPWM(NCP5623B::LED_3,16); // enable LED2 on EVB and set to 50% PWM + + sprintf(txtstr,"PB2 Press-SW2: %d", sw2_state); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + printf("%s \r\n",txtstr); + + pb2_low = false; + } + } + //MEMS + else if(!bHasLCD && bHasACC) + { + + std::vector<uint8_t> tx_data; + + + // Payload structure for mydevices cayenne: + // 1 byte Data1 ID + // 1 Byte Data1 Type + // N Bytes Data1 + // 1 byte data 2 ID + // 1 byte data 2 type + // n Bytes data 2 + // ... + + // formats: + // Temperature sensor: + /* + * IPSO: 3303 + * LPP 103 + * HEX: 67 + * Data size: 2 + * Resolution: 0.1 degres C + + * Humidity sensor + * IPSO: 3304 + * LPP: 104 + * Hex: 68 + * Datasize: 1 + * Resolution: 0.5% unsigned + + * Barometer/pressure sensor + * IPSO: 3315 + * LPP: 115 + * Hex: 73 + * Datasize: 2 + * Resolution 0.1hPa unsigned MSB + + * Accelerometer + * IPSO: 3313 + * LPP: 113 + * Hex: 71 + * Data size: 6 + * Resolution: 0.001G signed MSB per axis + + * Gyrometer + * IPSO: 3334 + * LPP: 134 + * Hex: 86 + * Data size: 6 + * Resolution: 0.01 degrees/s signed msb per axis + */ + + // HTS221 Humidity sensor + ret |= (!CALL_METH(memsTemp1, GetTemperature, &temp_value, 0.0f) ? 0x0 : 0x1); + ret |= (!CALL_METH(memsHumidity, GetHumidity, &humid_value, 0.0f) ? 0x0 : 0x2);; + + /* + //serialize data and append to packet + // Cayenne data: temperature; tag is 0x67, 2 bytes signed, 0.1 C/bit + tx_data.push_back(uint8_t(1)); // data id + tx_data.push_back(uint8_t(0x67)); // data type - temp + int_temp_value = floor(temp_value*10 + 0.5f); + tx_data.push_back(uint8_t( 0xFF & (int_temp_value >> 8))); + tx_data.push_back(uint8_t(0xFF & int_temp_value)); + + + tx_data.push_back(uint8_t(2)); // data id + tx_data.push_back(uint8_t(0x68)); // data type - humidity + int_humid_value = floor(humid_value * 2.0f + 0.5f); + tx_data.push_back(uint8_t(0xFF & int_humid_value )); + */ + + ret |= (!CALL_METH(memsPressure, GetPressure, &pressure_value, 0.0f) ? 0x0 : 0x4);; + + /* + // pressure is reported in mbar + // 1mbar = 1 hPa + int_pressure_value = floor(pressure_value * 100.0f + 0.5f); + + tx_data.push_back(uint8_t(3)); // data id + tx_data.push_back(uint8_t(0x73)); // data type - pressure + int_pressure_value = floor(pressure_value / 0.1f + 0.5f); + tx_data.push_back(uint8_t(0xFF & (int_pressure_value >> 8))); + tx_data.push_back(uint8_t(0xFF & int_pressure_value)); + */ + + // Get accelerometer data + // returns in mG + memsAccel->Get_X_Axes(accel_vector); + + /* + tx_data.push_back(uint8_t(4)); // data id + tx_data.push_back(uint8_t(0x71)); // data type - accelerometer + for(int i=0; i<3; i++) { + tx_data.push_back(uint8_t(0xFF & accel_vector[i]) >> 8); + tx_data.push_back(uint8_t(0xFF & accel_vector[i])); + } + */ + + // Get gyro data + memsGyro->Get_G_Axes(gyro_vector); + + /* + tx_data.push_back(uint8_t(5)); //data id + tx_data.push_back(uint8_t(0x86)); // data type - gyrometer + for(int i=0; i<3; i++) { + gyro_vector[i] /= 10; + tx_data.push_back(uint8_t(0xFF & (gyro_vector[i] >> 8))); + tx_data.push_back(uint8_t(0xFF & gyro_vector[i])); + } + */ + + // Get magnetometer data + memsMag->Get_M_Axes(mag_vector); + + /* + tx_data.push_back(uint8_t(5)); //data id + tx_data.push_back(uint8_t(0x99)); // data type - mangetometer + for(int i=0; i<3; i++) { + mag_vector[i] /= 10; + tx_data.push_back(uint8_t(0xFF & (mag_vector[i] >> 8))); + tx_data.push_back(uint8_t(0xFF & mag_vector[i])); + } + */ + + } + else + { + //Basic mDot... fabricated data + sprintf(lora_press_string, "%ld.%02d", 101967, 33 ); + sprintf(lora_alt_string, "%ld.%02d", 53, 22 ); + sprintf(lora_temp_string, "%ld.%03d", 22, 123 ); + sprintf(lora_light_string, "%ld.%02d", 399, 62 ); + sprintf(lora_current_string, "%ld.%01d", 88, 62 ); + } + + + //send_data(tx_data); + + //--------------------------------------------------------------------------- + // Verbose Text Format: Least Data Payload, Most Human Readible + //--------------------------------------------------------------------------- + + /* + if(!bHasLCD && bHasACC) + { + + sprintf(sensor_text, "accel-x:%d|accel-y:%d|accel-z:%d|gyro-x:%d|gyro-y:%d|gyro-z:%d|mag-x:%d|mag-y:%d|mag-x:%d|press:%s|temp:%s|humid:%s", + accel_vector[0], + accel_vector[1], + accel_vector[2], + gyro_vector[0], + gyro_vector[1], + gyro_vector[2], + mag_vector[0], + mag_vector[1], + mag_vector[2], + printDouble(buffer3, pressure_value), + printDouble(buffer1, temp_value), + printDouble(buffer2, humid_value)); + } + else + { + sprintf(sensor_text, "accel-x:%d|accel-y:%d|accel-z:%d|press:%s|alti:%s|temp:%s|light:%s|moist:%s", + accel_data._x, + accel_data._y, + accel_data._z, + lora_press_string, + lora_alt_string, + lora_temp_string, + lora_light_string, + lora_current_string); + + } + + + if ((mdot_ret = sendString((const std::string)sensor_text)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to Send Data", mdot_ret); + } else { + printf("Ok, Successfully Sent Data to Gateway...\r\n"); + } + */ + + //--------------------------------------------------------------------------- + // Byte Vector Format: More Data Payload, Less Human Readible + //--------------------------------------------------------------------------- + + //MDOT-BOX + if (bHasGPS) { + sprintf(sensor_text, "ax:%d,ay:%d,az:%d,ll:%d,la:%s,lg:%s,p:%s,a:%s,t:%s,l:%s,c:%s", + accel_data._x, + accel_data._y, + accel_data._z, + sat_lock, + lora_lat_string, + lora_lng_string, + lora_press_string, + lora_alt_string, + lora_temp_string, + lora_light_string, + lora_current_string); + //EVB + } else if(bHasLCD && bHasACC) { + sprintf(sensor_text, "ax:%d,ay:%d,az:%d,p:%s,a:%s,t:%s,l:%s,c:%s", + accel_data._x, + accel_data._y, + accel_data._z, + lora_press_string, + lora_alt_string, + lora_temp_string, + lora_light_string, + lora_current_string); + } + + //MEMS + else if(!bHasLCD && bHasACC){ + + sprintf(sensor_text, "ax:%d,ay:%d,az:%d,gx:%d,gy:%d,gz:%d,mx:%d,my:%d,mz:%d,p:%s,t:%s,h:%s", + accel_vector[0], + accel_vector[1], + accel_vector[2], + gyro_vector[0], + gyro_vector[1], + gyro_vector[2], + mag_vector[0], + mag_vector[1], + mag_vector[2], + printDouble(buffer3, pressure_value), + printDouble(buffer1, temp_value), + printDouble(buffer2, humid_value)); + } + + //Basic mDot + else{ + + sprintf(sensor_text, "p:%s,a:%s,t:%s,l:%s,c:%s", + lora_press_string, + lora_alt_string, + lora_temp_string, + lora_light_string, + lora_current_string); + } + + if ((mdot_ret = sendString((const std::string)sensor_text)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to Send Data", mdot_ret); + } else { + printf("Ok, Successfully Sent Data to Gateway...\r\n"); + } + + /* + //--------------------------------------------------------------------------- + // Binary Encoded Format: Most Data Payload, Not Human Readible + //--------------------------------------------------------------------------- + mdot_data.clear(); + mdot_data.push_back(0x0E); // key for Current Acceleration 3-Axis Value + converts.f_s = accel_data._x *4; // shift data 2 bits while retaining sign + mdot_data.push_back(converts.t_u[1]); // get 8 MSB of 14 bit value + converts.f_s = accel_data._y * 4; // shift data 2 bits while retaining sign + mdot_data.push_back(converts.t_u[1]); // get 8 MSB of 14 bit value + converts.f_s = accel_data._z * 4; // shift data 2 bits while retaining sign + mdot_data.push_back(converts.t_u[1]); // get 8 MSB of 14 bit value + mdot_data.push_back(0x08); // key for Current Pressure Value + convertl.f_u = pressure; // pressure data is 20 bits unsigned + mdot_data.push_back(convertl.t_u[2]); + mdot_data.push_back(convertl.t_u[1]); + mdot_data.push_back(convertl.t_u[0]); + mdot_data.push_back(0x05); // key for Current Ambient Light Value + converts.f_u = lux_data; // data is 16 bits unsigned + mdot_data.push_back(converts.t_u[1]); + mdot_data.push_back(converts.t_u[0]); + mdot_data.push_back(0x0B); // key for Current Temperature Value + converts.f_s = baro_data._temp; // temperature is signed 12 bit + mdot_data.push_back(converts.t_u[1]); + mdot_data.push_back(converts.t_u[0]); + + if ((mdot_ret = mdot_radio->send(mdot_data)) != mDot::MDOT_OK) { + log_error(mdot_radio, "ERROR: Failed to Send Data", mdot_ret); + } else { + printf("Ok, Successfully Sent Data to Gateway...\r\n"); + } + + */ + + osDelay(CYCLE_TIME); + sprintf(txtstr,"Scanning... "); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + + + // Put Thread to Sleep for 30 Seconds... + // osDelay(30000); + + } while(i < 86400); + + printf("End of Data Collection Cycle (24 Hours) - Ending Application, GoodBye...\r\n"); + + if( bHasLCD ) evbLCD->clearBuffer(); + sprintf(txtstr,"Exiting Program"); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); +} + +/*** Interrupt Handler Top-Halves ------------------------------------------------------ ***/ +/* Called in interrupt context, therefore just set a trigger variable */ +static void timer_irq(void) { + timer_irq_triggered = true; +} + +/* Called in interrupt context, therefore just set a trigger variable */ +static void ff_irq(void) { + ff_irq_triggered = true; + + /* Disable IRQ until handled */ + mems_expansion_board->gyro_lsm6ds3->Disable_Free_Fall_Detection_IRQ(); +} + + +/*** Interrupt Handler Bottom-Halves ------------------------------------------------- ***/ +/* Handle Free Fall Interrupt + (here we are in "normal" context, i.e. not in IRQ context) +*/ +static void handle_ff_irq(void) { + printf("\nFree Fall Detected!\n\n"); + + /* Re-enable IRQ */ + mems_expansion_board->gyro_lsm6ds3->Enable_Free_Fall_Detection_IRQ(); +} + +/*=================================================================================== +Send String Payload to Conduit Gateway +===================================================================================*/ +int32_t sendString(const std::string text) +{ + int32_t ret; + if (mdot_radio->getNextTxMs() != 0) + { + printf("Sending in %lu ms...\r\n", mdot_radio->getNextTxMs()); + return false; + } + + printf("Sending: '%s'\r\n", text.c_str()); + std::vector<uint8_t> data(text.begin(), text.end()); + if ((ret = mdot_radio->send(data, 1)) != mDot::MDOT_OK) + { + log_error(mdot_radio, "ERROR: Failed to Send Data", ret); + } + + return ret; +} + +/*=================================================================================== +Interrupt Service Request Handler - Sets pb1_low flag. Flag is cleared in pb1_debounce thread +===================================================================================*/ +void pb1ISR(void) +{ + pb1_low = true; +} + +/*=================================================================================== +Pushbutton Debounce - Debounces pb1 PB1 changes SW1 State Value (Sets LED Off) +===================================================================================*/ +void pb1_debounce(void const *args) +{ + printf("Thread pb1_debounce started...\r\n"); + + while(true) + { + // if( pb1_low && (mDot08 == 0)) + if( pb1_low ) + { + sprintf(txtstr,"PB1 Pressed..."); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + printf("%s\r\n",txtstr); + + pb1_low = false; + } + + Thread::wait(50); + } +} + +/*=================================================================================== +Interrupt Service Request Handler - Sets pb1_low flag. Flag is cleared in pb1_debounce thread +===================================================================================*/ +void pb2ISR(void) +{ + pb2_low = true; +} + +/*=================================================================================== +Pushbutton Debounce - Debounces pb2 PB2 changes SW2 State Value (Sets LED On) +===================================================================================*/ +void pb2_debounce(void const *args) +{ + printf("Thread pb2_debounce started...\r\n"); + + while(true) + { + // if( pb2_low && (mDot09 == 1)) + if( pb2_low ) + { + sprintf(txtstr,"PB2 Pressed..."); + if( bHasLCD ) evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); + printf("%s \r\n",txtstr); + + pb2_low = false; + } + + Thread::wait(50); + } +} + +/*=================================================================================== +Display Value/Error String of Barometric Pressure Sensor +===================================================================================*/ +bool writeValueOrError() +{ + bool res; + + if (failtime==0) + { + sprintf(lora_press_string, "%s", "--.--"); + sprintf(txtstr, "%s", "--.--"); + if( bHasLCD ) evbLCD->writeText(0,4,font_6x8,txtstr, strlen(txtstr)); + res=false; + } + else + { + sprintf(lora_press_string, "%ld.%02d", num_whole, num_frac); + if( bHasLCD ) evbLCD->writeText(0,3,font_6x8,txtstr,strlen(txtstr)); + res=true; + } + + return res; +} + +/*=================================================================================== +Resets Barometric Pressure Sensor +===================================================================================*/ +MPL3115A2* resetBaro(const MPL3115A2* oldBaro) +{ + delete oldBaro; + MPL3115A2* baro = new MPL3115A2(mDoti2c); + baro->testWhoAmI(); + + printf("Resetting barometer.. %x \n\r", baro->getStatus() ); + baro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16, MPL3115A2::AT_1); + evbBaro->clearMinMaxRegs(); + + return baro; +} + +/*=================================================================================== +Print clear text verion of mDot/EVB errors +===================================================================================*/ +void log_error(mDot* dot, const char* msg, int32_t retval) +{ + printf("%s - %ld:%s, %s\r\n", msg, retval, mDot::getReturnCodeString(retval).c_str(), dot->getLastError().c_str()); +}