LoRaWAN demo.
Dependencies: modem_ref_helper DebouncedInterrupt
Diff: main.cpp
- Revision:
- 20:49a8ecd1dda3
- Parent:
- 16:59d93cb1efee
- Child:
- 21:f0aecd41db08
--- a/main.cpp Thu May 28 09:12:40 2020 +0000 +++ b/main.cpp Wed Jan 27 14:45:50 2021 +0000 @@ -2,8 +2,10 @@ // @date: 2017-09-21 #include "DebouncedInterrupt.h" -#include "modem_ref_helper.h" -#include "modem_callbacks.h" +#include "modem_d7a.h" +#include "modem_lwan.h" +#include "d7a_callbacks.h" +#include "lwan_callbacks.h" #include "files.h" #include "sensor.h" @@ -21,9 +23,10 @@ Semaphore modem_urc(0); Semaphore button_user(0); sensor_config_t g_light_config; -Queue<void, 8> g_file_modified; +Queue<uint8_t, 8> g_file_modified; Queue<void, 8> modem_resp; -int32_t itf_busy = 0; +Queue<uint32_t, 8> g_urc; +uint32_t itf_busy; Timer busy_tim; bool alarm_ready = false; @@ -50,28 +53,62 @@ #endif -lwan_itf_cfg_t lwan_itf_ttn = { - .type = ALP_ITF_TYPE_LWAN, - // 0: NONE, 1: OTAA, 2: ABP - .cfg.activation_mode = 1, // XXX Only OTAA +lwan_cfg_t lwan_cfg = { // LoRaWAN device class - .cfg.dev_class = LWAN_CLASS_A, - .cfg.dev_address = 0x700006BF, // For ABP Mode (Big Endian) - .cfg.app_id = MY_APP_ID, - .cfg.app_key = MY_APP_KEY, + .dev_class = LWAN_CLASS_A, // State of adaptative Datarate - .cfg.adr_enable = 1, - .cfg.app_skey = {0}, // For ABP Mode - .cfg.nw_skey = {0}, // For ABP Mode - .cfg.nw_id = 0, // - // Enable or disable a public network - .cfg.nw_public = 1, + .adr_enable = 1, // Uplink datarate, if adr_enable is off - .cfg.tx_datarate = 0, + .tx_datarate = 0, // ISM Band - .cfg.ism_band = ISM_BAND_868, + .ism_band = ISM_BAND_868, + // maximum join attempts + .join_trials = 2, + // Rejoin period (hours) + .rejoin_period = 24 +}; + +lwan_nls_t lwan_nls = { + // Application identifier + .app_id = MY_APP_ID, + // Application key + .app_key = MY_APP_KEY, }; +alp_d7a_itf_t report_itf = { + .type = ALP_ITF_TYPE_D7A, + .cfg.to = D7A_CTF(0), + .cfg.te = D7A_CTF(0), + .cfg.qos.bf.resp = D7A_RESP_PREFERRED, + .cfg.qos.bf.retry = ALP_RPOL_ONESHOT, + .cfg.addressee.ctrl.bf.nls = D7A_NLS_AES_CCM_64, + .cfg.addressee.ctrl.bf.idf = D7A_ID_NBID, + .cfg.addressee.xcl.bf = {.m = 0x1, .s = 2},// XXX D7A_XCL_GW, + .cfg.addressee.id = { D7A_CTF_ENCODE(2) } +}; + +modem_ref_callbacks_t callbacks = { + .read = my_read, + .write = my_write, + .read_fprop = my_read_fprop, + .flush = my_flush, + .remove = my_delete, + .udata = my_udata, + .lqual = my_lqual, + .ldown = my_ldown, + .reset = my_reset, + .boot = my_boot, + .busy = my_busy, + .itf_busy = NULL, +}; + +modem_lwan_callbacks_t lwan_callbacks = { + .packet_sent = lwan_packet_sent, + .itf_busy = lwan_busy, + .join_failed = lwan_join_failed, +}; + + // Interrupt Service Routine on button press. void button_push_isr( void ) { @@ -114,19 +151,19 @@ } // Check parameters to see if data should be send -static bool report_needed(sensor_config_t* config, int32_t value, int32_t last_value, uint32_t last_report_time, uint8_t id) +static bool report_needed(sensor_config_t* config, int32_t value, int32_t last_value, uint32_t last_report_time) { switch (config->report_type) { case REPORT_ALWAYS: // Send a report at each measure - PRINT("Report[%d] always\r\n", id); + PRINT("Report always\r\n"); return report_ok(last_report_time); 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) >= config->max_diff && config->max_diff) { - PRINT("Report[%d] on difference (last:%d new:%d max_diff:%d)\r\n", id, last_value, value, config->max_diff); + PRINT("Report on difference (last:%d new:%d max_diff:%d)\r\n", last_value, value, config->max_diff); return report_ok(last_report_time); } break; @@ -137,7 +174,7 @@ || (value < config->threshold_high && last_value >= config->threshold_high) || (value > config->threshold_low && last_value <= config->threshold_low)) { - PRINT("Report[%d] on threshold (last:%d new:%d th:%d tl:%d)\r\n", id, last_value, value, config->threshold_high, config->threshold_low); + PRINT("Reporton threshold (last:%d new:%d th:%d tl:%d)\r\n", last_value, value, config->threshold_high, config->threshold_low); return report_ok(last_report_time); } break; @@ -148,53 +185,13 @@ // Send a report if it's been more than max_period since the last report if (((last_report_time/1000) >= config->max_period) && config->max_period) { - PRINT("Report[%d] on period (max_period:%d time:%d)\r\n", id, config->max_period, last_report_time); + PRINT("Report on period (max_period:%d time:%d)\r\n", config->max_period, last_report_time); return report_ok(last_report_time); } return false; } -void thread_sensor_light() -{ - light_value_t light_level; - light_value_t light_level_old = 0; - uint8_t id = modem_get_id(my_main_callback); - - // To force a first report - uint32_t last_report_time = 0xFFFFFFFF; - - FPRINT("(id:0x%08x)\r\n", osThreadGetId()); - - // Get the sensor configuration - ram_fs_read(FID_SENSOR_CONFIG, 0, SIZE_SENSOR_CONFIG, (uint8_t*)&g_light_config); - - while (true) - { - light_level = sensor_get_light(); - - //PRINT("Light %d\r\n", light_level); - - if (report_needed(&g_light_config, light_level, light_level_old, last_report_time, id)) - { - PRINT("Light report %d\r\n", light_level); - - // Send notification - modem_write_file(FID_SENSOR_LIGHT, &light_level, 0, SIZE_SENSOR_LIGHT, id); - modem_ready[id].acquire(); - - // Update - light_level_old = light_level; - last_report_time = 0; - } - - // Update last report time - last_report_time += g_light_config.read_period; - - ThisThread::sleep_for(g_light_config.read_period); - } -} - void thread_file_modified() { uint8_t fid; @@ -209,7 +206,7 @@ { case FID_SENSOR_CONFIG: // Update sensor configuration - ram_fs_read(FID_SENSOR_CONFIG, 0, SIZE_SENSOR_CONFIG, (uint8_t*)&g_light_config); + ram_fs_read(FID_SENSOR_CONFIG, (uint8_t*)&g_light_config, 0, SIZE_SENSOR_CONFIG); PRINT("Sensor configuration updated\r\n"); break; default: @@ -218,25 +215,86 @@ } } -void button_user_thread() +void d7a_thread() +{ + light_value_t light_level; + light_value_t light_level_old = 0; + alp_pub_payload_t* alp = NULL; + revision_t rev; + + // To force a first report + uint32_t last_report_time = 0xFFFFFFFF; + + // Add files to local file system + ram_fs_new(FID_SENSOR_CONFIG, (uint8_t*)&h_sensor_config, (uint8_t*)&f_sensor_config); + ram_fs_new(FID_ALARM, (uint8_t*)&h_alarm, (uint8_t*)&f_alarm); + + DPRINT("D7A: Register Files\n"); + // Allow remote access. + modem_declare_file(FID_SENSOR_CONFIG, (alp_file_header_t*)&h_sensor_config); + modem_declare_file(FID_ALARM, (alp_file_header_t*)&h_alarm); + + PRINT("D7A: Notify Revision\n"); + + // Host revision file is in the modem. Update it. + modem_write_file(FID_HOST_REV, &f_rev, 0, sizeof(revision_t)); + + // Retrieve modem revision + modem_read_file(FID_WM_REV, &rev, 0, sizeof(revision_t)); + + // Send both to the server + // Build payload + alp = NULL; + alp = alp_payload_rsp_f_data(alp, FID_WM_REV, &rev, 0, sizeof(revision_t)); + alp = alp_payload_rsp_f_data(alp, FID_HOST_REV, &f_rev, 0, sizeof(revision_t)); + // Send + modem_remote_raw_alp(&report_itf, NULL, alp); + + // Get the sensor configuration + ram_fs_read(FID_SENSOR_CONFIG, (uint8_t*)&g_light_config, 0, SIZE_SENSOR_CONFIG); + + while (true) + { + light_level = sensor_get_light(); + + //PRINT("Light %d\r\n", light_level); + + if (report_needed(&g_light_config, light_level, light_level_old, last_report_time)) + { + PRINT("D7A: Light report %d\r\n", light_level); + + // Send notification + modem_write_file(FID_SENSOR_LIGHT, &light_level, 0, SIZE_SENSOR_LIGHT); + + // Update + light_level_old = light_level; + last_report_time = 0; + } + + // Update last report time + last_report_time += g_light_config.read_period; + + ThisThread::sleep_for(g_light_config.read_period); + } +} + +void lwan_thread() { alarm_t alarm; - uint8_t id = modem_get_id(my_main_callback); + alp_pub_payload_t* alp = NULL; - // Use LoRaWAN Interface for the alarm - typedef uint8_t lwan_itf_t; - lwan_itf_t alarm_itf = ALP_ITF_TYPE_LWAN; + DebouncedInterrupt user_interrupt(DEBUG_BUTTON); + user_interrupt.attach(button_push_isr, IRQ_FALL, 500, true); // Load alarm value - ram_fs_read(FID_ALARM, 0, SIZE_ALARM, &alarm); + ram_fs_read(FID_ALARM, (uint8_t*)&alarm, 0, SIZE_ALARM); - PRINT("Setup LoRaWAN URCs\n"); - modem_enable_urc(ALP_URC_TYPE_ITF_BUSY, FID_LWAN_ITF0, 1, true, id); - modem_ready[id].acquire(); - - PRINT("Start LoRaWAN Stack (Join)\n"); - modem_activate_itf(ALP_ITF_TYPE_LWAN, 1, FID_LWAN_ITF0, 0, true, id); - modem_ready[id].acquire(); + PRINT("LoRaWAN: Update parameters\n"); + modem_lwan_set_cfg(&lwan_cfg); + modem_lwan_set_nls(&lwan_nls); + + PRINT("LoRaWAN: Start (first join)\n"); + modem_lwan_open(&lwan_callbacks); while (true) { @@ -250,7 +308,7 @@ if (itf_busy > 0) { - PRINT("LoRaWAN Still busy for %ds.\r\n", itf_busy); + PRINT("LoRaWAN: Still busy for %ds.\r\n", itf_busy); busy_tim.reset(); } else @@ -258,62 +316,25 @@ busy_tim.stop(); // load/save value to keep choerency in case of remote access... - ram_fs_read(FID_ALARM, 0, SIZE_ALARM, &alarm); + ram_fs_read(FID_ALARM, (uint8_t*)&alarm, 0, SIZE_ALARM); // Toggle alarm state alarm = !alarm; - ram_fs_write(FID_ALARM, 0, SIZE_ALARM, &alarm); + ram_fs_write(FID_ALARM, &alarm, 0, SIZE_ALARM); PRINT("BUTTON ALARM %d\r\n", alarm); - - modem_send_file_content((uint8_t*)&alarm_itf, sizeof(lwan_itf_t), NULL, FID_ALARM, &alarm, 0, SIZE_ALARM, id); - modem_ready[id].acquire(); + + // Build payload + alp = NULL; + alp = alp_payload_rsp_f_data(alp, FID_ALARM, &alarm, 0, sizeof(alarm_t)); + + // Send + modem_lwan_send(alp); } } } -void urc_thread() -{ - while (true) - { - modem_urc.acquire(); - - if (MAX_U32 == itf_busy) - { - // Failed to join - PRINT("LoRaWAN Join failed.\r\n"); - - // Clear busy, join will be retried at next send. - itf_busy = 0; - } - else if (itf_busy) - { - // Packet will be sent in x seconds - PRINT("LoRaWAN Busy for %ds.\r\n", itf_busy); - } - else - { - // Packet has been sent - PRINT("LoRaWAN Done.\r\n"); - } - } -} - -modem_callbacks_t callbacks = { - .read = my_read, - .write = my_write, - .read_fprop = my_read_fprop, - .flush = my_flush, - .remove = my_delete, - .udata = my_udata, - .lqual = my_lqual, - .ldown = my_ldown, - .reset = my_reset, - .boot = my_boot, - .busy = my_busy, - .itf_busy = my_itf_busy, -}; /*** Main function ------------------------------------------------------------- ***/ int main() @@ -328,44 +349,9 @@ "-----------------------------------------\n" "-------------- Demo LoRaWAN -------------\n" "-----------------------------------------\n"); - - FPRINT("(id:0x%08x)\r\n", osThreadGetId()); - - modem_helper_open(&callbacks); - - uint8_t id = modem_get_id(my_main_callback); - - DPRINT("Register Files\n"); - // Create report file on modem. - modem_update_file(FID_SENSOR_LIGHT, (alp_file_header_t*)&h_sensor_light, NULL); - - // Allow remote access. - modem_update_file(FID_SENSOR_CONFIG, (alp_file_header_t*)&h_sensor_config, (uint8_t*)&f_sensor_config); - modem_update_file(FID_ALARM, (alp_file_header_t*)&h_alarm, (uint8_t*)&f_alarm); - - PRINT("Update LoRaWAN Interface file\n"); - modem_write_file(FID_LWAN_ITF0, &lwan_itf_ttn, 0, sizeof(lwan_itf_cfg_t), id); - modem_ready[id].acquire(); + + modem_open(&callbacks); - // Configure URC: LQUAL on report file notification every 10 reports - PRINT("Setup D7A URCs\n"); - modem_enable_urc(ALP_URC_TYPE_LQUAL, IFID_REPORT, 10, true, id); - modem_ready[id].acquire(); - - PRINT("Start D7A Stack\n"); - modem_activate_itf(ALP_ITF_TYPE_D7A, 24, 0, ALP_D7A_ISTAT_UNS | ALP_D7A_ISTAT_RESP | ALP_D7A_ISTAT_EOP, true, id); - modem_ready[id].acquire(); - - PRINT("Notify Modem Version\n"); - modem_notify_file(D7A_FID_FIRMWARE_VERSION, 0, SIZE_HOST_REV, id); - modem_ready[id].acquire(); - - PRINT("Notify FW Version\n"); - uint8_t default_root_key[16] = DEFAULT_ROOT_KEY; - modem_notify_host_rev(&f_rev, &h_rev, default_root_key); - - modem_free_id(id); - // Start file modified thread Thread th_file_modified(osPriorityNormal, 1024, NULL); osStatus status = th_file_modified.start(thread_file_modified); @@ -373,21 +359,12 @@ // Start light measure thread Thread th_sensor_light(osPriorityNormal, 1024, NULL); - status = th_sensor_light.start(thread_sensor_light); - ASSERT(status == osOK, "Failed to start thread_sensor_light (err: %d)\r\n", status); - -#ifdef DEBUG_BUTTON - DebouncedInterrupt user_interrupt(DEBUG_BUTTON); - user_interrupt.attach(button_push_isr, IRQ_FALL, 500, true); + status = th_sensor_light.start(d7a_thread); + ASSERT(status == osOK, "Failed to start d7a_thread (err: %d)\r\n", status); Thread but_th(osPriorityNormal, 1024, NULL); - status = but_th.start(button_user_thread); + status = but_th.start(lwan_thread); ASSERT(status == osOK, "Failed to start but thread (err: %d)\r\n", status); - - Thread urc_th(osPriorityNormal, 1024, NULL); - status = urc_th.start(urc_thread); - ASSERT(status == osOK, "Failed to start urc thread (err: %d)\r\n", status); -#endif #ifdef DEBUG_LED DigitalOut my_led(DEBUG_LED);