[Feature] add GA346 baseline version
Change-Id: Ic62933698569507dcf98240cdf5d9931ae34348f
diff --git a/src/connectivity/gps/2.0/geofenceinf_example/geofence.h b/src/connectivity/gps/2.0/geofenceinf_example/geofence.h
new file mode 100755
index 0000000..f4c5d09
--- /dev/null
+++ b/src/connectivity/gps/2.0/geofenceinf_example/geofence.h
@@ -0,0 +1,178 @@
+#ifndef __GEOFENCE_H__
+#define __GEOFENCE_H__
+
+#pragma pack(push)
+#pragma pack(4)
+
+typedef struct {
+ bool geofence_support;
+}mtk_geofence_client_capability;
+
+typedef struct {
+ bool geofence_support;
+}mtk_geofence_server_capability;
+
+typedef enum {
+ GEOFENCE_CLIENT_CAP,//geofence client capability
+ INIT_GEOFENCE,//Reserved
+ ADD_GEOFENCE_AREA,
+ PAUSE_GEOFENCE,//Reserved
+ RESUME_GEOFENCE,//Reserved
+ REMOVE_GEOFENCE,
+ RECOVER_GEOFENCE,//Reserved
+ CLEAR_GEOFENCE,
+ QUERY_GEOFENCE_NUM
+} mtk_geofence_command;
+
+typedef enum {
+ GEOFENCE_UNKNOWN = 0,
+ GEOFENCE_ENTERED = 1,
+ GEOFENCE_EXITED = 2,
+} mtk_geofence_status;
+
+typedef int mtk_monitor_transition;
+#define MTK_GEOFENCE_ENTER 0x01
+#define MTK_GEOFENCE_EXIT 0x02
+#define MTK_GEOFENCE_UNCERTAIN 0x04//Reserved
+
+typedef struct mtk_geofence_area {
+ double latitude;
+ double longitude;
+ double radius;
+ int latest_state; /*current state(mtk_geofence_status), most cases is GEOFENCE_UNKNOWN*/
+ mtk_monitor_transition monitor_transition; /*bitwise , MTK_GEOFENCE_EXIT/MTK_GEOFENCE_ENTER/MTK_GEOFENCE_UNCERTAIN*/
+ int unknown_timer;/*The time limit after which the UNCERTAIN transition should be triggered. This paramter is defined in milliseconds.*/
+} mtk_geofence_property;
+
+typedef struct mtk_geofence_alert {
+ int id;
+ int alert_state;//mtk_geofence_status
+ double latitude;
+ double longitude;
+ double altitude;
+ double speed;
+ double heading;
+ int h_acc;
+ int h_err_majoraxis;
+ int h_err_minoraxis;
+ int h_err_angle;
+ int hor_conf;
+ double pdop;
+ double hdop;
+ double vdop;
+}mtk_geofence_alert;
+
+typedef struct mtk_gnss_tracking_status {
+ int status; //GNSS service tracking OK = 0,GNSS service tracking failure = -1
+ int year;
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+}mtk_gnss_tracking_status;
+
+typedef struct {
+ void (*geofence_connection_broken)();
+ void (*geofence_fence_alert_callback)(mtk_geofence_alert *ptr);
+ void (*geofence_tracking_status_callback)(mtk_gnss_tracking_status *ptr);
+ void (*geofence_capability_update)(mtk_geofence_server_capability *cap);
+}mtk_geofence_callback;
+
+#define MTK_GFC_SUCCESS (0)
+#define MTK_GFC_ERROR (-1)
+
+#pragma pack(pop)
+
+/*****************************************************************************
+ * FUNCTION
+ * geofenceinf_add_geofence
+ * DESCRIPTION
+ * add one geofence
+ * PARAMETERS
+ * fence: fence detail information
+ * RETURNS
+ * Success: geofence id, >=1
+ * Fail: -1, create fence fail. -2, insufficient_memory. -3,too many fences
+ *****************************************************************************/
+int geofenceinf_add_geofence(mtk_geofence_property *fence);
+
+/*****************************************************************************
+ * FUNCTION
+ * geofenceinf_remove_geofence
+ * DESCRIPTION
+ * romve one geofence
+ * PARAMETERS
+ * geofence_id: geofence id
+ * RETURNS
+ * MTK_GFC_ERROR
+ * MTK_GFC_SUCCESS
+ *****************************************************************************/
+int geofenceinf_remove_geofence(const int geofence_id) ;
+
+/*****************************************************************************
+ * FUNCTION
+ * geofenceinf_clear_geofences
+ * DESCRIPTION
+ * clear all geofences
+ * PARAMETERS
+ * RETURNS
+ * MTK_GFC_ERROR
+ * MTK_GFC_SUCCESS
+ *****************************************************************************/
+int geofenceinf_clear_geofences(void) ;
+
+/*****************************************************************************
+ * FUNCTION
+ * geofenceinf_query_geofences_num
+ * DESCRIPTION
+ * query geofence numbers that geofence feature support
+ * PARAMETERS
+ * RETURNS
+ * MTK_GFC_ERROR(-1)
+ * number: geofence numbers, >= 1
+ *****************************************************************************/
+int geofenceinf_query_geofences_num(void);
+
+/*****************************************************************************
+ * FUNCTION
+ * geofenceinf_client_register
+ * DESCRIPTION
+ * register geofence client
+ * PARAMETERS
+ * name: client name
+ * mtk_geofence_callback *callback: data messsage callback function
+ * RETURNS
+ * MTK_GFC_ERROR(-1), means error
+ * fd:file descriptor
+ *****************************************************************************/
+int geofenceinf_client_register(const char* name, mtk_geofence_callback *callback);
+
+/*****************************************************************************
+ * FUNCTION
+ * geofenceinf_client_capability_config
+ * DESCRIPTION
+ * config client capability, and send to geofence server
+ * PARAMETERS
+ * cap: client capability
+ * RETURNS
+ * MTK_GFC_ERROR
+ * MTK_GFC_SUCCESS
+ *****************************************************************************/
+int geofenceinf_client_capability_config(mtk_geofence_client_capability *cap);
+
+/*****************************************************************************
+ * FUNCTION
+ * mnl2geofence_hdlr
+ * DESCRIPTION
+ * mnl to geofence adaptor handle function
+ * PARAMETERS
+ * fd:file descriptor
+ * mtk_geofence_callback *callback: data messsage callback function
+ * RETURNS
+ * MTK_GFC_ERROR
+ * MTK_GFC_SUCCESS
+ *****************************************************************************/
+int mnl2geofence_hdlr (int fd, mtk_geofence_callback *callback);
+
+#endif
diff --git a/src/connectivity/gps/2.0/geofenceinf_example/geofence_adapt_mock.c b/src/connectivity/gps/2.0/geofenceinf_example/geofence_adapt_mock.c
new file mode 100755
index 0000000..6e78755
--- /dev/null
+++ b/src/connectivity/gps/2.0/geofenceinf_example/geofence_adapt_mock.c
@@ -0,0 +1,699 @@
+#include <string.h> //strstr
+#include <dirent.h>
+#include <sys/stat.h> //mkdir
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stddef.h> // offsetof
+#include <stdarg.h>
+#include <unistd.h> // usleep
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <arpa/inet.h> // inet_addr
+#include <sys/un.h> // struct sockaddr_un
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <signal.h> //struct sigevent
+#include <string.h> //memset, strncpy
+#include <netdb.h> //struct addrinfo
+#include <sys/types.h> //gettid
+#include <netinet/in.h> //struct sockaddr_in
+#include <netinet/tcp.h> //TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT
+#include <netinet/ip.h> //IPTOS_LOWDELAY
+#include <sys/epoll.h> //epoll_create
+#include <semaphore.h> //sem_t
+#include <inttypes.h> //PRId64
+#include <stdbool.h>
+#include "geofence.h"
+
+#define GEOFENCEADP_VERSION "2.02"
+
+#define GEOFENCE_USER_NAME "mtk_geofence_adaptor"
+//---------------------------------- channel -------------------------------------------
+// LBS EM (client) <-> GNSS ADP (server)
+
+#define LOGD(...) { printf(__VA_ARGS__); printf("\n"); fflush(stdout); }
+#define LOGW(...) { printf("\E[1;35;40m"); printf(__VA_ARGS__); printf("\E[0m"); printf("\n"); fflush(stdout); }
+#define LOGE(...) { printf("\E[1;31;40m"); printf(__VA_ARGS__); printf("\E[0m"); printf("\n"); fflush(stdout); }
+#define LOGI(...) { printf("\E[1;35;40m"); printf(__VA_ARGS__); printf("\E[0m"); printf("\n"); fflush(stdout); }
+
+//--------------------------------------------------------------------------------------------------------
+#define MNLD_STRNCPY(dst,src,size) do{\
+ strncpy((char *)(dst), (src), (size - 1));\
+ (dst)[size - 1] = '\0';\
+ }while(0)
+
+timer_t g_handler_timer;
+
+int tcp_client_fd;
+int epfd;
+char std_in_buff[1024];
+
+typedef void (*timer_routine) (int id);
+
+void msleep(int interval) {
+ usleep(interval * 1000);
+}
+
+// in millisecond
+time_t get_tick() {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ LOGE("clock_gettime failed reason=[%s]", strerror(errno));
+ return -1;
+ }
+ return (ts.tv_sec*1000) + (ts.tv_nsec/1000000);
+}
+
+// in millisecond
+time_t get_time_in_millisecond() {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+ LOGE("get_time_in_millisecond failed reason=[%s]", strerror(errno));
+ return -1;
+ }
+ return ((long long)ts.tv_sec*1000) + ((long long)ts.tv_nsec/1000000);
+}
+
+/*************************************************
+* Timer
+**************************************************/
+// -1 means failure
+//NULL means fail or timerid is returned
+timer_t timer_init(timer_routine cb, int id) {
+ struct sigevent sevp;
+ timer_t timerid;
+
+ memset(&sevp, 0, sizeof(sevp));
+ sevp.sigev_value.sival_int = id;
+ sevp.sigev_notify = SIGEV_THREAD;
+ sevp.sigev_notify_function = (void*)cb;
+
+ if(timer_create(CLOCK_BOOTTIME, &sevp, &timerid) == -1) {
+ LOGE("timer_init() timer_create() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ return NULL;
+ }
+ return timerid;
+}
+
+bool timer_deinit(timer_t timerid) {
+ if(timer_delete(timerid) == -1) {
+ LOGE("timer_deinit() timer_delete() failed, reason=[%s]%d", strerror(errno), errno);
+ return false;
+ }
+ return true;
+}
+
+bool timer_start(timer_t timerid, int milliseconds) {
+ struct itimerspec expire;
+ expire.it_interval.tv_sec = 0;
+ expire.it_interval.tv_nsec = 0;
+ expire.it_value.tv_sec = milliseconds/1000;
+ expire.it_value.tv_nsec = (milliseconds%1000)*1000000;
+ if(timer_settime(timerid, 0, &expire, NULL) == -1) {
+ LOGE("timer_start() timer_settime() failed, reason=[%s]%d", strerror(errno), errno);
+ return false;
+ }
+ return true;
+}
+
+bool timer_stop(timer_t timerid) {
+ return timer_start(timerid, 0);
+}
+
+//-1 means fail or the remaining time is returned
+int64_t timer_get_remaining_time(timer_t timerid) {
+ struct itimerspec ts;
+ if(timer_gettime(timerid, &ts) == -1) {
+ LOGE("timer_get_remaining_time() timer_gettime() failed, reason=[%s]%d", strerror(errno), errno);
+ return -1;
+ }
+ return ((int64_t)ts.it_value.tv_sec * 1000 + ts.it_value.tv_nsec / 1000000);
+}
+
+/*************************************************
+* Epoll
+**************************************************/
+// -1 means failure
+int epoll_add_fd(int epfd, int fd) {
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.data.fd = fd;
+ ev.events = EPOLLIN;
+ // don't set the fd to edge trigger
+ // the some event like accept may be lost if two or more clients are connecting to server at the same time
+ // level trigger is preferred to avoid event lost
+ // do not set EPOLLOUT due to it will always trigger when write is available
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ LOGE("epoll_add_fd() epoll_ctl() failed reason=[%s]%d epfd=%d fd=%d",
+ strerror(errno), errno, epfd, fd);
+ return -1;
+ }
+ return 0;
+}
+
+// -1 failed
+int epoll_add_fd2(int epfd, int fd, uint32_t events) {
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.data.fd = fd;
+ ev.events = events;
+ // don't set the fd to edge trigger
+ // the some event like accept may be lost if two or more clients are connecting to server at the same time
+ // level trigger is preferred to avoid event lost
+ // do not set EPOLLOUT due to it will always trigger when write is available
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ LOGE("epoll_add_fd2() epoll_ctl() failed reason=[%s]%d epfd=%d fd=%d",
+ strerror(errno), errno, epfd, fd);
+ return -1;
+ }
+ return 0;
+}
+
+int epoll_del_fd(int epfd, int fd) {
+ struct epoll_event ev;
+ int ret;
+
+ if (epfd == -1)
+ return -1;
+
+ ev.events = EPOLLIN;
+ ev.data.fd = fd;
+ do {
+ ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+// -1 failed
+int epoll_mod_fd(int epfd, int fd, uint32_t events) {
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.data.fd = fd;
+ ev.events = events;
+ if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) == -1) {
+ LOGE("epoll_mod_fd() epoll_ctl() failed reason=[%s]%d epfd=%d fd=%d",
+ strerror(errno), errno, epfd, fd);
+ return -1;
+ }
+ return 0;
+}
+
+/*************************************************
+* Local UDP Socket
+**************************************************/
+// -1 means failure
+int socket_bind_udp(const char* path) {
+ int fd;
+ struct sockaddr_un addr;
+
+ fd = socket(PF_LOCAL, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ LOGE("socket_bind_udp() socket() failed reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+ LOGD("fd=%d,path=%s\n", fd, path);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_path[0] = 0;
+ MNLD_STRNCPY(addr.sun_path + 1, path,sizeof(addr.sun_path) - 1);
+ addr.sun_family = AF_UNIX;
+ unlink(path);
+
+ if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ LOGE("socket_bind_udp() bind() failed path=[%s] reason=[%s]%d",
+ addr.sun_path+1, strerror(errno), errno);
+ close(fd);
+ return -1;
+ }else
+ LOGI("bind ok path=[%s]", addr.sun_path+1);
+ return fd;
+}
+
+// -1 means failure
+int socket_set_blocking(int fd, int blocking) {
+ if (fd < 0) {
+ LOGE("socket_set_blocking() invalid fd=%d", fd);
+ return -1;
+ }
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1) {
+ LOGE("socket_set_blocking() fcntl() failed invalid flags=%d reason=[%s]%d",
+ flags, strerror(errno), errno);
+ return -1;
+ }
+
+ flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
+ return (fcntl(fd, F_SETFL, flags) == 0) ? 0 : -1;
+}
+
+// -1 means failure
+int safe_sendto(const char* path, const char* buff, int len) {
+ int ret = 0;
+ struct sockaddr_un addr;
+ int retry = 10;
+ int fd = socket(PF_LOCAL, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ LOGE("safe_sendto() socket() failed reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1){
+ LOGE("fcntl failed reason=[%s]%d",
+ strerror(errno), errno);
+
+ close(fd);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_path[0] = 0;
+ MNLD_STRNCPY(addr.sun_path + 1, path,sizeof(addr.sun_path) - 1);
+ addr.sun_family = AF_UNIX;
+
+ while ((ret = sendto(fd, buff, len, 0,
+ (const struct sockaddr *)&addr, sizeof(addr))) == -1) {
+ if (errno == EINTR) {
+ LOGE("errno==EINTR\n");
+ continue;
+ }
+ if (errno == EAGAIN) {
+ if (retry-- > 0) {
+ usleep(100 * 1000);
+ LOGE("errno==EAGAIN\n");
+ continue;
+ }
+ }
+ LOGE("safe_sendto() sendto() failed path=[%s] ret=%d reason=[%s]%d",
+ path, ret, strerror(errno), errno);
+ break;
+ }
+
+ close(fd);
+ return ret;
+}
+
+// -1 means failure
+int safe_recvfrom(int fd, char* buff, int len) {
+ int ret = 0;
+ int retry = 10;
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1){
+ LOGE("fcntl failed reason=[%s]%d",
+ strerror(errno), errno);
+
+ close(fd);
+ return -1;
+ }
+
+ while ((ret = recvfrom(fd, buff, len, 0,
+ NULL, NULL)) == -1) {
+ LOGW("safe_recvfrom() ret=%d len=%d", ret, len);
+ if (errno == EINTR) continue;
+ if (errno == EAGAIN) {
+ if (retry-- > 0) {
+ usleep(100 * 1000);
+ continue;
+ }
+ }
+ LOGE("safe_recvfrom() recvfrom() failed reason=[%s]%d",
+ strerror(errno), errno);
+ break;
+ }
+ return ret;
+}
+
+/******************************************************************************
+* Socket
+******************************************************************************/
+
+//-1 means fail or serverfd is returned
+int socket_tcp_server_bind_local(bool abstract, const char* name) {
+ int fd;
+ int size;
+ struct sockaddr_un addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ size = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
+ if(abstract) {
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, strlen(name));
+ } else {
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+ if(unlink(addr.sun_path) == -1) {
+ LOGW("socket_tcp_server_bind_local() unlink() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ }
+ }
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(fd == -1) {
+ LOGE("socket_tcp_server_bind_local() socket() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+ if(bind(fd, (struct sockaddr*)&addr, size) == -1) {
+ LOGE("socket_tcp_server_bind_local() bind() failed, abstruct=%d name=[%s] reason=[%s]%d",
+ abstract, name, strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+ if(listen(fd, 5) == -1) {
+ LOGW("socket_tcp_server_bind_local() listen() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ }
+ return fd;
+}
+
+//-1 means fail or new clientfd is returned
+int socket_tcp_server_new_connect(int serverfd) {
+ int newfd;
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+
+ newfd = accept(serverfd, (struct sockaddr*)&addr, &len);
+ if(newfd == -1) {
+ LOGE("socket_tcp_server_new_connect() accept() failed, serverfd=%d reason=[%s]%d",
+ serverfd, strerror(errno), errno);
+ return -1;
+ }
+ return newfd;
+}
+
+//-1 means fail or serverfd is returned
+int socket_tcp_client_connect_local(bool abstract, const char* name) {
+ int fd;
+ int size;
+ struct sockaddr_un addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ size = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
+ if(abstract) {
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, strlen(name));
+ } else {
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+ if(unlink(addr.sun_path) == -1) {
+ LOGW("socket_tcp_client_connect_local() unlink() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ }
+ }
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(fd == -1) {
+ LOGE("socket_tcp_client_connect_local() socket() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+ if(connect(fd, (struct sockaddr*)&addr, size) == -1) {
+ LOGE("socket_tcp_client_connect_local() connect() failed, abstruct=%d name=[%s] reason=[%s]%d",
+ abstract, name, strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+
+//-1 means fail or serverfd is returned
+int socket_udp_server_bind_local(bool abstract, const char* name) {
+ int fd;
+ int size;
+ struct sockaddr_un addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ size = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
+ if(abstract) {
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, strlen(name));
+ } else {
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+ if(unlink(addr.sun_path) == -1) {
+ LOGW("socket_udp_server_bind_local() unlink() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ }
+ }
+ fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(fd == -1) {
+ LOGE("socket_udp_server_bind_local() socket() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+ if(bind(fd, (struct sockaddr*)&addr, size) == -1) {
+ LOGE("socket_udp_server_bind_local() bind() failed, abstract=%d name=[%s] reason=[%s]%d",
+ abstract, name, strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+//-1 means fail or clientfd is returned
+int socket_udp_client_create_local(bool abstract, const char* name) {
+ int fd;
+ int size;
+ struct sockaddr_un addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ size = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
+ if(abstract) {
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, strlen(name));
+ } else {
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+ }
+ fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(fd == -1) {
+ LOGE("socket_udp_client_create_local() socket() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+ if(connect(fd, (struct sockaddr*)&addr, size) == -1) {
+ LOGE("socket_udp_client_create_local() connect() failed, abstract=%d name=[%s] reason=[%s]%d",
+ abstract, name, strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+bool socket_udp_exist_local(bool abstract, const char* name) {
+ int fd;
+ int size;
+ struct sockaddr_un addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ size = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
+ if(abstract) {
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, strlen(name));
+ } else {
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+ }
+ fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(fd == -1) {
+ LOGE("socket_udp_is_bind_local() socket() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ return false;
+ }
+ if(connect(fd, (struct sockaddr*)&addr, size) == -1) {
+ close(fd);
+ return false;
+ }
+ close(fd);
+ return true;
+
+}
+
+void geofenceadp_timer_handler_protection(int id) {
+ LOGE("geofenceadp_timer_handler_protection() timeout");
+}
+
+void geofenceadp_add_geofence(void)
+{
+ mtk_geofence_property fence;
+ int fence_id;
+ memset(&fence, 0, sizeof(fence));
+ fence.latitude = 24.123456;
+ fence.longitude = 121.012345;
+ fence.radius = 200.0;
+ fence.latest_state = GEOFENCE_UNKNOWN;
+ fence.monitor_transition = MTK_GEOFENCE_ENTER;
+ fence.unknown_timer = 100000;
+ fence_id = geofenceinf_add_geofence(&fence);
+ LOGD("geofenceadp_add_geofence success id=%d", fence_id);
+}
+
+void geofenceadp_delete_geofence(int id)
+{
+ if (geofenceinf_remove_geofence(id) < 0){
+ LOGE("geofenceadp_delete_geofence fail:%d", id);
+ } else {
+ LOGD("geofenceadp_delete_geofence success:%d", id);
+ }
+}
+
+void geofenceadp_clear_geofence(void)
+{
+ if (geofenceinf_clear_geofences() < 0){
+ LOGE("geofenceadp_clear_geofence fail");
+ } else {
+ LOGD("geofenceadp_clear_geofence success");
+ }
+}
+
+void geofenceadp_query_geofence_num(void)
+{
+ int fence_num;
+ fence_num = geofenceinf_query_geofences_num();
+ LOGD("geofenceadp_query_geofence_num success number=%d", fence_num);
+}
+
+void geofenceadp_std_handler_process(char *buffer) {
+ char buff[1024];
+
+ MNLD_STRNCPY(buff, buffer, sizeof(buff));
+ if (strncmp(buff, "addfence", strlen("addfence")) == 0){
+ geofenceadp_add_geofence();
+ } else if (strncmp(buff, "clearfence", strlen("clearfence")) == 0){
+ geofenceadp_clear_geofence();
+ } else if (strncmp(buff, "queryfence", strlen("queryfence")) == 0){
+ geofenceadp_query_geofence_num();
+ } else if (strncmp(buff, "delfence", strlen("delfence")) == 0){
+ int id;
+ id = atoi(&buff[9]);
+ geofenceadp_delete_geofence(id);
+ }
+}
+
+void geofenceadp_connection_broken()
+{
+ LOGD("geofenceadp_connection_broken");
+}
+
+void geofenceadp_fence_alert(mtk_geofence_alert *alert)
+{
+ LOGD("geofenceadp_fence_alert");
+}
+
+void geofenceadp_tracking_status(mtk_gnss_tracking_status *status)
+{
+ LOGD("geofenceadp_tracking_status");
+}
+
+void geofenceadp_capability_update(mtk_geofence_server_capability *cap)
+{
+ LOGD("geofenceadp_capability_update server capability update");
+}
+
+static mtk_geofence_callback geofence_callbacks = {
+ geofenceadp_connection_broken,
+ geofenceadp_fence_alert,
+ geofenceadp_tracking_status,
+ geofenceadp_capability_update
+};
+
+
+//--------------------------------------------------------------------------------------------------------
+
+void geofenceadp_epoll_client_disconnect_server(int fd) {
+ LOGD("geofenceadp_epoll_client_disconnect_server fd=%d", fd);
+ epoll_del_fd(epfd, fd);
+}
+
+int geofenceadp_epoll_stdin_hdlr(int fd) {
+ char buff[2048] = {0};
+ int ret = read(fd, buff, sizeof(buff));
+ if(ret == -1) {
+ LOGE("STDIN read() failed, fd=%d reason=[%s]%d", fd, strerror(errno), errno);
+ return -1;
+ }
+ LOGD("stdin has data [%s]", buff);
+ geofenceadp_std_handler_process(buff);
+
+ return 0;
+}
+
+void geofencedp_mock_start() {
+ LOGD("gnssadp_mock_start() ver=%s", GEOFENCEADP_VERSION);
+
+ //memset(&client_ctx, 0, sizeof(geofence_client_ctx));
+
+ tcp_client_fd = geofenceinf_client_register(GEOFENCE_USER_NAME, &geofence_callbacks);
+ if(tcp_client_fd == -1) {
+ LOGE("socket_tcp_client_connect_local(true, GEOFENCEADP_MNL_SOCKET) failed");
+ exit(1);
+ } else {
+ mtk_geofence_client_capability client_cap;
+ client_cap.geofence_support = true;
+ geofenceinf_client_capability_config(&client_cap);
+ }
+ g_handler_timer = timer_init(geofenceadp_timer_handler_protection, 0);
+
+ #define MAX_EPOLL_EVENT 10
+ struct epoll_event events[MAX_EPOLL_EVENT];
+ epfd = epoll_create(MAX_EPOLL_EVENT);
+ if(epfd == -1) {
+ LOGE("epoll_create() failed");
+ exit(1);
+ }
+
+ epoll_add_fd2(epfd, STDIN_FILENO, EPOLLIN);
+ epoll_add_fd2(epfd, tcp_client_fd, EPOLLIN);
+
+ while(true) {
+ int i, n;
+ n = epoll_wait(epfd, events, MAX_EPOLL_EVENT, -1);
+ if(n == -1) {
+ if(errno == EINTR) {
+ continue;
+ } else {
+ LOGE("epoll_wait() failed reason=[%s]%d", strerror(errno), errno);
+ exit(1);
+ }
+ }
+
+ for(i = 0; i < n; i++) {
+ int fd = events[i].data.fd;
+ timer_start(g_handler_timer, 30 * 1000);
+ if(fd == STDIN_FILENO) {
+ if(events[i].events & EPOLLIN) {
+ if (geofenceadp_epoll_stdin_hdlr(fd) == -1){
+ goto exit;
+ }
+ }
+ } else if(fd == tcp_client_fd) {
+ if(events[i].events & EPOLLIN) {
+ mnl2geofence_hdlr(fd, &geofence_callbacks);
+ }
+ } else {
+ LOGE("unexpected fd=%d coming", fd);
+ }
+ timer_stop(g_handler_timer);
+ }
+ }
+
+exit:
+ close(epfd);
+ close(tcp_client_fd);
+ timer_deinit(g_handler_timer);
+}
+
+int main() {
+ geofencedp_mock_start();
+ return 0;
+}
+
diff --git a/src/connectivity/gps/2.0/geofenceinf_example/geofenceinf.c b/src/connectivity/gps/2.0/geofenceinf_example/geofenceinf.c
new file mode 100755
index 0000000..c240d9f
--- /dev/null
+++ b/src/connectivity/gps/2.0/geofenceinf_example/geofenceinf.c
@@ -0,0 +1,1166 @@
+#include <string.h> //strstr
+#include <dirent.h>
+#include <sys/stat.h> //mkdir
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stddef.h> // offsetof
+#include <stdarg.h>
+#include <unistd.h> // usleep
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <arpa/inet.h> // inet_addr
+#include <sys/un.h> // struct sockaddr_un
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <signal.h> //struct sigevent
+#include <string.h> //memset, strncpy
+#include <netdb.h> //struct addrinfo
+#include <sys/types.h> //gettid
+#include <netinet/in.h> //struct sockaddr_in
+#include <netinet/tcp.h> //TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT
+#include <netinet/ip.h> //IPTOS_LOWDELAY
+#include <sys/epoll.h> //epoll_create
+#include <semaphore.h> //sem_t
+#include <inttypes.h> //PRId64
+#include <stdbool.h>
+#include "geofence.h"
+//------------------MTK LBS Utility---------------------------------------------------
+#ifndef LOGD
+#define LOGD(...) { printf(__VA_ARGS__); printf("\n"); fflush(stdout); }
+#define LOGW(...) { printf("\E[1;35;40m"); printf(__VA_ARGS__); printf("\E[0m"); printf("\n"); fflush(stdout); }
+#define LOGE(...) { printf("\E[1;31;40m"); printf(__VA_ARGS__); printf("\E[0m"); printf("\n"); fflush(stdout); }
+#define LOGI(...) { printf("\E[1;35;40m"); printf(__VA_ARGS__); printf("\E[0m"); printf("\n"); fflush(stdout); }
+#endif
+
+#define GEOFENCEADP_MNL_TCP_DATA "mtk_geofenceadp_mnl_data"
+#define GEOFENCEADP_MNL_TCP_CONTROL "mtk_geofenceadp_mnl_control"
+
+//#define AT_COMMAND_PRINT
+
+#define MTK_ADD_GEOFENCE_SUCCESS 0
+#define MTK_ADD_GEOFENCE_ERROR -1
+#define MTK_ADD_GEOFENCE_INSUFFICIENT_MEM -2
+#define MTK_ADD_GEOFENCE_TOO_MANY -3
+
+#define MNLD_STRNCPY(dst,src,size) do{\
+ strncpy((char *)(dst), (src), (size - 1));\
+ (dst)[size - 1] = '\0';\
+ }while(0)
+
+#define GEOFENCE_BUFF_SIZE (1 * 1024)
+#define GEOFENCE_DATAPATH_SIZE (10*1024)
+
+typedef struct {
+ int type; //MTK_GFC_COMMAND_T
+ unsigned int length;
+} mtk_geofence_msg;
+
+typedef struct {
+ bool geofence_support;
+ int server_data_fd;
+}mtk_geofence_server_init_msg;
+
+typedef enum {
+ GEOFENCE_SERVER_CAP,//geofence server capability
+ EXCUTE_RESULT,
+ GEOFENCE_NUM,
+ GEOFENCE_RESPONSE_INFO,
+ GEOFENCE_ALERT_INFO,
+ GNSS_TRACKING_STATUS,
+} mtk_geofence_ret_command;
+
+typedef struct mtk_geofence_create_status {
+ int createstat;// success : 0, error : -1, insufficient_memory : -2, too many fences : -3
+ int id;
+}mtk_geofence_create_status;
+
+typedef struct {
+ int cmdtype;//mtk_geofence_command
+ int result;
+} mtk_geofence_result;
+
+typedef struct cyclical_buffer{
+ char *next_write;
+ char *next_read;
+ char *start_buffer;
+ char *end_buffer;
+ int buffer_size;
+} cyclical_buffer_t;
+
+static char geofence_raw_data[GEOFENCE_DATAPATH_SIZE] = {0};
+static cyclical_buffer_t g_cyclical_buffer; // io - cyclic buffer
+int server_data_fd = -1;
+
+//-1 means fail or serverfd is returned
+static int geofenceinf_socket_tcp_client_connect_local(bool abstract, const char* name) {
+ int fd;
+ int size;
+ struct sockaddr_un addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ size = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
+ if(abstract) {
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, strlen(name));
+ } else {
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+ if(unlink(addr.sun_path) == -1) {
+ LOGW("geofenceinf_socket_tcp_client_connect_local() unlink() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ }
+ }
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(fd == -1) {
+ LOGE("geofenceinf_socket_tcp_client_connect_local() socket() failed, reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+ if(connect(fd, (struct sockaddr*)&addr, size) == -1) {
+ LOGE("geofenceinf_socket_tcp_client_connect_local() connect() failed, abstruct=%d name=[%s] reason=[%s]%d",
+ abstract, name, strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+void geofenceinf_buffer_initialize
+ ( cyclical_buffer_t *buffer, // buffer to initialize
+ unsigned int buffer_size ) // size of buffer to create
+{
+ // Set up buffer manipulation pointers
+ // end_buffer points to the next byte after the buffer
+ buffer->end_buffer = buffer->start_buffer + buffer_size;
+ buffer->next_read = buffer->start_buffer;
+ buffer->next_write = buffer->start_buffer;
+ buffer->buffer_size = buffer_size;
+ return;
+}
+
+int geofenceinf_check_fence_vadility(mtk_geofence_property *fence) {
+ if ((fence->latest_state != GEOFENCE_ENTERED)
+ && (fence->latest_state != GEOFENCE_EXITED)
+ && (fence->latest_state != GEOFENCE_UNKNOWN)){
+ LOGE("geofenceinf_check_fence_vadility latest_state:%d fail", fence->latest_state);
+ return MTK_GFC_ERROR;
+ }
+
+ if (!(fence->monitor_transition & MTK_GEOFENCE_ENTER) && !(fence->monitor_transition & MTK_GEOFENCE_EXIT)){
+ LOGE("geofenceinf_check_fence_vadility monitor_transition:%d fail", fence->monitor_transition);
+ return MTK_GFC_ERROR;
+ }
+
+ return MTK_GFC_SUCCESS;
+}
+
+int geofenceinf_socket_set_blocking(int fd, int blocking) {
+ if (fd < 0) {
+ LOGE("geofenceinf_socket_set_blocking() invalid fd=%d", fd);
+ return -1;
+ }
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1) {
+ LOGE("geofenceinf_socket_set_blocking() fcntl() failed invalid flags=%d reason=[%s]%d",
+ flags, strerror(errno), errno);
+ return -1;
+ }
+
+ flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
+ return (fcntl(fd, F_SETFL, flags) == 0) ? 0 : -1;
+}
+
+int geofenceinf_epoll_add_fd2(int epfd, int fd, uint32_t events) {
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.data.fd = fd;
+ ev.events = events;
+ // don't set the fd to edge trigger
+ // the some event like accept may be lost if two or more clients are connecting to server at the same time
+ // level trigger is preferred to avoid event lost
+ // do not set EPOLLOUT due to it will always trigger when write is available
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ LOGE("epoll_add_fd2() epoll_ctl() failed reason=[%s]%d epfd=%d fd=%d",
+ strerror(errno), errno, epfd, fd);
+ return -1;
+ }
+ return 0;
+}
+
+int geofenceinf_socket_bind_udp(const char* path) {
+ int fd;
+ struct sockaddr_un addr;
+
+ fd = socket(PF_LOCAL, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ LOGE("socket_bind_udp() socket() failed reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+ LOGD("fd=%d,path=%s", fd, path);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_path[0] = 0;
+ MNLD_STRNCPY(addr.sun_path + 1, path,sizeof(addr.sun_path) - 1);
+ addr.sun_family = AF_UNIX;
+ unlink(addr.sun_path);
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ LOGE("socket_bind_udp() bind() failed path=[%s] reason=[%s]%d",
+ path, strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+
+// -1 means failure
+int geofenceinf_safe_sendto(const char* path, const char* buff, int len) {
+ int ret = 0;
+ struct sockaddr_un addr;
+ int retry = 10;
+ int fd = socket(PF_LOCAL, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ LOGE("safe_sendto() socket() failed reason=[%s]%d",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1){
+ LOGE("fcntl failed reason=[%s]%d",
+ strerror(errno), errno);
+
+ close(fd);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_path[0] = 0;
+ MNLD_STRNCPY(addr.sun_path + 1, path,sizeof(addr.sun_path) - 1);
+ addr.sun_family = AF_UNIX;
+
+ while ((ret = sendto(fd, buff, len, 0,
+ (const struct sockaddr *)&addr, sizeof(addr))) == -1) {
+ if (errno == EINTR) continue;
+ if (errno == EAGAIN) {
+ if (retry-- > 0) {
+ usleep(100 * 1000);
+ continue;
+ }
+ }
+ LOGE("safe_sendto() sendto() failed path=[%s] ret=%d reason=[%s]%d",
+ path, ret, strerror(errno), errno);
+ break;
+ }
+
+ close(fd);
+ return ret;
+}
+void geofenceinf_client_init(void)
+{
+ g_cyclical_buffer.start_buffer = &geofence_raw_data[0];
+ geofenceinf_buffer_initialize(&g_cyclical_buffer, GEOFENCE_DATAPATH_SIZE);
+}
+
+int geofenceinf_get_server_init_msg(int fd, mtk_geofence_callback *callback)
+{
+ int ret;
+ int recv_len = 0;
+ unsigned int read_count = 0, msg_len = 0;
+ char buffer[GEOFENCE_BUFF_SIZE] = {0};
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+ mtk_geofence_msg *prmsg = NULL;
+ mtk_geofence_server_init_msg server_init_msg;
+ mtk_geofence_server_capability cap;
+
+ memset(&server_init_msg, 0, sizeof(mtk_geofence_server_init_msg));
+ //receive geofence server ack capability & server data fd
+ do {
+ ret = read(fd, buffer, GEOFENCE_BUFF_SIZE);
+ if(ret == -1) {
+ LOGW("geofenceinf_get_server_init_msg() read() fd=[%d] failed, reason=[%s]%d", fd, strerror(errno), errno);
+ return ret;
+ } else if(ret == 0) {
+ LOGW("geofenceinf_get_server_init_msg() read() fd=[%d] find the remote side has closed the session", fd);
+ return ret;
+ } else {
+ memcpy((char *)(data + recv_len), buffer, ret);
+ recv_len += ret;
+ read_count++;
+ if ((recv_len >= sizeof(mtk_geofence_msg)) && (msg_len == 0)){
+ prmsg = (mtk_geofence_msg *)&buffer[0];
+ msg_len = prmsg->length;
+ }
+ if (read_count >= 10){
+ LOGW("geofenceinf_get_server_init_msg() read() fd:%d too much counts:%d", fd, read_count);
+ return MTK_GFC_ERROR;
+ }
+ }
+ memset(buffer, 0, GEOFENCE_BUFF_SIZE);
+ } while((recv_len < msg_len) || (msg_len == 0));
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_server_init_msg);
+ prmsg = (mtk_geofence_msg *)&data[0];
+ if (prmsg->length == msg_len){
+ memcpy(&server_init_msg, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_server_init_msg));
+ } else if (prmsg->length > msg_len) {
+ memcpy(&server_init_msg, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_server_init_msg));
+ LOGD("mnl msg len:%d > struct len:%d", prmsg->length, msg_len);
+ } else {
+ memset(buffer, 0, GEOFENCE_BUFF_SIZE);
+ memcpy(buffer, (char*)prmsg, prmsg->length);
+ memset((char *)(buffer + prmsg->length), 0, (msg_len - prmsg->length));
+ memcpy(&server_init_msg, (((char*)buffer)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_server_init_msg));
+ LOGD("mnl msg len:%d < struct len:%d", prmsg->length, msg_len);
+ }
+
+ if (server_init_msg.server_data_fd >= 0){
+ server_data_fd = server_init_msg.server_data_fd;
+ LOGD("geofenceinf_get_server_init_msg:server data fd:%d", server_data_fd);
+ }
+
+ if (callback->geofence_capability_update != NULL){
+ memset(&cap, 0, sizeof(mtk_geofence_server_capability));
+ cap.geofence_support = server_init_msg.geofence_support;
+ callback->geofence_capability_update(&cap);
+ }
+ return MTK_GFC_SUCCESS;
+}
+
+int geofenceinf_client_register(const char* name, mtk_geofence_callback *callback)
+{
+ int fd;
+
+ if ( (fd = geofenceinf_socket_tcp_client_connect_local(true, GEOFENCEADP_MNL_TCP_DATA)) < 0){
+ LOGE("Geofence connect server failed:%d", fd);
+ } else {
+ LOGD("Geofence new client [%s], fd:%d", name, fd);
+ geofenceinf_client_init();
+ if (geofenceinf_get_server_init_msg(fd, callback) < 0){
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+ geofenceinf_socket_set_blocking(fd, 0);
+ }
+
+ return fd;
+}
+
+int geofenceinf_send2mnl(int fd, const char* buff, int len) {
+ int ret = write(fd, buff, len);
+ LOGD("geofence_send2mnl() write():length:%d", len);
+ if(ret == -1) {
+ LOGE("geofence_send2mnl() write() failed, reason=[%s]%d", strerror(errno), errno);
+ }
+ return ret;
+}
+
+int geofenceinf_safe_recv(int fd, char* buff, int len) {
+ int ret = 0;
+ int retry = 10;
+
+ while ((ret = read(fd, buff, len)) == -1) {
+ LOGW("geofenceinf_safe_recv() ret=%d len=%d", ret, len);
+ if (errno == EINTR) continue;
+ if (errno == EAGAIN) {
+ if (retry-- > 0) {
+ usleep(100 * 1000);
+ continue;
+ }
+ }
+ LOGE("geofenceinf_safe_recv() recvfrom() failed reason=[%s]%d",
+ strerror(errno), errno);
+ break;
+ }
+ return ret;
+}
+
+int geofenceinf_control_path_safe_recv(int fd, char* buff, int len, int expect_len) {
+ int ret = 0, ret1 = 0;
+ int retry = 10;
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+
+ ret = read(fd, buff, len);
+ if(ret == -1) {
+ LOGW("geofenceinf_control_path_safe_recv() read() fd=[%d] failed, reason=[%s]%d",
+ fd, strerror(errno), errno);
+ return ret;
+ } else if(ret == 0) {
+ LOGW("geofenceinf_control_path_safe_recv() read() fd=[%d] find the remote side has closed the session", fd);
+ return ret;
+ }
+
+ if (ret < expect_len){
+ //set fd non-blocking, try it again.
+ geofenceinf_socket_set_blocking(fd, 0);
+ while ((ret1 = read(fd, data, GEOFENCE_BUFF_SIZE)) == -1) {
+ LOGW("geofenceinf_control_path_safe_recv() ret=%d", ret1);
+ if (errno == EINTR) continue;
+ if (errno == EAGAIN) {
+ if (retry-- > 0) {
+ usleep(100 * 1000);
+ continue;
+ }
+ }
+ LOGE("geofenceinf_safe_recv() recvfrom() failed reason=[%s]%d",
+ strerror(errno), errno);
+ break;
+ }
+ if ((ret1 > 0) && ((ret + ret1) < len)){
+ memcpy((char *)(buff + ret), data, ret1);
+ ret = ret + ret1;
+ }
+ }
+
+ return ret;
+}
+
+int geofenceinf_geofence_add_result(mtk_geofence_msg *prmsg, mtk_geofence_create_status *fence_ret) {
+ unsigned int msg_len;
+ #ifdef AT_COMMAND_PRINT
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+ #endif
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_create_status);
+ if (prmsg->length == msg_len){
+ memcpy(fence_ret, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_create_status));
+ } else {
+ //LOGE("geofenceinf_geofence_add_result:message len error %d %d",prmsg->length, msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ #ifdef AT_COMMAND_PRINT
+ /*Construct AT command */
+ if (fence_ret->createstat == MTK_ADD_GEOFENCE_SUCCESS){
+ sprintf(data, "+EGEOADDCIRCLE:%d,%d/r/n", fence_ret->createstat, fence_ret->id);
+ //Send AT command
+
+ } else {
+ sprintf(data, "+EGEOADDCIRCLE:%d/r/n", fence_ret->createstat);
+ //Send AT command
+ }
+ LOGD("AT command:%s",data);
+ #endif
+
+ return MTK_GFC_SUCCESS;
+}
+
+int geofenceinf_geofence_remove_result(mtk_geofence_msg *prmsg, mtk_geofence_result *remove_result) {
+ unsigned int msg_len;
+ #ifdef AT_COMMAND_PRINT
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+ #endif
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_result);
+ if (prmsg->length == msg_len){
+ memcpy(remove_result, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_result));
+ } else {
+ //LOGE("geofenceinf_get_remove_result:message len error %d %d",prmsg->length, msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ #ifdef AT_COMMAND_PRINT
+ /*Construct AT command */
+ if (remove_result->result == 0){
+ sprintf(data, "OK/r/n");
+ } else {
+ sprintf(data, "FAIL/r/n");
+ }
+ LOGD("AT command:%s",data);
+ #endif
+
+ return MTK_GFC_SUCCESS;
+}
+
+int geofenceinf_geofence_clear_result(mtk_geofence_msg *prmsg, mtk_geofence_result *clear_result) {
+ unsigned int msg_len;
+ #ifdef AT_COMMAND_PRINT
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+ #endif
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_result);
+ if (prmsg->length == msg_len){
+ memcpy(clear_result, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_result));
+ } else {
+ //LOGE("geofenceinf_geofence_clear_result:message len error %d %d",prmsg->length, msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ #ifdef AT_COMMAND_PRINT
+ /*Construct AT command */
+ if (clear_result->result == 0){
+ sprintf(data, "OK/r/n");
+ } else {
+ sprintf(data, "FAIL/r/n");
+ }
+ LOGD("AT command:%s",data);
+ #endif
+
+ return MTK_GFC_SUCCESS;
+}
+
+int geofenceinf_geofence_get_geofences_num(mtk_geofence_msg *prmsg, int *fence_nums) {
+ unsigned int msg_len;
+ #ifdef AT_COMMAND_PRINT
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+ #endif
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(int);
+ if (prmsg->length == msg_len){
+ memcpy(fence_nums, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(int));
+ } else {
+ //LOGE("geofenceinf_geofence_get_geofences_numgeofenceinf_geofence_get_geofences_numgeofenceinf_geofence_get_geofences_num:message len error %d %d",prmsg->length, msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ #ifdef AT_COMMAND_PRINT
+ /*Construct AT command */
+ sprintf(data, "+EGEOMAX: :%d/r/n", *fence_nums);
+ LOGD("AT command:%s",data);
+ #endif
+
+ return MTK_GFC_SUCCESS;
+}
+
+// GNSS Adaptor --> MNLD Message
+int geofenceinf_add_geofence(mtk_geofence_property *fence) {
+ int ret;
+ mtk_geofence_msg *geo_header = NULL;
+ unsigned int msg_len;
+ int recv_len, expect_len;
+ char buffer[GEOFENCE_BUFF_SIZE] = {0};
+ char geo_data[GEOFENCE_BUFF_SIZE] = {0};
+ mtk_geofence_create_status fence_status;
+ int fd = -1, temp_server_data_fd = -1;
+ mtk_geofence_msg *prmsg = NULL;
+
+ LOGD("geofence_add_geofences");
+ if (server_data_fd < 0){
+ LOGE("geofenceinf_add_geofence:wait server data fd");
+ return -1;
+ } else {
+ temp_server_data_fd = server_data_fd;
+ }
+ /* For geofence recover mechanism */
+ ret = geofenceinf_check_fence_vadility(fence);
+ if(ret < 0) {
+ LOGE("geofenceinf_check_fence_vadility fail");
+ return -1;
+ }
+
+ //construct add fence cmd
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(int) + sizeof(mtk_geofence_property);
+ geo_header = (mtk_geofence_msg *)&geo_data[0];
+ if (msg_len > GEOFENCE_BUFF_SIZE){
+ LOGE("geofenceinf message length too long:%d", msg_len);
+ return MTK_GFC_ERROR;
+ }
+ //construct total message
+ //construct header
+ geo_header->type = ADD_GEOFENCE_AREA;
+ geo_header->length = msg_len;
+ //input server data fd
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg), &temp_server_data_fd, sizeof(int));
+ //input geofence property payload
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg) + sizeof(int), fence, sizeof(mtk_geofence_property));
+
+ //Create TCP client fd, and connect tcp server
+ if ( (fd = geofenceinf_socket_tcp_client_connect_local(true, GEOFENCEADP_MNL_TCP_CONTROL)) < 0){
+ LOGE("geofenceinf_add_geofence:create client fd failed:%d", fd);
+ return -1;
+ }
+
+ ret = geofenceinf_send2mnl(fd, (char *)geo_header, msg_len);
+ if(ret < 0) {
+ LOGE("geofenceinf_add_geofence:send message to mnl failed");
+ close(fd);
+ return -1;
+ }
+
+ //wait ack
+ expect_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_create_status);
+ if ( (recv_len = geofenceinf_control_path_safe_recv(fd, buffer, GEOFENCE_BUFF_SIZE, expect_len)) <= 0){
+ LOGE("geofenceinf_add_geofence:don't recv any data");
+ close(fd);
+ return -1;
+ } else {
+ prmsg = (mtk_geofence_msg *)&buffer[0];
+ ret = geofenceinf_geofence_add_result(prmsg, &fence_status);
+ if (ret == MTK_GFC_ERROR){
+ LOGE("geofenceinf_add_geofence:message data don't match struct %d %d", recv_len, expect_len);
+ close(fd);
+ return -1;
+ }
+ }
+
+ if (fence_status.createstat == 0){
+ close(fd);
+ return fence_status.id;
+ } else {
+ close(fd);
+ return fence_status.createstat;
+ }
+}
+
+int geofenceinf_remove_geofence(const int geofence_id) {
+ int ret;
+ mtk_geofence_msg *geo_header=NULL;
+ unsigned int msg_len;
+ int recv_len;
+ int expect_len;
+ char buffer[GEOFENCE_BUFF_SIZE] = {0};
+ char geo_data[GEOFENCE_BUFF_SIZE] = {0};
+ int fd = -1, temp_server_data_fd = -1;
+ mtk_geofence_msg *prmsg = NULL;
+ mtk_geofence_result remove_result;
+
+ LOGD("geofence_remove_geofences,fence id:%d", geofence_id);
+ if (server_data_fd < 0){
+ LOGE("geofenceinf_remove_geofence:wait server data fd");
+ return MTK_GFC_ERROR;
+ } else {
+ temp_server_data_fd = server_data_fd;
+ }
+
+ //construct remove fence cmd
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(int) + sizeof(int);
+ geo_header = (mtk_geofence_msg *)&geo_data[0];
+ if (msg_len > GEOFENCE_BUFF_SIZE){
+ LOGE("geofenceinf message length too long:%d", msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ //construct total message
+ //construct header
+ geo_header->type = REMOVE_GEOFENCE;
+ geo_header->length = msg_len;
+ //input server data fd
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg), &temp_server_data_fd, sizeof(int));
+ //input geofence property payload
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg) + sizeof(int), &geofence_id, sizeof(int));
+
+ //Create TCP client fd, and connect tcp server
+ if ( (fd = geofenceinf_socket_tcp_client_connect_local(true, GEOFENCEADP_MNL_TCP_CONTROL)) < 0){
+ LOGE("geofenceinf_remove_geofence:create client fd failed:%d", fd);
+ return MTK_GFC_ERROR;
+ }
+
+ ret = geofenceinf_send2mnl(fd, (char *)geo_header, msg_len);
+ if(ret < 0) {
+ LOGE("geofenceinf_remove_geofence:send message to mnl failed");
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+
+ //wait ack
+ expect_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_result);
+ if ( (recv_len = geofenceinf_control_path_safe_recv(fd, buffer, GEOFENCE_BUFF_SIZE, expect_len)) <= 0){
+ LOGE("geofenceinf_remove_geofence:don't recv any data");
+ close(fd);
+ return MTK_GFC_ERROR;
+ } else {
+ prmsg = (mtk_geofence_msg *)&buffer[0];
+ ret = geofenceinf_geofence_remove_result(prmsg, &remove_result);
+ if (ret == MTK_GFC_ERROR){
+ LOGE("geofenceinf_remove_geofence:message data don't match struct %d %d", recv_len, expect_len);
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+ }
+
+ if (remove_result.result == 0){
+ close(fd);
+ return MTK_GFC_SUCCESS;
+ } else {
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+}
+
+int geofenceinf_clear_geofences(void) {
+ int ret;
+ mtk_geofence_msg *geo_header=NULL;
+ unsigned int msg_len;
+ int recv_len;
+ int expect_len;
+ char buffer[GEOFENCE_BUFF_SIZE] = {0};
+ char geo_data[GEOFENCE_BUFF_SIZE] = {0};
+ int fd = -1, temp_server_data_fd = -1;
+ mtk_geofence_msg *prmsg = NULL;
+ mtk_geofence_result clear_result;
+
+ LOGD("geofence_clear_geofences");
+ if (server_data_fd < 0){
+ LOGE("geofenceinf_clear_geofences:wait server data fd");
+ return MTK_GFC_ERROR;
+ } else {
+ temp_server_data_fd = server_data_fd;
+ }
+
+ //construct remove fence cmd
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(int);
+ geo_header = (mtk_geofence_msg *)&geo_data[0];
+ if (msg_len > GEOFENCE_BUFF_SIZE){
+ LOGE("geofenceinf message length too long:%d", msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ //construct total message
+ //construct header
+ geo_header->type = CLEAR_GEOFENCE;
+ geo_header->length = msg_len;
+ //input server data fd
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg), &temp_server_data_fd, sizeof(int));
+
+ //Create TCP client fd, and connect tcp server
+ if ( (fd = geofenceinf_socket_tcp_client_connect_local(true, GEOFENCEADP_MNL_TCP_CONTROL)) < 0){
+ LOGE("geofenceinf_clear_geofences:create client fd failed:%d", fd);
+ return MTK_GFC_ERROR;
+ }
+
+ ret = geofenceinf_send2mnl(fd, (char *)geo_header, msg_len);
+ if(ret < 0) {
+ LOGE("geofenceinf_clear_geofences:send message to mnl failed");
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+
+ //wait ack
+ expect_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_result);
+ if ( (recv_len = geofenceinf_control_path_safe_recv(fd, buffer, GEOFENCE_BUFF_SIZE, expect_len)) <= 0){
+ LOGE("geofenceinf_clear_geofences:don't recv any data");
+ close(fd);
+ return MTK_GFC_ERROR;
+ } else {
+ prmsg = (mtk_geofence_msg *)&buffer[0];
+ ret = geofenceinf_geofence_clear_result(prmsg, &clear_result);
+ if (ret == MTK_GFC_ERROR){
+ LOGE("geofenceinf_clear_geofences:message data don't match struct %d %d", recv_len, expect_len);
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+ }
+
+ if (clear_result.result == 0){
+ close(fd);
+ return MTK_GFC_SUCCESS;
+ } else {
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+}
+
+int geofenceinf_query_geofences_num(void) {
+ int ret;
+ mtk_geofence_msg *geo_header=NULL;
+ unsigned int msg_len;
+ int recv_len;
+ int expect_len;
+ char buffer[GEOFENCE_BUFF_SIZE] = {0};
+ char geo_data[GEOFENCE_BUFF_SIZE] = {0};
+ int fence_nums;
+ int fd = -1, temp_server_data_fd = -1;
+ mtk_geofence_msg *prmsg = NULL;
+
+ LOGD("geofence_query_geofences_num");
+ if (server_data_fd < 0){
+ LOGE("geofence_query_geofences_num:wait server data fd");
+ return -1;
+ } else {
+ temp_server_data_fd = server_data_fd;
+ }
+
+ //construct remove fence cmd
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(int);
+ geo_header = (mtk_geofence_msg *)&geo_data[0];
+ if (msg_len > GEOFENCE_BUFF_SIZE){
+ LOGE("geofenceinf message length too long:%d", msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ //construct total message
+ //construct header
+ geo_header->type = QUERY_GEOFENCE_NUM;
+ geo_header->length = msg_len;
+ //input server data fd
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg), &temp_server_data_fd, sizeof(int));
+
+ //Create TCP client fd, and connect tcp server
+ if ( (fd = geofenceinf_socket_tcp_client_connect_local(true, GEOFENCEADP_MNL_TCP_CONTROL)) < 0){
+ LOGE("geofence_query_geofences_num:create client fd failed:%d", fd);
+ return -1;
+ }
+
+ ret = geofenceinf_send2mnl(fd, (char *)geo_header, msg_len);
+ if(ret < 0) {
+ LOGE("geofence_query_geofences_num:send message to mnl failed");
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+
+ //wait ack
+ expect_len = sizeof(mtk_geofence_msg) + sizeof(fence_nums);
+ if ( (recv_len = geofenceinf_control_path_safe_recv(fd, buffer, GEOFENCE_BUFF_SIZE, expect_len)) <= 0){
+ LOGE("geofence_query_geofences_num:don't recv any data");
+ close(fd);
+ return MTK_GFC_ERROR;
+ } else {
+ prmsg = (mtk_geofence_msg *)&buffer[0];
+ ret = geofenceinf_geofence_get_geofences_num(prmsg, &fence_nums);
+ if (ret == MTK_GFC_ERROR){
+ LOGE("geofence_query_geofences_num:message data don't match struct %d %d", recv_len, expect_len);
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+ }
+
+ if (fence_nums > 0){
+ close(fd);
+ return fence_nums;
+ } else {
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+}
+
+// GNSS Adaptor --> MNLD Message
+int geofenceinf_client_capability_config(mtk_geofence_client_capability *cap) {
+ int ret;
+ mtk_geofence_msg *geo_header=NULL;
+ char geo_data[GEOFENCE_BUFF_SIZE] = {0};
+ unsigned int msg_len;
+ int fd = -1, temp_server_data_fd = -1;
+
+ LOGD("geofenceinf_client_capability_config");
+ if (server_data_fd < 0){
+ LOGE("geofenceinf_client_capability_config:wait server data fd");
+ return -1;
+ } else {
+ temp_server_data_fd = server_data_fd;
+ }
+
+ //construct remove fence cmd
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(int) + sizeof(mtk_geofence_client_capability);
+ geo_header = (mtk_geofence_msg *)&geo_data[0];
+ if (msg_len > GEOFENCE_BUFF_SIZE){
+ LOGE("geofenceinf message length too long:%d", msg_len);
+ return MTK_GFC_ERROR;
+ }
+
+ //construct total message
+ //construct header
+ geo_header->type = GEOFENCE_CLIENT_CAP;
+ geo_header->length = msg_len;
+ //input server data fd
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg), &temp_server_data_fd, sizeof(int));
+ memcpy( ((char*)geo_header) + sizeof(mtk_geofence_msg) + sizeof(int), cap, sizeof(mtk_geofence_client_capability));
+
+ //Create TCP client fd, and connect tcp server
+ if ( (fd = geofenceinf_socket_tcp_client_connect_local(true, GEOFENCEADP_MNL_TCP_CONTROL)) < 0){
+ LOGE("geofenceinf_client_capability_config:create client fd failed:%d", fd);
+ return -1;
+ }
+
+ ret = geofenceinf_send2mnl(fd, (char *)geo_header, msg_len);
+ if(ret < 0) {
+ LOGE("geofenceinf_client_capability_config:send message to mnl failed");
+ close(fd);
+ return MTK_GFC_ERROR;
+ }
+ return MTK_GFC_SUCCESS;
+}
+
+void geofenceinf_server_capability_sync(mtk_geofence_msg *prmsg, mtk_geofence_callback *at_callback) {
+ mtk_geofence_server_capability cap;
+ unsigned int msg_len;
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_server_capability);
+ if (prmsg->length == msg_len){
+ memcpy(&cap, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_server_capability));
+ } else if (prmsg->length > msg_len) {
+ memcpy(&cap, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_server_capability));
+ LOGD("mnl msg len:%d > struct len:%d", prmsg->length, msg_len);
+ } else {
+ memcpy(data, (char*)prmsg, prmsg->length);
+ memset((char *)(data + prmsg->length), 0, (msg_len - prmsg->length));
+ memcpy(&cap, (((char*)data)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_server_capability));
+ LOGD("mnl msg len:%d < struct len:%d", prmsg->length, msg_len);
+ }
+
+ if (at_callback->geofence_capability_update != NULL){
+ at_callback->geofence_capability_update(&cap);
+ }
+
+ return;
+}
+
+void geofenceinf_get_server_data_fd(mtk_geofence_msg *prmsg) {
+ int data_fd;
+ unsigned int msg_len;
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(int);
+ if (prmsg->length == msg_len){
+ memcpy(&data_fd, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(int));
+ } else if (prmsg->length > msg_len) {
+ memcpy(&data_fd, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(int));
+ LOGD("mnl msg len:%d > struct len:%d", prmsg->length, msg_len);
+ } else {
+ memcpy(data, (char*)prmsg, prmsg->length);
+ memset((char *)(data + prmsg->length), 0, (msg_len - prmsg->length));
+ memcpy(&data_fd, (((char*)data)+sizeof(mtk_geofence_msg)), sizeof(int));
+ LOGD("mnl msg len:%d < struct len:%d", prmsg->length, msg_len);
+ }
+
+ if (data_fd < 0){
+ LOGD("geofenceinf_get_server_data_fd error");
+ } else {
+ server_data_fd = data_fd;
+ LOGD("geofenceinf_get_server_data_fd:%d", server_data_fd);
+ }
+
+ return;
+}
+
+void geofenceinf_geofence_alert(mtk_geofence_msg *prmsg, mtk_geofence_callback *at_callback) {
+ mtk_geofence_alert fence_alert;
+ unsigned int msg_len;
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(mtk_geofence_alert);
+ if (prmsg->length == msg_len){
+ memcpy(&fence_alert, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_alert));
+ } else if (prmsg->length > msg_len) {
+ memcpy(&fence_alert, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_alert));
+ LOGD("mnl msg len:%d > struct len:%d", prmsg->length, msg_len);
+ } else {
+ memcpy(data, (char*)prmsg, prmsg->length);
+ memset((char *)(data + prmsg->length), 0, (msg_len - prmsg->length));
+ memcpy(&fence_alert, (((char*)data)+sizeof(mtk_geofence_msg)), sizeof(mtk_geofence_alert));
+ LOGD("mnl msg len:%d < struct len:%d", prmsg->length, msg_len);
+ }
+
+ #ifdef AT_COMMAND_PRINT
+ /*Construct AT command */
+ sprintf(data, "+EGEORESP:%d,%d,%.6f,%.6f,%.2f,%.2f,%.2f,%d,%d,%d,%d,%d,%.2f,%.2f,%.2f/r/n",
+ fence_alert.id,
+ fence_alert.alert_state,
+ fence_alert.latitude,
+ fence_alert.longitude,
+ fence_alert.altitude,
+ fence_alert.speed,
+ fence_alert.heading,
+ fence_alert.h_acc,
+ fence_alert.h_err_majoraxis,
+ fence_alert.h_err_minoraxis,
+ fence_alert.h_err_angle,
+ fence_alert.hor_conf,
+ fence_alert.pdop,
+ fence_alert.hdop,
+ fence_alert.vdop);
+ LOGD("AT command:%s",data);
+ #endif
+ //Send AT command
+ if (at_callback->geofence_fence_alert_callback != NULL){
+ at_callback->geofence_fence_alert_callback(&fence_alert);
+ }
+
+ return;
+}
+
+void geofenceinf_gnss_tracking_status(mtk_geofence_msg *prmsg, mtk_geofence_callback *at_callback) {
+ mtk_gnss_tracking_status tracking_Status;
+ unsigned int msg_len;
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+
+ msg_len = sizeof(mtk_geofence_msg) + sizeof(mtk_gnss_tracking_status);
+ if (prmsg->length == msg_len){
+ memcpy(&tracking_Status, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_gnss_tracking_status));
+ } else if (prmsg->length > msg_len) {
+ memcpy(&tracking_Status, (((char*)prmsg)+sizeof(mtk_geofence_msg)), sizeof(mtk_gnss_tracking_status));
+ LOGD("mnl msg len:%d > struct len:%d", prmsg->length, msg_len);
+ } else {
+ memcpy(data, (char*)prmsg, prmsg->length);
+ memset((char *)(data + prmsg->length), 0, (msg_len - prmsg->length));
+ memcpy(&tracking_Status, (((char*)data)+sizeof(mtk_geofence_msg)), sizeof(mtk_gnss_tracking_status));
+ LOGD("mnl msg len:%d < struct len:%d", prmsg->length, msg_len);
+ }
+
+ #ifdef AT_COMMAND_PRINT
+ /*Construct AT command */
+ sprintf(data, "+EGEOTRACK:%d,\"%d/%d/%d,%d:%d:%d\"",
+ tracking_Status.status,
+ tracking_Status.year,
+ tracking_Status.month,
+ tracking_Status.day,
+ tracking_Status.hour,
+ tracking_Status.minute,
+ tracking_Status.second
+ );
+ LOGD("AT command:%s",data);
+ #endif
+ //Send AT command
+ if (at_callback->geofence_tracking_status_callback != NULL){
+ at_callback->geofence_tracking_status_callback(&tracking_Status);
+ }
+
+ return;
+}
+
+int geofenceinf_add_rawdata_to_buffer(char *data, int length)
+{
+ int i;
+ LOGD("geofenceadp rev raw data:%d", length);
+ for (i = 0; i < length; i++)
+ {
+ *(g_cyclical_buffer.next_write++) = data[i];
+ if (g_cyclical_buffer.next_write == g_cyclical_buffer.end_buffer){
+ g_cyclical_buffer.next_write = g_cyclical_buffer.start_buffer;
+ }
+
+ if (g_cyclical_buffer.next_write == g_cyclical_buffer.next_read){
+ LOGE("geofence ring_buffer overflow\r\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int geofenceinf_get_one_message(char *data, unsigned int len)
+{
+ char *next_write, *next_read;
+ unsigned int data_size, i, header_len;
+ char buffer[GEOFENCE_BUFF_SIZE] = {0};
+ unsigned int return_len = 0;
+ mtk_geofence_msg geo_header;
+
+ next_write = g_cyclical_buffer.next_write;
+ next_read = g_cyclical_buffer.next_read;
+
+ if (g_cyclical_buffer.next_read == next_write)
+ {
+ //buffer empty
+ return -1;
+ }
+
+ header_len = sizeof(mtk_geofence_msg);
+ /*Compute data length*/
+ if (g_cyclical_buffer.next_read < next_write)
+ {
+ data_size = (unsigned long)next_write - (unsigned long)g_cyclical_buffer.next_read;
+ }
+ else
+ {
+ data_size = (unsigned long)g_cyclical_buffer.end_buffer - (unsigned long)g_cyclical_buffer.next_read +
+ (unsigned long)next_write - (unsigned long)g_cyclical_buffer.start_buffer;
+ }
+
+ /*Copy data header to buffer*/
+ if (data_size >= header_len)
+ {
+ for (i = 0; i < header_len; i++)
+ {
+ buffer[i] = *(next_read++);
+ if (next_read == g_cyclical_buffer.end_buffer){
+ next_read = g_cyclical_buffer.start_buffer;
+ }
+ }
+
+ memset(&geo_header, 0, sizeof(mtk_geofence_msg));
+ memcpy(&geo_header, buffer, sizeof(mtk_geofence_msg));
+ if (geo_header.length <= data_size){
+ for (i = 0; (i < geo_header.length)&&(i < len); i++)
+ {
+ data[i] = *(g_cyclical_buffer.next_read++);
+ return_len++;
+ if (g_cyclical_buffer.next_read == g_cyclical_buffer.end_buffer){
+ g_cyclical_buffer.next_read = g_cyclical_buffer.start_buffer;
+ }
+ }
+ }
+ else {
+ //no enough data
+ return -2;
+ }
+ }
+ else
+ {
+ //no enough data
+ return -2;
+ }
+
+ return return_len;
+}
+
+int mnl2geofence_hdlr (int fd, mtk_geofence_callback *callback) {
+ char data[GEOFENCE_BUFF_SIZE] = {0};
+ char buff[GEOFENCE_BUFF_SIZE] = {0};
+ int len;
+ int read_len;
+ int msg_len;
+ mtk_geofence_ret_command cmd;
+ mtk_geofence_msg *prmsg = NULL;
+
+ read_len = geofenceinf_safe_recv(fd, buff, sizeof(buff));
+ if (read_len <= 0) {
+ close(fd);
+ server_data_fd = -1;
+ if(callback->geofence_connection_broken) {
+ LOGW("Connection broken...");
+ callback->geofence_connection_broken();
+ }
+ LOGE("mnl2geofence_hdlr() geofenceinf_safe_recv() failed read_len=%d, %s", read_len, strerror(errno));
+ return MTK_GFC_ERROR;
+ }
+
+ if (geofenceinf_add_rawdata_to_buffer(buff, read_len) < 0){
+ //error handle
+ LOGE("geofenceinf_add_rawdata_to_buffer() overflow\r\n");
+ }
+
+ while ((len = geofenceinf_get_one_message(data, GEOFENCE_BUFF_SIZE)) > 0)
+ {
+ if((len > 0) && (len <= GEOFENCE_BUFF_SIZE)) {
+ prmsg = (mtk_geofence_msg *)&data[0];
+ } else {
+ LOGE("len err:%d",len);
+ return MTK_GFC_ERROR;
+ }
+
+ cmd = prmsg->type;
+ msg_len = prmsg->length;
+ if (msg_len < 0){
+ LOGE("mnl2geofence_hdlr() message length error:%d", msg_len);
+ return MTK_GFC_ERROR;
+ }
+ //LOGD("command %d, len %d", cmd, msg_len);
+ switch (cmd) {
+ case GEOFENCE_ALERT_INFO:
+ geofenceinf_geofence_alert(prmsg, callback);
+ break;
+ case GNSS_TRACKING_STATUS:
+ geofenceinf_gnss_tracking_status(prmsg, callback);
+ break;
+ case GEOFENCE_SERVER_CAP:
+ geofenceinf_server_capability_sync(prmsg, callback);
+ break;
+ default:
+ LOGE("invalid geofence cmd:%d",cmd);
+ break;
+ }
+
+ memset(data, 0, GEOFENCE_BUFF_SIZE);
+ len = 0;
+ }
+ return MTK_GFC_SUCCESS;
+}