mdot UDK & STMicro MEMS Shield Sensor packet example

Dependencies:   libmDot-mbed5 DOGS102 ISL29011 MMA845x MPL3115A2 NCP5623B X_NUCLEO_IKS01A1 Senet_Packet

Fork of MTDOT-UDKDemo_Senet by canuck lehead

main.cpp

Committer:
Shaun Nelson
Date:
2017-08-30
Revision:
43:55e7bb4d9b60
Parent:
39:022b327d6bf0

File content as of revision 43:55e7bb4d9b60:

 /*       _____                         _
 *      / ____|                       | |  
 *     | (___     ___   _ __     ___  | |_ 
 *      \___ \   / _ \ | '_ \   / _ \ | __|
 *      ____) | |  __/ | | | | |  __/ | |_ 
 *     |_____/   \___| |_| |_|  \___|  \__|
 *         (C) 2016 Senet, Inc                                
 *                                         
 */

#include "board.h"
#include "senet_packet.h"


/******************************************************************************
 * LoRaWAN Configuration                                                      *
 ******************************************************************************/
 // Senet Developer Portal Application EUI
static uint8_t APP_EUI[8]  = {0x00,0x25,0x0C,0x00,0x00,0x01,0x00,0x01};

// Get Application Key from Senet Developer Portal Device Edit page
static uint8_t APP_KEY[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

#define DATARATE            mDot::DR0
#define TXPOWER             20
#define JOIN_RETRIES        1

static std::vector<uint8_t> appEUI(APP_EUI,APP_EUI+sizeof(APP_EUI)/sizeof(uint8_t));
static std::vector<uint8_t> appKey(APP_KEY,APP_KEY+sizeof(APP_KEY)/sizeof(uint8_t));
static uint8_t              fsb     = 0;
static bool                 adrOn   = true;
/******************************************************************************/


/******************************************************************************
 * Application Configuration                                                      *
 ******************************************************************************/
#define APP_TX_DUTY_CYCLE_NORMAL 300000 // 5 min
#define APP_TX_DUTY_CYCLE_ALARM  15000  // 15 s

// Backend configured state. Set true to enable alarm rate transmits until backend response
static bool  BackendEnabled = false;
/******************************************************************************/

// Transmitted orientation values
#define HORIZONTAL_ORIENTATION_VALUE 1 // transmitted value when device is horizontal
#define VERTICAL_ORIENTATION_VALUE   2 // transmitted value when device is vertical


// Set to true when backend is synchronized
static bool             BackendSynchronized   = true;
// Set to true to force backend resync
static bool             OrientationInit       = true;
static bool             DisplayBackendState   = true;
static BoardOrientation BackendOrientation;
static Ticker           joinTicker;
static Ticker           nextTxTimer;
static BoardSensorData  sensorData;
static BoardOrientation txOrientation;
static BoardOrientation lastOrientation;
static bool             NextTx  = true;
static uint32_t         AppTxDutyCycle = APP_TX_DUTY_CYCLE_NORMAL;
static uint32_t         orientationChangeCount = 0;

// Orientation comparison
inline bool orientationIsEqual(BoardOrientation &a, BoardOrientation &b)
{
	// For this application only vertical/horizontal state is tested
	return ( a.vertical == b.vertical );
}

static void log_error(mDot* dot, const char* msg, int32_t retval);
static void joinLedToggle();
static void onNextTxTimerEvent();
static void ReceiveData(std::vector<uint8_t> frame);


void JoinNetwork()
{
	bool    ok;
	int32_t mdot_ret;

	do{
		ok = true;

		// reset to default config so we know what state we're in
		mDotPtr->resetConfig();
		mDotPtr->setLogLevel(6);
		mDotPtr->setAntennaGain(-3);

		// Read node ID
		std::vector<uint8_t> mdot_EUI;
		mdot_EUI = mDotPtr->getDeviceId();
		printf("mDot EUI = ");

		for (uint8_t i=0; i<mdot_EUI.size(); i++)
			printf("%02x ", mdot_EUI[i]);
		printf("\n\r");

	  /*
	   * This call sets up private or public mode on the MTDOT. Set the function to true if
	   * connecting to a public network
	   */
		printf("setting Public Network Mode\r\n");
		if ((mdot_ret = mDotPtr->setPublicNetwork(true)) != mDot::MDOT_OK)
			log_error(mDotPtr, "failed to set Public Network Mode", mdot_ret);

		mDotPtr->setTxDataRate(DATARATE);
		mDotPtr->setTxPower(TXPOWER);
		mDotPtr->setJoinRetries(JOIN_RETRIES);
		mDotPtr->setJoinMode(mDot::OTA);

	  /*
	   * 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 = mDotPtr->setFrequencySubBand(fsb)) != mDot::MDOT_OK) {
			log_error(mDotPtr, "failed to set frequency sub band", mdot_ret);
			ok = false;
		}

		printf("setting ADR\r\n");
		if ((mdot_ret = mDotPtr->setAdr(adrOn)) != mDot::MDOT_OK) {
			log_error(mDotPtr, "failed to set ADR", mdot_ret);
			ok = false;
		}

	   /*
		* setNetworkName is used for private networks.
		* Use setNetworkID(AppID) for public networks
		*/
		printf("setting network name\r\n");
		if ((mdot_ret = mDotPtr->setNetworkId(appEUI)) != mDot::MDOT_OK) {
			log_error(mDotPtr, "failed to set network name", mdot_ret);
			ok = false;
		}

	   /*
		* setNetworkPassphrase is used for private networks
		* Use setNetworkKey for public networks
		*/
		printf("setting network key\r\n");
		if ((mdot_ret = mDotPtr->setNetworkKey(appKey)) != mDot::MDOT_OK) {
			log_error(mDotPtr, "failed to set network password", mdot_ret);
			ok = false;
		}

	} while(ok == false);

	joinTicker.attach(joinLedToggle, 5);

	// attempt to join the network
	printf("joining network\r\n");
	while ((mdot_ret = mDotPtr->joinNetwork()) != mDot::MDOT_OK)
	{
		log_error(mDotPtr,"failed to join network:", mdot_ret);
		uint32_t delay_s = (mDotPtr->getNextTxMs() / 1000) + 1;
		wait(delay_s);
	}

	printf("network joined\r\n");

	joinTicker.detach();
	CBoard::SetLED(1, false);
}

void SendFrame()
{
	std::vector<uint8_t> frame;
    int32_t              mdot_ret;
    uint8_t              buffer[20];
    SensorPacket         packet(buffer, sizeof(buffer));

    // Sensor packet type serialized to the frame buffer
    packet.setPrimarySensor(txOrientation.vertical ? VERTICAL_ORIENTATION_VALUE : HORIZONTAL_ORIENTATION_VALUE);
    packet.setTemperature(sensorData.temperature);
    packet.setPressure(sensorData.pressure);
    packet.serialize();

    frame.assign(packet.payload(), packet.payload() + packet.length());
    if ((mdot_ret = mDotPtr->send(frame)) != mDot::MDOT_OK)
    {
        log_error(mDotPtr, "failed to send", mdot_ret);
    }
    else
    {
        printf("successfully sent data\r\n");
        frame.clear();
        if ((mdot_ret = mDotPtr->recv(frame)) == mDot::MDOT_OK)
        {
            printf("recv data: ");
            for(uint32_t i = 0;i < frame.size();i++)
                printf("%02X",frame[i]);
            printf("\r\n");

            ReceiveData(frame);
        }
    }
}

void ReceiveData(std::vector<uint8_t> frame)
{
	BackendOrientation.vertical = (frame[0] == VERTICAL_ORIENTATION_VALUE);
	BackendSynchronized = !BackendEnabled || orientationIsEqual(BackendOrientation, txOrientation);

	// Blink LED
	bool ledState = false;
	for(uint8_t i=0; i<3; i++)
	{
		CBoard::SetLED(1, ledState);
		ledState = !ledState;
		osDelay(500);
	}
}

static void onButtonPress(uint8_t buttonNum)
{
	DisplayBackendState = true;

	if(buttonNum == 1)
	{
		OrientationInit = true;
		BackendEnabled  = !BackendEnabled;

		// Start next transmit immediately
		if( BackendEnabled && !NextTx )
		{
			nextTxTimer.detach();
			nextTxTimer.attach_us(onNextTxTimerEvent, 1000);
		}
	}
}

int main()
{
	time_t lastTxT;

	// Initialize Board
	BoardInit();

	// Register pushbutton handler
	CBoard::SetButtonCallback(onButtonPress);

	// Join Network
	JoinNetwork();

	// Start Board sensors
	CBoard::Start();

	while( true )
	{
    	// Read sensors
		if( CBoard::ReadSensors(sensorData) == Board_Ok )
		{
			if( !orientationIsEqual(sensorData.orientation, lastOrientation) || OrientationInit)
			{
				orientationChangeCount++;
				lastOrientation = sensorData.orientation;
			}
		}

		// Initialize orientation state
		if( OrientationInit )
		{
			OrientationInit             = false;
			orientationChangeCount      = 1;
			// Set tx orientation to opposite of current as it will be toggled  before transmit
			txOrientation.vertical      = !lastOrientation.vertical;
			// Set backend to be out of sync
			BackendOrientation.vertical =  txOrientation.vertical;
		}

		// Display backend enabled state
		if(DisplayBackendState)
		{
			DisplayBackendState = false;

			uint8_t ledToggleCount = BackendEnabled ? 3 : 2;
			CBoard::SetLED(1, false);
			// blink LED to indicate backend state
			for(uint32_t i=0; i < ledToggleCount*2; i++)
			{
				osDelay(1000);
				CBoard::ToggleLED(1);
			}

			// Set LED to reflect Backend synchronized state
			CBoard::SetLED(1, BackendOrientation.vertical != txOrientation.vertical);
		}

		// Get next orientation change to transmit after backend sync of the last transmitted orientation is finished
		if( ( BackendSynchronized == true ) && ( orientationChangeCount != 0 ) )
		{
			BackendSynchronized = false;

			// Set transmit orientation
			txOrientation.vertical = !txOrientation.vertical;
			orientationChangeCount--;

			// Turn on out-of-sync LED
			CBoard::SetLED(1, true);

			// Get elapsed time since last transmit
			time_t currT    = time(NULL);
			time_t elapsedT = ( currT - lastTxT ) * 1e3;

			// Stop transmit timer
			AppTxDutyCycle = 0;
			nextTxTimer.detach();

			// Wait to transmit until elapsed time is greater than alarm mode dutycycle
			NextTx = ( elapsedT >= APP_TX_DUTY_CYCLE_ALARM );
			if( !NextTx )
			{
				AppTxDutyCycle = APP_TX_DUTY_CYCLE_ALARM - elapsedT;
				nextTxTimer.attach_us(onNextTxTimerEvent, AppTxDutyCycle * 1e3);
			}
		}

		if ( NextTx == true )
		{
			NextTx = false;

			/*  Backend synchronized flag set true when
			 *    o  Backend not enabled
			 *    o  Backend in sync
			 */
			BackendSynchronized = !BackendEnabled || orientationIsEqual(BackendOrientation, txOrientation);

			// Transmit application frame
			SendFrame();

			// Update transmit timestamp
			lastTxT = time(NULL);

			// Set next transmit time
			if( BackendSynchronized == false )
			{
				if( ( AppTxDutyCycle != APP_TX_DUTY_CYCLE_ALARM ) )
				{
					AppTxDutyCycle = APP_TX_DUTY_CYCLE_ALARM;
					nextTxTimer.detach();
					nextTxTimer.attach_us(onNextTxTimerEvent, AppTxDutyCycle * 1e3);
				}
			}
			else if( AppTxDutyCycle != APP_TX_DUTY_CYCLE_NORMAL )
			{
				AppTxDutyCycle = APP_TX_DUTY_CYCLE_NORMAL;
				nextTxTimer.detach();
				nextTxTimer.attach_us(onNextTxTimerEvent, AppTxDutyCycle * 1e3);
			}

			// Set LED to reflect Backend synchronized state
			CBoard::SetLED(1, BackendOrientation.vertical != txOrientation.vertical);
		}

		// Delay before next sensor poll
		osDelay(2000);
	}
}


/*
 *  prints of mDot error
 */
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());
}

void joinLedToggle() { CBoard::ToggleLED(1); }

void onNextTxTimerEvent( void ) { NextTx = true; }