-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp_clock.h
203 lines (181 loc) · 7.46 KB
/
app_clock.h
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
* app_clock.h
*
* Implementation of LoRaWAN Application Layer Clock Synchronization v1.0.0 Specification
* https://lora-alliance.org/resource-hub/lorawanr-application-layer-clock-synchronization-specification-v100
*
* LoRaWAN® Application Layer Clock Synchronization Specification, authored by the FUOTA Working Group of the
* LoRa Alliance® Technical Committee, proposes an application layer messaging package running over LoRaWAN®
* to synchronize the real-time clock of an end-device to the network’s GPS clock with second accuracy.
*
* This package is useful for end-devices which do not have access to other accurate time source.
* An end-device using LoRaWAN 1.1 or above SHOULD use DeviceTimeReq MAC command instead of this package.
* ClassB end-devices have a more efficient way of synchronizing their clock, the classB network beacon. They
* SHOULD NOT use this package and directly use the beacon time information.
* End-devices with an accurate external clock source (e.g.: GPS) SHOULD use that clock source instead.
*
* Remark: Since GPS clock sources can be jammed or spoofed, this package can be used for secure time distribution.
* https://wiki.eclipse.org/images/3/3a/Eclipse-IoTDay2020Grenoble-friedt.pdf
*/
/**
* @ingroup pkg_lorawan_app_clock
* @{
*
* @file
* @brief Implementation of Implementation of LoRaWAN Application Layer Clock Synchronization v1.0.0 Specification.
*
* @author Didier Donsez <didier.donsez@univ-grenoble-alpes.fr>
*
* @}
*/
#ifndef APP_CLOCK_H_
#define APP_CLOCK_H_
#include <inttypes.h>
#include "semtech_loramac.h"
// Comment the following define for removing experimental CID
#define EXPERIMENTAL
#define APP_CLOCK_PORT (uint8_t) 202 // Application Layer Clock
// Server : Used by the AS to request the package version implemented by the end-device
#define APP_CLOCK_CID_PackageVersionReq (uint8_t)0x00
// Endpoint : Conveys the answer to PackageVersionReq
#define APP_CLOCK_CID_PackageVersionAns (uint8_t)0x00
// Endpoint : Used by end-device to request clock correction
#define APP_CLOCK_CID_AppTimeReq (uint8_t)0x01
// Server : Conveys the clock timing correction
#define APP_CLOCK_CID_AppTimeAns (uint8_t)0x01
// Server = Used by the application server for 2 purposes: Set the periodicity at which the end- device shall transmit AppTimeReq messages and request an immediate transmission of end-device time
#define APP_CLOCK_CID_DeviceAppTimePeriodicityReq (uint8_t)0x02
// Endpoint
#define APP_CLOCK_CID_DeviceAppTimePeriodicityAns (uint8_t)0x02
// Server: Used by the application server to the end-device to trigger a clock resynchronization
#define APP_CLOCK_CID_ForceDeviceResyncReq (uint8_t)0x03
#ifdef EXPERIMENTAL
// Server: (eXperimental) Used by the application server to the end-device to set the endpoint clock
#define X_APP_CLOCK_CID_AppTimeSetReq (uint8_t)0xFE
#endif
/**
* 3.1 PackageVersionReq & Ans
*/
// No PackageVersionReq struct
typedef struct {
/**
* PackageIdentifier uniquely identifies the package. For the “clock synchronization package”
* this identifier is 1.
*/
unsigned int PackageIdentifier :8;
/**
* PackageVersion corresponds to the version of the package specification implemented by the
* end-device
*/
unsigned int PackageVersion :8;
} __attribute__((packed)) APP_CLOCK_PackageVersionAns_t;
/**
* 3.2 AppTimeReq & Ans
*/
typedef struct {
/**
* DeviceTime is the current end-device clock and is expressed as the time in seconds
* since 180 00:00:00, Sunday 6th of January 1980 (start of the GPS epoch) modulo 2^32.
*/
unsigned int DeviceTime :32;
/**
* TokenReq is a 4 bits counter initially set to 0. TokenReq is incremented (modulo 16) each time the end-device receives and processes successfully an AppTimeAns message.
*/
unsigned int TokenReq :4;
// If the AnsRequired bit is set to 1 the end-device expects an answer whether its clock is well
// synchronized or not. If this bit is set to 0, this signals to the AS that it only needs to answer if
// the end-device clock is de-synchronized.
unsigned int AnsRequired :1;
unsigned int RFU :3;
} __attribute__((packed)) APP_CLOCK_AppTimeReq_t;
typedef struct {
/**
* TimeCorrection is a signed 32-bit integer, stipulating the time delta correction in seconds.
*/
int TimeCorrection :32;
/**
* TokenReq is a 4 bits counter initially set to 0. TokenReq is incremented (modulo 16) each time the end-device receives and processes successfully an AppTimeAns message.
*/
unsigned int TokenAns :4;
unsigned int RFU :4;
} __attribute__((packed)) APP_CLOCK_AppTimeAns_t;
typedef struct {
/**
* Period encodes the periodicity of the AppTimeReq transmissions. The actual periodicity in
* seconds is 128*2^𝑃𝑒𝑟𝑖𝑜𝑑 ±𝑟𝑎𝑛𝑑(30) where 𝑟𝑎𝑛𝑑(30) is a random integer in the +/-30sec
* range varying with each transmission.
*/
unsigned int Period :4;
unsigned int RFU :4;
} __attribute__((packed)) APP_CLOCK_DeviceAppTimePeriodicityReq_t;
typedef struct {
/**
* NotSupported bit is set to 1 if the end-device’s application does not accept a periodicity set
* by the application server and manages the clock synchronization process and periodicity
* itself.
*/
unsigned int NotSupported :1;
unsigned int RFU :7;
/**
* Time is the current end-device’s clock time captured immediately before the transmission of
* the radio message.
*/
unsigned int Time :32;
} __attribute__((packed)) APP_CLOCK_DeviceAppTimePeriodicityAns_t;
typedef struct {
/**
* The end-device responds by sending up to NbTransmissions AppTimeReq messages
* with the AnsRequired bit set to 0.
* The end-device stops re-transmissions of the AppTimeReq if a valid AppTimeAns is received.
* If the NbTransmissions field is 0, the command SHALL be silently discarded.
* The delay between consecutive transmissions of the AppTimeReq is application specific.
*/
unsigned int NbTransmissions :3;
unsigned int RFU :5;
} __attribute__((packed)) APP_CLOCK_ForceDeviceResyncReq_t;
#ifdef EXPERIMENTAL
typedef struct {
/**
* TimeToSet is the time for setting the end-device clock and is expressed as the time in seconds
* since 180 00:00:00, Sunday 6th of January 1980 (start of the GPS epoch) modulo 2^32.
*/
unsigned int TimeToSet :32;
} __attribute__((packed)) X_APP_CLOCK_AppTimeSetReq_t;
#endif
#define APP_CLOCK_OK (int8_t)0
#define APP_CLOCK_ERROR_OVERFLOW (int8_t)-1
#define APP_CLOCK_NOT_IMPLEMENTED (int8_t)-2
#define APP_CLOCK_UNKNOWN_CID (int8_t)-3
#define APP_CLOCK_BAD_TOKEN (int8_t)-4
#define APP_CLOCK_CID_ALREADY_PROCESS (int8_t)-5
#define APP_CLOCK_TX_KO (int8_t)-6
#define APP_CLOCK_TX_RETRY_LATER (int8_t)-7
/**
* Print the RTC time
*/
extern void app_clock_print_rtc(void);
/**
* Process the payload of APP_CLOCK downlink frame
*
* @param loramac the LoRaMac context
*/
extern int8_t app_clock_process_downlink(semtech_loramac_t *loramac);
/**
* Send a uplink frame with a APP_TIME_REQ paylaod
*
* @param loramac the LoRaMac context
*/
extern int8_t app_clock_send_app_time_req(semtech_loramac_t *loramac);
/**
* Send a uplink frame with a payload built by the app_clock_process_downlink function.
*
* @param loramac the LoRaMac context
*/
extern int8_t app_clock_send_buffer(semtech_loramac_t *loramac);
/**
* Check if the payload built by the app_clock_process_downlink function had to be sent.
*
* @param loramac the LoRaMac context
*/
extern bool app_clock_is_pending_buffer(void);
#endif /* APP_CLOCK_H_ */