I added functionality to get the RSSI, BER, and Cell Neighbor for reporting connection issues to M2X

Dependencies:   mbed FXOS8700CQ mbed-rtos WNCInterface M2XStreamClient-JMF jsonlite

main.cpp

Committer:
ng977t
Date:
2019-04-18
Revision:
13:99c72ab600c9
Parent:
12:0dfd0129f75d

File content as of revision 13:99c72ab600c9:

//
// This file contains an example implementation of M2X using the HTTP interface as the underlying 
// transport.
//

#include "mbed.h"
#include "WNCInterface.h"
#include "IOTSMS.h"

#define MBED_PLATFORM
#define M2X_ENABLE_READER

#include <jsonlite.h>
#include "M2XStreamClient.h"

#include "sensors.h"
#include "config_me.h"

#define CRLF "\n\r"

//startup SMS, disabled by default
//#define STARTUP_SMS

//command processing enabled by default
#define COMMANDS_ENABLED

//update all streams in one command, disabled by default
//#define SINGLE_UPDATE

WNCInterface eth;
WNCSms sms;
Client client;
M2XStreamClient m2xClient(&client, m2xKey);
TimeService timeService(&m2xClient);

I2C i2c(PTC11, PTC10);    //SDA, SCL -- define the I2C pins being used
Serial pc(USBTX, USBRX); // tx, rx
DigitalOut led_green(LED_GREEN);
DigitalOut led_red(LED_RED);
DigitalOut led_blue(LED_BLUE);

K64F_Sensors_t  SENSOR_DATA = {};
K64F_Sensors_t  OLD_SENSOR_DATA = {};
bool bStop = false;
bool bSendDataNow = false;
bool bSendSMS = false;
bool bM2XConfigured;

Ticker WatchdogTicker;
int watchdogTicks = 0;
bool bWatchdogOn = false;
unsigned char lastLedColor = 0;

InterruptIn btn3(SW3);
InterruptIn btn2(SW2);

#ifdef SINGLE_UPDATE
const char* allStreamNames[] = { hStreamName, tStreamName, accelStreamNames[0], accelStreamNames[1], accelStreamNames[2] };
#endif
 
//********************************************************************************************************************************************
//* Set the RGB LED's Color
//* LED Color 0=Off to 7=White.  3 bits represent BGR (bit0=Red, bit1=Green, bit2=Blue) 
//********************************************************************************************************************************************
void SetLedColor(unsigned char ucColor)
{
    //Note that when an LED is on, you write a 0 to it:
    led_red = !(ucColor & 0x1); //bit 0
    led_green = !(ucColor & 0x2); //bit 1
    led_blue = !(ucColor & 0x4); //bit 2
    
    lastLedColor = ucColor;
} //SetLedColor()

struct Watchdog {
    Watchdog() {
        bWatchdogOn = true;
        };
        
    ~Watchdog() {
        bWatchdogOn = false;
        };
};

#define WATCHDOG struct Watchdog aWatchdog;

void watchdog_check()
{
  // watchdog function is run every 1/4th of a second
  if(bWatchdogOn) {
     watchdogTicks++;
     
     // blink LED while watchdog is running
    if  (watchdogTicks % 2 == 1) {
        led_red = led_green = led_blue = 1;
    } else {
        SetLedColor(lastLedColor);
    };
  } else {
     watchdogTicks = 0;
     SetLedColor(lastLedColor);
  }
  
  // reset if the watchod is on for more than 10 seconds
  if(watchdogTicks > 30 * 4)  NVIC_SystemReset();
}


bool power_on() {
    return (RCM->SRS0 & RCM_SRS0_POR_MASK);
}


bool ExecuteCommand(const char* Command)
{
    char cLedColor = *Command;
    switch(cLedColor)
    {
        case 'O':
        { //Off
            SetLedColor(0);
            break;
        }
        case 'R':
        { //Red
            SetLedColor(1);
            break;
        }
        case 'G':
        { //Green
            SetLedColor(2);
            break;
        }
        case 'Y':
        { //Yellow
            SetLedColor(3);
            break;
        }
        case 'B':
        { //Blue
            SetLedColor(4);
            break;
        }
        case 'M':
        { //Magenta or M2X
            char Key[33], Device[33];
        
            int count = sscanf(Command, "M2X:%32s:%32s", Key, Device);
            if (count == 2) {
                pc.printf("Got key %s and device %s" CRLF, Key, Device);
                strncpy(deviceId, Device, 32);
                strncpy(m2xKey, Key, 32);
                bM2XConfigured = true;
            } else
                SetLedColor(5);
            break;
        }
        case 'T':
        { //Turquoise
            SetLedColor(6);
            break;
        }
        case 'W':
        { //White
            int Delay = 0, Polls = 0;
            
            pc.printf("Processing WAIT command" CRLF);            
            int count = sscanf(Command, "WAIT:%d:%d", Delay, Polls);
            if (count == 2) {
                pc.printf("Reconfiguring wait loop to %d delay and %d polls ...", Delay, Polls);                
                if ((Delay > 5) && (Delay < 300) 
                 && (Polls > 0) && (Polls < 100)) {
                    bSendDataNow = true;                    
                    commandDelay = Delay;                               
                    commandPolls = Polls;       
                    pc.printf("done" CRLF);
                } else 
                    pc.printf("discarding invalid parameters!" CRLF);
            } else 
                SetLedColor(7);
            break;
        }
        case 'S':
        { //Stop
            bStop = true;
            break;
        }  
        default:
        {
            return false;
        }
    } //switch(cLedColor)
    return true;
}


void on_data_point_found(const char* at, const char* value, int index, void* context, int type) {
    pc.printf(">>Found a data point, index: %d type: %d" CRLF, index, type);
    pc.printf(">>At: %s" CRLF " Value: %s" CRLF, at, value);
}

void on_fill_data(Print *print, void *context) {
    // no data to fill
}


void on_command_found(const char* id, const char* name, int index, void *context) {
    pc.printf("\t|Found a command, index: %d" CRLF, index);
    pc.printf("\t|ID: %s" CRLF "\t|Name: %s" CRLF, id, name);
    ExecuteCommand(name);
    m2xClient.markCommandProcessed(deviceId, id, on_fill_data, NULL);
    pc.printf("\t|Command confirmed" CRLF, id, name);
}


void on_msg_rcvd( WNCSmsMsg& msg ) {
  pc.printf(YEL "SMS received from %s" CRLF, msg.number.c_str());
  pc.printf("|Timestamp: %s %s" CRLF, msg.date.c_str(), msg.time.c_str());
  pc.printf("|Text: '%s'" CRLF, msg.msg.c_str());
  pc.printf(WHT);
  ExecuteCommand(msg.msg.c_str());
}


void button_2_pressed() {
    bSendSMS = true;
}


void button_3_pressed() {
    bSendDataNow = true;
}


void process_buttons() {
    char smsText[100];    
    
    if (bSendSMS) {
        bSendSMS = false;
        
        snprintf(smsText, 100, "Last temperature was %.2f", SENSOR_DATA.Temperature);
        int response = sms.send("5277", smsText);
        pc.printf(YEL "Button SMS %s sent." CRLF, response ? "was" : "NOT");
        pc.printf(WHT);  
    };    
}

bool check_accelerometer_change() {
    read_sensors();
    
    float diffX, diffY, diffZ;
    diffX = abs(SENSOR_DATA.AccelX - OLD_SENSOR_DATA.AccelX);
    diffY = abs(SENSOR_DATA.AccelY - OLD_SENSOR_DATA.AccelY);
    diffZ = abs(SENSOR_DATA.AccelZ - OLD_SENSOR_DATA.AccelZ); 
    
    bool changed = (diffX > 0.5) || (diffY > 0.5) || (diffZ > 0.5);
    if (changed) {
        bSendDataNow = true;
        pc.printf("Accelerometer changed, sending data immediately." CRLF);        
    };
    
    return changed;
}
    

int main() {
    char timestamp[25];
    int length = 25;
    int response;
    
    ExecuteCommand("Red");
    
    pc.baud(115200);    
    pc.printf("M2X StarterKit demo (compiled " __DATE__ ", " __TIME__  "): initializing the network"  CRLF);
    response = eth.init("m2m.com.attz");                     
    pc.printf("WNC Module %s initialized (%02X)." CRLF, response?"IS":"IS NOT", response);
    if( !response ) {
        pc.printf(" - - - - - - - SYSTEM RESET - - - - - - - " CRLF CRLF);
        NVIC_SystemReset();
    }
    
    response = sms.init(1, on_msg_rcvd);
    pc.printf("SMS interface %s initialized (%02X)." CRLF, response?"IS NOT":"IS", response);    
    if (!response) {
        pc.printf("SMS number is %s" CRLF , sms.getSMSNbr());
    };
    
    response = eth.connect();                 
    pc.printf("IP Address: %s " CRLF CRLF, eth.getIPAddress());

    ExecuteCommand("Yellow");
    
    pc.printf("Initialize the sensors" CRLF);    
    sensors_init();
    read_sensors();
    
    bM2XConfigured = *deviceId && *m2xKey;
    if (!bM2XConfigured) {
        pc.printf(RED "Waiting for SMS configuration" CRLF);
        
        while (!bM2XConfigured) {
            ExecuteCommand("Red");
            delay(1000);
            ExecuteCommand("Yellow");            
            delay(1000);
        }
    };
    
    // set up watchdog ticker running every quarter of a second
    WatchdogTicker.attach(watchdog_check, 0.25);
            
    { //WATCHDOG
        pc.printf(WHT "initialize the M2X time service" CRLF);
        if (!m2x_status_is_success(timeService.init())) 
            pc.printf("Cannot initialize time service!" CRLF);
        else {
            timeService.getTimestamp(timestamp, &length);
            pc.printf("Current timestamp: %s" CRLF, timestamp);
        };
    };

    btn2.fall(&button_2_pressed);    
    btn3.fall(&button_3_pressed);        
                
    ExecuteCommand("Green");    
        
#ifdef STARTUP_SMS    
    response = sms.send("5277", "IoT StarterKit is now running!");
    pc.printf("Startup SMS %s sent." CRLF, response ? "was" : "NOT");
#endif

#ifdef COMMANDS_ENABLED    
    { WATCHDOG 
        pc.printf("Query for pending commands ..." CRLF);
        response = m2xClient.listCommands(deviceId, on_command_found, NULL, "status=pending");
        pc.printf("listCommands response code: %d" CRLF, response);  
    };
#endif
    
    while (!bStop) {
        // read sensor values 
        read_sensors();

        { WATCHDOG 
#ifndef SINGLE_UPDATE        
            // post the humidity value
            pc.printf("Post updateStreamValue (humidity = %.2f)..." CRLF, SENSOR_DATA.Humidity);
            response = m2xClient.updateStreamValue(deviceId, hStreamName, SENSOR_DATA.Humidity);
            pc.printf("Post response code: %d" CRLF, response);
            
            // post the temp value
            pc.printf("Post updateStreamValue (temp = %.2f)..." CRLF, SENSOR_DATA.Temperature);
            response = m2xClient.updateStreamValue(deviceId, tStreamName, SENSOR_DATA.Temperature);
            pc.printf("Post response code: %d" CRLF, response);
    
            // post accelerometer values
            pc.printf("Post postDeviceUpdate (accelerometer [%.2f,%.2f,%.2f])..." CRLF, SENSOR_DATA.AccelX, SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ);
            response = m2xClient.postDeviceUpdate(deviceId, 3, accelStreamNames, (float []){SENSOR_DATA.AccelX, SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ});
            pc.printf("Post response code: %d" CRLF, response);
            
            // post the signal value
            pc.printf("Post updateStreamValue (signal = %.2f)..." CRLF, SENSOR_DATA.Signal_Strength);
            response = m2xClient.updateStreamValue(deviceId, sStreamName, SENSOR_DATA.Signal_Strength);
            pc.printf("Post response code: %d" CRLF, response);
        
            // post the signal error value
            pc.printf("Post updateStreamValue (error = %d)..." CRLF, SENSOR_DATA.Error);
            response = m2xClient.updateStreamValue(deviceId, eStreamName, SENSOR_DATA.Error);
            pc.printf("Post response code: %d" CRLF, response);
        
            // post the neighbor value
            pc.printf("Post updateStreamValue (neighbor = %s)..." CRLF, SENSOR_DATA.Neighbor);
          //response = m2xClient.updateStreamValues(deviceId, nStreamName, SENSOR_DATA.Neighbor);
            pc.printf("Post response code: %d" CRLF, response);

#else
            // post all values at one
            pc.printf("Post all stream values [%.2f,%.2f,%.2f,%.2f,%.2f])..." CRLF, SENSOR_DATA.Humidity, SENSOR_DATA.Temperature, SENSOR_DATA.AccelX, SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ);
            response = m2xClient.postDeviceUpdate(deviceId, 5, allStreamNames, (float []){SENSOR_DATA.Humidity, SENSOR_DATA.Temperature, SENSOR_DATA.AccelX, SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ});
            pc.printf("Post response code: %d" CRLF, response);
#endif
            timeService.getTimestamp(timestamp, &length);
            pc.printf("%s waiting for %d seconds... " CRLF , timestamp, commandDelay * commandPolls);
        };
        
        // save old sensor data, we will use them to check for accelerometer change
        OLD_SENSOR_DATA = SENSOR_DATA;
        // sleep loop, check for accelerometer changes and pending commands
        for (short idx=0; idx < commandPolls; idx++) {
            // wait commandDelay seconds
            for (short delays=0; delays < commandDelay; delays++) {
                delay(1000);
                // if the buttons were pressed process them immediately 
                process_buttons();               
                check_accelerometer_change();
                // button 3 skips wait and sends data right away
                if (bSendDataNow || bStop) 
                    break;                
            };
            
#ifdef COMMANDS_ENABLED
            // and then query for commands
            { WATCHDOG 
                pc.printf("\tQuery for pending commands ..." CRLF);
                response = m2xClient.listCommands(deviceId, on_command_found, NULL, "status=pending");
                pc.printf("\tlistCommands response code: %d" CRLF, response);              
            };                        
#endif      
      
            //if button 3 was pressed skip the wait and send data right away
            if (bSendDataNow || bStop) {
                bSendDataNow = false;
                break;
            };                
        }
    };
    
    pc.printf("Done sending data. Still accepting SMS commands." CRLF);
    bStop = false;
    while (!bStop) {
        delay(1000);
    };        
    
    pc.printf("- - - - - - - THE END - - - - - - - " CRLF);    
    NVIC_SystemReset();
}