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-29
Branch:
develop
Revision:
39:022b327d6bf0
Parent:
36:cd1077f40dbf
Child:
43:55e7bb4d9b60

File content as of revision 39:022b327d6bf0:

 /*       _____                         _
 *      / ____|                       | |  
 *     | (___     ___   _ __     ___  | |_ 
 *      \___ \   / _ \ | '_ \   / _ \ | __|
 *      ____) | |  __/ | | | | |  __/ | |_ 
 *     |_____/   \___| |_| |_|  \___|  \__|
 *         (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


static bool             BackendSynchronized = true;
static BoardOrientation BackendOrientation;
static Ticker           joinTicker;
static Ticker           nextTxTimer;
static BoardSensorData  sensorData;
static BoardOrientation txOrientation;
static bool             NextTx  = true;
static uint32_t         AppTxDutyCycle = APP_TX_DUTY_CYCLE_NORMAL;

// Board Orientation
enum EOrientationType
{
	Orientation_Horizontal = 0,
	Orientation_Vertical,
	Orientation_Max,
};
//orientation change count
uint32_t orientationCount[Orientation_Max];
// orientation transmit count
uint32_t orientationTxCount[Orientation_Max];

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

// Next  orientation change to transmit
inline uint8_t getNextTxOrientation(BoardOrientation &orientation)
{
	static uint8_t txOrientationType = Orientation_Max;

	if (++txOrientationType >= Orientation_Max)
		txOrientationType = 0;

	for( ; txOrientationType < Orientation_Max; txOrientationType++)
	{
		if( orientationTxCount[txOrientationType] < orientationCount[txOrientationType] )
		{
			orientationTxCount[txOrientationType]++;
			switch(txOrientationType)
			{
				case Orientation_Horizontal:
					orientation.vertical = false;
					break;
				case Orientation_Vertical:
					orientation.vertical = true;
					break;
				default:
					break;
			}
			break;
		}
	}

	return txOrientationType;
}

inline void incrementOrientation(BoardOrientation &orientation)
{
	orientation.vertical ? orientationCount[Orientation_Vertical]++ : orientationCount[Orientation_Horizontal]++;
}

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 = orientationIsEqual(BackendOrientation, txOrientation);
}

int main()
{
	time_t           lastTxT;
	BoardOrientation lastOrientation;

    memset(orientationCount, 0, sizeof(orientationCount));
    memset(orientationTxCount, 0, sizeof(orientationTxCount));

	// Initialize Board
	BoardInit();

	// Join Network
	JoinNetwork();

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

	// Send initial state
	if( CBoard::ReadSensors(sensorData) == Board_Ok )
	{
		lastOrientation = sensorData.orientation;
		incrementOrientation(lastOrientation);

		//Initialize backend state to opposite of current to trigger
		// backend synchronization if enabled
		BackendOrientation.vertical = !lastOrientation.vertical;
	}

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

		// Determine next orientation to transmit after backend sync of the last transmitted orientation is finished
		if( ( BackendSynchronized == true )  &&  ( getNextTxOrientation(txOrientation) < Orientation_Max ) )
		{
			BackendSynchronized = false;
			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
			if( !( NextTx = ( elapsedT >= APP_TX_DUTY_CYCLE_ALARM ) ) )
			{
				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 state == current orientation
			 */
			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);
			}

			if(BackendSynchronized == true)
				CBoard::SetLED(1, false);
		}

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