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
Diff: main.cpp
- Revision:
- 0:7e1fdc4d6e1c
- Child:
- 1:711fb7d8127b
diff -r 000000000000 -r 7e1fdc4d6e1c main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Dec 20 14:07:12 2016 +0000 @@ -0,0 +1,487 @@ +// 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" + +// Semaphore for notifiying button presses +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 = D10, + .rx = D2, + .rts = D13, + .cts = D9, +}; + + +// 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() +{ + // Get thread context + sensor_thread_ctx_t* th_ctx = g_thread_ctx; + + thread_ready.release(); + + 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); + + while (true) + { + // Read the sensor values + bool err = th_ctx->read_value(th_ctx->current_value); + + WARNING(!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() +{ + PinName DBG_LED = D12; + + // Go to sleep when idle + //rtos_attach_idle_hook(sleep); + + // Start & initialize + dbg_open(DBG_LED); + PRINT("\r\n--- Starting new run ---\r\n"); + + DigitalOut myled(DBG_LED); + DebouncedInterrupt user_interrupt(USER_BUTTON); + user_interrupt.attach(button_push_isr, IRQ_FALL, 200, true); + myled = 1; + + extern uint16_t const os_maxtaskrun; + //IPRINT("Max user threads: %d\r\n", os_maxtaskrun-1-9); + + d7a_open(&shield_config, A3, &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 + sensors_init(); + +#endif // _SENSORS_SIMU_ + + osStatus status; + + // Start sensors threads +#define THREAD_START(_name) Thread _name##_th(osPriorityNormal, DEFAULT_STACK_SIZE);\ + 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; + fm_th.start(file_modified_thread); + + // For button irq + Thread but_th(osPriorityNormal, DEFAULT_STACK_SIZE*4, NULL); + but_th.start(button_user_thread); + + // Set main task to lowest priority + osThreadSetPriority(osThreadGetId(), osPriorityIdle); + while(true) + { + // Wait to avoid beeing stuck in loop + Thread::wait(200); + myled = !myled; + } +} \ No newline at end of file