Attribute.c 9.8 KB
#include "JZsdkLib.h"
#include <sys/time.h> // 对于 settimeofday 可能需要这个头文件
#include <time.h>  
#include <unistd.h>
#include <string.h>
#include "Attribute.h"

// 每个月的天数表(索引0为占位)
const uint8_t days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

static T_JZsdkAttributeGpsTime g_GpsTime = 0;
static T_JZsdkAttributeGpsDate g_GpsDate = 0;
static T_JZsdkAttributeGpsPosition g_GpsPositino = {0};

// static int GpsYear = 0;
// static int GpsMonth = 0;
// static int GpsDay = 0;
// static int GpsHour = 0;
// static int GpsMinute = 0;
// static int GpsSecond = 0;

void * Attribute_Task(void *arg)
{
    t_JZdateTime dt;

    const time_t GPS_EPOCH_OFFSET = 315964800; // 1980-01-06 -> 1970-01-01的秒数
    const uint8_t GPS_LEAP_SECONDS = 18;       // GPS-UTC闰秒差(需动态更新)

    //每60s更新一次psdk时间
    while (1)
    {
        //获取gps时间
        T_JZsdkAttributeGpsTime gpsTime = Attribute_GetGpsTime();

        JZsdk_convert_gpstime(gpsTime, &dt);

        JZSDK_LOG_INFO("GPS Time: %u seconds\n", gpsTime);
        JZSDK_LOG_INFO("Converted: %04u-%02u-%02u %02u:%02u:%02u\n", 
           dt.year, dt.month, dt.day, 
           dt.hour, dt.minute, dt.second);

        //将gps时间转换为unix时间
        time_t gps_utc = gpsTime + GPS_EPOCH_OFFSET - GPS_LEAP_SECONDS;

        //获取系统时间
        struct timeval tv;
        if (gettimeofday(&tv, NULL) != 0) {
            JZSDK_LOG_ERROR("获取系统时间失败");
            delayS(10);
            continue;
        }

        // 计算时间差
        time_t time_diff = labs(gps_utc - tv.tv_sec);

        // 超阈值时更新系统时间
        if (time_diff > 60) 
        {
            JZSDK_LOG_INFO("时间差超过60秒: GPS=%u, 系统=%ld", gpsTime, tv.tv_sec);
            
            struct timeval new_tv = { .tv_sec = gps_utc, .tv_usec = 0 };
            if (settimeofday(&new_tv, NULL) == 0) {
                JZSDK_LOG_INFO("系统时间更新成功");
            } else {
                JZSDK_LOG_ERROR("系统时间更新失败(需root权限)");
            }
        }

        delayS(20);
    }
    
    return NULL;
}



static T_JZsdkReturnCode is_system_utc() 
{
    // 方法1:检查 /etc/localtime 是否链接到 UTC
    char cmd[256];
    snprintf(cmd, sizeof(cmd), "readlink /etc/localtime | grep -q UTC");
    if (system(cmd) == 0) {
        JZSDK_LOG_INFO("系统时区为 UTC (检测到 /etc/localtime 链接)");
        return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
    }

    // 方法2:检查 /etc/timezone 文件内容
    FILE *tz_file = fopen("/etc/timezone", "r");
    if (tz_file) {
        char tz[32] = {0};
        fgets(tz, sizeof(tz), tz_file);
        fclose(tz_file);
        if (strstr(tz, "UTC") || strstr(tz, "Etc/UTC")) {
            JZSDK_LOG_INFO("系统时区为 UTC (检测到 /etc/timezone)");
            return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
        }
    }

    return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}

static T_JZsdkReturnCode set_system_utc() 
{
    // 1. 检查 root 权限
    if (geteuid() != 0) {
        JZSDK_LOG_ERROR("修改时区需要 root 权限");
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    // 2. 更新 /etc/localtime
    system("rm -f /etc/localtime");
    system("ln -sf /usr/share/zoneinfo/UTC /etc/localtime");

    // 3. 更新 /etc/timezone(如果存在)
    system("echo 'UTC' > /etc/timezone 2>/dev/null");

    // 4. 通知系统时区变更(如果使用 systemd)
    system("timedatectl set-timezone UTC 2>/dev/null");

    // 5. 验证是否成功
    return is_system_utc();
}

static T_JZsdkReturnCode Attribute_ChangeTimezone()
{
    if (is_system_utc() == JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        JZSDK_LOG_INFO("系统已是 UTC,无需修改");
        return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
    }

    T_JZsdkReturnCode ret = set_system_utc();
    if (ret == JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        JZSDK_LOG_INFO("系统时区已永久修改为 UTC");
    } else {
        JZSDK_LOG_ERROR("修改时区失败");
    }
    return ret;
}
T_JZsdkReturnCode Attribute_Init()
{
    T_JZsdkOsalHandler *OsalHandle = JZsdk_Platform_GetOsalHandler();
    
    //系统时区修改
    //Attribute_ChangeTimezone();

    //将进程修改为UTC时区
    setenv("TZ", "UTC", 1);  // 强制使用UTC时区
    tzset();                 // 生效时区设置


    //创建任务
    T_JZTaskHandle taskHandle = NULL;
    OsalHandle->TaskCreate("attribute_task",Attribute_Task, 4096, NULL, &taskHandle);

    JZSDK_LOG_INFO("Attribute_Init_Complete");

    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

// 函数:获取GPS时间
// 返回值:T_JZsdkAttributeGpsTime类型的GPS时间
T_JZsdkAttributeGpsTime Attribute_GetGpsTime()
{
    // 返回全局变量g_GpsTime的值
    return g_GpsTime;
}

// 设置GPS时间
T_JZsdkReturnCode Attribute_SetGpsTime(T_JZsdkAttributeGpsTime GpsTime)
{
    // 将传入的参数GpsTime赋值给全局变量g_GpsTime
    g_GpsTime = GpsTime;
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

/********************************
 * 
 *   获取gps的坐标值
 * 
 * **************************/
T_JZsdkAttributeGpsPosition Attribute_GetGpsPosition()
{
    // 返回全局变量g_GpsPositino的值
    return g_GpsPositino;
}

/********************************
 * 
 *   设置gps的坐标值
 * 
 * **************************/
T_JZsdkReturnCode Attribute_SetGpsPosition(T_JZsdkAttributeGpsPosition GpsPosition)
{
    // 将传入的参数GpsPosition赋值给全局变量g_GpsPositino
    g_GpsPositino = GpsPosition;
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

/***********************
 * 
 *  设置gps的日期
 * 
 * 
 * *******************/
T_JZsdkReturnCode Attribute_SetGpsDate(T_JZsdkAttributeGpsDate GpsDate)
{
    // 将传入的参数GpsDate赋值给全局变量g_GpsDate
    g_GpsDate = GpsDate;
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

/***********************
 * 
 *  获取gps的日期
 * 
 * 
 * *******************/
T_JZsdkAttributeGpsDate Attribute_GetGpsDate()
{
    // 返回全局变量g_GpsDate的值
    return g_GpsDate;
}

// 函数定义
void decimal_to_dms(float decimal_degrees, char* dms_string, char direction) 
{
    int degrees = (int)decimal_degrees;
    float decimal_minutes = fabs(decimal_degrees - degrees) * 60;
    int minutes = (int)decimal_minutes;
    float seconds = (decimal_minutes - minutes) * 60;
 
    // 格式化DMS字符串,保留两位小数
    snprintf(dms_string, 50, "%d°%d'%.0f\"%c", abs(degrees), minutes, seconds, direction);
}

/************************
 * 
 *  获取gps显示的xyz值
 * 
 * 
 * ****************************/
T_JZsdkReturnCode Attribute_GetGpsXYZ_ByStr(unsigned char *latitude, unsigned char *longitude, float *z)
{
    float x = g_GpsPositino.x/10000000.0;
    float y = g_GpsPositino.y/10000000.0;
    *z = g_GpsPositino.z/10000000.0;

    char dmsX[50];
    char dmsY[50];

    memset(dmsX, 0, sizeof(dmsX));
    memset(dmsY, 0, sizeof(dmsY));
 
    // 调用函数将经度转换为DMS格式,并传入正确的方向字符
    decimal_to_dms(x, dmsX, (g_GpsPositino.x >= 0) ? 'E' : 'W');
    // 调用函数将纬度转换为DMS格式,并传入正确的方向字符
    decimal_to_dms(y, dmsY, (g_GpsPositino.y >= 0) ? 'N' : 'S');
 
    // // 打印结果
    // printf("%d  %f 经度: %s\n",g_GpsPositino.x, x , dmsX);
    // printf("%d  %f 纬度: %s\n",g_GpsPositino.y, y , dmsY);

    memcpy(latitude, dmsX, strlen(dmsX));
    memcpy(longitude, dmsY, strlen(dmsY));

    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}




/************************
 * 
 *  获取gps显示的度分秒值
 * 
 * 
 * ****************************/
T_JZsdkReturnCode Attribute_GetGpsXYZ_ByF(float *x, float *y, float *z)
{
    *x = g_GpsPositino.x/10000000.0;
    *y = g_GpsPositino.y/10000000.0;
    *z = g_GpsPositino.z/10000000.0;

    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}


// 判断是否为闰年
static bool is_leap_year(uint16_t year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 计算日期
static void calculate_date(uint32_t total_days, t_JZdateTime *date) {
    // GPS起始时间:1980年1月6日
    date->year = 1980;
    date->month = 1;
    date->day = 6;

    while (total_days > 0) {
        // 计算当前年是否是闰年
        uint16_t days_in_year = is_leap_year(date->year) ? 366 : 365;
        
        if (total_days >= days_in_year) {
            total_days -= days_in_year;
            date->year++;
        } else {
            // 处理月份
            uint8_t month = date->month;
            while (total_days > 0 && month <= 12) {
                uint8_t dim = days_in_month[month];
                // 闰年2月特殊处理
                if (month == 2 && is_leap_year(date->year)) dim++;
                
                if (total_days >= dim) {
                    total_days -= dim;
                    month++;
                } else {
                    date->day += total_days;
                    total_days = 0;
                    if (date->day > dim) {
                        date->day -= dim;
                        month++;
                    }
                }
            }
            date->month = month;
            break;
        }
    }
}

T_JZsdkReturnCode JZsdk_convert_gpstime(T_JZsdkAttributeGpsTime gpstime, t_JZdateTime *result) 
{
    const U32_t SECONDS_PER_DAY = 86400;
    const U32_t SECONDS_PER_HOUR = 3600;
    const U8_t SECONDS_PER_MINUTE = 60;

    // 计算时分秒
    U32_t total_days = gpstime / SECONDS_PER_DAY;
    U32_t remaining = gpstime % SECONDS_PER_DAY;

    result->hour = remaining / SECONDS_PER_HOUR;
    remaining %= SECONDS_PER_HOUR;

    result->minute = remaining / SECONDS_PER_MINUTE;
    result->second = remaining % SECONDS_PER_MINUTE;

    // 计算年月日
    calculate_date(total_days, result);
}