#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; | |
} |