1 /**
2 * @file aiot_ntp_api.c
3 * @brief ntp模块的API接口实现, 提供获取utc时间的能力
4 *
5 * @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
6 *
7 */
8
9 /* TODO: 对本模块的头文件, 仅需包含ntp_private.h, 不需包含aiot_ntp_api.h */
10 #include "ntp_private.h"
11
12 /* TODO: 列出对core模块需要包含的头文件 */
13 #include "core_string.h"
14 #include "core_log.h"
15 #include "core_global.h"
16 #include "core_mqtt.h"
17
_core_ntp_exec_inc(ntp_handle_t * ntp_handle)18 static void _core_ntp_exec_inc(ntp_handle_t *ntp_handle)
19 {
20 ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
21 ntp_handle->exec_count++;
22 ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
23 }
24
_core_ntp_exec_dec(ntp_handle_t * ntp_handle)25 static void _core_ntp_exec_dec(ntp_handle_t *ntp_handle)
26 {
27 ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
28 ntp_handle->exec_count--;
29 ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
30 }
31
_ntp_recv_handler(void * handle,const aiot_mqtt_recv_t * packet,void * userdata)32 static void _ntp_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
33 {
34 ntp_handle_t *ntp_handle = (ntp_handle_t *)userdata;
35
36 switch (packet->type) {
37 case AIOT_MQTTRECV_PUB: {
38 char *dst_key = "deviceSendTime", *srt_key = "serverRecvTime", *sst_key = "serverSendTime";
39 char *dst_value = NULL, *srt_value = NULL, *sst_value = NULL;
40 uint32_t dst_value_len = 0, srt_value_len = 0, sst_value_len = 0;
41 uint64_t dst = 0, srt = 0, sst = 0, utc = 0;
42
43 if (core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, dst_key, (uint32_t)strlen(dst_key),
44 &dst_value, &dst_value_len) == STATE_SUCCESS &&
45 core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, srt_key, (uint32_t)strlen(srt_key),
46 &srt_value, &srt_value_len) == STATE_SUCCESS &&
47 core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, sst_key, (uint32_t)strlen(sst_key),
48 &sst_value, &sst_value_len) == STATE_SUCCESS) {
49 if (core_str2uint64(dst_value, (uint8_t)dst_value_len, &dst) == STATE_SUCCESS &&
50 core_str2uint64(srt_value, (uint8_t)srt_value_len, &srt) == STATE_SUCCESS &&
51 core_str2uint64(sst_value, (uint8_t)sst_value_len, &sst) == STATE_SUCCESS) {
52 core_date_t date;
53 utc = (srt + sst + ntp_handle->sysdep->core_sysdep_time() - dst) / 2;
54
55 core_log_set_timestamp(ntp_handle->sysdep, utc);
56
57 memset(&date, 0, sizeof(core_date_t));
58 core_utc2date(utc, ntp_handle->time_zone, &date);
59 if (ntp_handle->recv_handler != NULL) {
60 aiot_ntp_recv_t recv;
61
62 memset(&recv, 0, sizeof(aiot_ntp_recv_t));
63 recv.type = AIOT_NTPRECV_LOCAL_TIME;
64 recv.data.local_time.timestamp = utc;
65 recv.data.local_time.year = date.year;
66 recv.data.local_time.mon = date.mon;
67 recv.data.local_time.day = date.day;
68 recv.data.local_time.hour = date.hour;
69 recv.data.local_time.min = date.min;
70 recv.data.local_time.sec = date.sec;
71 recv.data.local_time.msec = date.msec;
72
73 ntp_handle->recv_handler(ntp_handle, &recv, ntp_handle->userdata);
74 }
75 } else {
76 if (ntp_handle->event_handler != NULL) {
77 aiot_ntp_event_t event;
78
79 memset(&event, 0, sizeof(aiot_ntp_event_t));
80 event.type = AIOT_NTPEVT_INVALID_TIME_FORMAT;
81 ntp_handle->event_handler(ntp_handle, &event, ntp_handle->userdata);
82 }
83 }
84 } else {
85 if (ntp_handle->event_handler != NULL) {
86 aiot_ntp_event_t event;
87
88 memset(&event, 0, sizeof(aiot_ntp_event_t));
89 event.type = AIOT_NTPEVT_INVALID_RESPONSE;
90 ntp_handle->event_handler(ntp_handle, &event, ntp_handle->userdata);
91 }
92 }
93 }
94 default: {
95
96 }
97 break;
98 }
99 }
100
_ntp_operate_topic_map(ntp_handle_t * ntp_handle,aiot_mqtt_option_t option)101 static int32_t _ntp_operate_topic_map(ntp_handle_t *ntp_handle, aiot_mqtt_option_t option)
102 {
103 int32_t res = STATE_SUCCESS;
104 aiot_mqtt_topic_map_t map;
105 char *topic = NULL;
106 char *topic_src[] = { core_mqtt_get_product_key(ntp_handle->mqtt_handle), core_mqtt_get_device_name(ntp_handle->mqtt_handle) };
107 char *topic_fmt = NTP_RESPONSE_TOPIC_FMT;
108
109 memset(&map, 0, sizeof(aiot_mqtt_topic_map_t));
110
111 res = core_sprintf(ntp_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
112 NTP_MODULE_NAME);
113 if (res < STATE_SUCCESS) {
114 return res;
115 }
116
117 map.topic = topic;
118 map.handler = _ntp_recv_handler;
119 map.userdata = (void *)ntp_handle;
120
121 res = aiot_mqtt_setopt(ntp_handle->mqtt_handle, option, &map);
122 ntp_handle->sysdep->core_sysdep_free(topic);
123
124 return res;
125 }
126
_ntp_core_mqtt_process_handler(void * context,aiot_mqtt_event_t * event,core_mqtt_event_t * core_event)127 static void _ntp_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
128 {
129 ntp_handle_t *ntp_handle = (ntp_handle_t *)context;
130
131 if (core_event != NULL) {
132 switch (core_event->type) {
133 case CORE_MQTTEVT_DEINIT: {
134 ntp_handle->mqtt_handle = NULL;
135 return;
136 }
137 break;
138 default: {
139
140 }
141 break;
142 }
143 }
144 }
145
_ntp_core_mqtt_operate_process_handler(ntp_handle_t * ntp_handle,core_mqtt_option_t option)146 static int32_t _ntp_core_mqtt_operate_process_handler(ntp_handle_t *ntp_handle, core_mqtt_option_t option)
147 {
148 core_mqtt_process_data_t process_data;
149
150 memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
151 process_data.handler = _ntp_core_mqtt_process_handler;
152 process_data.context = ntp_handle;
153
154 return core_mqtt_setopt(ntp_handle->mqtt_handle, option, &process_data);
155 }
156
aiot_ntp_init(void)157 void *aiot_ntp_init(void)
158 {
159 ntp_handle_t *ntp_handle = NULL;
160 aiot_sysdep_portfile_t *sysdep = NULL;
161
162 sysdep = aiot_sysdep_get_portfile();
163 if (sysdep == NULL) {
164 return NULL;
165 }
166
167 ntp_handle = sysdep->core_sysdep_malloc(sizeof(ntp_handle_t), NTP_MODULE_NAME);
168 if (ntp_handle == NULL) {
169 return NULL;
170 }
171 memset(ntp_handle, 0, sizeof(ntp_handle_t));
172
173 ntp_handle->sysdep = sysdep;
174 ntp_handle->deinit_timeout_ms = NTP_DEFAULT_DEINIT_TIMEOUT_MS;
175
176 ntp_handle->data_mutex = sysdep->core_sysdep_mutex_init();
177
178 ntp_handle->exec_enabled = 1;
179
180 return ntp_handle;
181 }
182
aiot_ntp_setopt(void * handle,aiot_ntp_option_t option,void * data)183 int32_t aiot_ntp_setopt(void *handle, aiot_ntp_option_t option, void *data)
184 {
185 int32_t res = STATE_SUCCESS;
186 ntp_handle_t *ntp_handle = (ntp_handle_t *)handle;
187
188 if (handle == NULL || data == NULL) {
189 return STATE_USER_INPUT_NULL_POINTER;
190 }
191
192 if (option >= AIOT_NTPOPT_MAX) {
193 return STATE_USER_INPUT_OUT_RANGE;
194 }
195
196 if (ntp_handle->exec_enabled == 0) {
197 return STATE_USER_INPUT_EXEC_DISABLED;
198 }
199
200 _core_ntp_exec_inc(ntp_handle);
201
202 ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
203 switch (option) {
204 case AIOT_NTPOPT_MQTT_HANDLE: {
205 ntp_handle->mqtt_handle = data;
206 ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
207 res = _ntp_operate_topic_map(ntp_handle, AIOT_MQTTOPT_APPEND_TOPIC_MAP);
208 if (res >= STATE_SUCCESS) {
209 res = _ntp_core_mqtt_operate_process_handler(ntp_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
210 }
211 ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
212 }
213 break;
214 case AIOT_NTPOPT_TIME_ZONE: {
215 ntp_handle->time_zone = *(int8_t *)data;
216 }
217 break;
218 case AIOT_NTPOPT_RECV_HANDLER: {
219 ntp_handle->recv_handler = (aiot_ntp_recv_handler_t)data;
220 }
221 break;
222 case AIOT_NTPOPT_EVENT_HANDLER: {
223 ntp_handle->event_handler = (aiot_ntp_event_handler_t)data;
224 }
225 break;
226 case AIOT_NTPOPT_USERDATA: {
227 ntp_handle->userdata = data;
228 }
229 break;
230 case AIOT_NTPOPT_DEINIT_TIMEOUT_MS: {
231 ntp_handle->deinit_timeout_ms = *(uint32_t *)data;
232 }
233 break;
234 default: {
235 res = STATE_USER_INPUT_UNKNOWN_OPTION;
236 }
237 break;
238 }
239 ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
240
241 _core_ntp_exec_dec(ntp_handle);
242
243 return res;
244 }
245
aiot_ntp_deinit(void ** handle)246 int32_t aiot_ntp_deinit(void **handle)
247 {
248 uint64_t deinit_timestart = 0;
249 ntp_handle_t *ntp_handle = NULL;
250
251 if (handle == NULL || *handle == NULL) {
252 return STATE_USER_INPUT_NULL_POINTER;
253 }
254
255 ntp_handle = *(ntp_handle_t **)handle;
256
257 if (ntp_handle->exec_enabled == 0) {
258 return STATE_USER_INPUT_EXEC_DISABLED;
259 }
260
261 ntp_handle->exec_enabled = 0;
262
263 _ntp_core_mqtt_operate_process_handler(ntp_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
264 _ntp_operate_topic_map(ntp_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP);
265
266 deinit_timestart = ntp_handle->sysdep->core_sysdep_time();
267 do {
268 if (ntp_handle->exec_count == 0) {
269 break;
270 }
271 ntp_handle->sysdep->core_sysdep_sleep(NTP_DEINIT_INTERVAL_MS);
272 } while ((ntp_handle->sysdep->core_sysdep_time() - deinit_timestart) < ntp_handle->deinit_timeout_ms);
273
274 if (ntp_handle->exec_count != 0) {
275 return STATE_MQTT_DEINIT_TIMEOUT;
276 }
277
278 *handle = NULL;
279
280 ntp_handle->sysdep->core_sysdep_mutex_deinit(&ntp_handle->data_mutex);
281
282 ntp_handle->sysdep->core_sysdep_free(ntp_handle);
283
284 return STATE_SUCCESS;
285 }
286
aiot_ntp_send_request(void * handle)287 int32_t aiot_ntp_send_request(void *handle)
288 {
289 int32_t res = STATE_SUCCESS;
290 char *topic = NULL, *payload = NULL;
291 ntp_handle_t *ntp_handle = (ntp_handle_t *)handle;
292
293 if (handle == NULL) {
294 return STATE_USER_INPUT_NULL_POINTER;
295 }
296
297 if (ntp_handle->mqtt_handle == NULL) {
298 return STATE_NTP_MISSING_MQTT_HANDLE;
299 }
300
301 if (ntp_handle->exec_enabled == 0) {
302 return STATE_USER_INPUT_EXEC_DISABLED;
303 }
304
305 _core_ntp_exec_inc(ntp_handle);
306
307 {
308 char *topic_src[] = { core_mqtt_get_product_key(ntp_handle->mqtt_handle), core_mqtt_get_device_name(ntp_handle->mqtt_handle) };
309 char *topic_fmt = NTP_REQUEST_TOPIC_FMT;
310 char time_str[21] = {0};
311 char *payload_src[] = { time_str };
312 char *payload_fmt = NTP_REQUEST_PAYLOAD_FMT;
313
314 res = core_sprintf(ntp_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
315 NTP_MODULE_NAME);
316 if (res < STATE_SUCCESS) {
317 _core_ntp_exec_dec(ntp_handle);
318 return res;
319 }
320
321 core_uint642str(ntp_handle->sysdep->core_sysdep_time(), time_str, NULL);
322 res = core_sprintf(ntp_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src) / sizeof(char *),
323 NTP_MODULE_NAME);
324 if (res < STATE_SUCCESS) {
325 ntp_handle->sysdep->core_sysdep_free(topic);
326 _core_ntp_exec_dec(ntp_handle);
327 return res;
328 }
329 }
330
331 res = aiot_mqtt_pub(ntp_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), 0);
332 ntp_handle->sysdep->core_sysdep_free(topic);
333 ntp_handle->sysdep->core_sysdep_free(payload);
334 if (res < STATE_SUCCESS) {
335 _core_ntp_exec_dec(ntp_handle);
336 return res;
337 }
338
339 _core_ntp_exec_dec(ntp_handle);
340
341 return STATE_SUCCESS;
342 }
343
344