root / tidsense / event.c @ 172:8c8328364b9d
History | View | Annotate | Download (3.3 kB)
1 | #include "config.h" |
---|---|
2 | |
3 | #include <stdlib.h> |
4 | #include <string.h> |
5 | |
6 | #include "scheduler.h" |
7 | #include "power.h" |
8 | #include "node.h" |
9 | #include "network.h" |
10 | #include "assoc.h" |
11 | #include "sysclock.h" |
12 | #include "event.h" |
13 | |
14 | sched_task_t *event_task; |
15 | |
16 | event_record_t event_buffer[MAX_EVENTS]; |
17 | uint8_t event_flags = 0;
|
18 | |
19 | bool events_with_status(event_status_t status) {
|
20 | for(uint8_t i=0; i<MAX_EVENTS; i++) { |
21 | if(event_buffer[i].status == status) {
|
22 | return true; |
23 | } |
24 | } |
25 | return false; |
26 | } |
27 | |
28 | void event_mark_transmitted(event_status_t status) {
|
29 | for(uint8_t i=0; i<MAX_EVENTS; i++) { |
30 | if(event_buffer[i].status == EVENT_TRANSMITTED) {
|
31 | event_buffer[i].status = status; |
32 | } |
33 | } |
34 | } |
35 | |
36 | void event_confirm(NWK_DataReq_t *req) {
|
37 | if(req->status == NWK_SUCCESS_STATUS) {
|
38 | event_mark_transmitted(EVENT_FREE); |
39 | event_flags = 0;
|
40 | } else {
|
41 | event_mark_transmitted(EVENT_PENDING); |
42 | event_flags |= EVENT_FLAG_RETRANSMIT; |
43 | } |
44 | network_free_request(req); |
45 | } |
46 | |
47 | void event_task_fn(void *data) { |
48 | // only if we have a master
|
49 | if(assoc_get_state() != ASSOC_STATE_ASSOCIATED) return; |
50 | |
51 | if(!events_with_status(EVENT_PENDING)) return; |
52 | |
53 | // Don't continue if there are currently events in the air
|
54 | if(events_with_status(EVENT_TRANSMITTED)) return; |
55 | |
56 | |
57 | NWK_DataReq_t *req = network_alloc_request(1);
|
58 | if(!req) return; |
59 | |
60 | power_radio_on(); |
61 | |
62 | req->dstAddr = assoc_get_master(); |
63 | req->dstEndpoint = CONTROL_ENDPOINT; |
64 | req->srcEndpoint = CONTROL_ENDPOINT; |
65 | req->options = NWK_OPT_ACK_REQUEST; |
66 | req->confirm = event_confirm; |
67 | req->size = sizeof(event_report_t);
|
68 | |
69 | event_report_t *report = (event_report_t*)req->data; |
70 | report->header.cmd = CMD_EVENT_REPORT; |
71 | report->header.flags = 0;
|
72 | report->header.id = cmd_get_next_id(); |
73 | |
74 | report->n = 0;
|
75 | report->flags = event_flags; |
76 | sysclock_get_time(&report->timestamp, NULL);
|
77 | |
78 | for(uint8_t i=0; i<MAX_EVENTS; i++) { |
79 | event_record_t *e = &event_buffer[i]; |
80 | if(e->status == EVENT_PENDING) {
|
81 | e->status = EVENT_TRANSMITTED; |
82 | memcpy(&req->data[req->size], e, sizeof(event_record_t));
|
83 | req->size += sizeof(event_record_t);
|
84 | report->n++; |
85 | } |
86 | |
87 | // keep from overfilling a packet; events not sent here will get
|
88 | // handled on the next iteration
|
89 | if(req->size >= 100) break; |
90 | } |
91 | |
92 | NWK_DataReq(req); |
93 | } |
94 | |
95 | event_record_t *event_get_free(void) {
|
96 | event_record_t *oldest = NULL;
|
97 | uint32_t oldest_ts = 2147483647UL;
|
98 | for(uint8_t i=0; i<MAX_EVENTS; i++) { |
99 | event_record_t *e = &event_buffer[i]; |
100 | if(e->status == EVENT_FREE) return e; |
101 | if(e->timestamp < oldest_ts) {
|
102 | oldest = e; |
103 | oldest_ts = e->timestamp; |
104 | } |
105 | } |
106 | event_flags |= EVENT_FLAG_OVERFLOW; |
107 | oldest->status = EVENT_FREE; |
108 | return oldest;
|
109 | } |
110 | |
111 | void event_create(event_type_t event, uint32_t data, uint8_t priority) {
|
112 | event_record_t *e = event_get_free(); |
113 | e->status = EVENT_PENDING; |
114 | e->event = event; |
115 | e->data = data; |
116 | e->priority = priority; |
117 | sysclock_get_time(&e->timestamp, NULL);
|
118 | } |
119 | |
120 | void event_setup(void) { |
121 | for(uint8_t i=0; i<MAX_EVENTS; i++) { |
122 | event_buffer[i].status = EVENT_FREE; |
123 | } |
124 | event_flags = 0;
|
125 | |
126 | event_task = sched_task_create(event_task_fn, NULL, 30, 0, SCHED_ENABLED | SCHED_RUN_IDLE); |
127 | } |
128 |