summaryrefslogtreecommitdiff
path: root/recipes-connectivity/lora/lora-packet-forwarder/lora-packet-forwarder-duty-cycle.patch
blob: b1790e7aecd23aaf97ea9c1ac03d2f22c14d4db7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
diff --git a/lora_pkt_fwd/src/lora_pkt_fwd.c b/lora_pkt_fwd/src/lora_pkt_fwd.c
index 801f28d..7b63b8f 100644
--- a/lora_pkt_fwd/src/lora_pkt_fwd.c
+++ b/lora_pkt_fwd/src/lora_pkt_fwd.c
@@ -134,6 +134,12 @@ static char serv_port_up[8] = STR(DEFAULT_PORT_UP); /* server port for upstream traffic */
 static char serv_port_down[8] = STR(DEFAULT_PORT_DW); /* server port for downstream traffic */
 static int keepalive_time = DEFAULT_KEEPALIVE; /* send a PULL_DATA request every X seconds, negative = disabled */
 
+static bool duty_cycle_enabled = true;
+static uint32_t duty_cycle_time_avail = 0;
+static uint32_t duty_cycle_period = 3600; // seconds in one hour
+static double duty_cycle_ratio = 0.10; // 10%
+static uint32_t duty_cycle_time_max = 3600 * 0.10 * 1000u; // max time-on-air in window 
+
 /* statistics collection configuration variables */
 static unsigned stat_interval = DEFAULT_STAT; /* time interval (in sec) at which statistics are collected and displayed */
 
@@ -729,8 +746,32 @@ static int parse_gateway_configuration(const char * conf_file) {
         push_timeout_half.tv_usec = 500 * (long int)json_value_get_number(val);
         MSG("INFO: upstream PUSH_DATA time-out is configured to %u ms\n", (unsigned)(push_timeout_half.tv_usec / 500));
     }
+    
+    /* duty-cycle limiting */
+    val = json_object_get_value(conf_obj, "duty_cycle_enabled");
+    if (json_value_get_type(val) == JSONBoolean) {
+        duty_cycle_enabled = (bool)json_value_get_boolean(val);
+    }
+    MSG("INFO: duty cycle will%s be enforced\n", (duty_cycle_enabled ? "" : " NOT"));
+
+    if (duty_cycle_enabled) {
+        val = json_object_get_value(conf_obj, "duty_cycle_period");
+        if (val != NULL) {
+            duty_cycle_period = (unsigned)json_value_get_number(val);
+        }
+        MSG("INFO: duty cycle period %u s\n", (duty_cycle_period));
+
+        val = json_object_get_value(conf_obj, "duty_cycle_ratio");
+        if (val != NULL) {
+            duty_cycle_ratio = (double)json_value_get_number(val);
+        }
+        MSG("INFO: duty cycle %f %%\n", (duty_cycle_ratio * 100));
+
+        duty_cycle_time_max = duty_cycle_period * 1000u * duty_cycle_ratio;
+    }
+
 
     /* packet filtering parameters */
     val = json_object_get_value(conf_obj, "best_packet_filter");
     if (json_value_get_type(val) == JSONBoolean) {
         fwd_best_pkt = (bool)json_value_get_boolean(val);
@@ -1349,6 +1406,8 @@ int main(void)
         printf("# PUSH_DATA datagrams sent: %u (%u bytes)\n", cp_up_dgram_sent, cp_up_network_byte);
         printf("# PUSH_DATA acknowledged: %.2f%%\n", 100.0 * up_ack_ratio);
         printf("### [DOWNSTREAM] ###\n");
+        if (duty_cycle_enabled) 
+            printf("# TIME ON AIR available: %u ms\n", duty_cycle_time_avail);
         printf("# PULL_DATA sent: %u (%.2f%% acknowledged)\n", cp_dw_pull_sent, 100.0 * dw_ack_ratio);
         printf("# PULL_RESP(onse) datagrams received: %u (%u bytes)\n", cp_dw_dgram_rcv, cp_dw_network_byte);
         printf("# RF packets sent to concentrator: %u (%u bytes)\n", (cp_nb_tx_ok+cp_nb_tx_fail), cp_dw_payload_byte);

@@ -2833,6 +2921,25 @@ void thread_valid(void) {
     while (!exit_sig && !quit_sig) {
         wait_ms(1000);
 
+       if (duty_cycle_enabled) {
+            static struct timespec last = { 0, 0 };
+            struct timespec now;
+            clock_gettime(CLOCK_MONOTONIC, &now);
+
+            if (last.tv_sec != 0) {
+                // uint64(now.tv_sec) * 1000 + now.tv_nsec / 1000000
+                
+                duty_cycle_time_avail += difftimespec(now, last) * 1000u * duty_cycle_ratio;
+
+               if (duty_cycle_time_avail > duty_cycle_time_max) {
+                    duty_cycle_time_avail = duty_cycle_time_max;
+                }
+            }
+
+            last = now;
+        }
+
+
         /* calculate when the time reference was last updated */
         pthread_mutex_lock(&mx_timeref);
         gps_ref_age = (long)difftime(time(NULL), time_reference_gps.systime);