blob: c240d9f2f71674ea3791e3e1a8c409a3dc7a9c62 [file] [log] [blame]
#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;
}