[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;

+}