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-25
Revision:
32:5873d0638277
Parent:
26:752359e19a97
Parent:
29:055824db068a
Child:
36:cd1077f40dbf

File content as of revision 32:5873d0638277:

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

/******************************************************************************/

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

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

// Transmit rate related variables
static bool     NextTx          = true;
static uint32_t AppTxDutyCycle  = APP_TX_DUTY_CYCLE_NORMAL;

static Ticker           joinTicker;
static Ticker           nextTxTimer;
static BoardSensorData  sensorData;
static BoardOrientation txOrientation;


// Backend service state (set to false if backend is not configured)
static bool      BackendSynchronized = true;
BoardOrientation BackendOrientation;


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

// Forward
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,1);

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

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

	if( BackendOrientation.vertical == txOrientation.vertical )
		BackendSynchronized = true;
}

inline uint8_t getNextTxOrientation()
{
	static uint8_t txOrientationType = Orientation_Max;

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

	for( ; txOrientationType < Orientation_Max; txOrientationType++)
	{
		if( orientationTxCount[txOrientationType] < orientationCount[txOrientationType] )
		{
			orientationTxCount[txOrientationType]++;
			break;
		}
	}

	return txOrientationType;
}

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


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

	// Start transmit timer
	nextTxTimer.attach_us(onNextTxTimerEvent, AppTxDutyCycle * 1e3);

	while( true )
	{
		uint8_t nextTxOrientation;

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

		// Determine next orientation to transmit after backend sync of the last orientation is finished
		if( ( BackendSynchronized == true )  &&  ( ( nextTxOrientation = getNextTxOrientation() ) < Orientation_Max ) )
		{
			BackendSynchronized  = false;

			switch(nextTxOrientation)
			{
			    case Orientation_Horizontal:
			    	txOrientation.vertical = false;
			    	break;
			    case Orientation_Vertical:
			    	txOrientation.vertical = true;
			    	break;
			    default:
			    	break;
			}

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

			// Transmit now if elapsed time since last tx is greater than alarm mode dutycycle
			if( elapsedT >= APP_TX_DUTY_CYCLE_ALARM )
			{
				nextTxTimer.detach();
				NextTx = true;
			}
			// Otherwise wait until alarm time has elapased
			else
			{
				nextTxTimer.detach();
				nextTxTimer.attach_us(onNextTxTimerEvent, (APP_TX_DUTY_CYCLE_ALARM - elapsedT)* 1e3);
			}

			AppTxDutyCycle = APP_TX_DUTY_CYCLE_ALARM;
		}

		if ( NextTx == true )
		{
			/*  Backend synchronized flag set true when
			 *    - Backend not enabled
			 *    - Downlink received for current orientation
			 */
			BackendSynchronized = !BackendEnabled;

			// Transmit application frame
			SendFrame();
			lastTxT = time(NULL);

			NextTx = false;

			// Fast transmit rate while backend is out of sync with device state
			if(BackendSynchronized == false)
			{
				if( ( AppTxDutyCycle != APP_TX_DUTY_CYCLE_ALARM ) )
				{
					AppTxDutyCycle = APP_TX_DUTY_CYCLE_ALARM;
					nextTxTimer.detach();
					nextTxTimer.attach_us(onNextTxTimerEvent, APP_TX_DUTY_CYCLE_ALARM * 1e3);
				}
			}
			else if( AppTxDutyCycle != APP_TX_DUTY_CYCLE_NORMAL )
			{
				AppTxDutyCycle = APP_TX_DUTY_CYCLE_NORMAL;
				nextTxTimer.detach();
				nextTxTimer.attach_us(onNextTxTimerEvent, APP_TX_DUTY_CYCLE_NORMAL * 1e3);
			}
		}

		// 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()
{
    appLED= !appLED;
}

void onNextTxTimerEvent( void )
{
	NextTx = true;
}