Example of using the mDot UDK with the X-NUCLEO-IKS01A2 board
Dependencies: MTS_X_NUCLEO_IKS01A2 libmDot-mbed5
Fork of mDot-IKS01A1 by
main.cpp
- Committer:
- pferland
- Date:
- 2018-01-30
- Revision:
- 15:fb9fa3ac530e
- Parent:
- 13:e165a137c3af
File content as of revision 15:fb9fa3ac530e:
#include "mbed.h"
#include "mDot.h"
#include "ChannelPlan.h"
#include "XNucleoIKS01A2.h"
#include "dot_util.h"
#include "RadioEvent.h"
#include <cmath>
#define TTN
#if !defined(CHANNEL_PLAN)
#define CHANNEL_PLAN CP_US915
#endif
// mDot UDK board demo with X-NUCLEO-IKS01A1 sensor card
// For more examples see the Dot-Examples project:
// https://developer.mbed.org/teams/MultiTech/code/Dot-Examples/
// This triggers an I2C issue in mbed-os 5.1.5
// Use any other revision to compile. (Tested with libmDot-dev/mbed-os 5.2.2
//#define ACTILITY
#ifdef ACTILITY
// Network Id for Senet public network
static uint8_t network_id[] = {0xF0, 0x3D, 0x29,0xAC,0x71,0x00,0x00, 0x00};
static uint8_t network_key[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uint8_t frequency_sub_band = 0;
static bool public_network = true;
#elif defined(SENET)
// Network Id for Senet public network
static uint8_t network_id[] = {0x00,0x25,0x0C,0x00,0x00,0x01,0x00,0x01};
// Register at or Sign in to http://portal.senetco.com/ and register your NodeId to receive your AppId
//
static uint8_t network_key[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// 1 For Senet, configurable on your Conduit
static uint8_t frequency_sub_band = 1;
// True for Senet, false for your Conduit.
static bool public_network = true;
#elif defined(TTN)
// Network Id for TheThingsNetwork public network
static uint8_t network_id[] = {0x70,0xB3,0xD5,0x7E,0xD0,0x00,0x98,0xE6};
// Network Key is known as "App Key" in TTN console
static uint8_t network_key[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// FSB if supported by region
static uint8_t frequency_sub_band = 1;
static bool public_network = true;
#else
//Replace with settings on your Conduit
static std::string network_name = "TestTest";
static std::string network_passphrase = "TestTest";
// 1 For Senet, configurable on your Conduit
static uint8_t frequency_sub_band = 1;
// True for Senet, false for your Conduit.
static bool public_network = false;
#endif
static uint8_t ack = 0;
static uint8_t tx_datarate = lora::DR_3;
// deepsleep consumes slightly less current than sleep
// in sleep mode, IO state is maintained, RAM is retained, and application will resume after waking up
// in deepsleep mode, IOs float, RAM is lost, and application will start from beginning after waking up
// if deep_sleep == true, device will enter deepsleep mode
static bool deep_sleep = false;
mDot *dot = NULL;
lora::ChannelPlan* plan = NULL;
int main()
{
Serial pc(USBTX, USBRX);
/* Instantiate the expansion board */
XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(I2C_SDA, I2C_SCL, PC_1);
/* Retrieve the composing elements of the expansion board */
/* Retrieve the composing elements of the expansion board */
// LSM303AGRMagSensor *magnetometer = mems_expansion_board->magnetometer;
// HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor;
// LPS22HBSensor *press_temp = mems_expansion_board->pt_sensor;
// LSM6DSLSensor *acc_gyro = mems_expansion_board->acc_gyro;
// LSM303AGRAccSensor *accelerometer = mems_expansion_board->accelerometer;
GyroSensor *gyroscope = mems_expansion_board->acc_gyro;
mems_expansion_board->acc_gyro->enable_g();
MotionSensor *accelerometer = mems_expansion_board->accelerometer;
mems_expansion_board->accelerometer->enable();
MagneticSensor *magnetometer = mems_expansion_board->magnetometer;
mems_expansion_board->magnetometer->enable();
HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor;
mems_expansion_board->ht_sensor->enable();
PressureSensor *pressure_sensor = mems_expansion_board->pt_sensor;
mems_expansion_board->pt_sensor->enable();
TempSensor *temp_sensor1 = mems_expansion_board->ht_sensor;
TempSensor *temp_sensor2 = mems_expansion_board->pt_sensor;
// Custom event handler for automatically displaying RX data
RadioEvent events;
pc.baud(115200);
#if CHANNEL_PLAN == CP_US915
plan = new lora::ChannelPlan_US915();
#elif CHANNEL_PLAN == CP_AU915
plan = new lora::ChannelPlan_AU915();
#elif CHANNEL_PLAN == CP_EU868
plan = new lora::ChannelPlan_EU868();
#elif CHANNEL_PLAN == CP_KR920
plan = new lora::ChannelPlan_KR920();
#elif CHANNEL_PLAN == CP_AS923
plan = new lora::ChannelPlan_AS923();
#elif CHANNEL_PLAN == CP_AS923_JAPAN
plan = new lora::ChannelPlan_AS923_Japan();
#elif CHANNEL_PLAN == CP_IN865
plan = new lora::ChannelPlan_IN865();
#endif
/* Initialize mDot */
dot = mDot::getInstance(plan);
//dot->setAdr(true);
mts::MTSLog::setLogLevel(mts::MTSLog::INFO_LEVEL);
dot->setEvents(&events);
if (!dot->getStandbyFlag()) {
logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);
// start from a well-known state
logInfo("defaulting Dot configuration");
dot->resetConfig();
dot->resetNetworkSession();
// update configuration if necessary
// in AUTO_OTA mode the session is automatically saved, so saveNetworkSession and restoreNetworkSession are not needed
if (dot->getJoinMode() != mDot::AUTO_OTA) {
logInfo("changing network join mode to AUTO_OTA");
if (dot->setJoinMode(mDot::AUTO_OTA) != mDot::MDOT_OK) {
logError("failed to set network join mode to AUTO_OTA");
}
}
uint32_t current_tx_datarate = dot->getTxDataRate();
if (current_tx_datarate != tx_datarate) {
logInfo("changing TX datarate from %u to %u", current_tx_datarate, tx_datarate);
if (dot->setTxDataRate(tx_datarate) != mDot::MDOT_OK) {
logError("failed to set TX datarate to %u", tx_datarate);
}
}
// in OTA and AUTO_OTA join modes, the credentials can be passed to the library as a name and passphrase or an ID and KEY
// only one method or the other should be used!
// network ID = crc64(network name)
#if defined(SENET) || defined(ACTILITY) || defined(TTN)
// network KEY = cmac(network passphrase)
update_ota_config_id_key(network_id, network_key, frequency_sub_band, public_network, ack);
#else
update_ota_config_name_phrase(network_name, network_passphrase, frequency_sub_band, public_network, ack);
#endif
// configure network link checks
// network link checks are a good alternative to requiring the gateway to ACK every packet and should allow a single gateway to handle more Dots
// check the link every count packets
// declare the Dot disconnected after threshold failed link checks
// for count = 3 and threshold = 5, the Dot will be considered disconnected after 15 missed packets in a row
update_network_link_check_config(3, 5);
// save changes to configuration
logInfo("saving configuration");
if (!dot->saveConfig()) {
logError("failed to save configuration");
}
// display configuration
display_config();
} else {
// restore the saved session if the dot woke from deepsleep mode
// useful to use with deepsleep because session info is otherwise lost when the dot enters deepsleep
logInfo("restoring network session from NVM");
dot->restoreNetworkSession();
}
while (true) {
std::vector<uint8_t> tx_data;
// join network if not joined
if (!dot->getNetworkJoinStatus()) {
join_network();
}
// Payload structure for mydevices cayenne:
// 1 byte Data1 ID
// 1 Byte Data1 Type
// N Bytes Data1
// 1 byte data 2 ID
// 1 byte data 2 type
// n Bytes data 2
// ...
// formats:
// Temperature sensor:
/*
* IPSO: 3303
* LPP 103
* HEX: 67
* Data size: 2
* Resolution: 0.1 degrees C
* Humidity sensor
* IPSO: 3304
* LPP: 104
* Hex: 68
* Datasize: 1
* Resolution: 0.5% unsigned
* Barometer/pressure sensor
* IPSO: 3315
* LPP: 115
* Hex: 73
* Datasize: 2
* Resolution 0.1hPa unsigned MSB
* Accelerometer
* IPSO: 3313
* LPP: 113
* Hex: 71
* Data size: 6
* Resolution: 0.001G signed MSB per axis
* Gyrometer
* IPSO: 3334
* LPP: 134
* Hex: 86
* Data size: 6
* Resolution: 0.01 degrees/s signed msb per axis
*/
//temp floats
float value1, value2;
// HTS221 Humidity sensor
temp_sensor1->get_temperature(&value1);
humidity_sensor->get_humidity(&value2);
//serialize data and append to packet
// Cayenne data: temperature; tag is 0x67, 2 bytes signed, 0.1 C/bit
tx_data.push_back(uint8_t(1)); // data id
tx_data.push_back(uint8_t(0x67)); // data type - temp
int16_t temp = floor(value1*10 + 0.5f);
logInfo("Temp payload: %d", temp);
tx_data.push_back(uint8_t( 0xFF & (temp >> 8)));
tx_data.push_back(uint8_t(0xFF & temp));
tx_data.push_back(uint8_t(2)); // data id
tx_data.push_back(uint8_t(0x68)); // data type - humidity
temp = floor(value2 * 2.0f + 0.5f);
tx_data.push_back(uint8_t(0xFF & temp ));
logInfo("Temperature data %f", value1);
logInfo("Humidity data: %f", value2);
pressure_sensor->get_pressure(&value1);
logInfo("Pressure data: %f", value1);
// pressure is reported in mbar, cayenne wants it in 0.1 hPa
// 1mbar = 1 hPa
temp = floor(value1 * 100.0f + 0.5f);
tx_data.push_back(uint8_t(3)); // data id
tx_data.push_back(uint8_t(0x73)); // data type - pressure
temp = floor(value1 / 0.1f + 0.5f);
tx_data.push_back(uint8_t(0xFF & (temp >> 8)));
tx_data.push_back(uint8_t(0xFF & temp));
// Get accelerometer data
int32_t accel_vector[3];
// returns in mG
accelerometer->get_x_axes(accel_vector);
logInfo("Acclerometer Z axis: %d", accel_vector[2]);
tx_data.push_back(uint8_t(4)); // data id
tx_data.push_back(uint8_t(0x71)); // data type - accelerometer
for(int i=0; i<3; i++){
tx_data.push_back(uint8_t(0xFF & accel_vector[i]) >> 8);
tx_data.push_back(uint8_t(0xFF & accel_vector[i]));
}
// Get gyro data
gyroscope->get_g_axes
(accel_vector);
// gyro reports in milidegrees/sec, cayenne wants centidegrees/sec
tx_data.push_back(uint8_t(5)); //data id
tx_data.push_back(uint8_t(0x86)); // data type - gyrometer
for(int i=0; i<3; i++){
accel_vector[i] /= 10;
tx_data.push_back(uint8_t(0xFF & (accel_vector[i] >> 8)));
tx_data.push_back(uint8_t(0xFF & accel_vector[i]));
}
send_data(tx_data);
if(deep_sleep){
// if going into deepsleep mode, save the session so we don't need to join again after waking up
// not necessary if going into sleep mode since RAM is retained
logInfo("saving network session to NVM");
dot->saveNetworkSession();
}
// ONLY ONE of the three functions below should be uncommented depending on the desired wakeup method
sleep_wake_rtc_only(deep_sleep);
//sleep_wake_interrupt_only(deep_sleep);
//sleep_wake_rtc_or_interrupt(deep_sleep);
}
return 0;
}
