Demonstration connecting an xDot to Telit Devicewise using the libxDot-mbed5 library.

Dependencies:   ISL29011 libxDot-mbed5

main.cpp

Committer:
pferland
Date:
2017-08-01
Revision:
0:dd2c9d4723e7

File content as of revision 0:dd2c9d4723e7:

/*================================================================================
 *
 * 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
 *
** WEB SITE:          www.telit.com
 *
 * WRITTEN BY:        John Keever
 *
 * DATE:              27 July, 2017
 *
 * VERSION:           1.00
 *
 * 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                                        */
/*----------+--------+----------+-------------------------------------------------*/
/*07-27-2017|JEK     |V1.00     |Original Version - xDot (Light Sensor, S2 Button)*/
/*          |        |          |                                                 */
/*================================================================================*/
/*NOTE:  Please keep the change log up to date!!!                                 */
/*================================================================================*/

#include "mbed.h"
#include "mDot.h"
#include "rtos.h"
#include "ChannelPlans.h"

#include "ISL29011.h"

#include <cmath>
#include <string>
#include <vector>
#include <ctime>

#ifndef CHANNEL_PLAN
#define CHANNEL_PLAN CP_US915
#endif

static volatile bool timer_irq_triggered = false;
static volatile bool ff_irq_triggered = false;

//static std::string config_network_name = "MTCDT-19186797";
//static std::string config_network_pass = "MTCDT-19186797";
//static uint8_t config_frequency_sub_band = 1;

static std::string config_network_name = "MTCDT-19186799";
static std::string config_network_pass = "MTCDT-19186799";
static uint8_t config_frequency_sub_band = 1;

uint8_t result;
uint8_t data;
uint8_t sf_val = mDot::DR2;
uint8_t pwr_val = 11; // dBm
uint8_t swp_pwr;
uint8_t swp_sf;

int32_t mdot_ret;
int32_t join_delay;

osThreadId mainThreadID;

// Physical I/O Instantiation
DigitalOut led(LED1);
DigitalIn s2(PA_0);

I2C i2c(I2C_SDA, I2C_SCL);
ISL29011 lux(i2c);
// InterruptIn btn(PA_0); /* S2 - button */

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

mDot* mdot_radio;
Mutex mdot_mutex;

static Ticker ticker;

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];

bool bHasGPS = false;
bool bHasACC = false;
bool bHasLCD = false;

//Helper Functions... Interrupt Handlers

void rise() 
{
    printf("\r\nS2 Button Interrupt... RISE (on)\r\n");
    //led.write(true);
    led = 1;
}

void fall() 
{
    printf("\r\nS2 Button Interrupt... FALL (off)\r\n");
    //led.write(false);
    led = 0;
}

int xmitDataPayload( int, int, int );

/*===================================================================================
Main Program Logic - Entry
===================================================================================*/
int main()
{
    std::vector<uint8_t> mdot_data;
    std::vector<uint8_t> mdot_EUI;
    uint16_t i = 0;
    
    printf ("\r\nStarting xDot Demonstration Application...\r\n");

    mainThreadID = osThreadGetId();

    printf("Begin I2C/SPI Device Initialization...\r\n");

    printf("Initializing Light Sensor...\r\n");

    lux.setMode(ISL29011::ALS_CONT);
    lux.setResolution(ISL29011::ADC_16BIT);
    lux.setRange(ISL29011::RNG_64000);    

    printf("I2C/SPI Device Initialization Complete...\r\n");

    printf("Setup PushButton Interface Handlers...\r\n");

    //btn.rise(&rise);
    //btn.fall(&fall);

    printf("S2 IRQs Set...\r\n");

    printf("PushButton Interface Handlers Setup...\r\n");
 
    printf("\r\nSetup xDot Radio Communications...\r\n");
    
    #if CHANNEL_PLAN == CP_AS923
        lora::ChannelPlan* plan = new lora::ChannelPlan_AS923();
    #elif CHANNEL_PLAN == CP_US915
        lora::ChannelPlan* plan = new lora::ChannelPlan_US915();
    #elif CHANNEL_PLAN == CP_AU915
        lora::ChannelPlan* plan = new lora::ChannelPlan_AU915();
    #elif CHANNEL_PLAN == CP_EU868
        lora::ChannelPlan* plan = new lora::ChannelPlan_EU868();
    #elif CHANNEL_PLAN == CP_KR920
        lora::ChannelPlan* plan = new lora::ChannelPlan_KR920();
    #elif CHANNEL_PLAN == CP_IN865
        lora::ChannelPlan* plan = new lora::ChannelPlan_IN865();
    #elif CHANNEL_PLAN == CP_AS923_JAPAN
        lora::ChannelPlan* plan = new lora::ChannelPlan_AS923_Japan();
    #endif

    printf("xDot getInstance()...\r\n");

    // get an xDot handle
    mdot_radio = mDot::getInstance( plan ); 
    
    if (mdot_radio)
    {
        printf("xDot getInstance()... Successful!\r\n");  

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

        // Turning ADR off for the purposes of demonstrating TX data rates
        printf("Setting ADR to Off...\r\n");
        if((mdot_ret = mdot_radio->setAdr(false)) != mDot::MDOT_OK){
            log_error(mdot_radio, "ERROR: Failed to set ADR", 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);
        }

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

                join_delay = 100;

                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");
    }
    else
    {
        printf("ERROR:  Unable to Join LoRa Network...\r\n");
        printf("getInstance... Radio Initialization Failed!\r\n");

        exit(1);
    }

    printf("Initialization/Configuration Completed...\r\n");

    osDelay(1500);

    // Enter Main Data Acquisition Loop...
    printf("Processing Data Acquisition Scan Loop...\r\n");

    i = 0;
    cycle_cnt = 100;

    bool s2_last = 0;
    int  lum_last = 0;
    int  lum_delta = 0;

    do
    {
            // Read Pushbutton #2 (S2) State...
            if( s2 > 0 )
            {
                printf("S2 Pressed... State: %d\r\n", (int) s2);
            }         

            int delta = rand()%16;
            int temperature = 20 + delta;
            int luminosity = lux.getData();
            int current = s2;

            printf("Scan... Temperature: %d degC (delta=%d), Light: %d lux, Button: %d\r\n", temperature, delta, luminosity, current );

            lum_delta = abs( luminosity - lum_last );

            if( s2 != s2_last || lum_delta > 20 )
            {
                printf("Data Change Event...\r\n");

                xmitDataPayload( temperature, luminosity, current );
                
                cycle_cnt = 0;
            } 
           
            if( cycle_cnt > 30 )
            {   
                printf("Transmitting Data... \r\n");

                sprintf(sensor_text, "t:%d,l:%d,c:%d",
                    temperature,
                    luminosity,
                    current );

                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(500);

                printf("Scanning...     \r\n");
                cycle_cnt = 0;
            }

        s2_last = s2;
        lum_last = luminosity;

        osDelay(1000);
        cycle_cnt++;
                
        // 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");
}

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

    led = 0;

    return ret;
}

/*===================================================================================
Transmit Data Payload to Cloud Platform
===================================================================================*/
int32_t xmitDataPayload( int temperature, int luminosity, int current )
{
    int32_t mdot_ret;

    printf("Transmitting Data... \r\n");

    sprintf(sensor_text, "t:%d,l:%d,c:%d", temperature, luminosity, current );

    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");
    }

    return mdot_ret;
}

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