Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: X_NUCLEO_IKS01A1 MLX90614 d7a_1x wizzi-utils
Fork of D7A_1x_demo_sensors_OS5 by
main.cpp
- Committer:
- Jeej
- Date:
- 2017-01-30
- Revision:
- 4:8ac150ec1532
- Parent:
- 3:5f2917933ece
- Child:
- 5:ef4b5c422d3a
File content as of revision 4:8ac150ec1532:
// This project is a demo of the DASH7 1.x stack
// @autor: jeremie@wizzilab.com
// @date: 2016-12-20
//
// ----- SETUP -----
// This programm has been tested with the following hardware:
// --> NUCLEO-L152RE + DASH7 enabled SHIELD_SP1ML_v1.0
// For this demo to work, you need the previously described hardware.
// A DASH7 1.x gateway have to be available in your area in order to retreive the data.
//
// ----- FILE SYSTEM -----
// DASH7 is a file system based protocol. You read and write in files that are present on your device or your modem.
// Some callbacks can be implemented by the user for allowing the stack to acceed the local file system. (See description of the callbacks for more details)
// The file system is user defined and can be changed to fit your needs.
// This demo uses a simple RAM file system.
// The files are defined in files.h
// The files values are initialized in files.cpp
//
// ----- SENSORS -----
// The sensors can be simulated (random data).
//
// ----- DEMO -----
// This demo starts 7 threads (one for each sensor value) that will periodically read the sensor value
// and depending on the sensor configuration file, will send the data to the DASH7 network (notification)
// You can also report the alarm status by pushing the board's button (blue)
//
// ----- DEBUG -----
// Several debugging options are available in wizzi-utils/dbg/dbg.h
// An ASSERT is a fatal error. By default, this error will reboot the device.
#include "mbed.h"
#include "rtos.h"
#include "rtos_idle.h"
#include "d7a.h"
#include "sensors.h"
#include "simul.h"
#include "dbg.h"
#include "DebouncedInterrupt.h"
#include "files.h"
// -----------------------------------------------
// Hardware configuration
// -----------------------------------------------
#if defined(TARGET_STM32L152RE)
#define D7A_PIN_TX (D10)
#define D7A_PIN_RX (D2)
#define D7A_PIN_RTS (D13)
#define D7A_PIN_CTS (D9)
#define D7A_PIN_RESET (A3)
#define DEBUG_LED (NC)
#define DEBUG_BUTTON (USER_BUTTON)
#elif defined(TARGET_STM32L432KC)
#define D7A_PIN_TX (D5)
#define D7A_PIN_RX (D4)
#define D7A_PIN_RTS (D11)
#define D7A_PIN_CTS (D10)
#define D7A_PIN_RESET (D12)
#define DEBUG_LED (D13) // LED1
#else
#error "Please choose or add the right platform."
#endif
Semaphore button_user(0);
Semaphore thread_ready(0);
// Interrupt Service Routine on button press.
void button_push_isr( void )
{
button_user.release();
}
// file modified queue
Queue<void, 8> fm_queue;
sensor_thread_ctx_t* g_thread_ctx;
// -----------------------------------------------
// callbacks
// -----------------------------------------------
/**
Write data into a file.
@param const uint8_t File ID
@param const uint16_t Offset from start of data
@param const uint16_t Size of data to be written
@param const uint8_t* const Pointer to the data to write
@return uint32_t Size of written data
*/
uint32_t write_file_callback(const uint8_t file_id,
const uint16_t offset,
const uint16_t size,
const uint8_t* const content)
{
uint32_t ret = 0;
IPRINT("Write file %d offset:%d size:%d\r\n", file_id, offset, size);
ret = fs_write_file(file_id, offset, size, content);
WARNING(ret, "File %d not found\r\n", file_id);
// Indicate that the file has been modified
fm_queue.put((void*)file_id);
return ret;
}
/**
Read data from a file.
@param const uint8_t File ID
@param const uint16_t Offset from start of data
@param const uint16_t Size of data to be read
@param const uint8_t* const Pointer to the reading buffer
@return uint32_t Size of read data
*/
uint32_t read_file_callback(const uint8_t file_id,
const uint16_t offset,
const uint16_t size,
uint8_t* buf)
{
uint32_t ret = 0;
IPRINT("Read file %d offset:%d size:%d\r\n", file_id, offset, size);
ret = fs_read_file(file_id, offset, size, buf);
WARNING(ret, "File %d not found\r\n", file_id);
return ret;
}
/**
Called when a notification is finished
@param const uint8_t File ID
@param const uint8_t Error code
@return void
*/
void notif_done_callback(const uint8_t file_id, const uint8_t error)
{
PRINT("Notif FID %d done. err %d\r\n", file_id, error);
}
void unsolicited_callback(d7a_msg_t** uns)
{
PRINT("UNSOLICITED MESSAGE:\r\n");
d7a_print_msg(uns);
d7a_free_msg(uns);
}
// callbacks structure
const d7a_callbacks_t callbacks = {
.write_file = write_file_callback, // If NULL you cannot declare files
.read_file = read_file_callback, // If NULL you cannot declare files
.notif_done = notif_done_callback,
.unsolicited_msg = unsolicited_callback,
};
// Com configuration for the DASH7 shield
const d7a_com_config_t shield_config = {
.tx = D7A_PIN_TX,
.rx = D7A_PIN_RX,
.rts = D7A_PIN_RTS,
.cts = D7A_PIN_CTS,
};
// Check parameters to see if data should be send
static bool report_needed(sensor_config_t* cfg, int32_t value, int32_t last_value, uint32_t last_report_time)
{
switch (cfg->report_type)
{
case REPORT_ALWAYS:
// Send a report at each measure
IPRINT("Notif cause 1\r\n");
return true;
case REPORT_ON_DIFFERENCE:
// Send a report when the difference between the last reported measure and the current mesure is greater than max_diff
if (abs(last_value - value) >= cfg->max_diff)
{
IPRINT("Notif cause 2 last:%d new:%d max_diff:%d\r\n", last_value, value, cfg->max_diff);
return true;
}
break;
case REPORT_ON_THRESHOLD:
// Send a report when crossing a threshold
if ( (value >= cfg->threshold_high && last_value < cfg->threshold_high)
|| (value <= cfg->threshold_low && last_value > cfg->threshold_low)
|| (value < cfg->threshold_high && last_value >= cfg->threshold_high)
|| (value > cfg->threshold_low && last_value <= cfg->threshold_low))
{
IPRINT("Notif cause 3 last:%d new:%d th:%d tl:%d\r\n", last_value, value, cfg->threshold_high, cfg->threshold_low);
return true;
}
break;
default:
break;
}
// Send a report if it's been more than max_period since the last report
if (((last_report_time/1000) >= cfg->max_period) && (cfg->max_period != 0))
{
IPRINT("Notif cause 4 max_period:%d time:%d\r\n", cfg->max_period, last_report_time);
return true;
}
return false;
}
SENSOR_THREAD_CTX(mag, MAG_VALUE_FILE_ID, MAG_CFG_FILE_ID, mag_get_value, 3);
SENSOR_THREAD_CTX(acc, ACC_VALUE_FILE_ID, ACC_CFG_FILE_ID, acc_get_value, 3);
SENSOR_THREAD_CTX(gyr, GYR_VALUE_FILE_ID, GYR_CFG_FILE_ID, gyr_get_value, 3);
SENSOR_THREAD_CTX(pre, PRE_VALUE_FILE_ID, PRE_CFG_FILE_ID, pre_get_value, 1);
SENSOR_THREAD_CTX(hum, HUM_VALUE_FILE_ID, HUM_CFG_FILE_ID, hum_get_value, 1);
SENSOR_THREAD_CTX(tem1, TEM1_VALUE_FILE_ID, TEM1_CFG_FILE_ID, tem1_get_value, 1);
SENSOR_THREAD_CTX(tem2, TEM2_VALUE_FILE_ID, TEM2_CFG_FILE_ID, tem2_get_value, 1);
// -----------------------------------------------
// Threads
// -----------------------------------------------
void sensor_thread()
{
FPRINT("(id:0x%08x)\r\n", osThreadGetId());
// Get thread context
sensor_thread_ctx_t* th_ctx = g_thread_ctx;
d7a_msg_t** resp = NULL;
uint32_t last_report_time = 0;
// Force a first notification
bool first_notif = true;
// Retrieve notification config from local file
fs_read_file(th_ctx->cfg_file_id, 0, sizeof(sensor_config_t), (uint8_t*)&(th_ctx->cfg));
// Declare the config file to allow it to be accessed via the modem
d7a_declare(th_ctx->cfg_file_id, VOLATILE, RW_RW, sizeof(sensor_config_t), sizeof(sensor_config_t));
// Create a file on the modem to store and notify the sensor value
d7a_create(th_ctx->value_file_id, VOLATILE, RW_R, th_ctx->data_size, th_ctx->data_size, D7A_NOTIFICATION_FULL, D7A_ITF_REPORT_CHECKED);
thread_ready.release();
while (true)
{
// Read the sensor values
bool err = th_ctx->read_value(th_ctx->current_value);
ASSERT(!err, "Failed to read sensor value for FID: %d\r\n", th_ctx->value_file_id);
// Check if data should be send
for (uint8_t i = 0; i < th_ctx->nb_values; i++)
{
if (report_needed(&(th_ctx->cfg),
th_ctx->current_value[i],
th_ctx->last_report_value[i],
last_report_time) || first_notif)
{
first_notif = false;
PRINT("NOTIFY %3d: ", th_ctx->value_file_id);
for (uint8_t i = 0; i < th_ctx->nb_values; i++)
{
PRINT("%9ld ", (int32_t)th_ctx->current_value[i]);
}
PRINT("\r\n");
// Send data to the modem
resp = d7a_write(th_ctx->value_file_id, 0, th_ctx->data_size, (uint8_t*)th_ctx->current_value);
d7a_free_msg(resp);
// Update last report value
memcpy(th_ctx->last_report_value, th_ctx->current_value, th_ctx->data_size);
// Reset last report time
last_report_time = 0;
break;
}
}
// Update last report time
last_report_time += th_ctx->cfg.period;
// Wait for period
Thread::wait(th_ctx->cfg.period);
}
}
void file_modified_thread()
{
FPRINT("(id:0x%08x)\r\n", osThreadGetId());
while (true)
{
// Wait for a file modified event
osEvent evt = fm_queue.get();
// Retrieve FID of modified file
uint8_t fid = (uint8_t)(uint32_t)evt.value.p;
PRINT("File %d has been modified\r\n", fid);
switch (fid)
{
// If a configuration file has been modified, update the context
case MAG_CFG_FILE_ID:
fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(mag_thread_ctx.cfg));
break;
case ACC_CFG_FILE_ID:
fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(acc_thread_ctx.cfg));
break;
case GYR_CFG_FILE_ID:
fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(gyr_thread_ctx.cfg));
break;
case PRE_CFG_FILE_ID:
fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(pre_thread_ctx.cfg));
break;
case HUM_CFG_FILE_ID:
fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(hum_thread_ctx.cfg));
break;
case TEM1_CFG_FILE_ID:
fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(tem1_thread_ctx.cfg));
break;
case TEM2_CFG_FILE_ID:
fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(tem2_thread_ctx.cfg));
break;
default:
break;
}
}
}
void button_user_thread()
{
FPRINT("(id:0x%08x)\r\n", osThreadGetId());
uint8_t alarm = 255;
d7a_msg_t** resp = NULL;
// Create the alarm file
d7a_create(ALARM_FILE_ID, VOLATILE, RW_R, sizeof(uint8_t), sizeof(uint8_t), D7A_NOTIFICATION_FULL, D7A_ITF_SINGLE);
// Update it with the default value
resp = d7a_write(ALARM_FILE_ID, 0, sizeof(uint8_t), (uint8_t*)&alarm);
d7a_free_msg(resp);
while (true)
{
// Wait for button press
button_user.wait();
// Toggle alarm state
alarm = !alarm;
PRINT("BUTTON ALARM %d\r\n", alarm);
#if 1 // Switch between Notify and Distant Read/Write example
// Send alarm state to the modem
resp = d7a_write(ALARM_FILE_ID, 0, sizeof(uint8_t), (uint8_t*)&alarm);
WARNING(!resp[0]->err, "BUTTON ALARM ERR %d\r\n", resp[0]->err);
d7a_free_msg(resp);
#else
// Distant device that I want to acceed
#if 0 // Unicast / Broadcast
// Unicast
d7a_addressee_t target = {
// Access Class
.xcl.byte = D7A_XCL_ENDPOINT_NO,
// Type of security you want to use
.ctrl.bf.nls = D7A_NLS_AES_CCM_64,
// Type of ID
.ctrl.bf.idf = D7A_ID_UID,
// Device ID
.id = { 0x00, 0x1B, 0xC5, 0x0C, 0x70, 0x00, 0x07, 0xA3 },
};
#else
// Broadcast
d7a_addressee_t target = {
// Access Class
.xcl.byte = D7A_XCL_ENDPOINT_NO,
// Type of security you want to use
.ctrl.bf.nls = D7A_NLS_AES_CCM_64,
// Type of ID
.ctrl.bf.idf = D7A_ID_NBID,
// Maximum number of responses (1-32)
.id[0] = D7A_NBID(8),
};
#endif
#if 1 // Read / Write
// Read example
//resp = d7a_read(MAG_CFG_FILE_ID, 12, 5, &target, D7A_ITF_ONESHOT);
resp = d7a_read(ALARM_FILE_ID, 0, 1, NULL, &target, D7A_ITF_ONESHOT);
#else
// Write example
uint8_t v = 0x01;
resp = d7a_write(ALARM_FILE_ID, 0, 1, &v, NULL, &target, D7A_ITF_ONESHOT);
#endif
// Check received response(s)
d7a_print_msg(resp);
PRINT("Resp done.\r\n");
d7a_free_msg(resp);
#endif
}
}
/*** Main function ------------------------------------------------------------- ***/
int main()
{
// Start & initialize
DBG_OPEN(DEBUG_LED);
PRINT("\r\n--- Starting new run ---\r\n");
extern uint16_t const os_maxtaskrun;
//IPRINT("Max user threads: %d\r\n", os_maxtaskrun-1-9);
d7a_open(&shield_config, D7A_PIN_RESET, &callbacks);
d7a_modem_print_infos();
// Create the revision file for the Dash7board
d7a_create(65, PERMANENT, RW_R, sizeof(d7a_revision_t), sizeof(d7a_revision_t), D7A_NOTIFICATION_FULL, D7A_ITF_REPORT_CHECKED);
// Notify revision
d7a_msg_t** resp = d7a_write(65, 0, sizeof(d7a_revision_t), (uint8_t*)&f_dev_rev);
d7a_free_msg(resp);
#if _SENSORS_SIMU_
PRINT("(Simulated sensors)\r\n");
uint32_t divider;
// Retreive the simulation parameter from local file
fs_read_file(SIMUL_FILE_ID, 0, sizeof(uint32_t), (uint8_t*)÷r);
// Update the simulation parameters
simul_update_param(divider);
// Declare the simulation parameter file
d7a_declare(SIMUL_FILE_ID, PERMANENT, RW_RW, sizeof(sensor_config_t), sizeof(sensor_config_t));
#else
// Open I2C and initialise the sensors
DevI2C ext_i2c(IKS01A1_PIN_I2C_SDA, IKS01A1_PIN_I2C_SCL);
#if (_HUM_EN_ || _TEM1_EN_)
humidity_sensor = new HTS221(ext_i2c);
ASSERT(Init_HTS221(humidity_sensor), "Failed to init HTS221\r\n");
temp_sensor1 = humidity_sensor;
#endif // _TEM_EN_
#if _MAG_EN_
magnetometer = new LIS3MDL(ext_i2c);
ASSERT(Init_LIS3MDL(magnetometer), "Failed to init LIS3MDL\r\n");
#endif // _MAG_EN_
#if (_ACC_EN_ || _GYR_EN_)
accelerometer = new LSM6DS0(ext_i2c);
ASSERT(Init_LSM6DS0(accelerometer), "Failed to init LSM6DS0\r\n");
gyroscope = accelerometer;
#endif // _ACC_EN_ || _GYR_EN_
#if (_PRE_EN_ || _TEM2_EN_)
pressure_sensor = new LPS25H(ext_i2c);
ASSERT(Init_LPS25H(pressure_sensor), "Failed to init LPS25H\r\n");
temp_sensor2 = pressure_sensor;
#endif // _PRE_EN_
#endif // _SENSORS_SIMU_
osStatus status;
// Start sensors threads
#define THREAD_START(_name) Thread _name##_th(osPriorityNormal, 1024, NULL);\
g_thread_ctx = &_name##_thread_ctx;\
status = _name##_th.start(sensor_thread);\
ASSERT(status == osOK, "Failed to start ##_name## thread (err: %d)\r\n", status);\
thread_ready.wait();
#if _MAG_EN_
THREAD_START(mag);
#endif // _MAG_EN_
#if _ACC_EN_
THREAD_START(acc);
#endif // _ACC_EN_
#if _GYR_EN_
THREAD_START(gyr);
#endif // _GYR_EN_
#if _PRE_EN_
THREAD_START(pre);
#endif // _PRE_EN_
#if _HUM_EN_
THREAD_START(hum);
#endif // _HUM_EN_
#if _TEM1_EN_
THREAD_START(tem1);
#endif // _TEM1_EN_
#if _TEM2_EN_
THREAD_START(tem2);
#endif // _TEM2_EN_
// File modified thread
Thread fm_th(osPriorityNormal, 512, NULL);
status = fm_th.start(file_modified_thread);
ASSERT(status == osOK, "Failed to start fm thread (err: %d)\r\n", status);
// For button
#ifdef DEBUG_BUTTON
DebouncedInterrupt user_interrupt(DEBUG_BUTTON);
user_interrupt.attach(button_push_isr, IRQ_FALL, 200, true);
Thread but_th(osPriorityNormal, 512, NULL);
status = but_th.start(button_user_thread);
ASSERT(status == osOK, "Failed to start but thread (err: %d)\r\n", status);
#endif
// Set main task to lowest priority
osThreadSetPriority(osThreadGetId(), osPriorityIdle);
while(true)
{
// Wait to avoid beeing stuck in loop
Thread::wait(osWaitForever);
}
}
