blob: 11bbfd3388941727e9b77a1cbe10e06440d33876 [file] [log] [blame]
b.liue77ac3a2024-07-17 17:36:57 +08001/*
2* mbtk_gnss.c
3*
4* MBTK GNSS API source.
5*
6*/
7/******************************************************************************
8
9 EDIT HISTORY FOR FILE
10
11 WHEN WHO WHAT,WHERE,WHY
12-------- -------- -------------------------------------------------------
132024/7/11 LiuBin Initial version
14
15******************************************************************************/
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19#include <errno.h>
20#include <pthread.h>
21#include <sys/socket.h>
22#include <sys/un.h>
23#include <netinet/in.h>
24#include <fcntl.h>
25#include <sys/epoll.h>
26
27#include "mbtk_gnss_inter.h"
28#include "mbtk_log.h"
29#include "mbtk_utils.h"
30
31#define GNSS_BUFF_SIZE 2048
32
33static int gnss_cli_fd = -1;
34static pthread_t read_thread_id;
35static int exit_fd[2] = {-1};
36static mbtk_gnss_callback_func gnss_cb = NULL;
37static bool gnss_busy = FALSE;
38static pthread_cond_t gnss_cond;
39static pthread_mutex_t gnss_mutex;
40static gnss_err_enum gnss_result;
41
42static int sock_read(int fd, uint8 *msg, int data_len)
43{
44 memset(msg, 0, data_len);
45 int len = 0;
46
47 int read_len = 0;
48 while(1)
49 {
50 len = read(fd, msg + read_len, data_len - read_len);
51 if(len > 0)
52 {
53 read_len += len;
54 }
55 else if(len == 0)
56 {
57 LOGE("read() end.");
58 break;
59 }
60 else
61 {
62 if(EAGAIN == errno)
63 {
b.liu42f558e2024-07-18 14:06:49 +080064 LOGV("Read end, lenght = %d", read_len);
b.liue77ac3a2024-07-17 17:36:57 +080065 }
66 else
67 {
68 LOGE("read() error[%d].", errno);
69 }
70 break;
71 }
72 }
73
74 if(read_len > 0)
75 {
76 // log_hex("DATA_RECV", msg, read_len);
77 return read_len;
78 }
79 else
80 {
81 return -1;
82 }
83}
84
85static int sock_write(int fd, uint8 *msg, int data_len)
86{
87 int len = 0;
88 int write_len = 0;
89 while(write_len < data_len)
90 {
91 len = write(fd, msg + write_len, data_len - write_len);
92 if(len > 0)
93 {
94 write_len += len;
95 }
96 else if(len == 0)
97 {
98 LOGE("write() end.");
99 break;
100 }
101 else
102 {
103 LOGE("write() error[%d].", errno);
104 break;
105 }
106 }
107
108 if(write_len > 0)
109 {
110 // log_hex("DATA_SEND", msg, write_len);
111 return write_len;
112 }
113 else
114 {
115 return -1;
116 }
117}
118
119static void gnss_timer_cb(int signo)
120{
121 if(gnss_busy) {
122 pthread_mutex_lock(&gnss_mutex);
123 pthread_cond_signal(&gnss_cond);
124 pthread_mutex_unlock(&gnss_mutex);
125 gnss_result = GNSS_ERR_TIMEOUT;
126 }
127 return;
128}
129
130static void gnss_rsp_process(const char *data, int data_len)
131{
132 int index = 0;
133 char buff[GNSS_BUFF_SIZE];
134 int buff_len = 0;
135 while(index < data_len) {
136 if(data[index] == MBTK_IND_START_FLAG) {
137 memset(buff, 0, sizeof(buff));
138 buff_len = 0;
139 } else if(data[index] == MBTK_IND_END_FLAG) {
140 buff[buff_len] = '\0';
b.liue77ac3a2024-07-17 17:36:57 +0800141 if(memcmp(MBTK_IND_LOCATION_TAG, buff, strlen(MBTK_IND_LOCATION_TAG)) == 0) {
142 if(gnss_cb) {
143 gnss_cb(MBTK_GNSS_IND_LOCATION, buff, buff_len);
144 }
145 } else if(memcmp(MBTK_IND_NMEA_TAG, buff, strlen(MBTK_IND_NMEA_TAG)) == 0) {
146 if(gnss_cb) {
147 gnss_cb(MBTK_GNSS_IND_NMEA, buff, buff_len);
148 }
149 } else {
b.liu42f558e2024-07-18 14:06:49 +0800150 LOGD("RSP[len - %d] : %s", buff_len, buff);
b.liue77ac3a2024-07-17 17:36:57 +0800151 if(gnss_busy) {
b.liu42f558e2024-07-18 14:06:49 +0800152 // XXXXXX:<result>
153 char *ptr = strstr(buff, ":");
154 if(ptr) {
155 gnss_result = atoi(ptr + 1);
156 }
b.liue77ac3a2024-07-17 17:36:57 +0800157 pthread_mutex_lock(&gnss_mutex);
158 pthread_cond_signal(&gnss_cond);
159 pthread_mutex_unlock(&gnss_mutex);
160 }
161 }
162 } else {
163 buff[buff_len++] = data[index];
164 }
165 index++;
166 }
167}
168
169static void* gnss_read_run(void* arg)
170{
171 int epoll_fd = epoll_create(5);
172 if(epoll_fd < 0)
173 {
174 LOGE("epoll_create() fail[%d].", errno);
175 return NULL;
176 }
177
178 uint32 event = EPOLLIN | EPOLLET;
179 struct epoll_event ev_cli, ev_exit;
180 ev_cli.data.fd = gnss_cli_fd;
181 ev_cli.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
182 epoll_ctl(epoll_fd,EPOLL_CTL_ADD,gnss_cli_fd,&ev_cli);
183
184 ev_exit.data.fd = exit_fd[0];
185 ev_exit.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
186 epoll_ctl(epoll_fd,EPOLL_CTL_ADD,exit_fd[0],&ev_exit);
187
188 int nready = -1;
189 struct epoll_event epoll_events[EPOLL_LISTEN_MAX];
190 while(1)
191 {
192 nready = epoll_wait(epoll_fd, epoll_events, EPOLL_LISTEN_MAX, -1);
193 if(nready > 0)
194 {
195 int i;
196 for(i = 0; i < nready; i++)
197 {
b.liu42f558e2024-07-18 14:06:49 +0800198 LOGV("fd[%d] event = %x",epoll_events[i].data.fd, epoll_events[i].events);
b.liue77ac3a2024-07-17 17:36:57 +0800199 if(epoll_events[i].events & EPOLLHUP) // Closed by server.
200 {
201
202 }
203 else if(epoll_events[i].events & EPOLLIN)
204 {
205 if(gnss_cli_fd == epoll_events[i].data.fd) // Server data arrive.
206 {
207 char buff[GNSS_BUFF_SIZE + 1];
208 int len = sock_read(gnss_cli_fd, buff, GNSS_BUFF_SIZE);
209 if(len > 0) {
210 gnss_rsp_process(buff, len);
211 }
212 }
213 else if(exit_fd[0] == epoll_events[i].data.fd) //
214 {
215 char buff[100] = {0};
216 int len = read(exit_fd[0], buff, 100);
217 if(len > 0) {
218 LOGI("CMD : %s", buff);
219 if(strcmp(buff, "EXIT") == 0) {
220 goto read_thread_exit;
221 } else {
222 LOGD("Unkonw cmd : %s", buff);
223 }
224 } else {
225 LOGE("sock_read() fail.");
226 }
227 }
228 else
229 {
230 LOGW("Unknown socket : %d", epoll_events[i].data.fd);
231 }
232 }
233 else
234 {
235 LOGW("Unknown event : %x", epoll_events[i].events);
236 }
237 }
238 }
239 else
240 {
241 LOGW("epoll_wait() fail[%d].", errno);
242 }
243 }
244
245read_thread_exit:
246 LOGD("info_read thread exit.");
247 return NULL;
248}
249
250gnss_err_enum mbtk_gnss_init(mbtk_gnss_callback_func cb)
251{
252 if(gnss_cli_fd > 0) {
253 LOGW("GNSS client has inited.");
254 return GNSS_ERR_OK;
255 }
256
257 gnss_cli_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
258 if(gnss_cli_fd < 0)
259 {
260 LOGE("socket() fail[%d].", errno);
261 goto error;
262 }
263
264 // Set O_NONBLOCK
265 int flags = fcntl(gnss_cli_fd, F_GETFL, 0);
266 if (flags < 0)
267 {
268 LOGE("Get flags error:%d", errno);
269 goto error;
270 }
271 flags |= O_NONBLOCK;
272 if (fcntl(gnss_cli_fd, F_SETFL, flags) < 0)
273 {
274 LOGE("Set flags error:%d", errno);
275 goto error;
276 }
277
278 struct sockaddr_un cli_addr;
279 memset(&cli_addr, 0, sizeof(cli_addr));
280 cli_addr.sun_family = AF_LOCAL;
281 strcpy(cli_addr.sun_path, SOCK_GNSS_PATH);
282 if(connect(gnss_cli_fd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
283 {
284 LOGE("connect() fail[%d].", errno);
285 goto error;
286 }
287
288 if(pipe(exit_fd)) {
289 LOGE("pipe() fail[%d].", errno);
290 goto error;
291 }
292
293 if(pthread_create(&read_thread_id, NULL, gnss_read_run, NULL))
294 {
295 LOGE("pthread_create() fail.");
296 goto error;
297 }
298 pthread_mutex_init(&gnss_mutex, NULL);
299 pthread_cond_init(&gnss_cond, NULL);
300 gnss_cb = cb;
301 return GNSS_ERR_OK;
302
303error:
304 if(gnss_cli_fd > 0) {
305 close(gnss_cli_fd);
306 gnss_cli_fd = -1;
307 }
308 if(exit_fd[0] > 0) {
309 close(exit_fd[0]);
310 exit_fd[0] = -1;
311 }
312 if(exit_fd[1] > 0) {
313 close(exit_fd[1]);
314 exit_fd[1] = -1;
315 }
316
317 return GNSS_ERR_UNKNOWN;
318}
319
320gnss_err_enum mbtk_gnss_deinit()
321{
322 if(gnss_cli_fd < 0) {
323 LOGW("GNSS client not inited.");
324 return GNSS_ERR_UNKNOWN;
325 }
326
327 if(gnss_busy) {
328 LOGE("BUSY");
329 return GNSS_ERR_BUSY;
330 }
331
332 if(exit_fd[1] > 0) {
333 write(exit_fd[1], "EXIT", 4);
334 }
335
336 int ret = pthread_join(read_thread_id, NULL);
337 if(ret){
338 LOGE("pthrad_join fail(%d)",ret);
339 return GNSS_ERR_UNKNOWN;
340 }
341
342 close(gnss_cli_fd);
343 gnss_cli_fd = -1;
344 close(exit_fd[0]);
345 exit_fd[0] = -1;
346 close(exit_fd[1]);
347 exit_fd[1] = -1;
348 gnss_cb = NULL;
349 gnss_busy = FALSE;
350 pthread_mutex_destroy(&gnss_mutex);
351 pthread_cond_destroy(&gnss_cond);
352
353 return GNSS_ERR_OK;
354}
355
b.liuc223a942024-07-18 15:44:12 +0800356/*===========================================================================
357FUNCTION mbtk_gnss_open
358
359DESCRIPTION:
360 Open/Close GNSS.
361
362PARAMETERS:
363 type [IN]: How to turn on or off GNSS,The available values are as follows:
364 0 : Close GNSS;
365 1-15 : Open GNSS with NMEA print;
366 (GNSS_PRINT_PORT_UART1 / GNSS_PRINT_PORT_USB_NMEA / GNSS_PRINT_PORT_USB_AT / GNSS_PRINT_PORT_TTY_AT)
367 Other : Open GNSS without print NMEA
368 timeout [IN]: Timeout with second.
369
370RETURN VALUE:
371 gnss_err_enum
372
373===========================================================================*/
b.liue77ac3a2024-07-17 17:36:57 +0800374gnss_err_enum mbtk_gnss_open(int type, int timeout)
375{
376 if(gnss_cli_fd < 0) {
377 LOGW("GNSS client not inited.");
378 return GNSS_ERR_UNKNOWN;
379 }
380
381 if(gnss_busy) {
382 LOGE("BUSY");
383 return GNSS_ERR_BUSY;
384 } else {
385 gnss_result = GNSS_ERR_OK;
386 gnss_busy = TRUE;
387 if(timeout > 0) {
388 mbtk_timer_set(gnss_timer_cb, timeout * 1000);
389 }
390
391 // gnss_init:x
392 char cmd[32] = {0};
393 snprintf(cmd, sizeof(cmd), "gnss_init:%d", type);
394 sock_write(gnss_cli_fd, cmd, strlen(cmd));
395
396 pthread_mutex_lock(&gnss_mutex);
397 pthread_cond_wait(&gnss_cond, &gnss_mutex);
398 pthread_mutex_unlock(&gnss_mutex);
399
400 gnss_busy = FALSE;
401
402 return gnss_result;
403 }
404}
405
406gnss_err_enum mbtk_gnss_close(int timeout)
407{
408 if(gnss_cli_fd < 0) {
409 LOGW("GNSS client not inited.");
410 return GNSS_ERR_UNKNOWN;
411 }
412
413 if(gnss_busy) {
414 LOGE("BUSY");
415 return GNSS_ERR_BUSY;
416 } else {
417 gnss_result = GNSS_ERR_OK;
418 gnss_busy = TRUE;
419 if(timeout > 0) {
420 mbtk_timer_set(gnss_timer_cb, timeout * 1000);
421 }
422
423 // gnss_deinit
424 char *cmd = "gnss_deinit";
425 sock_write(gnss_cli_fd, cmd, strlen(cmd));
426
427 pthread_mutex_lock(&gnss_mutex);
428 pthread_cond_wait(&gnss_cond, &gnss_mutex);
429 pthread_mutex_unlock(&gnss_mutex);
430
431 gnss_busy = FALSE;
432
433 return gnss_result;
434 }
435}
436
437
438gnss_err_enum mbtk_gnss_setting(const char *setting_cmd, int timeout)
439{
440 if(gnss_cli_fd < 0) {
441 LOGW("GNSS client not inited.");
442 return GNSS_ERR_UNKNOWN;
443 }
444
445 if(gnss_busy) {
446 LOGE("BUSY");
447 return GNSS_ERR_BUSY;
448 } else {
449 gnss_result = GNSS_ERR_OK;
450 gnss_busy = TRUE;
451 if(timeout > 0) {
452 mbtk_timer_set(gnss_timer_cb, timeout * 1000);
453 }
454
455 // gnss_setting:cmd
456 char cmd[32] = {0};
457 snprintf(cmd, sizeof(cmd), "gnss_setting:%s", setting_cmd);
458 sock_write(gnss_cli_fd, cmd, strlen(cmd));
459
460 pthread_mutex_lock(&gnss_mutex);
461 pthread_cond_wait(&gnss_cond, &gnss_mutex);
462 pthread_mutex_unlock(&gnss_mutex);
463
464 gnss_busy = FALSE;
465
466 return gnss_result;
467 }
468}
469
470gnss_err_enum mbtk_gnss_dl(const char *fw_path, int timeout)
471{
472 if(gnss_cli_fd < 0) {
473 LOGW("GNSS client not inited.");
474 return GNSS_ERR_UNKNOWN;
475 }
476
477 if(gnss_busy) {
478 LOGE("BUSY");
479 return GNSS_ERR_BUSY;
480 } else {
481 gnss_result = GNSS_ERR_OK;
482 gnss_busy = TRUE;
483 if(timeout > 0) {
484 mbtk_timer_set(gnss_timer_cb, timeout * 1000);
485 }
486
487 // gnss_dl:fw_name
488 char cmd[32] = {0};
489 snprintf(cmd, sizeof(cmd), "gnss_dl:%s", fw_path);
490 sock_write(gnss_cli_fd, cmd, strlen(cmd));
491
492 pthread_mutex_lock(&gnss_mutex);
493 pthread_cond_wait(&gnss_cond, &gnss_mutex);
494 pthread_mutex_unlock(&gnss_mutex);
495
496 gnss_busy = FALSE;
497
498 return gnss_result;
499 }
500}
501
b.liuc223a942024-07-18 15:44:12 +0800502/**
503* Set GNSS data callback.
504*
505* gnss_ind : MBTK_GNSS_IND_LOCATION / MBTK_GNSS_IND_NMEA
506* timeout : Timeout with second.
507*
508*/
b.liue77ac3a2024-07-17 17:36:57 +0800509gnss_err_enum mbtk_gnss_ind_set(uint32 gnss_ind, int timeout)
510{
511 if(gnss_cli_fd < 0) {
512 LOGW("GNSS client not inited.");
513 return GNSS_ERR_UNKNOWN;
514 }
515
516 if(gnss_busy) {
517 LOGE("BUSY");
518 return GNSS_ERR_BUSY;
519 } else {
520 gnss_result = GNSS_ERR_OK;
521 gnss_busy = TRUE;
522 if(timeout > 0) {
523 mbtk_timer_set(gnss_timer_cb, timeout * 1000);
524 }
525
526 // gnss_ind:ind_type
527 char cmd[32] = {0};
528 snprintf(cmd, sizeof(cmd), "gnss_ind:%d", gnss_ind);
529 sock_write(gnss_cli_fd, cmd, strlen(cmd));
530
531 pthread_mutex_lock(&gnss_mutex);
532 pthread_cond_wait(&gnss_cond, &gnss_mutex);
533 pthread_mutex_unlock(&gnss_mutex);
534
535 gnss_busy = FALSE;
536
537 return gnss_result;
538 }
539}
540