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
00001 // This project is a demo of the DASH7 1.x stack 00002 // @autor: jeremie@wizzilab.com 00003 // @date: 2016-12-20 00004 // 00005 // ----- SETUP ----- 00006 // This programm has been tested with the following hardware: 00007 // --> NUCLEO-L152RE + DASH7 enabled SHIELD_SP1ML_v1.0 00008 // For this demo to work, you need the previously described hardware. 00009 // A DASH7 1.x gateway have to be available in your area in order to retreive the data. 00010 // 00011 // ----- FILE SYSTEM ----- 00012 // DASH7 is a file system based protocol. You read and write in files that are present on your device or your modem. 00013 // 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) 00014 // The file system is user defined and can be changed to fit your needs. 00015 // This demo uses a simple RAM file system. 00016 // The files are defined in files.h 00017 // The files values are initialized in files.cpp 00018 // 00019 // ----- SENSORS ----- 00020 // The sensors can be simulated (random data). 00021 // 00022 // ----- DEMO ----- 00023 // This demo starts 7 threads (one for each sensor value) that will periodically read the sensor value 00024 // and depending on the sensor configuration file, will send the data to the DASH7 network (notification) 00025 // You can also report the alarm status by pushing the board's button (blue) 00026 // 00027 // ----- DEBUG ----- 00028 // Several debugging options are available in wizzi-utils/dbg/dbg.h 00029 // An ASSERT is a fatal error. By default, this error will reboot the device. 00030 #include "mbed.h" 00031 #include "rtos.h" 00032 #include "rtos_idle.h" 00033 #include "d7a.h" 00034 #include "sensors.h" 00035 #include "simul.h" 00036 #include "dbg.h" 00037 #include "DebouncedInterrupt.h" 00038 #include "files.h" 00039 #include "MLX90614.h" 00040 #include "DevI2C.h" 00041 00042 #if defined(TARGET_STM32L152RE) 00043 #define D7A_PIN_TX (D10) 00044 #define D7A_PIN_RX (D2) 00045 #define D7A_PIN_RTS (D13) 00046 #define D7A_PIN_CTS (D9) 00047 #define D7A_PIN_RESET (A3) 00048 #define DEBUG_LED (LED1) 00049 #define DEBUG_BUTTON (USER_BUTTON) 00050 #define SENSOR_I2C_SDA (D14) 00051 #define SENSOR_I2C_SCL (D15) 00052 #define VOLT_PIN (A0) 00053 00054 #elif defined(TARGET_STM32L432KC) 00055 // ----------------------------------------------- 00056 // Hardware configuration for sh2050 00057 // ----------------------------------------------- 00058 #define D7A_PIN_TX (D5) 00059 #define D7A_PIN_RX (D4) 00060 #define D7A_PIN_RTS (D11) 00061 #define D7A_PIN_CTS (D10) 00062 #define D7A_PIN_RESET (D12) 00063 #define DEBUG_LED (D13) // LED1 00064 #define DEBUG_BUTTON (D9) 00065 #define SENSOR_I2C_SDA (D0) 00066 #define SENSOR_I2C_SCL (D1) 00067 // TODO Check which pin to use on the small board for voltage stuff 00068 #define VOLT_PIN (A0) 00069 00070 #else 00071 #error "Please choose or add the right platform." 00072 #endif 00073 00074 #define DGB_LED_BLINK_PERIOD (500) 00075 #define _TEM1_EN_ (1) 00076 #define _VOLTAGE_EN_ (1) 00077 #if (_VOLTAGE_EN_ == 1) 00078 AnalogIn volt_pin(VOLT_PIN); 00079 #endif 00080 00081 MLX90614 *mlxSensor; 00082 Semaphore button_user(0); 00083 Semaphore thread_ready(0); 00084 00085 // Interrupt Service Routine on button press. 00086 void button_push_isr( void ) 00087 { 00088 button_user.release(); 00089 } 00090 00091 // file modified queue 00092 Queue<void, 8> fm_queue; 00093 00094 // ----------------------------------------------- 00095 // callbacks 00096 // ----------------------------------------------- 00097 /** 00098 Write data into a file. 00099 00100 @param const uint8_t File ID 00101 @param const uint16_t Offset from start of data 00102 @param const uint16_t Size of data to be written 00103 @param const uint8_t* const Pointer to the data to write 00104 @return uint32_t Size of written data 00105 */ 00106 uint32_t write_file_callback(const uint8_t file_id, 00107 const uint16_t offset, 00108 const uint16_t size, 00109 const uint8_t* const content) 00110 { 00111 uint32_t ret = 0; 00112 00113 IPRINT("Write file %d offset:%d size:%d\r\n", file_id, offset, size); 00114 00115 ret = fs_write_file(file_id, offset, size, content); 00116 00117 WARNING(ret, "File %d not found\r\n", file_id); 00118 00119 // Indicate that the file has been modified 00120 fm_queue.put((void*)file_id); 00121 00122 return ret; 00123 } 00124 00125 /** 00126 Read data from a file. 00127 00128 @param const uint8_t File ID 00129 @param const uint16_t Offset from start of data 00130 @param const uint16_t Size of data to be read 00131 @param const uint8_t* const Pointer to the reading buffer 00132 @return uint32_t Size of read data 00133 */ 00134 uint32_t read_file_callback(const uint8_t file_id, 00135 const uint16_t offset, 00136 const uint16_t size, 00137 uint8_t* buf) 00138 { 00139 PRINT("Read file %d offset:%d size:%d\r\n", file_id, offset, size); 00140 uint32_t ret = fs_read_file(file_id, offset, size, buf); 00141 WARNING(ret, "File %d not found\r\n", file_id); 00142 return ret; 00143 } 00144 00145 /** 00146 Called when a notification is finished 00147 00148 @param const uint8_t File ID 00149 @param const uint8_t Error code 00150 @return void 00151 */ 00152 void notif_done_callback(const uint8_t file_id, const uint8_t error) 00153 { 00154 PRINT("Notif FID %d done. err %d\r\n", file_id, error); 00155 } 00156 00157 void unsolicited_callback(d7a_msg_t** uns) 00158 { 00159 PRINT("UNSOLICITED MESSAGE:\r\n"); 00160 d7a_print_msg(uns); 00161 d7a_free_msg(uns); 00162 } 00163 00164 // callbacks structure 00165 const d7a_callbacks_t callbacks = { 00166 .write_file = write_file_callback, // If NULL you cannot declare files 00167 .read_file = read_file_callback, // If NULL you cannot declare files 00168 .notif_done = notif_done_callback, 00169 .unsolicited_msg = unsolicited_callback, 00170 }; 00171 00172 // Com configuration for the DASH7 shield 00173 const d7a_com_config_t shield_config = { 00174 .tx = D7A_PIN_TX, 00175 .rx = D7A_PIN_RX, 00176 .rts = D7A_PIN_RTS, 00177 .cts = D7A_PIN_CTS, 00178 }; 00179 00180 // Check parameters to see if data should be send 00181 static bool report_needed(sensor_config_t* cfg, int32_t value, int32_t last_value, uint32_t last_report_time) 00182 { 00183 switch (cfg->report_type) 00184 { 00185 case REPORT_ALWAYS: 00186 // Send a report at each measure 00187 IPRINT("Notif cause 1\r\n"); 00188 return true; 00189 case REPORT_ON_DIFFERENCE: 00190 // Send a report when the difference between the last reported measure and the current mesure is greater than max_diff 00191 if (abs(last_value - value) >= cfg->max_diff) 00192 { 00193 IPRINT("Notif cause 2 last:%d new:%d max_diff:%d\r\n", last_value, value, cfg->max_diff); 00194 return true; 00195 } 00196 break; 00197 case REPORT_ON_THRESHOLD: 00198 // Send a report when crossing a threshold 00199 if ( (value >= cfg->threshold_high && last_value < cfg->threshold_high) 00200 || (value <= cfg->threshold_low && last_value > cfg->threshold_low) 00201 || (value < cfg->threshold_high && last_value >= cfg->threshold_high) 00202 || (value > cfg->threshold_low && last_value <= cfg->threshold_low)) 00203 { 00204 IPRINT("Notif cause 3 last:%d new:%d th:%d tl:%d\r\n", last_value, value, cfg->threshold_high, cfg->threshold_low); 00205 return true; 00206 } 00207 break; 00208 default: 00209 break; 00210 } 00211 00212 // Send a report if it's been more than max_period since the last report 00213 if (((last_report_time/1000) >= cfg->max_period) && (cfg->max_period != 0)) 00214 { 00215 IPRINT("Notif cause 4 max_period:%d time:%d\r\n", cfg->max_period, last_report_time); 00216 return true; 00217 } 00218 00219 return false; 00220 } 00221 00222 // ----------------------------------------------- 00223 // Sensor Threads 00224 // ----------------------------------------------- 00225 typedef struct 00226 { 00227 // Number of data fields 00228 uint32_t nb_values; 00229 // Total size of data 00230 uint32_t data_size; 00231 // Read value function 00232 bool (*read_value)(int32_t*); 00233 // Last reported value 00234 int32_t* last_report_value; 00235 // Current measured value 00236 int32_t* current_value; 00237 00238 // File ID of the sensor value file 00239 uint8_t value_file_id; 00240 // Sensor configuration file ID 00241 uint8_t cfg_file_id; 00242 // Sensor configuration context 00243 sensor_config_t cfg; 00244 00245 } sensor_thread_ctx_t; 00246 00247 sensor_thread_ctx_t* g_thread_ctx; 00248 00249 // Initialisation of the sensor thread's context 00250 #define SENSOR_THREAD_CTX(_name,_vfid,_cfid,_read_func,_nb_values) \ 00251 int32_t _name##_last_report[_nb_values];\ 00252 int32_t _name##_current_value[_nb_values];\ 00253 sensor_thread_ctx_t _name##_thread_ctx = {\ 00254 .nb_values = _nb_values,\ 00255 .data_size = _nb_values * sizeof(int32_t),\ 00256 .read_value = _read_func,\ 00257 .last_report_value = (int32_t*)&_name##_last_report,\ 00258 .current_value = (int32_t*)&_name##_current_value,\ 00259 .value_file_id = _vfid,\ 00260 .cfg_file_id = _cfid\ 00261 } 00262 00263 __inline int32_t float2_to_int(float v) 00264 { 00265 return (int32_t)(v*100); 00266 } 00267 00268 bool tem1_get_value(int32_t* buf) 00269 { 00270 #if (_TEM1_EN_ == 0) 00271 return simul_sensor_value(buf, 1, 1100, 3900); 00272 #elif (_TEM1_EN_ == 1) 00273 float ambient = mlxSensor->ambientTemp(); 00274 float object = mlxSensor->objectTemp(); 00275 PRINT("Got %f || %f\r\n", ambient, object); 00276 buf[0] = float2_to_int(object); 00277 buf[1] = float2_to_int(ambient); 00278 return false; 00279 #endif 00280 } 00281 SENSOR_THREAD_CTX(tem1, TEM1_VALUE_FILE_ID, TEM1_CFG_FILE_ID, tem1_get_value, 2); 00282 00283 bool volt_get_value(int32_t* buf) 00284 { 00285 #if (_VOLTAGE_EN_ == 0) 00286 return simul_sensor_value(buf, 1, 0, 1000); 00287 #elif (_VOLTAGE_EN_ == 1) 00288 float voltage = volt_pin*1000; 00289 PRINT("Voltage value %f\r\n", voltage); 00290 buf[0] = float2_to_int(voltage); 00291 return false; 00292 #else 00293 return false; 00294 #endif 00295 } 00296 SENSOR_THREAD_CTX(volt, VOLT_VALUE_FILE_ID, VOLT_CFG_FILE_ID, volt_get_value, 1); 00297 00298 00299 void sensor_thread() 00300 { 00301 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00302 00303 // Get thread context 00304 sensor_thread_ctx_t* th_ctx = g_thread_ctx; 00305 00306 d7a_msg_t** resp = NULL; 00307 uint32_t last_report_time = 0; 00308 00309 // Force a first notification 00310 bool first_notif = true; 00311 00312 // Retrieve notification config from local file 00313 fs_read_file(th_ctx->cfg_file_id, 0, sizeof(sensor_config_t), (uint8_t*)&(th_ctx->cfg)); 00314 00315 // Declare the config file to allow it to be accessed via the modem 00316 d7a_declare(th_ctx->cfg_file_id, VOLATILE, RW_RW, sizeof(sensor_config_t), sizeof(sensor_config_t)); 00317 00318 // Create a file on the modem to store and notify the sensor value 00319 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); 00320 00321 thread_ready.release(); 00322 00323 while (true) 00324 { 00325 // Read the sensor values 00326 bool err = th_ctx->read_value(th_ctx->current_value); 00327 00328 ASSERT(!err, "Failed to read sensor value for FID: %d\r\n", th_ctx->value_file_id); 00329 00330 // Check if data should be send 00331 for (uint8_t i = 0; i < th_ctx->nb_values; i++) 00332 { 00333 if (report_needed(&(th_ctx->cfg), 00334 th_ctx->current_value[i], 00335 th_ctx->last_report_value[i], 00336 last_report_time) || first_notif) 00337 { 00338 first_notif = false; 00339 00340 PRINT("NOTIFY %3d: ", th_ctx->value_file_id); 00341 for (uint8_t i = 0; i < th_ctx->nb_values; i++) 00342 { 00343 PRINT("%9ld ", (int32_t)th_ctx->current_value[i]); 00344 } 00345 PRINT("\r\n"); 00346 00347 // Send data to the modem 00348 resp = d7a_write(th_ctx->value_file_id, 0, th_ctx->data_size, (uint8_t*)th_ctx->current_value); 00349 d7a_free_msg(resp); 00350 00351 // Update last report value 00352 memcpy(th_ctx->last_report_value, th_ctx->current_value, th_ctx->data_size); 00353 // Reset last report time 00354 last_report_time = 0; 00355 break; 00356 } 00357 } 00358 00359 // Update last report time 00360 last_report_time += th_ctx->cfg.period; 00361 00362 // Wait for period 00363 Thread::wait(th_ctx->cfg.period); 00364 } 00365 } 00366 00367 void file_modified_thread() 00368 { 00369 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00370 00371 while (true) 00372 { 00373 // Wait for a file modified event 00374 osEvent evt = fm_queue.get(); 00375 // Retrieve FID of modified file 00376 uint8_t fid = (uint8_t)(uint32_t)evt.value.p; 00377 PRINT("File %d has been modified\r\n", fid); 00378 00379 switch (fid) 00380 { 00381 // If a configuration file has been modified, update the context 00382 case VOLT_CFG_FILE_ID: 00383 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(volt_thread_ctx.cfg)); 00384 break; 00385 case TEM1_CFG_FILE_ID: 00386 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(tem1_thread_ctx.cfg)); 00387 break; 00388 default: 00389 break; 00390 } 00391 } 00392 } 00393 00394 void button_user_thread() 00395 { 00396 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00397 00398 uint8_t alarm = 255; 00399 d7a_msg_t** resp = NULL; 00400 00401 // Create the alarm file 00402 d7a_create(ALARM_FILE_ID, VOLATILE, RW_R, sizeof(uint8_t), sizeof(uint8_t), D7A_NOTIFICATION_FULL, D7A_ITF_SINGLE); 00403 00404 // Update it with the default value 00405 resp = d7a_write(ALARM_FILE_ID, 0, sizeof(uint8_t), (uint8_t*)&alarm); 00406 d7a_free_msg(resp); 00407 00408 while (true) 00409 { 00410 // Wait for button press 00411 button_user.wait(); 00412 00413 // Toggle alarm state 00414 alarm = !alarm; 00415 00416 PRINT("BUTTON ALARM %d\r\n", alarm); 00417 #if 1 // Switch between Notify and Distant Read/Write example 00418 // Send alarm state to the modem 00419 resp = d7a_write(ALARM_FILE_ID, 0, sizeof(uint8_t), (uint8_t*)&alarm); 00420 WARNING(!resp[0]->err, "BUTTON ALARM ERR %d\r\n", resp[0]->err); 00421 d7a_free_msg(resp); 00422 #else 00423 // Distant device that I want to acceed 00424 #if 0 // Unicast / Broadcast 00425 // Unicast 00426 d7a_addressee_t target = { 00427 // Access Class 00428 .xcl.byte = D7A_XCL_ENDPOINT_NO, 00429 // Type of security you want to use 00430 .ctrl.bf.nls = D7A_NLS_AES_CCM_64, 00431 // Type of ID 00432 .ctrl.bf.idf = D7A_ID_UID, 00433 // Device ID 00434 .id = { 0x00, 0x1B, 0xC5, 0x0C, 0x70, 0x00, 0x07, 0xA3 }, 00435 }; 00436 #else 00437 // Broadcast 00438 d7a_addressee_t target = { 00439 // Access Class 00440 .xcl.byte = D7A_XCL_ENDPOINT_NO, 00441 // Type of security you want to use 00442 .ctrl.bf.nls = D7A_NLS_AES_CCM_64, 00443 // Type of ID 00444 .ctrl.bf.idf = D7A_ID_NBID, 00445 // Maximum number of responses (1-32) 00446 .id[0] = D7A_NBID(8), 00447 }; 00448 #endif 00449 00450 #if 1 // Read / Write 00451 // Read example 00452 //resp = d7a_read(MAG_CFG_FILE_ID, 12, 5, &target, D7A_ITF_ONESHOT); 00453 resp = d7a_read(ALARM_FILE_ID, 0, 1, NULL, &target, D7A_ITF_ONESHOT); 00454 #else 00455 // Write example 00456 uint8_t v = 0x01; 00457 resp = d7a_write(ALARM_FILE_ID, 0, 1, &v, NULL, &target, D7A_ITF_ONESHOT); 00458 #endif 00459 // Check received response(s) 00460 d7a_print_msg(resp); 00461 00462 PRINT("Resp done.\r\n"); 00463 d7a_free_msg(resp); 00464 #endif 00465 } 00466 } 00467 00468 /*** Main function ------------------------------------------------------------- ***/ 00469 int main() 00470 { 00471 // Start & initialize 00472 DBG_OPEN(DEBUG_LED); 00473 PRINT("\r\n--- Starting new run ---\r\n"); 00474 00475 extern uint16_t const os_maxtaskrun; 00476 //IPRINT("Max user threads: %d\r\n", os_maxtaskrun-1-9); 00477 00478 d7a_open(&shield_config, D7A_PIN_RESET, &callbacks); 00479 d7a_modem_print_infos(); 00480 00481 // Create the revision file for the Dash7board 00482 d7a_create(65, PERMANENT, RW_R, sizeof(d7a_revision_t), sizeof(d7a_revision_t), D7A_NOTIFICATION_FULL, D7A_ITF_REPORT_CHECKED); 00483 // Notify revision 00484 d7a_msg_t** resp = d7a_write(65, 0, sizeof(d7a_revision_t), (uint8_t*)&f_dev_rev); 00485 d7a_free_msg(resp); 00486 00487 uint32_t divider; 00488 00489 // Retreive the simulation parameter from local file 00490 fs_read_file(SIMUL_FILE_ID, 0, sizeof(uint32_t), (uint8_t*)÷r); 00491 00492 // Update the simulation parameters 00493 simul_update_param(divider); 00494 00495 // Declare the simulation parameter file 00496 d7a_declare(SIMUL_FILE_ID, PERMANENT, RW_RW, sizeof(sensor_config_t), sizeof(sensor_config_t)); 00497 00498 #if (_TEM1_EN_ == 1) 00499 // Open I2C and initialise the sensors 00500 DevI2C ext_i2c(SENSOR_I2C_SDA, SENSOR_I2C_SCL); 00501 ext_i2c.frequency(100000); 00502 mlxSensor = new MLX90614(&ext_i2c); 00503 #endif 00504 00505 osStatus status; 00506 00507 // Start sensors threads 00508 #define THREAD_START(_name) Thread _name##_th(osPriorityNormal, 1024, NULL);\ 00509 g_thread_ctx = &_name##_thread_ctx;\ 00510 status = _name##_th.start(sensor_thread);\ 00511 ASSERT(status == osOK, "Failed to start ##_name## thread (err: %d)\r\n", status);\ 00512 thread_ready.wait(); 00513 00514 #if (_TEM1_EN_ >= 0) 00515 THREAD_START(tem1); 00516 #endif // _TEM1_EN_ 00517 00518 #if (_VOLTAGE_EN_ >=0) 00519 THREAD_START(volt); 00520 #endif 00521 00522 // File modified thread 00523 Thread fm_th(osPriorityNormal, 512, NULL); 00524 status = fm_th.start(file_modified_thread); 00525 ASSERT(status == osOK, "Failed to start fm thread (err: %d)\r\n", status); 00526 00527 // For button 00528 #ifdef DEBUG_BUTTON 00529 DebouncedInterrupt user_interrupt(DEBUG_BUTTON); 00530 user_interrupt.attach(button_push_isr, IRQ_FALL, 500, true); 00531 00532 Thread but_th(osPriorityNormal, 512, NULL); 00533 status = but_th.start(button_user_thread); 00534 ASSERT(status == osOK, "Failed to start but thread (err: %d)\r\n", status); 00535 #endif 00536 00537 #ifdef DGB_LED_BLINK_PERIOD 00538 DigitalOut my_led(DEBUG_LED); 00539 #endif 00540 00541 // Set main task to lowest priority 00542 osThreadSetPriority(osThreadGetId(), osPriorityIdle); 00543 while(true) 00544 { 00545 #ifdef DGB_LED_BLINK_PERIOD 00546 // Wait to avoid beeing stuck in loop 00547 Thread::wait(DGB_LED_BLINK_PERIOD); 00548 my_led = !my_led; 00549 #else 00550 Thread::wait(osWaitForever); 00551 #endif 00552 } 00553 }
Generated on Thu Jul 14 2022 01:19:43 by
1.7.2
