LoRaWAN demo.

Dependencies:   modem_ref_helper DebouncedInterrupt

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);