Complete sensor demo.
Dependencies: modem_ref_helper CRC X_NUCLEO_IKS01A1 DebouncedInterrupt
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 #include "DebouncedInterrupt.h" 00006 #include "sensors.h" 00007 #include "sensors_cfg.h" 00008 #include "simul.h" 00009 #include "modem_d7a.h" 00010 #include "modem_callbacks.h" 00011 #include "files.h" 00012 #include "crc.h" 00013 00014 #define MIN_REPORT_PERIOD (10) // Seconds 00015 00016 enum { 00017 MODEM_RESP_NO, 00018 MODEM_RESP_TERMINAL, 00019 MODEM_RESP_DONE, 00020 }; 00021 00022 Semaphore button_user(1); 00023 Semaphore thread_ready(0); 00024 sensor_config_t g_light_config; 00025 int sensor_id = 0; 00026 Queue<touch_t, 8> g_file_modified; 00027 00028 static bool report_ok(uint32_t last_report_time) 00029 { 00030 // Do not send a report if it's been less than MIN_REPORT_PERIOD since the last report 00031 if ((last_report_time/1000) < MIN_REPORT_PERIOD) 00032 { 00033 PRINT("Report Skipped. (Locked for %ds)\n", MIN_REPORT_PERIOD - (last_report_time/1000)); 00034 return false; 00035 } 00036 00037 return true; 00038 } 00039 00040 // Check parameters to see if data should be send 00041 static bool report_needed(sensor_config_t* config, int32_t value, int32_t last_value, uint32_t last_report_time, uint8_t thread_id) 00042 { 00043 char thread_name[10]; 00044 switch (thread_id) 00045 { 00046 case 0: strcpy(thread_name,"Magnetometer"); break; 00047 case 1: strcpy(thread_name,"Accelerometer"); break; 00048 case 2: strcpy(thread_name,"Pressure"); break; 00049 case 3: strcpy(thread_name,"Humidity"); break; 00050 case 4: strcpy(thread_name,"Temperature sensor 1"); break; 00051 case 5: strcpy(thread_name,"Temperature sensor 2"); break; 00052 case 6: strcpy(thread_name,"Light sensor"); break; 00053 default: strcpy(thread_name,"Unknown"); break; 00054 } 00055 00056 switch (config->report_type) 00057 { 00058 case REPORT_ALWAYS: 00059 // Send a report at each measure 00060 PRINT("Report[%d] : %s always\r\n", thread_id, thread_name); 00061 return report_ok(last_report_time); 00062 case REPORT_ON_DIFFERENCE: 00063 // Send a report when the difference between the last reported measure and the current mesure is greater than max_diff 00064 if (abs(last_value - value) >= config->max_diff && config->max_diff) 00065 { 00066 PRINT("Report[%d] : %s on difference (last:%d new:%d max_diff:%d)\r\n", thread_id, thread_name, last_value, value, config->max_diff); 00067 return report_ok(last_report_time); 00068 } 00069 break; 00070 case REPORT_ON_THRESHOLD: 00071 // Send a report when crossing a threshold 00072 if ( (value >= config->threshold_high && last_value < config->threshold_high) 00073 || (value <= config->threshold_low && last_value > config->threshold_low) 00074 || (value < config->threshold_high && last_value >= config->threshold_high) 00075 || (value > config->threshold_low && last_value <= config->threshold_low)) 00076 { 00077 PRINT("Report[%d] : %s on threshold (last:%d new:%d th:%d tl:%d)\r\n", thread_id, thread_name, last_value, value, config->threshold_high, config->threshold_low); 00078 return report_ok(last_report_time); 00079 } 00080 break; 00081 default: 00082 break; 00083 } 00084 00085 // Send a report if it's been more than max_period since the last report 00086 if (((last_report_time/1000) >= config->max_period) && config->max_period) 00087 { 00088 PRINT("Report[%d] : %s on period (max_period:%d time:%d)\r\n", thread_id, thread_name, config->max_period, last_report_time); 00089 return report_ok(last_report_time); 00090 } 00091 return false; 00092 } 00093 00094 // Interrupt Service Routine on button press. 00095 void button_push_isr( void ) 00096 { 00097 button_user.release(); 00098 } 00099 00100 modem_ref_callbacks_t callbacks = { 00101 .read = my_read, 00102 .write = my_write, 00103 .read_fprop = my_read_fprop, 00104 .flush = my_flush, 00105 .remove = my_delete, 00106 .udata = my_udata, 00107 .lqual = my_lqual, 00108 .ldown = my_ldown, 00109 .reset = my_reset, 00110 .boot = my_boot, 00111 .busy = my_busy, 00112 }; 00113 00114 00115 // ----------------------------------------------- 00116 // Sensor Threads 00117 // ----------------------------------------------- 00118 typedef struct 00119 { 00120 // Number of data fields 00121 uint32_t nb_values; 00122 // Total size of data 00123 uint32_t data_size; 00124 // Read value function 00125 bool (*read_value)(int32_t*); 00126 // Last reported value 00127 int32_t* last_report_value; 00128 // Current measured value 00129 int32_t* current_value; 00130 00131 // File ID of the sensor value file 00132 uint8_t value_file_id; 00133 // Sensor configuration file ID 00134 uint8_t config_file_id; 00135 // Sensor configuration context 00136 sensor_config_t config; 00137 00138 } sensor_thread_ctx_t; 00139 00140 sensor_thread_ctx_t* g_thread_ctx; 00141 00142 // Initialisation of the sensor thread's context 00143 #define SENSOR_THREAD_CTX(name,NAME,_nb_values) \ 00144 int32_t name##_last_report[_nb_values];\ 00145 int32_t name##_current_value[_nb_values];\ 00146 sensor_thread_ctx_t name##_thread_ctx = {\ 00147 .nb_values = _nb_values,\ 00148 .data_size = _nb_values * sizeof(int32_t),\ 00149 .read_value = name##_get_value,\ 00150 .last_report_value = (int32_t*)&name##_last_report,\ 00151 .current_value = (int32_t*)&name##_current_value,\ 00152 .value_file_id = FID_SENSOR_VALUE_##NAME,\ 00153 .config_file_id = FID_SENSOR_CONFIG_##NAME\ 00154 } 00155 00156 SENSOR_THREAD_CTX(mag, MAG, 3); 00157 SENSOR_THREAD_CTX(acc, ACC, 3); 00158 SENSOR_THREAD_CTX(gyr, GYR, 3); 00159 SENSOR_THREAD_CTX(pre, PRE, 1); 00160 SENSOR_THREAD_CTX(hum, HUM, 1); 00161 SENSOR_THREAD_CTX(tem1, TEM1, 1); 00162 SENSOR_THREAD_CTX(tem2, TEM2, 1); 00163 SENSOR_THREAD_CTX(light, LIGHT, 1); 00164 00165 void thread_sensor() 00166 { 00167 int thread_id = sensor_id++; 00168 00169 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00170 00171 // To force a first report 00172 uint32_t last_report_time = 0xFFFFFFFF; 00173 sensor_thread_ctx_t* ctx = g_thread_ctx; 00174 00175 // Get the sensor configuration 00176 ram_fs_read(ctx->config_file_id, (uint8_t*)&(ctx->config), 0, sizeof(sensor_config_t)); 00177 00178 thread_ready.release(); 00179 00180 while (true) 00181 { 00182 bool err = ctx->read_value(ctx->current_value); 00183 00184 ASSERT(err == 0, "Failed to read sensor\n"); 00185 00186 //PRINT("Got %3d: ", ctx->value_file_id); 00187 //for (uint8_t i = 0; i < ctx->nb_values; i++) 00188 //{ 00189 // PRINT("%9ld ", (int32_t)ctx->current_value[i]); 00190 //} 00191 //PRINT("\r\n"); 00192 00193 for (uint8_t i = 0; i < ctx->nb_values; i++) 00194 { 00195 if (report_needed(&(ctx->config), ctx->current_value[i], ctx->last_report_value[i], last_report_time, thread_id)) 00196 { 00197 // Send notification 00198 modem_write_file(ctx->value_file_id, ctx->current_value, 0, ctx->data_size); 00199 00200 // Update last report value 00201 memcpy(ctx->last_report_value, ctx->current_value, ctx->data_size); 00202 // Reset last report time 00203 last_report_time = 0; 00204 } 00205 } 00206 00207 // Update last report time 00208 last_report_time += ctx->config.read_period; 00209 00210 ThisThread::sleep_for(ctx->config.read_period); 00211 } 00212 } 00213 00214 void thread_file_modified() 00215 { 00216 uint8_t fid; 00217 osEvent evt; 00218 00219 while (true) 00220 { 00221 evt = g_file_modified.get(); 00222 fid = (evt.status == osEventMessage)? (uint8_t)(uint32_t)evt.value.p : NULL; 00223 00224 switch (fid) 00225 { 00226 // If a configuration file has been modified, update the context 00227 case FID_SENSOR_CONFIG_MAG: 00228 ram_fs_read(fid, (uint8_t*)&(mag_thread_ctx.config), 0, sizeof(sensor_config_t)); 00229 break; 00230 case FID_SENSOR_CONFIG_ACC: 00231 ram_fs_read(fid, (uint8_t*)&(mag_thread_ctx.config), 0, sizeof(sensor_config_t)); 00232 break; 00233 case FID_SENSOR_CONFIG_GYR: 00234 ram_fs_read(fid, (uint8_t*)&(gyr_thread_ctx.config), 0, sizeof(sensor_config_t)); 00235 break; 00236 case FID_SENSOR_CONFIG_PRE: 00237 ram_fs_read(fid, (uint8_t*)&(gyr_thread_ctx.config), 0, sizeof(sensor_config_t)); 00238 break; 00239 case FID_SENSOR_CONFIG_HUM: 00240 ram_fs_read(fid, (uint8_t*)&(gyr_thread_ctx.config), 0, sizeof(sensor_config_t)); 00241 break; 00242 case FID_SENSOR_CONFIG_TEM1: 00243 ram_fs_read(fid, (uint8_t*)&(gyr_thread_ctx.config), 0, sizeof(sensor_config_t)); 00244 break; 00245 case FID_SENSOR_CONFIG_TEM2: 00246 ram_fs_read(fid, (uint8_t*)&(gyr_thread_ctx.config), 0, sizeof(sensor_config_t)); 00247 break; 00248 case FID_SENSOR_CONFIG_LIGHT: 00249 ram_fs_read(fid, (uint8_t*)&(gyr_thread_ctx.config), 0, sizeof(sensor_config_t)); 00250 break; 00251 default: 00252 break; 00253 } 00254 } 00255 } 00256 00257 // Callback for button 00258 void my_response_callback(uint8_t terminal, int8_t err, uint8_t id) 00259 { 00260 UNUSED(id); 00261 00262 if (ALP_ERR_NONE != err) 00263 { 00264 modem_print_error(ALP_ITF_TYPE_D7A, err); 00265 } 00266 00267 if (terminal) 00268 { 00269 g_file_modified.put((touch_t*)MODEM_RESP_TERMINAL); 00270 } 00271 else 00272 { 00273 if (ALP_ERR_NONE == err) 00274 { 00275 g_file_modified.put((touch_t*)MODEM_RESP_DONE); 00276 } 00277 } 00278 } 00279 00280 void thread_user_button() 00281 { 00282 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00283 00284 osEvent evt; 00285 uint32_t resp; 00286 uint8_t alarm; 00287 d7a_sp_res_t istat; 00288 alp_payload_t* alp; 00289 alp_payload_t* alp_rsp; 00290 uint8_t nb = 0; 00291 int err; 00292 00293 alp_d7a_itf_t alarm_itf = { 00294 .type = ALP_ITF_TYPE_D7A, 00295 .cfg.to.byte = D7A_CTF_ENCODE(0), 00296 .cfg.te.byte = D7A_CTF_ENCODE(0), 00297 .cfg.qos.bf.resp = D7A_RESP_PREFERRED, 00298 .cfg.qos.bf.retry = ALP_RPOL_ONESHOT_RETRY, 00299 .cfg.addressee.ctrl.bf.nls = D7A_NLS_AES_CCM_64, 00300 .cfg.addressee.ctrl.bf.idf = D7A_ID_NBID, 00301 .cfg.addressee.xcl.bf = {.s = 2, .m = 0x1},// XXX D7A_XCL_GW, 00302 .cfg.addressee.id[0] = D7A_CTF_ENCODE(4), 00303 }; 00304 00305 // Load alarm value 00306 ram_fs_read(FID_ALARM, &alarm, 0, 1); 00307 00308 while (true) 00309 { 00310 // Wait for button press 00311 button_user.acquire(); 00312 00313 // load/save value to keep coherence in case of remote access... 00314 ram_fs_read(FID_ALARM, &alarm, 0, 1); 00315 00316 // Initial value 00317 if (alarm != 255) 00318 { 00319 // Toggle alarm state 00320 alarm = !alarm; 00321 ram_fs_write(FID_ALARM, &alarm, 0, 1); 00322 } 00323 00324 PRINT("BUTTON ALARM %d\r\n", alarm); 00325 00326 nb = 0; 00327 alp = NULL; 00328 alp = alp_payload_rsp_f_data(alp, FID_ALARM, &alarm, 0, 1); 00329 00330 err = modem_remote_raw_alp((void*)&alarm_itf, alp, &alp_rsp, (uint32_t)15000); 00331 00332 do 00333 { 00334 evt = g_file_modified.get(); 00335 resp = (evt.status == osEventMessage)? (uint32_t)evt.value.p : MODEM_RESP_NO; 00336 00337 if (MODEM_RESP_DONE == resp) 00338 { 00339 nb++; 00340 PRINT("%d: ", nb); 00341 PRINT_DATA("UID:", "%02X", istat.addressee.id, 8, " "); 00342 PRINT("SNR: %3ddB RXLEV: -%-3ddBm LB: %3ddB\n", istat.snr, istat.rxlev, istat.lb); 00343 00344 // Reset variable 00345 memset(&istat, 0, sizeof(d7a_sp_res_t)); 00346 } 00347 00348 } while (MODEM_RESP_TERMINAL != resp); 00349 00350 if (alarm == 255) 00351 { 00352 // Toggle alarm state 00353 alarm = !!alarm; 00354 ram_fs_write(FID_ALARM, &alarm, 0, 1); 00355 } 00356 } 00357 } 00358 00359 // Todo for each sensor 00360 #define SENSOR_SETUP(NAME,name) ram_fs_new(FID_SENSOR_VALUE_##NAME, (uint8_t*)&h_sensor_value_##name, (uint8_t*)f_sensor_value_##name); modem_declare_file(FID_SENSOR_VALUE_##NAME, (alp_file_header_t*)&h_sensor_value_##name);\ 00361 ram_fs_new(FID_SENSOR_CONFIG_##NAME, (uint8_t*)&h_sensor_config_##name, (uint8_t*)&f_sensor_config_##name);\ 00362 modem_declare_file(FID_SENSOR_CONFIG_##NAME, (alp_file_header_t*)&h_sensor_config_##name);\ 00363 g_thread_ctx = &name##_thread_ctx;\ 00364 Thread th_##name(osPriorityNormal, 1024, NULL);\ 00365 status = th_##name.start(thread_sensor);\ 00366 ASSERT(status == osOK, "Failed to start thread (err: %d)\r\n", status);\ 00367 thread_ready.acquire() 00368 00369 /*** Main function ------------------------------------------------------------- ***/ 00370 int main() 00371 { 00372 // Start & initialize 00373 #ifdef DEBUG_LED 00374 DBG_OPEN(DEBUG_LED); 00375 #else 00376 DBG_OPEN(NC); 00377 #endif 00378 PRINT("\n" 00379 "-----------------------------------------\n" 00380 "------------- Demo Sensors --------------\n" 00381 "-----------------------------------------\n"); 00382 00383 00384 FPRINT("(id:0x%08x)\r\n", osThreadGetId()); 00385 00386 modem_open(&callbacks); 00387 00388 PRINT("Register Files\n"); 00389 ram_fs_new(FID_ALARM, (uint8_t*)&h_alarm, (uint8_t*)&f_alarm); 00390 modem_declare_file(FID_ALARM, (alp_file_header_t*)&h_alarm); 00391 00392 PRINT("Enable D7A interface\n"); 00393 modem_d7a_enable_itf(); 00394 00395 // Host revision file is in the modem. Update it. 00396 PRINT("Update host revision\n"); 00397 modem_write_file(FID_HOST_REV, (void*)&f_rev, 0, sizeof(revision_t)); 00398 00399 00400 // Retrieve modem revision 00401 PRINT("Send revision\n"); 00402 00403 revision_t rev; 00404 00405 modem_read_file(FID_WM_REV, &rev, 0, sizeof(revision_t)); 00406 00407 // Start file modified thread 00408 Thread th_file_modified(osPriorityNormal, 1024, NULL); 00409 osStatus status = th_file_modified.start(thread_file_modified); 00410 ASSERT(status == osOK, "Failed to start thread_file_modified (err: %d)\r\n", status); 00411 00412 #if (_HUM_EN_ > 0 || _TEM1_EN_ > 0 || _MAG_EN_ > 0 || _ACC_EN_ > 0 || _GYR_EN_ > 0 || _PRE_EN_ > 0 || _TEM2_EN_ > 0) 00413 // Open I2C and initialise the sensors 00414 DevI2C ext_i2c(SENSOR_I2C_SDA, SENSOR_I2C_SCL); 00415 #endif 00416 00417 #if (_HUM_EN_ > 0 || _TEM1_EN_ > 0) 00418 humidity_sensor = new HTS221(ext_i2c); 00419 ASSERT(Init_HTS221(humidity_sensor), "Failed to init HTS221\r\n"); 00420 temp_sensor1 = humidity_sensor; 00421 #endif // _TEM_EN_ 00422 #if (_PRE_EN_ > 0 || _TEM2_EN_ > 0) 00423 pressure_sensor = new LPS25H(ext_i2c); 00424 ASSERT(Init_LPS25H(pressure_sensor), "Failed to init LPS25H\r\n"); 00425 temp_sensor2 = pressure_sensor; 00426 #endif // _PRE_EN_ 00427 00428 #if defined(TARGET_STM32L152RE) 00429 #if (_MAG_EN_ > 0) 00430 magnetometer = new LIS3MDL(ext_i2c); 00431 ASSERT(Init_LIS3MDL(magnetometer), "Failed to init LIS3MDL\r\n"); 00432 #endif // _MAG_EN_ 00433 #if (_ACC_EN_ > 0 || _GYR_EN_ > 0) 00434 accelerometer = new LSM6DS0(ext_i2c); 00435 ASSERT(Init_LSM6DS0(accelerometer), "Failed to init LSM6DS0\r\n"); 00436 gyroscope = accelerometer; 00437 #endif // _ACC_EN_ || _GYR_EN_ 00438 #elif defined(TARGET_STM32L432KC) 00439 #if (_ACC_EN_ > 0) 00440 accelerometer = new LSM303C_ACC_Sensor(ext_i2c); 00441 ASSERT(Init_LSM303C_ACC(accelerometer), "Failed to init LSM303C_ACC\r\n"); 00442 #endif // _ACC_EN_ 00443 #if (_MAG_EN_ > 0) 00444 magnetometer = new LSM303C_MAG_Sensor(ext_i2c); 00445 ASSERT(Init_LSM303C_MAG(magnetometer), "Failed to init LSM303C_MAG\r\n"); 00446 #endif // _MAG_EN_ 00447 #endif 00448 00449 #if (_MAG_EN_ > 0) 00450 SENSOR_SETUP(MAG,mag); 00451 #endif 00452 #if (_ACC_EN_ > 0) 00453 SENSOR_SETUP(ACC,acc); 00454 #endif 00455 #if (_GYR_EN_ > 0) 00456 SENSOR_SETUP(GYR,gyr); 00457 #endif 00458 #if (_PRE_EN_ > 0) 00459 SENSOR_SETUP(PRE,pre); 00460 #endif 00461 #if (_HUM_EN_ > 0) 00462 SENSOR_SETUP(HUM,hum); 00463 #endif 00464 #if (_TEM1_EN_ > 0) 00465 SENSOR_SETUP(TEM1,tem1); 00466 #endif 00467 #if (_TEM2_EN_ > 0) 00468 SENSOR_SETUP(TEM2,tem2); 00469 #endif 00470 #if (_LIGHT_EN_ > 0) 00471 SENSOR_SETUP(LIGHT,light); 00472 #endif 00473 00474 00475 // For button 00476 #ifdef DEBUG_BUTTON 00477 DebouncedInterrupt user_interrupt(DEBUG_BUTTON); 00478 user_interrupt.attach(button_push_isr, IRQ_FALL, 500, true); 00479 00480 Thread but_th(osPriorityNormal, 1024, NULL); 00481 status = but_th.start(thread_user_button); 00482 ASSERT(status == osOK, "Failed to start but thread (err: %d)\r\n", status); 00483 #endif 00484 00485 #ifdef DEBUG_LED 00486 DigitalOut my_led(DEBUG_LED); 00487 #endif 00488 00489 // Set main task to lowest priority 00490 osThreadSetPriority(osThreadGetId(), osPriorityLow); 00491 while(true) 00492 { 00493 // Wait to avoid beeing stuck in loop 00494 ThisThread::sleep_for(500); 00495 #ifdef DEBUG_LED 00496 my_led = !my_led; 00497 #endif 00498 } 00499 }
Generated on Tue Jul 12 2022 15:22:26 by 1.7.2