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 d7a_1x mbed-rtos mbed wizzi-utils
main.cpp
00001 // This project is a demo of the DASH7 1.x stack 00002 // @autor: jeremie@wizzilab.com 00003 // @date: 2016-08-23 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 00031 #include "mbed.h" 00032 #include "rtos.h" 00033 #include "rtos_idle.h" 00034 #include "d7a.h" 00035 #include "sensors.h" 00036 #include "simul.h" 00037 #include "dbg.h" 00038 #include "DebouncedInterrupt.h" 00039 #include "files.h" 00040 00041 // Select the sensors 00042 #if 0 00043 #define _MAG_EN_ 1 00044 #define _ACC_EN_ 1 00045 #define _GYR_EN_ 1 00046 #define _PRE_EN_ 1 00047 #define _HUM_EN_ 1 00048 #define _TEM1_EN_ 1 00049 #define _TEM2_EN_ 1 00050 #else 00051 #define _MAG_EN_ 0 00052 #define _ACC_EN_ 0 00053 #define _GYR_EN_ 0 00054 #define _PRE_EN_ 0 00055 #define _HUM_EN_ 0 00056 #define _TEM1_EN_ 0 00057 #define _TEM2_EN_ 0 00058 #endif 00059 00060 // Semaphore for notifiying button presses 00061 Semaphore button_user(0); 00062 00063 // Interrupt Service Routine on button press. 00064 void button_push_isr( void ) 00065 { 00066 button_user.release(); 00067 } 00068 00069 // file modified queue 00070 Queue<void, 8> fm_queue; 00071 00072 00073 // ----------------------------------------------- 00074 // callbacks 00075 // ----------------------------------------------- 00076 /** 00077 Write data into a file. 00078 00079 @param const uint8_t File ID 00080 @param const uint16_t Offset from start of data 00081 @param const uint16_t Size of data to be written 00082 @param const uint8_t* const Pointer to the data to write 00083 @return uint32_t Size of written data 00084 */ 00085 uint32_t write_file_callback(const uint8_t file_id, 00086 const uint16_t offset, 00087 const uint16_t size, 00088 const uint8_t* const content) 00089 { 00090 uint32_t ret = 0; 00091 00092 IPRINT("Write file %d offset:%d size:%d\r\n", file_id, offset, size); 00093 00094 ret = fs_write_file(file_id, offset, size, content); 00095 00096 WARNING(ret, "File %d not found\r\n", file_id); 00097 00098 // Indicate that the file has been modified 00099 fm_queue.put((void*)file_id); 00100 00101 return ret; 00102 } 00103 00104 /** 00105 Read data from a file. 00106 00107 @param const uint8_t File ID 00108 @param const uint16_t Offset from start of data 00109 @param const uint16_t Size of data to be read 00110 @param const uint8_t* const Pointer to the reading buffer 00111 @return uint32_t Size of read data 00112 */ 00113 uint32_t read_file_callback(const uint8_t file_id, 00114 const uint16_t offset, 00115 const uint16_t size, 00116 uint8_t* buf) 00117 { 00118 uint32_t ret = 0; 00119 00120 IPRINT("Read file %d offset:%d size:%d\r\n", file_id, offset, size); 00121 00122 ret = fs_read_file(file_id, offset, size, buf); 00123 00124 WARNING(ret, "File %d not found\r\n", file_id); 00125 00126 return ret; 00127 } 00128 00129 /** 00130 Called when a notification is finished 00131 00132 @param const uint8_t File ID 00133 @param const uint8_t Error code 00134 @return void 00135 */ 00136 void notif_done_callback(const uint8_t file_id, const uint8_t error) 00137 { 00138 PRINT("Notif FID %d done. err %d\r\n", file_id, error); 00139 } 00140 00141 void unsolicited_callback(d7a_msg_t** uns) 00142 { 00143 PRINT("UNSOLICITED MESSAGE:\r\n"); 00144 d7a_print_msg(uns); 00145 d7a_free_msg(uns); 00146 } 00147 00148 // callbacks structure 00149 const d7a_callbacks_t callbacks = { 00150 .write_file = write_file_callback, // If NULL you cannot declare files 00151 .read_file = read_file_callback, // If NULL you cannot declare files 00152 .notif_done = notif_done_callback, 00153 .unsolicited_msg = unsolicited_callback, 00154 }; 00155 00156 // Com configuration for the DASH7 shield 00157 const d7a_com_config_t shield_config = { 00158 .tx = D10, 00159 .rx = D2, 00160 .rts = D13, 00161 .cts = D9, 00162 .rx_buffer_size = 512, 00163 }; 00164 00165 00166 // Check parameters to see if data should be send 00167 static bool report_needed(sensor_config_t* cfg, int32_t value, int32_t last_value, uint32_t last_report_time) 00168 { 00169 switch (cfg->report_type) 00170 { 00171 case REPORT_ALWAYS: 00172 // Send a report at each measure 00173 IPRINT("Notif cause 1\r\n"); 00174 return true; 00175 case REPORT_ON_DIFFERENCE: 00176 // Send a report when the difference between the last reported measure and the current mesure is greater than max_diff 00177 if (abs(last_value - value) >= cfg->max_diff) 00178 { 00179 IPRINT("Notif cause 2 last:%d new:%d max_diff:%d\r\n", last_value, value, cfg->max_diff); 00180 return true; 00181 } 00182 break; 00183 case REPORT_ON_THRESHOLD: 00184 // Send a report when crossing a threshold 00185 if ( (value >= cfg->threshold_high && last_value < cfg->threshold_high) 00186 || (value <= cfg->threshold_low && last_value > cfg->threshold_low) 00187 || (value < cfg->threshold_high && last_value >= cfg->threshold_high) 00188 || (value > cfg->threshold_low && last_value <= cfg->threshold_low)) 00189 { 00190 IPRINT("Notif cause 3 last:%d new:%d th:%d tl:%d\r\n", last_value, value, cfg->threshold_high, cfg->threshold_low); 00191 return true; 00192 } 00193 break; 00194 default: 00195 break; 00196 } 00197 00198 // Send a report if it's been more than max_period since the last report 00199 if (((last_report_time/1000) >= cfg->max_period) && (cfg->max_period != 0)) 00200 { 00201 IPRINT("Notif cause 4 max_period:%d time:%d\r\n", cfg->max_period, last_report_time); 00202 return true; 00203 } 00204 00205 return false; 00206 } 00207 00208 // Initialisation of the sensor thread's context 00209 #define SENSOR_THREAD_CTX(_name,_vfid,_cfid,_read_func,_nb_values) \ 00210 int32_t _name##_last_report[_nb_values];\ 00211 int32_t _name##_current_value[_nb_values];\ 00212 sensor_thread_ctx_t _name##_thread_ctx = {\ 00213 .nb_values = _nb_values,\ 00214 .data_size = _nb_values * sizeof(int32_t),\ 00215 .read_value = _read_func,\ 00216 .last_report_value = (int32_t*)&_name##_last_report,\ 00217 .current_value = (int32_t*)&_name##_current_value,\ 00218 .last_report_time = 0,\ 00219 .value_file_id = _vfid,\ 00220 .cfg_file_id = _cfid\ 00221 } 00222 00223 00224 SENSOR_THREAD_CTX(mag, MAG_VALUE_FILE_ID, MAG_CFG_FILE_ID, mag_get_value, 3); 00225 SENSOR_THREAD_CTX(acc, ACC_VALUE_FILE_ID, ACC_CFG_FILE_ID, acc_get_value, 3); 00226 SENSOR_THREAD_CTX(gyr, GYR_VALUE_FILE_ID, GYR_CFG_FILE_ID, gyr_get_value, 3); 00227 SENSOR_THREAD_CTX(pre, PRE_VALUE_FILE_ID, PRE_CFG_FILE_ID, pre_get_value, 1); 00228 SENSOR_THREAD_CTX(hum, HUM_VALUE_FILE_ID, HUM_CFG_FILE_ID, hum_get_value, 1); 00229 SENSOR_THREAD_CTX(tem1, TEM1_VALUE_FILE_ID, TEM1_CFG_FILE_ID, tem1_get_value, 1); 00230 SENSOR_THREAD_CTX(tem2, TEM2_VALUE_FILE_ID, TEM2_CFG_FILE_ID, tem2_get_value, 1); 00231 00232 // ----------------------------------------------- 00233 // Threads 00234 // ----------------------------------------------- 00235 void sensor_thread(const void* p) 00236 { 00237 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00238 d7a_msg_t** resp = NULL; 00239 00240 // Get thread context 00241 sensor_thread_ctx_t* th_ctx = (sensor_thread_ctx_t*)p; 00242 00243 // Force a first notification 00244 bool first_notif = true; 00245 00246 // Retrieve notification config from local file 00247 fs_read_file(th_ctx->cfg_file_id, 0, sizeof(sensor_config_t), (uint8_t*)&(th_ctx->cfg)); 00248 00249 // Declare the config file to allow it to be accessed via the modem 00250 d7a_declare(th_ctx->cfg_file_id, VOLATILE, RW_RW, sizeof(sensor_config_t), sizeof(sensor_config_t)); 00251 00252 // Create a file on the modem to store and notify the sensor value 00253 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); 00254 00255 while (true) 00256 { 00257 // Read the sensor values 00258 bool err = th_ctx->read_value(th_ctx->current_value); 00259 00260 ASSERT(!err, "Failed to read sensor value for FID: %d\r\n", th_ctx->value_file_id); 00261 00262 // Check if data should be send 00263 for (uint8_t i = 0; i < th_ctx->nb_values; i++) 00264 { 00265 if (report_needed(&(th_ctx->cfg), 00266 th_ctx->current_value[i], 00267 th_ctx->last_report_value[i], 00268 th_ctx->last_report_time) || first_notif) 00269 { 00270 first_notif = false; 00271 00272 PRINT("NOTIFY %3d: ", th_ctx->value_file_id); 00273 for (uint8_t i = 0; i < th_ctx->nb_values; i++) 00274 { 00275 PRINT("%9ld ", (int32_t)th_ctx->current_value[i]); 00276 } 00277 PRINT("\r\n"); 00278 00279 // Send data to the modem 00280 resp = d7a_write(th_ctx->value_file_id, 0, th_ctx->data_size, (uint8_t*)th_ctx->current_value); 00281 d7a_free_msg(resp); 00282 00283 // Update last report value 00284 memcpy(th_ctx->last_report_value, th_ctx->current_value, th_ctx->data_size); 00285 // Reset last report time 00286 th_ctx->last_report_time = 0; 00287 break; 00288 } 00289 } 00290 00291 // Update last report time 00292 th_ctx->last_report_time += th_ctx->cfg.period; 00293 00294 // Wait for period 00295 Thread::wait(th_ctx->cfg.period); 00296 } 00297 } 00298 00299 void file_modified_thread(const void *p) 00300 { 00301 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00302 00303 while (true) 00304 { 00305 // Wait for a file modified event 00306 osEvent evt = fm_queue.get(); 00307 00308 // Retrieve FID of modified file 00309 uint8_t fid = (uint8_t)(uint32_t)evt.value.p; 00310 00311 PRINT("File %d has been modified\r\n", fid); 00312 00313 switch (fid) 00314 { 00315 // If a configuration file has been modified, update the context 00316 case MAG_CFG_FILE_ID: 00317 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(mag_thread_ctx.cfg)); 00318 break; 00319 case ACC_CFG_FILE_ID: 00320 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(acc_thread_ctx.cfg)); 00321 break; 00322 case GYR_CFG_FILE_ID: 00323 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(gyr_thread_ctx.cfg)); 00324 break; 00325 case PRE_CFG_FILE_ID: 00326 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(pre_thread_ctx.cfg)); 00327 break; 00328 case HUM_CFG_FILE_ID: 00329 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(hum_thread_ctx.cfg)); 00330 break; 00331 case TEM1_CFG_FILE_ID: 00332 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(tem1_thread_ctx.cfg)); 00333 break; 00334 case TEM2_CFG_FILE_ID: 00335 fs_read_file(fid, 0, sizeof(sensor_config_t), (uint8_t*)&(tem2_thread_ctx.cfg)); 00336 break; 00337 case SIMUL_FILE_ID: 00338 uint32_t divider; 00339 // Retreive the simulation parameter from local file 00340 fs_read_file(SIMUL_FILE_ID, 0, sizeof(uint32_t), (uint8_t*)÷r); 00341 // Update the simulation parameters 00342 update_simul_param(divider); 00343 PRINT("Simulation Divider is Now %d\r\n", divider); 00344 break; 00345 default: 00346 break; 00347 } 00348 } 00349 } 00350 00351 void button_user_thread(const void *p) 00352 { 00353 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00354 00355 uint8_t alarm = 255; 00356 d7a_msg_t** resp = NULL; 00357 00358 // Create the alarm file 00359 //d7a_create(ALARM_FILE_ID, VOLATILE, RW_R, sizeof(uint8_t), sizeof(uint8_t), D7A_NOTIFICATION_FULL, D7A_ITF_SINGLE); 00360 00361 // Update it with the default value 00362 //resp = d7a_write(ALARM_FILE_ID, 0, sizeof(uint8_t), (uint8_t*)&alarm); 00363 //d7a_free_msg(resp); 00364 00365 while (true) 00366 { 00367 // Wait for button press 00368 button_user.wait(); 00369 00370 // Toggle alarm state 00371 alarm = !alarm; 00372 00373 PRINT("BUTTON ALARM %d\r\n", alarm); 00374 #if 1 // Switch between Notify and Distant Read/Write example 00375 00376 // Send alarm state to the modem 00377 //resp = d7a_write(ALARM_FILE_ID, 0, sizeof(uint8_t), (uint8_t*)&alarm); 00378 //WARNING(!resp[0]->err, "BUTTON ALARM ERR %d\r\n", resp[0]->err); 00379 //d7a_free_msg(resp); 00380 #else 00381 // Distant device that I want to acceed 00382 #if 0 // Unicast / Broadcast 00383 // Unicast 00384 d7a_addressee_t target = { 00385 // Access Class 00386 .xcl.byte = D7A_XCL_ENDPOINT_LO, 00387 // Type of security you want to use 00388 .ctrl.bf.nls = D7A_NLS_AES_CCM_64, 00389 // Type of ID 00390 .ctrl.bf.idf = D7A_ID_UID, 00391 // Device ID 00392 .id = { 0x00, 0x1B, 0xC5, 0x0C, 0x70, 0x00, 0x07, 0xA3 }, 00393 }; 00394 #else 00395 // Broadcast 00396 d7a_addressee_t target = { 00397 // Access Class 00398 .xcl.byte = D7A_XCL_ENDPOINT_LO, 00399 // Type of security you want to use 00400 .ctrl.bf.nls = D7A_NLS_AES_CCM_64, 00401 // Type of ID 00402 .ctrl.bf.idf = D7A_ID_NBID, 00403 // Maximum number of responses (1-32) 00404 .id[0] = D7A_NBID(8), 00405 }; 00406 #endif 00407 00408 #if 1 // Read / Write 00409 // Read example 00410 //resp = d7a_read(MAG_CFG_FILE_ID, 12, 5, &target, D7A_ITF_ONESHOT); 00411 resp = d7a_read(ALARM_FILE_ID, 0, 1, NULL, &target, D7A_ITF_ONESHOT); 00412 #else 00413 // Write example 00414 uint8_t v = 0x01; 00415 resp = d7a_write(ALARM_FILE_ID, 0, 1, &v, NULL, &target, D7A_ITF_ONESHOT); 00416 #endif 00417 // Check received response(s) 00418 d7a_print_msg(resp); 00419 00420 PRINT("Resp done.\r\n"); 00421 d7a_free_msg(resp); 00422 #endif 00423 00424 00425 } 00426 } 00427 00428 00429 /*** Main function ------------------------------------------------------------- ***/ 00430 int main() 00431 { 00432 PinName DBG_LED = D12; 00433 00434 // Go to sleep when idle 00435 //rtos_attach_idle_hook(sleep); 00436 00437 // Start & initialize 00438 DBG_OPEN(DBG_LED); 00439 PRINT("\r\n--- Starting new run ---\r\n"); 00440 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00441 00442 DigitalOut myled(DBG_LED); 00443 DebouncedInterrupt user_interrupt(USER_BUTTON); 00444 user_interrupt.attach(button_push_isr, IRQ_FALL, 200, true); 00445 myled = 1; 00446 00447 extern uint16_t const os_maxtaskrun; 00448 //IPRINT("Max user threads: %d\r\n", os_maxtaskrun-1-9); 00449 #if 0 00450 d7a_open(&shield_config, A3, &callbacks); 00451 d7a_modem_print_infos(); 00452 00453 // Create the revision file for the Dash7board 00454 d7a_create(65, PERMANENT, RW_R, sizeof(d7a_revision_t), sizeof(d7a_revision_t), D7A_NOTIFICATION_FULL, D7A_ITF_REPORT_CHECKED); 00455 // Notify revision 00456 d7a_msg_t** resp = d7a_write(65, 0, sizeof(d7a_revision_t), (uint8_t*)&f_dev_rev); 00457 d7a_free_msg(resp); 00458 #endif 00459 00460 #if _SENSORS_SIMU_ 00461 PRINT("(Simulated sensors)\r\n"); 00462 uint32_t divider; 00463 00464 // Retreive the simulation parameter from local file 00465 fs_read_file(SIMUL_FILE_ID, 0, sizeof(uint32_t), (uint8_t*)÷r); 00466 00467 // Update the simulation parameters 00468 update_simul_param(divider); 00469 00470 // Declare the simulation parameter file 00471 //d7a_declare(SIMUL_FILE_ID, PERMANENT, RW_RW, sizeof(sensor_config_t), sizeof(sensor_config_t)); 00472 00473 #else 00474 // Open I2C and initialise the sensors 00475 DevI2C ext_i2c(D14, D15); 00476 00477 #if (_HUM_EN_ || _TEM1_EN_) 00478 humidity_sensor = new HTS221(ext_i2c); 00479 ASSERT(Init_HTS221(humidity_sensor), "Failed to init HTS221\r\n"); 00480 temp_sensor1 = humidity_sensor; 00481 #endif // _TEM_EN_ 00482 #if _MAG_EN_ 00483 magnetometer = new LIS3MDL(ext_i2c); 00484 ASSERT(Init_LIS3MDL(magnetometer), "Failed to init LIS3MDL\r\n"); 00485 #endif // _MAG_EN_ 00486 #if (_ACC_EN_ || _GYR_EN_) 00487 accelerometer = new LSM6DS0(ext_i2c); 00488 ASSERT(Init_LSM6DS0(accelerometer), "Failed to init LSM6DS0\r\n"); 00489 gyroscope = accelerometer; 00490 #endif // _ACC_EN_ || _GYR_EN_ 00491 #if (_PRE_EN_ || _TEM2_EN_) 00492 pressure_sensor = new LPS25H(ext_i2c); 00493 ASSERT(Init_LPS25H(pressure_sensor), "Failed to init LPS25H\r\n"); 00494 temp_sensor2 = pressure_sensor; 00495 #endif // _PRE_EN_ 00496 00497 #endif // _SENSORS_SIMU_ 00498 00499 // File modified thread 00500 Thread fm_th(file_modified_thread); 00501 00502 #if _MAG_EN_ 00503 Thread mag_th(sensor_thread, (void*)&mag_thread_ctx, osPriorityNormal, DEFAULT_STACK_SIZE*2); 00504 #endif // _MAG_EN_ 00505 #if _ACC_EN_ 00506 Thread acc_th(sensor_thread, (void*)&acc_thread_ctx, osPriorityNormal, DEFAULT_STACK_SIZE*2); 00507 #endif // _ACC_EN_ 00508 #if _GYR_EN_ 00509 Thread gyr_th(sensor_thread, (void*)&gyr_thread_ctx, osPriorityNormal, DEFAULT_STACK_SIZE*2); 00510 #endif // _GYR_EN_ 00511 #if _PRE_EN_ 00512 Thread pre_th(sensor_thread, (void*)&pre_thread_ctx, osPriorityNormal, DEFAULT_STACK_SIZE*2); 00513 #endif // _PRE_EN_ 00514 #if _HUM_EN_ 00515 Thread hum_th(sensor_thread, (void*)&hum_thread_ctx, osPriorityNormal, DEFAULT_STACK_SIZE*2); 00516 #endif // _HUM_EN_ 00517 #if _TEM1_EN_ 00518 Thread tem1_th(sensor_thread, (void*)&tem1_thread_ctx, osPriorityNormal, DEFAULT_STACK_SIZE*2); 00519 #endif // _TEM1_EN_ 00520 #if _TEM2_EN_ 00521 Thread tem2_th(sensor_thread, (void*)&tem2_thread_ctx, osPriorityNormal, DEFAULT_STACK_SIZE*2); 00522 #endif // _TEM2_EN_ 00523 00524 // For button irq 00525 Thread but_th(button_user_thread, NULL, osPriorityNormal, DEFAULT_STACK_SIZE*4); 00526 00527 // Set main task to lowest priority 00528 osThreadSetPriority(osThreadGetId(), osPriorityIdle); 00529 while(true) 00530 { 00531 // Wait to avoid beeing stuck in loop 00532 Thread::wait(200); 00533 myled = !myled; 00534 } 00535 }
Generated on Sat Jul 16 2022 12:41:18 by
1.7.2