gnssd: add 8122 agps func

Change-Id: Ie87dcafc1da9cf5cffd9f5397f1640f19aa36aab
diff --git a/mbtk/mbtk_gnssd/agps/8122_agnss.c b/mbtk/mbtk_gnssd/agps/8122_agnss.c
new file mode 100755
index 0000000..4acbe33
--- /dev/null
+++ b/mbtk/mbtk_gnssd/agps/8122_agnss.c
@@ -0,0 +1,418 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#include "8122_agnss.h"
+#include "mbtk_log.h"
+
+#define BUFFER_SIZE 1024
+
+#define INJECT_RESULT_SUCCESS 0
+#define INJECT_RESULT_FAIL    -1
+
+static int hd_fd = -1;
+static hd_eph_inject_status_type eph_inject_status = HD_EPH_INJECT_STATUS_SUCCESS;
+
+static void hd_agnss_delay(uint32_t nms)
+{
+    usleep(nms * 1000);
+}
+
+static int hd_agnss_uart_write(uint8_t *buf, uint32_t len)
+{
+    int TxLen;
+    if(hd_fd > 0)
+    {
+        TxLen = write(hd_fd,buf,len);
+        if(TxLen != (int)len)
+        {
+            LOGE("hd_agnss_uart_write fail.ret = [%d], len = [%d]", TxLen, len);
+            return INJECT_RESULT_FAIL;
+        }
+    }
+    else
+    {
+        LOGE("8122 agps fd error.");
+    }
+    return TxLen;
+}
+
+static int32_t message_package(uint8_t *dst, uint8_t *src, int32_t src_len)
+{
+    int32_t i = 0;
+    int8_t checksum1 = 0;
+    int8_t checksum2 = 0;
+
+    /* message header */
+    for (i = 0; i < 4; i++)
+    {
+        dst[i] = *(src + i);
+    }
+
+    /* message len */
+    dst[4] = src_len;
+    dst[5] = 0;
+
+    /* payload */
+    for( i = 0 ; i < src_len; i++)
+    {
+        dst[6 + i] = *(src + 4) ;
+        src++;
+    }
+
+    /* check sum */
+    for(i = 2; i < (6 + dst[4]); i++)
+    {
+        checksum1 += dst[i];
+        checksum2 += checksum1;
+    }
+
+    dst[src_len + 6] = checksum1;
+    dst[src_len + 7] = checksum2;
+
+    return src_len + 8;
+}
+
+/************************************time inject*************************************/ 
+static int gnss_inject_time(HD_AGNSS_UTC_TIME_TYPE *time)
+{
+    uint8_t cmd[24] = {0}; /* packet head+payload */
+    uint8_t message[30] = {0}; /* payload : 20, packet pad : 8 */
+    int32_t len = 0;
+
+    memset(cmd, 0, sizeof(cmd));
+
+    cmd[0] = 0xF1;
+    cmd[1] = 0xD9;
+    cmd[2] = 0x0B;
+    cmd[3] = 0x11;
+
+    cmd[4] = 0x00; /* UTC */
+    cmd[5] = 0x00; /* reserved */
+    cmd[6] = 0x12; /* leap cnt, hd8030 not used */
+
+    cmd[7] = time->year & 0xFF;
+    cmd[8] = ((time->year >> 8) & 0xFF); /* year */
+    cmd[9] = time->month; /* month */
+    cmd[10] = time->day; /* day */
+    cmd[11] = time->hour; /* hour */
+    cmd[12] = time->min; /* minu */
+    cmd[13] = time->second; /* sec */
+
+    cmd[18] = 0x00;
+    cmd[19] = 0x00;
+    for (int i = 0; i < 4; i++)
+    {
+        cmd[20 + i] = 0x00;
+    }
+
+    len = message_package(message, cmd, sizeof(cmd) - 4);
+
+    LOGE("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
+            message[0],message[1],message[2],message[3],message[4],message[5],message[6],message[7],
+            message[8],message[9],message[10],message[11],message[12],message[13],message[14],
+            message[15],message[16],message[17],message[18],message[19],message[20],
+            message[21],message[22],message[23],message[24],message[25],message[26],
+            message[27],message[28],message[29]);
+
+    hd_agnss_uart_write(message, len);
+    hd_agnss_delay(3); // just example, use wait 3ms instead of ACK
+
+    return 0;
+}
+
+/************************************location inject*************************************/
+static int gnss_inject_location(int32_t latitude, int32_t longitude, float altitude, float accuracy)
+{
+    uint8_t cmd[21] = { 0 }; /* packet head+payload */
+    uint32_t acc = (uint32_t)(fabs(accuracy));
+    uint32_t alti = (uint32_t)(altitude * 100); // m--->cm
+    uint32_t i = 0;
+    uint8_t message[25] = {0}; /* payload:17 + packet pad:8 */
+
+    memset(cmd, 0, sizeof(cmd));
+    cmd[0] = 0xF1;
+    cmd[1] = 0xD9;
+    cmd[2] = 0x0B;
+    cmd[3] = 0x10;
+
+    /* LLA : 1 */
+    cmd[4] = 0x01;
+
+    /* lat : 4 */
+    for (i = 0; i < 4; i++)
+    {
+        cmd[5 + i] = (latitude >> (i * 8)) & 0xff;
+    }
+
+    /* long : 4 */
+    for (i = 0; i < 4; i++)
+    {
+        cmd[9 + i] = (longitude >> (i * 8)) & 0xff;
+    }
+
+    /* alti : 4 */
+    for (i = 0; i < 4; i++)
+    {
+        cmd[13 + i] = (alti >> (i * 8)) & 0xff;
+    }
+
+    /* accuracy : 4 */
+    for (i = 0; i < 4; i++)
+    {
+        cmd[17 + i] = (acc >> (i * 8)) & 0xff;
+    }
+
+
+    int32_t len = message_package(message, cmd, sizeof(cmd) - 4);
+
+    LOGE("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
+                message[0],message[1],message[2],message[3],message[4],message[5],message[6],message[7],
+                message[8],message[9],message[10],message[11],message[12],message[13],message[14],
+                message[15],message[16],message[17],message[18],message[19],message[20],
+                message[21],message[22],message[23],message[24]);
+
+    hd_agnss_uart_write(message, len);
+    hd_agnss_delay(3); // just example, use wait 3ms instead of ACK
+
+    return 0;
+}
+
+/************************************eph data inject*************************************/ 
+/**
+* @brief get the eph frame and send to HD80xx
+* @param data: the pointer of the eph data file
+* @param len : the total length of eph data file(eg:the length of HD_GPS_BD.hdb )
+* @retval 0: successs -1 error
+*/
+static int gnss_eph_inject_data(const char *eph_file_path)
+{
+    int packet_length;
+    int eph_file_fd = -1;
+    int size = 0;
+    int left_size = 0;
+    int total_size = 0;
+    int write_size = 0;
+    int wait_time = 0;
+    uint8_t *databuf = (uint8_t *)malloc(BUFFER_SIZE);
+    if(databuf == NULL)
+    {
+        LOGE("malloc fail");
+        return INJECT_RESULT_FAIL;
+    }
+    
+    eph_file_fd = open(eph_file_path, O_RDWR);
+    if (eph_file_fd <= 0)
+    {
+        LOGE("%s open file FAIL. errno:%d\n", __FUNCTION__, errno);
+        goto error; 
+    }
+    while(0 < (size = read(eph_file_fd, (databuf + left_size), BUFFER_SIZE)))
+    {
+        total_size = size + left_size;
+        left_size = 0;
+        for(int i=0; i < total_size;)
+        {
+            if((databuf[i] == 0xF1) && (databuf[i + 1] == 0xD9))
+            {
+                packet_length = (databuf[i + 4] | (databuf[i + 5] << 8));
+                if (i + packet_length + 8 <= total_size)
+                {
+                    hd_set_eph_inject_status(HD_EPH_INJECT_STATUS_WAIT_RETURN);
+                    write_size = hd_agnss_uart_write(databuf + i, packet_length + 8);
+                    if(write_size < 0)
+                    {
+                        LOGE("hd_agnss_uart_write fail");
+                        goto error; 
+                    }
+                    LOGD("%s Write[%d]\r\n", __FUNCTION__, write_size);
+                    wait_time = 0;
+                    while(1)
+                    {
+                        wait_time += 100;
+                        hd_agnss_delay(wait_time);
+                        if(wait_time < 1000)
+                        {
+                            if(hd_get_eph_inject_status() == HD_EPH_INJECT_STATUS_SUCCESS)
+                            {
+                                break;
+                            }
+                            else if(hd_get_eph_inject_status() == HD_EPH_INJECT_STATUS_FAIL)
+                            {
+                                LOGE("8122 return fail");
+                                goto error;
+                            }
+                            else
+                            {
+                                LOGE("eph inject wait 8122 return");
+                            }
+                        }
+                        else
+                        {
+                            LOGE("8122 wait 1s return timeout");
+                            goto error;
+                        }
+                    }
+                    i = i + packet_length + 8;
+                }
+                else
+                {
+                    left_size = total_size - i;
+                    uint8_t *tmp = databuf;
+                    databuf = (uint8_t *)malloc(BUFFER_SIZE + left_size);
+                    memcpy(databuf, tmp + i ,left_size);
+                    free(tmp);
+                    break;
+                }
+            }
+            else
+            {
+                i++;
+            }
+        }
+    }
+    
+    if(databuf)
+    {
+        free(databuf);
+        databuf = NULL;
+    }
+    if(eph_file_fd > 0)
+    {
+        close(eph_file_fd);
+        eph_file_fd = -1;
+    }
+    hd_set_eph_inject_status(HD_EPH_INJECT_STATUS_SUCCESS);
+    return INJECT_RESULT_SUCCESS;
+error:
+    if(databuf)
+    {
+        free(databuf);
+        databuf = NULL;
+    }
+    if(eph_file_fd > 0)
+    {
+        close(eph_file_fd);
+        eph_file_fd = -1;
+    }
+    hd_set_eph_inject_status(HD_EPH_INJECT_STATUS_SUCCESS);
+    return INJECT_RESULT_FAIL;
+}
+
+/************************************choice func inject*************************************/
+/**
+  * @brief  AGNSS星历注入、位置注入、时间注入。星历、位置、时间可选择性注入。
+  * @param  eph_file_path:从服务器下载的星历数据文件路径;若无则填NULL
+
+            latitude:纬度,乘以10^7;若无则填0
+            longitude:经度,乘以10^7;若无则填0
+            altitude:高程,浮点,单位为m;若无则填0
+            accuracy:精度;若无则填0
+
+            UTC_time:UTC时间;若无则填NULL
+  * @retval VOID
+**/
+int hd_agnss_inject(const char *eph_file_path, int32_t latitude, int32_t longitude, float altitude, float accuracy, /****latitude和longitude由double型乘以10^7得到*****/
+                            HD_AGNSS_UTC_TIME_TYPE *UTC_time)
+{
+    int ret = INJECT_RESULT_SUCCESS;
+    if (UTC_time != NULL) 
+    {
+        gnss_inject_time(UTC_time);
+    }
+
+    if ((latitude != 0) && (longitude != 0)) 
+    {
+        gnss_inject_location(latitude, longitude, altitude, accuracy);
+    }
+
+    if (eph_file_path != NULL) 
+    {
+        ret = gnss_eph_inject_data(eph_file_path);
+        if(ret < 0)
+        {
+            LOGE("gnss_eph_inject_data fail");
+            return INJECT_RESULT_FAIL;
+        }
+    }
+    return INJECT_RESULT_SUCCESS;
+}
+
+
+/************************************set fd*************************************/
+void hd_set_gnss_dev_fd(int fd)
+{
+    hd_fd = fd;
+}
+
+/************************************check return*************************************/
+//gps f1 d9 05 01 02 00 0b 32 46 74
+//bds f1 d9 05 01 02 00 0b 33 46 74
+//glo f1 d9 05 01 02 00 0b 34 46 74
+
+int hd_eph_inject_result_check(const uint8_t *pack, int pack_len)
+{
+    if(pack_len == 0 || pack_len % 10)
+    {
+        LOGE("pack_len(%d) error.", pack_len);
+        return -1;
+    }
+    int count = pack_len / 10;
+    int i = 0;
+    while(i < count)
+    {
+        const uint8_t *ptr = pack + i * 10;
+        if(ptr[0] != 0xf1 || ptr[1] != 0xd9)
+        {
+            LOGE("Pack head error : %02x %02x", ptr[0], ptr[1]);
+            return INJECT_RESULT_FAIL;
+        }
+
+        if(ptr[2] != 0x05)
+        {
+            LOGE("Type not 0x05 : %02x", ptr[2]);
+            return INJECT_RESULT_FAIL;
+        }
+
+        if(ptr[6] != 0x0b || (ptr[7] < 0x32 && ptr[7] > 0x36))
+        {
+            LOGE("Unknown gid - %d, sid - %d", ptr[6], ptr[7]);
+            return INJECT_RESULT_FAIL;
+        }
+
+        if(ptr[3] == 0x01)
+        {
+            return INJECT_RESULT_SUCCESS;
+        }
+        else if(ptr[3] == 0x00)
+        {
+            return INJECT_RESULT_FAIL;
+        }
+        else
+        {
+            LOGE("ID not 0x00 or 0x01 : %02x", ptr[3]);
+            return INJECT_RESULT_FAIL;
+        }
+        i++;
+    }
+
+    return INJECT_RESULT_SUCCESS;
+}
+/************************************get or set status*************************************/
+void hd_set_eph_inject_status(hd_eph_inject_status_type status)
+{
+    eph_inject_status = status;
+}
+
+hd_eph_inject_status_type hd_get_eph_inject_status(void)
+{
+    return eph_inject_status;
+}
+