WizziLab / Mbed 2 deprecated D7A_1x_TRAINING

Dependencies:   X_NUCLEO_IKS01A1 d7a_1x mbed-rtos mbed wizzi-utils

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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*)&divider);
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*)&divider);
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 }