mDot EVB to M2X demo.

Dependencies:   DOGS102 ISL29011 MMA845x MPL3115A2 NCP5623B libmDot mbed-rtos mbed-src

Fork of MTDOT-EVBDemo by Multi-Hackers

main.cpp

Committer:
jamescmaki
Date:
2015-07-21
Revision:
8:5b33eee8e2a5
Parent:
7:c9d37522b975
Child:
9:46ce96e9954f

File content as of revision 8:5b33eee8e2a5:

/**
 * @file    main.cpp
 * @brief   Main application for mDot-EVB demo
 * @author  Tim Barr  MultiTech Systems Inc.
 * @version 1.03
 * @see
 *
 * Copyright (c) 2015
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * 1.01 TAB 7/6/15 Removed NULL pointer from evbAmbientLight creation call.
 *
 * 1.02 TAB 7/8/15 Send logo to LCD before attempting connection to LoRa network. Added
 *                 information on setting up for public LoRa network. Moved SW setup to
 *                 beginning of main. Removed printf call from ISR functions. Added
 *                 additional checks for exit_program.
 *
 * 1.03 TAB 7/15/15 Added threads for push button switch debounce.
 *
 * 1.04 JCM 7/16/15 Updated application for AT&T M2X Demo
 *
 * 1.05 JCM 7/20/15 Integrate Senet Public network demo
 *
 * 1.06 JCM 7/20/15 Clean up code, send message using clock
 *
 */

#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 <string>
#include <vector>

/*
 * General settings
 */
const bool public_net = false;
const bool senet_demo = false;
static uint8_t config_frequency_sub_band = 5;

/*
 * Conduit AEP settings
 *
 * AEP settings can be found at: https://<ip-address>/lora_network.html
 */
static std::string config_network_name = "testtest";
static std::string config_network_pass = "memememe";

/*
 * Public Network settings
 */
static uint8_t app_id[8] = {0x00,0x25,0x0C,0x00,0x00,0x01,0x00,0x01};
std::vector<uint8_t> config_app_id(app_id, app_id + sizeof(app_id)/sizeof(uint8_t));
static uint8_t app_key[16] = {0xB4,0xAD,0x1A,0x25,0x69,0x7F,0xF6,0x8E,0xD3,0x4B,0x83,0xC4,0xB6,0xC0,0xF2,0x3C};
std::vector<uint8_t> config_app_key(app_key, app_key + sizeof(app_key)/sizeof(uint8_t));

/*
 * M2X settings
 *
 * M2X settings can be found at: https://m2x.att.com/devices
 * Once a device is added you will see DEVICE ID and PRIMARY API KEY fields
 * for the device.
 */
const char *m2x_device = "f397d9c6c74cb1e2a1be5ef7731dc8af";
const char *m2x_key = "5899c8b045531d3634efa65096ee3ede";


enum LED1_COLOR {
    RED = 0,
    GREEN = 1
};

/*
 * 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
};

/*
 * 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

//Serial 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


uint8_t result;
uint8_t tx_interval = 30;
char data;
unsigned char test;
char txtstr[64];
int32_t num_whole;
int32_t mdot_ret;
uint32_t pressure;
int16_t num_frac;

uint8_t position_value; // 00 unknown, 01 is flat, 02 is vertical

bool exit_program = false;

MMA845x_DATA accel_data;
MPL3115A2_DATA baro_data;
uint16_t  lux_data;
MMA845x *evbAccel;
MPL3115A2 *evbBaro;
ISL29011 *evbAmbLight;
NCP5623B *evbBackLight;
DOGS102 *evbLCD;
mDot *mdot_radio;

convert32 convertl;
convert16 converts;

// flags for pushbutton debounce code
bool pb1_low = false;
bool pb2_low = false;

void pb1ISR(void);
void pb2ISR(void);
void pb1_debounce(void const *args);
void pb2_debounce(void const *args);
Thread* thread_3;

void log_error(mDot *dot, const char *msg, int32_t retval);

void config_pkt_xmit(void const *args);

int main()
{
    std::vector<uint8_t> lora_pl;
    std::vector<uint8_t> mdot_EUI;
    int count;
    int loops;
    int i;

    debugUART.baud(115200);
//  mDotUART.baud(9600);    // mdot UART unused but available on external connector

    Thread thread_1(pb1_debounce); // threads for de-bouncing pushbutton switches
    Thread thread_2(pb2_debounce);

    thread_3 = new Thread(config_pkt_xmit); // start thread that sends LoRa packet when SW2 pressed

    evbAccel = new MMA845x(mDoti2c, MMA845x::SA0_VSS); // setup Accelerometer
    evbBaro = new MPL3115A2(mDoti2c);                 // setup Barometric sensor
    evbAmbLight = new ISL29011(mDoti2c);              // Setup Ambient Light Sensor
    evbBackLight = new NCP5623B(mDoti2c);             // setup backlight and LED 2 driver chip
    evbLCD = new DOGS102(mDotspi, mDot17, mDot13);    // setup LCD

    /*
     *  Setup SW1 as program stop function
     */
    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 packet time change
     */
    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("font table address %p\n\r", &font_6x8);
    printf("bitmap address %p\n\r", &MultiTech_Logo);

    // Setup and display logo on LCD
    evbLCD->startUpdate();

    evbLCD->writeBitmap(0, 0, MultiTech_Logo);

    sprintf(txtstr,"MTDOT");
    evbLCD->writeText(24, 3, font_6x8, txtstr, strlen(txtstr));
    sprintf(txtstr,"Evaluation");
    evbLCD->writeText(24, 4, font_6x8, txtstr, strlen(txtstr));
    sprintf(txtstr,"Board");
    evbLCD->writeText(24, 5, font_6x8, txtstr, strlen(txtstr));

    evbLCD->endUpdate();

    printf("\n\r setup mdot\n\r");

    // get a mDot handle
    mdot_radio = mDot::getInstance();

    if (mdot_radio) {
        // reset to default config so we know what state we're in
        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("\n\r");

        printf("setting Network Mode to %s\r\n", public_net ? "public" : "private");
        if ((mdot_ret = mdot_radio->setPublicNetwork(public_net)) != mDot::MDOT_OK) {
            log_error(mdot_radio, "failed to set 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, "failed to set frequency sub band", mdot_ret);
        }

        printf("setting network name\r\n");
        if (public_net) {
            if ((mdot_ret = mdot_radio->setNetworkId(config_app_id)) != mDot::MDOT_OK) {
                log_error(mdot_radio, "failed to set network name", mdot_ret);
            }
        } else {
            if ((mdot_ret = mdot_radio->setNetworkName(config_network_name)) != mDot::MDOT_OK) {
                log_error(mdot_radio, "failed to set network name", mdot_ret);
            }
        }

        printf("setting network password\r\n");
        if (public_net) {
            if ((mdot_ret = mdot_radio->setNetworkKey(config_app_key)) != mDot::MDOT_OK) {
                log_error(mdot_radio, "failed to set network key", mdot_ret);
            }
        } else {
            if ((mdot_ret = mdot_radio->setNetworkPassphrase(config_network_pass)) != mDot::MDOT_OK) {
                log_error(mdot_radio, "failed to set network pass phrase", mdot_ret);
            }
        }

        // attempt to join the network
        printf("joining network\r\n");
        while (((mdot_ret = mdot_radio->joinNetwork()) != mDot::MDOT_OK) && (!exit_program)) {
            log_error(mdot_radio,"failed to join network:", mdot_ret);
            if (mdot_radio->getFrequencyBand() == mDot::FB_868) {
                mdot_ret = mdot_radio->getNextTxMs();
            } else {
                mdot_ret = 0;
            }
            printf("delay = %lu\n\r", mdot_ret);
            osDelay(mdot_ret + 1);
        }

        /*
         * Check for PB1 press during network join attempt
         */
        if (exit_program) {
            printf("Exiting program\n\r");
            evbLCD->clearBuffer();
            sprintf(txtstr,"Exiting Program");
            evbLCD->writeText(0, 4, font_6x8,txtstr,strlen(txtstr));
            exit(1);
        }
    } else {
        printf("radio setup failed\n\r");
        //exit(1);
    }

    osDelay(200);
    evbBackLight->setPWM(NCP5623B::LED_3, 16); // enable LED2 on EVB and set to 50% PWM

    // sets LED2 to 50% max current
    evbBackLight->setLEDCurrent(16);

    printf("Start of Test\n\r");

    osDelay (500); // allows other threads to process
    printf("shutdown LED:\n\r");
    evbBackLight->shutdown();

    osDelay (500); // allows other threads to process
    printf("Turn on LED2\n\r");
    evbBackLight->setLEDCurrent(16);

    data = evbAccel->getWhoAmI();
    printf("Accelerometer who_am_i value = %x \n\r", data);

    result = evbAccel->getStatus();
    printf("status byte = %x \n\r", result);

    printf("Barometer who_am_i check = %s \n\r", evbBaro->testWhoAmI() ? "TRUE" : "FALSE");

    result = evbBaro->getStatus();
    printf("status byte = %x \n\r", result);

    /*
     *  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();

    evbBackLight->setLEDCurrent(0);

    /*
     * Check for PB1 press during network join attempt
     */
    if (exit_program) {
        printf("Exiting program\n\r");
        evbLCD->clearBuffer();
        sprintf(txtstr,"Exiting Program");
        evbLCD->writeText(0, 4, font_6x8, txtstr, strlen(txtstr));
        exit(1);
    }

    if (!senet_demo) {
        lora_pl.clear();
        lora_pl.push_back(19);
        lora_pl.push_back(strlen(m2x_device));
        lora_pl.insert(lora_pl.end(), m2x_device, m2x_device + strlen(m2x_device));
        while ((mdot_ret = mdot_radio->send(lora_pl)) != mDot::MDOT_OK) {
            log_error(mdot_radio, "Failed to register m2x_device", mdot_ret);
            osDelay(2000);
        }

        lora_pl.clear();
        lora_pl.push_back(20);
        lora_pl.push_back(strlen(m2x_key));
        lora_pl.insert(lora_pl.end(), m2x_key, m2x_key + strlen(m2x_key));
        while ((mdot_ret = mdot_radio->send(lora_pl)) != mDot::MDOT_OK) {
            log_error(mdot_radio, "Failed to register m2x_key", mdot_ret);
            osDelay(2000);
        }
    }

    loops = 0;
    time_t tx_next = time(NULL) + tx_interval;

    /*
     * Main data acquisition loop
     */
    while (!exit_program) {
        osDelay(200);

        evbLCD->startUpdate();
        evbLCD->clearBuffer();

        /*
         * Test Accelerometer XYZ data ready bit to see if acquisition complete
         */
        count = 1;
        do {
            osDelay(100); // allows other threads to process
            result = evbAccel->getStatus();
            if ((count++ % 10) == 0) {
            	printf("waiting on accelerometer reading\r\n");
            }
        } while ((result & MMA845x::XYZDR) == 0);

        /*
         * Retrieve and print out accelerometer data
         */
        accel_data = evbAccel->getXYZ();

        sprintf(txtstr,"Accelerometer");
        evbLCD->writeText(0, 0, font_6x8, txtstr, strlen(txtstr));
        sprintf(txtstr, "x = %d", accel_data._x);
        evbLCD->writeText(20, 1, font_6x8, txtstr, strlen(txtstr));
        sprintf(txtstr, "y = %d", accel_data._y);
        evbLCD->writeText(20, 2, font_6x8, txtstr, strlen(txtstr));
        sprintf(txtstr, "z = %d", accel_data._z );
        evbLCD->writeText(20, 3, font_6x8, txtstr, strlen(txtstr));

        // convert to simple position value for use in send/recv
        if (accel_data._x > 500 && accel_data._z < 500) {
            position_value = 0x02;
        } else if (accel_data._x < 500 && accel_data._z > 500) {
            position_value = 0x01;
        } else {
            position_value= 0x00;
        }

        /*
         * Trigger a Pressure reading
         */
        evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16,
                               MPL3115A2::AT_1);
        evbBaro->triggerOneShot();

        /*
         * Test barometer device status to see if acquisition is complete
         */
        count = 1;
        do {
            osDelay(100); // allows other threads to process
            result = evbBaro->getStatus();
            if ((count++ % 10) == 0) {
            	printf("waiting on barometer reading\r\n");
            }
        } while ((result & MPL3115A2::PTDR) == 0);

        /*
         * Retrieve and print out 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
        sprintf(txtstr,"Press=%ld.%02d Pa", num_whole, num_frac);
        evbLCD->writeText(0, 4, font_6x8, txtstr, strlen(txtstr));

        /*
         * Trigger an Altitude reading
         */
        evbBaro->setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_ALTIMETER, MPL3115A2::OR_16,
                               MPL3115A2::AT_1);
        evbBaro->triggerOneShot();

        /*
         * Test barometer device status to see if acquisition is complete
         */
        count = 1;
        do {
            osDelay(100); // allows other threads to process
            result = evbBaro->getStatus();
            if ((count++ % 10) == 0) {
            	printf("waiting on temperature reading\r\n");
            }
        } while ((result & MPL3115A2::PTDR) == 0);

        /*
         * Retrieve and print out altitude and temperature
         */
        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
        num_frac = (baro_data._baro & 0xF) * 625 / 100; // 4 bit fractional .0625 per bit
        sprintf(txtstr, "Alti=%ld.%03d m", num_whole, num_frac);
        evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr));
        num_whole = baro_data._temp / 16; // 8 bit signed significant integer
        num_frac = (baro_data._temp & 0x0F) * 625 / 10; // 4 bit fractional .0625 per bit
        sprintf(txtstr, "Temp=%ld.%03d C", num_whole, num_frac);
        evbLCD->writeText(0, 6, font_6x8, txtstr, strlen(txtstr));

        /*
         * retrieve and print out 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);
        evbLCD->writeText(0, 7, font_6x8, txtstr, strlen(txtstr));

        evbLCD->endUpdate();

        if (time(NULL) > tx_next) {
            tx_next = time(NULL) + tx_interval;

            lora_pl.clear();

            if (senet_demo) {
                // Position Value
                lora_pl.push_back(0);
                lora_pl.push_back(position_value);
            } else {
                // Current Acceleration 3-Axis Value
                lora_pl.push_back(14);
                lora_pl.push_back(6);
                converts.f_s = accel_data._x;
                lora_pl.push_back(converts.t_u[1]);
                lora_pl.push_back(converts.t_u[0]);
                converts.f_s = accel_data._y;
                lora_pl.push_back(converts.t_u[1]);
                lora_pl.push_back(converts.t_u[0]);
                converts.f_s = accel_data._z;
                lora_pl.push_back(converts.t_u[1]);
                lora_pl.push_back(converts.t_u[0]);
                // Current Pressure Value
                lora_pl.push_back(8);
                lora_pl.push_back(3);
                convertl.f_u = pressure;
                lora_pl.push_back(convertl.t_u[2]);
                lora_pl.push_back(convertl.t_u[1]);
                lora_pl.push_back(convertl.t_u[0]);
                // Current Ambient Light Value
                lora_pl.push_back(5);
                lora_pl.push_back(2);
                converts.f_u = lux_data;
                lora_pl.push_back(converts.t_u[1]);
                lora_pl.push_back(converts.t_u[0]);
                // Current Temperature Value
                lora_pl.push_back(11);
                lora_pl.push_back(2);
                converts.f_s = baro_data._temp;
                lora_pl.push_back(converts.t_u[1]);
                lora_pl.push_back(converts.t_u[0]);
            }

            printf("Sending LoRa message, length: %d\r\n", lora_pl.size());
            if ((mdot_ret = mdot_radio->send(lora_pl)) != mDot::MDOT_OK) {
                log_error(mdot_radio, "failed to send", mdot_ret);
            } else {
                printf("successfully sent data to gateway\r\n");

                if (senet_demo) {
                    lora_pl.clear();
                    if ((mdot_ret = mdot_radio->recv(lora_pl)) != mDot::MDOT_OK) {
                        log_error(mdot_radio, "failed to recv:", mdot_ret);
                    } else {
                        printf("recv data: ");
                        for(int i = 0;i < lora_pl.size();i++) {
                            printf("%02X", lora_pl[i]);
                        }
                        printf("\r\n");
                        if(lora_pl[0] == position_value) {
                            evbBackLight->setLEDCurrent(16);
                        } else {
                            evbBackLight->setLEDCurrent(0);
                        }
                    }
                }
            }
        }

        printf("finished iteration %d\n\r", loops++);
    }

    evbBaro->triggerOneShot();

    do {
        osDelay(200); // allows other threads to process
        result = evbBaro->getStatus();
    } while ((result & MPL3115A2::PTDR) == 0);

    baro_data = evbBaro->getAllData(true);
    printf ("minBaro=%ld maxBaro=%ld minTemp=%d maxTemp=%d\n\r", baro_data._minbaro, baro_data._maxbaro,
            baro_data._mintemp, baro_data._maxtemp);

    printf("End of Test\n\r");

    evbLCD->clearBuffer();
    sprintf(txtstr,"Exiting Program");
    evbLCD->writeText(0, 4, font_6x8, txtstr, strlen(txtstr));
}

/*
 * Sets pb1_low flag. Slag is cleared in pb1_debounce thread
 */
void pb1ISR(void)
{
    if (!pb1_low)
        pb1_low = true;
}

/*
 * Debounces pb1. Also exits program if pushbutton 1 is pressed
 */
void pb1_debounce(void const *args)
{
    static uint8_t count = 0;

    while (true) {
        if (pb1_low && (mDot08 == 0)) {
            count++;
        } else {
            count = 0;
            pb1_low = false;
        }

        if (count == 5) {
            printf("pb1_debounce: setting exit_program\r\n");
            exit_program = true;
        }

        Thread::wait(5);
    }
}

/*
 * Sets pb2_low flag. Flag is cleared in pb2_debounce thread
 */
void pb2ISR(void)
{
    if (!pb2_low)
        pb2_low = true;
}

/*
 * Debounces pb2. Also changes packet transmit time to every other,
 * every fifth, or every tenth sample when SW2 pushed
 * Also triggers a thread to transmit a configuration packet
 */
void pb2_debounce(void const *args)
{
    static uint8_t count = 0;

    while (true) {
        if (pb2_low && (mDot09 == 0)) {
            count++;
        } else {
            count = 0;
            pb2_low = false;
        }

        if (count == 5) {
            if (tx_interval > 60) {
                tx_interval = 60;
            } else if (tx_interval > 30) {
                tx_interval = 30;
            } else if (tx_interval > 10) {
                tx_interval = 10;
            } else {
                tx_interval = 120;
            }

            thread_3->signal_set(0x10); // signal config_pkt_xmit to send packet
        }

        Thread::wait(5);
     }
 }

/*
 *  Function that print clear text verion of mDot 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());
}

/*
 * Thread that is triggered by SW2 ISR. Sends a packet to the LoRa server with the new Packet Transmission time setting
 */
void config_pkt_xmit(void const *args)
{
    std::vector<uint8_t> lora_pl;

    while (true) {
        Thread::signal_wait(0x10); // wait for pb2ISR to signal send

        lora_pl.clear();
        // Send packet transmission interval
        lora_pl.push_back(15);
        lora_pl.push_back(1);
        lora_pl.push_back(tx_interval);

        if ((mdot_ret = mdot_radio->send(lora_pl)) != mDot::MDOT_OK) {
            log_error(mdot_radio, "failed to send config data", mdot_ret);
        } else {
            printf("sent config data to gateway\r\n");
        }
    }
}