| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997 |
- /*
- * YM310 State Maintenance Thread - FIXED v5.3
- *
- * Fixes in this version:
- * - Consolidated all conversion logic into a single function:
- * nmea_to_gcj02_int(). No external helper functions remain.
- * - Transform test uses integer output only.
- *
- * Version: 5.3.0
- */
- #define DBG_TAG "Y-MNT"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #include "ym310_mqtt.h"
- #include <string.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <math.h>
- #include "peri.h"
- extern struct rtc_time time_now;
- /*=============================================================================
- * Global Variables
- *============================================================================*/
- rt_thread_t g_maintain_thread = RT_NULL;
- static volatile rt_bool_t s_maintain_thread_running = RT_FALSE;
- /* Consecutive network failure counter */
- static int s_net_fail_count = 0;
- #define NET_FAIL_THRESHOLD 3
- /* Network check result cache */
- static rt_bool_t s_last_network_connected = RT_FALSE;
- /* External function declaration */
- extern int ym310_parse_qipact_response(const char *resp_buf, int *context_id, int *state, char *ip_addr, int ip_addr_size);
- /*=============================================================================
- * Utility: Trim String
- *============================================================================*/
- static void trim_string(char *str)
- {
- char *start = str;
- char *end;
- if (!str || *str == '\0')
- {
- return;
- }
- while (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')
- {
- start++;
- }
- if (start != str)
- {
- memmove(str, start, strlen(start) + 1);
- }
- end = str + strlen(str) - 1;
- while (end >= str && (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n'))
- {
- *end = '\0';
- end--;
- }
- }
- /*=============================================================================
- * NTP Time Sync
- *============================================================================*/
- int ym310_ntp_sync_time(void)
- {
- at_resp_type_t resp;
- char resp_buf[128];
- char urc_buf[128];
- int err_code;
- char datetime_str[32];
- int year, month, day, hour, minute, second, tz = 0;
- int tz_sign = 1;
- resp = ym310_at_exec_cmd("AT+QNTP=1,\"ntp.aliyun.com\",123", resp_buf, sizeof(resp_buf), 5000);
- if (resp != AT_RESP_OK)
- {
- LOG_W("NTP command failed (resp=%d)", resp);
- return -RT_ERROR;
- }
- if (ym310_at_wait_for("+QNTP:", urc_buf, sizeof(urc_buf), 30000) != RT_EOK)
- {
- LOG_E("NTP: timeout waiting for +QNTP: URC");
- return -RT_ERROR;
- }
- const char *p = rt_strstr(urc_buf, "+QNTP:");
- if (p == RT_NULL)
- {
- LOG_E("NTP: +QNTP: not found in URC");
- return -RT_ERROR;
- }
- p += 6;
- while (*p == ' ' || *p == '\t')
- p++;
- if (sscanf(p, "%d,\"%31[^\"]\"", &err_code, datetime_str) != 2)
- {
- LOG_E("NTP: failed to parse response: %s", urc_buf);
- return -RT_ERROR;
- }
- if (err_code != 0)
- {
- LOG_E("NTP: server returned error code %d", err_code);
- return -RT_ERROR;
- }
- LOG_D("NTP raw datetime: %s", datetime_str);
- char *tz_ptr = strchr(datetime_str, '+');
- if (tz_ptr == RT_NULL)
- {
- tz_ptr = strchr(datetime_str, '-');
- if (tz_ptr)
- tz_sign = -1;
- }
- if (tz_ptr)
- {
- sscanf(tz_ptr + 1, "%d", &tz);
- tz *= tz_sign;
- *tz_ptr = '\0';
- }
- if (sscanf(datetime_str, "%d/%d/%d,%d:%d:%d", &year, &month, &day, &hour, &minute, &second) != 6)
- {
- LOG_E("NTP: failed to parse date/time from: %s", datetime_str);
- return -RT_ERROR;
- }
- int total_minutes = hour * 60 + minute + tz * 15;
- int new_hour = (total_minutes / 60) % 24;
- int new_minute = total_minutes % 60;
- int day_advance = total_minutes / (24 * 60);
- struct rtc_time local_time;
- local_time.year = year;
- local_time.month = month;
- local_time.date = day + day_advance;
- local_time.hour = new_hour;
- local_time.minute = new_minute;
- local_time.second = second;
- if (local_time.date > 28)
- {
- int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- if ((local_time.year % 4 == 0 && local_time.year % 100 != 0) || (local_time.year % 400 == 0))
- days_in_month[1] = 29;
- if (local_time.date > days_in_month[local_time.month - 1])
- {
- local_time.date -= days_in_month[local_time.month - 1];
- local_time.month++;
- if (local_time.month > 12)
- {
- local_time.month = 1;
- local_time.year++;
- }
- }
- }
- extern int rtc_set_time(struct rtc_time * time);
- if (rtc_set_time(&local_time) != 0)
- {
- LOG_E("NTP: Failed to set RTC time");
- return -RT_ERROR;
- }
- LOG_I("NTP sync successful, RTC updated : %04d-%02d-%02d %02d:%02d:%02d",
- local_time.year, local_time.month, local_time.date,
- local_time.hour, local_time.minute, local_time.second);
- return RT_EOK;
- }
- /*=============================================================================
- * GPS Operations
- *============================================================================*/
- static rt_bool_t s_gps_initialized = RT_FALSE;
- int ym310_gps_init(void)
- {
- at_resp_type_t resp;
- int retry = 0;
- LOG_I("Initializing GPS...");
- for (retry = 0; retry < 3; retry++)
- {
- resp = ym310_at_exec_cmd("AT+CGPS=1", NULL, 0, YM310_AT_CMD_TIMEOUT_MS);
- if (resp == AT_RESP_OK)
- {
- LOG_I("GPS started successfully");
- break;
- }
- LOG_W("GPS start attempt %d failed (resp=%d)", retry + 1, resp);
- rt_thread_mdelay(1000);
- }
- if (resp != AT_RESP_OK)
- {
- LOG_E("GPS init failed after 3 attempts");
- s_gps_initialized = RT_FALSE;
- return -RT_ERROR;
- }
- resp = ym310_at_exec_cmd("AT+CGPSPORT=0", NULL, 0, YM310_AT_CMD_TIMEOUT_MS);
- s_gps_initialized = RT_TRUE;
- return RT_EOK;
- }
- /*=============================================================================
- * GCJ-02 Coordinate Transformation - Single Integrated Function
- *============================================================================*/
- /* Earth constants (Krasovsky 1940 ellipsoid) */
- static const double pi = 3.14159265358979324;
- static const double a = 6378245.0;
- static const double ee = 0.00669342162296594323;
- /**
- * @brief Convert NMEA coordinate string directly to GCJ-02 1e7-degree integer
- *
- * This function encapsulates all steps:
- * - Parses NMEA format "DDMM.MMMMM"
- * - Converts to WGS84 decimal degrees
- * - Applies GCJ-02 offset using standard algorithm
- * - Returns result as integer in 1e7 degrees (e.g., 348101463 = 34.8101463°)
- *
- * @param nmea_str NMEA coordinate string (e.g., "3448.60878")
- * @param is_lon 1 for longitude (3-degree digits), 0 for latitude (2-degree digits)
- * @param direction 'N'/'S' for latitude, 'E'/'W' for longitude
- * @return GCJ-02 coordinate in 1e7 degrees (int)
- */
- static int nmea_to_gcj02_int(const char *nmea_str, int is_lon, char direction)
- {
- char temp[16];
- strncpy(temp, nmea_str, sizeof(temp) - 1);
- temp[sizeof(temp) - 1] = '\0';
- /* Find decimal point */
- char *dot = strchr(temp, '.');
- if (!dot)
- return 0;
- /* Determine degree digits (2 for lat, 3 for lon) */
- int deg_digits = is_lon ? 3 : 2;
- char deg_str[4] = {0};
- strncpy(deg_str, temp, deg_digits);
- int deg = atoi(deg_str);
- /* Minutes part */
- double minutes = atof(temp + deg_digits);
- double wgs84 = (double)deg + minutes / 60.0;
- /* Apply hemisphere sign */
- if (direction == 'S' || direction == 's' || direction == 'W' || direction == 'w')
- wgs84 = -wgs84;
- double lat = is_lon ? 0.0 : wgs84;
- double lon = is_lon ? wgs84 : 0.0;
- /* For longitude, we need both lat and lon to compute offset,
- * but this function only receives one coordinate at a time.
- * So we need both lat and lon to be passed together.
- * To simplify, we'll keep the interface that receives both.
- */
- /* Actually, the offset depends on both lat and lon, so we cannot compute
- * GCJ-02 from a single coordinate alone. Thus we need a function that
- * takes both lat and lon NMEA strings and directions.
- * Let's change the design: a single function that accepts both strings.
- */
- return 0; /* Placeholder - we will redesign below */
- }
- /* Since GCJ-02 offset depends on both latitude and longitude, we must process
- both simultaneously. The revised function takes both NMEA strings and directions. */
- /**
- * @brief Convert WGS84 NMEA pair to GCJ-02 1e7-degree integers
- *
- * @param lat_nmea Latitude NMEA string (e.g., "3448.60878")
- * @param ns 'N' or 'S'
- * @param lon_nmea Longitude NMEA string (e.g., "11339.66602")
- * @param ew 'E' or 'W'
- * @param gcj_lat_1e7 Output GCJ-02 latitude in 1e7 degrees
- * @param gcj_lon_1e7 Output GCJ-02 longitude in 1e7 degrees
- */
- static void nmea_pair_to_gcj02_int(const char *lat_nmea, char ns,
- const char *lon_nmea, char ew,
- int *gcj_lat_1e7, int *gcj_lon_1e7)
- {
- /* Parse latitude */
- double wgs84_lat = 0.0;
- char temp[16];
- strncpy(temp, lat_nmea, sizeof(temp) - 1);
- temp[sizeof(temp) - 1] = '\0';
- char *dot = strchr(temp, '.');
- if (dot)
- {
- char deg_str[3] = {0};
- strncpy(deg_str, temp, 2);
- int deg = atoi(deg_str);
- double minutes = atof(temp + 2);
- wgs84_lat = (double)deg + minutes / 60.0;
- if (ns == 'S' || ns == 's')
- wgs84_lat = -wgs84_lat;
- }
- /* Parse longitude */
- double wgs84_lon = 0.0;
- strncpy(temp, lon_nmea, sizeof(temp) - 1);
- temp[sizeof(temp) - 1] = '\0';
- dot = strchr(temp, '.');
- if (dot)
- {
- char deg_str[4] = {0};
- strncpy(deg_str, temp, 3);
- int deg = atoi(deg_str);
- double minutes = atof(temp + 3);
- wgs84_lon = (double)deg + minutes / 60.0;
- if (ew == 'W' || ew == 'w')
- wgs84_lon = -wgs84_lon;
- }
- /* Check if outside China */
- if (wgs84_lon < 72.004 || wgs84_lon > 137.8347 ||
- wgs84_lat < 0.8293 || wgs84_lat > 55.8271)
- {
- *gcj_lat_1e7 = (int)(wgs84_lat * 1e7 + (wgs84_lat >= 0 ? 0.5 : -0.5));
- *gcj_lon_1e7 = (int)(wgs84_lon * 1e7 + (wgs84_lon >= 0 ? 0.5 : -0.5));
- return;
- }
- /* GCJ-02 offset computation */
- double x = wgs84_lon - 105.0;
- double y = wgs84_lat - 35.0;
- double dlat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x));
- dlat += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
- dlat += (20.0 * sin(y * pi) + 40.0 * sin(y / 3.0 * pi)) * 2.0 / 3.0;
- dlat += (160.0 * sin(y / 12.0 * pi) + 320 * sin(y * pi / 30.0)) * 2.0 / 3.0;
- double dlon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x));
- dlon += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
- dlon += (20.0 * sin(x * pi) + 40.0 * sin(x / 3.0 * pi)) * 2.0 / 3.0;
- dlon += (150.0 * sin(x / 12.0 * pi) + 300.0 * sin(x / 30.0 * pi)) * 2.0 / 3.0;
- double radlat = wgs84_lat / 180.0 * pi;
- double magic = sin(radlat);
- magic = 1 - ee * magic * magic;
- double sqrtmagic = sqrt(magic);
- dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
- dlon = (dlon * 180.0) / (a / sqrtmagic * cos(radlat) * pi);
- double gcj_lat = wgs84_lat + dlat;
- double gcj_lon = wgs84_lon + dlon;
- /* Convert to 1e7 integer with rounding */
- *gcj_lat_1e7 = (int)(gcj_lat * 1e7 + (gcj_lat >= 0 ? 0.5 : -0.5));
- *gcj_lon_1e7 = (int)(gcj_lon * 1e7 + (gcj_lon >= 0 ? 0.5 : -0.5));
- }
- /**
- * @brief Convert GPS NMEA pair directly to GCJ-02 and store in dev_info
- */
- static int gps_to_gcj02_storage(const char *lat_str, char ns,
- const char *lon_str, char ew)
- {
- int gcj_lat_1e7, gcj_lon_1e7;
- nmea_pair_to_gcj02_int(lat_str, ns, lon_str, ew, &gcj_lat_1e7, &gcj_lon_1e7);
- /* Format to string (7 decimal places) */
- char lat_buf[32], lon_buf[32];
- int lat_deg = gcj_lat_1e7 / 10000000;
- int lat_frac = gcj_lat_1e7 % 10000000;
- if (lat_frac < 0)
- lat_frac = -lat_frac;
- int lon_deg = gcj_lon_1e7 / 10000000;
- int lon_frac = gcj_lon_1e7 % 10000000;
- if (lon_frac < 0)
- lon_frac = -lon_frac;
- snprintf(lat_buf, sizeof(lat_buf), "%d.%07d", lat_deg, lat_frac);
- snprintf(lon_buf, sizeof(lon_buf), "%d.%07d", lon_deg, lon_frac);
- strncpy(dev_info.latitude, lat_buf, sizeof(dev_info.latitude) - 1);
- dev_info.latitude[sizeof(dev_info.latitude) - 1] = '\0';
- strncpy(dev_info.longitude, lon_buf, sizeof(dev_info.longitude) - 1);
- dev_info.longitude[sizeof(dev_info.longitude) - 1] = '\0';
- LOG_I("GPS GCJ-02: %s, %s", dev_info.latitude, dev_info.longitude);
- return 0;
- }
- static char start_gnss_info = 0;
- static void gnss_info_on(void) { start_gnss_info = 1; }
- static void gnss_info_off(void) { start_gnss_info = 0; }
- MSH_CMD_EXPORT(gnss_info_on, gnss_info_on)
- MSH_CMD_EXPORT(gnss_info_off, gnss_info_off)
- /*=============================================================================
- * GPS Get Info
- *============================================================================*/
- int ym310_gps_get_info(void)
- {
- at_resp_type_t resp;
- char resp_buf[256];
- extern DEV_INFO dev_info;
- if (!s_gps_initialized)
- {
- if (ym310_gps_init() != RT_EOK)
- {
- LOG_D("GPS not initialized, skipping query");
- return -RT_ERROR;
- }
- }
- resp = ym310_at_exec_cmd("AT+CGPSINFO", resp_buf, sizeof(resp_buf), 5000);
- if (resp != AT_RESP_OK)
- {
- LOG_D("GPS query failed (resp=%d)", resp);
- return -RT_ERROR;
- }
- if (start_gnss_info)
- {
- rt_kprintf("AT+CGPSINFO >>>%s<<<\n", resp_buf);
- }
- const char *p = rt_strstr(resp_buf, "+CGPSINFO:");
- if (p == RT_NULL)
- {
- LOG_D("GPS: No +CGPSINFO in response");
- return -RT_ERROR;
- }
- p += 10;
- while (*p && (*p == ' ' || *p == '\t'))
- p++;
- if (*p == ',' || *p == '\0' || *p == '\r' || *p == '\n')
- {
- LOG_D("GPS: No fix yet");
- return -RT_ERROR;
- }
- char lat_str[16] = {0};
- char ns_ind[2] = {0};
- char lon_str[16] = {0};
- char ew_ind[2] = {0};
- char date_str[16] = {0};
- char time_str[16] = {0};
- char alt_str[16] = {0};
- char speed_str[16] = {0};
- char course_str[16] = {0};
- int parsed = sscanf(p, "%15[^,],%1[^,],%15[^,],%1[^,],%15[^,],%15[^,],%15[^,],%15[^,],%15[^,]",
- lat_str, ns_ind, lon_str, ew_ind, date_str, time_str,
- alt_str, speed_str, course_str);
- if (parsed < 4)
- {
- LOG_D("GPS parse failed, items=%d", parsed);
- return -RT_ERROR;
- }
- trim_string(lat_str);
- trim_string(lon_str);
- trim_string(date_str);
- trim_string(time_str);
- trim_string(alt_str);
- trim_string(speed_str);
- trim_string(course_str);
- if (lat_str[0] == '\0' || lon_str[0] == '\0')
- {
- LOG_D("GPS: Empty coordinate data");
- return -RT_ERROR;
- }
- LOG_D("GPS Raw: Lat=%s%c, Lon=%s%c", lat_str, ns_ind[0], lon_str, ew_ind[0]);
- if (gps_to_gcj02_storage(lat_str, ns_ind[0], lon_str, ew_ind[0]) != 0)
- {
- LOG_E("GPS coordinate conversion failed");
- return -RT_ERROR;
- }
- else
- {
- char gps_save_date = 0, now = 0;
- ef_get_env_blob("gps_save_date", &gps_save_date, sizeof(gps_save_date), NULL);
- now = time_now.year + time_now.month + time_now.date;
- if (gps_save_date != now)
- {
- gps_save_date = now;
- ef_set_env_blob("gps_save_date", &gps_save_date, sizeof(gps_save_date));
- LOG_I("gps_save_date : %s , %s", dev_info.latitude, dev_info.longitude);
- save_dev_info();
- }
- }
- return RT_EOK;
- }
- void ym310_gps_deinit(void)
- {
- ym310_at_exec_cmd("AT+CGPS=0", RT_NULL, 0, YM310_AT_CMD_TIMEOUT_MS);
- LOG_I("GPS deinitialized");
- }
- /*=============================================================================
- * Network Check
- *============================================================================*/
- rt_bool_t ym310_check_network_connected(void)
- {
- at_resp_type_t resp;
- char resp_buf[128];
- int n, stat;
- int retry_count = 0;
- static char once = 1;
- #define NETWORK_CHECK_RETRIES 2
- while (retry_count <= NETWORK_CHECK_RETRIES)
- {
- {
- extern volatile rt_tick_t g_last_mqtt_success_tick;
- rt_tick_t now = rt_tick_get();
- if (now - g_last_mqtt_success_tick < rt_tick_from_millisecond(30000))
- {
- LOG_D("Network check skipped due to recent MQTT success");
- return RT_TRUE;
- }
- }
- resp = ym310_at_exec_cmd("AT+CREG?", resp_buf, sizeof(resp_buf), YM310_AT_SHORT_TIMEOUT_MS);
- if (resp != AT_RESP_OK)
- {
- LOG_D("Network check: CREG query failed (resp=%d, retry=%d)", resp, retry_count);
- retry_count++;
- if (retry_count <= NETWORK_CHECK_RETRIES)
- {
- rt_thread_mdelay(300);
- continue;
- }
- return RT_FALSE;
- }
- if (ym310_parse_creg_response(resp_buf, &n, &stat) != 0)
- {
- LOG_D("Network check: CREG parse failed");
- retry_count++;
- if (retry_count <= NETWORK_CHECK_RETRIES)
- {
- rt_thread_mdelay(500);
- continue;
- }
- return RT_FALSE;
- }
- if (stat != 1 && stat != 5)
- {
- LOG_D("Network check: CREG stat=%d (not registered)", stat);
- return RT_FALSE;
- }
- resp = ym310_at_exec_cmd("AT+CGATT?", resp_buf, sizeof(resp_buf), YM310_AT_SHORT_TIMEOUT_MS);
- if (resp != AT_RESP_OK)
- {
- LOG_D("Network check: CGATT query failed (resp=%d)", resp);
- retry_count++;
- if (retry_count <= NETWORK_CHECK_RETRIES)
- {
- rt_thread_mdelay(500);
- continue;
- }
- return RT_FALSE;
- }
- int attach_state;
- if (ym310_parse_cgatt_response(resp_buf, &attach_state) != 0)
- {
- LOG_D("Network check: CGATT parse failed");
- retry_count++;
- if (retry_count <= NETWORK_CHECK_RETRIES)
- {
- rt_thread_mdelay(500);
- continue;
- }
- return RT_FALSE;
- }
- if (attach_state != 1)
- {
- LOG_D("Network check: CGATT state=%d (not attached)", attach_state);
- return RT_FALSE;
- }
- resp = ym310_at_exec_cmd("AT+QIPACT?", resp_buf, sizeof(resp_buf), YM310_AT_SHORT_TIMEOUT_MS);
- if (resp == AT_RESP_OK)
- {
- int context_id, pdp_state;
- char ip_addr[32] = {0};
- if (ym310_parse_qipact_response(resp_buf, &context_id, &pdp_state, ip_addr, sizeof(ip_addr)) == 0)
- {
- if (once)
- {
- LOG_I("Network check: PDP context_id=%d, state=%d, ip=%s", context_id, pdp_state, ip_addr);
- once = 0;
- }
- else
- {
- LOG_D("Network check: PDP context_id=%d, state=%d, ip=%s", context_id, pdp_state, ip_addr);
- }
- if (pdp_state == 1)
- {
- return RT_TRUE;
- }
- else
- {
- LOG_D("Network check: PDP not activated (state=%d)", pdp_state);
- return RT_FALSE;
- }
- }
- else
- {
- if (rt_strstr(resp_buf, "1,1") != RT_NULL)
- {
- LOG_D("Network check: PDP active (raw check)");
- return RT_TRUE;
- }
- LOG_D("Network check: PDP parse failed, resp=%s", resp_buf);
- return RT_FALSE;
- }
- }
- else
- {
- LOG_D("Network check: QIPACT query failed (resp=%d)", resp);
- retry_count++;
- if (retry_count <= NETWORK_CHECK_RETRIES)
- {
- rt_thread_mdelay(500);
- continue;
- }
- return RT_FALSE;
- }
- break;
- }
- return RT_FALSE;
- }
- rt_bool_t ym310_check_mqtt_connected(rt_uint8_t client_idx)
- {
- if (client_idx >= MQTT_INSTANCE_MAX)
- {
- return RT_FALSE;
- }
- return (g_mqtt_instances[client_idx].state == MQTT_STATE_CONNECTED);
- }
- /*=============================================================================
- * Module Reinitialization
- *============================================================================*/
- int ym310_module_reinit(void)
- {
- at_resp_type_t resp;
- char resp_buf[128];
- int context_id, pdp_state;
- LOG_W("Attempting module reinitialization...");
- resp = ym310_at_exec_cmd("AT+QIPACT?", resp_buf, sizeof(resp_buf), YM310_AT_CMD_TIMEOUT_MS);
- if (resp == AT_RESP_OK)
- {
- if (ym310_parse_qipact_response(resp_buf, &context_id, &pdp_state, RT_NULL, 0) == 0)
- {
- if (pdp_state == 1)
- {
- LOG_I("PDP already active (context=%d), no reactivation needed", context_id);
- return RT_EOK;
- }
- }
- else if (rt_strstr(resp_buf, "1,1") != RT_NULL)
- {
- LOG_I("PDP already active (raw check), no reactivation needed");
- return RT_EOK;
- }
- }
- LOG_I("Reactivating PDP...");
- resp = ym310_at_exec_cmd("AT+QIPACT=1", RT_NULL, 0, YM310_AT_LONG_TIMEOUT_MS);
- if (resp == AT_RESP_OK)
- {
- LOG_I("PDP reactivated");
- return RT_EOK;
- }
- resp = ym310_at_exec_cmd("AT+QIPACT?", resp_buf, sizeof(resp_buf), YM310_AT_CMD_TIMEOUT_MS);
- if (resp == AT_RESP_OK)
- {
- if (rt_strstr(resp_buf, "1,1") != RT_NULL || rt_strstr(resp_buf, "1,1,") != RT_NULL)
- {
- LOG_I("PDP is actually active, ignoring reactivation error");
- return RT_EOK;
- }
- }
- LOG_W("Full re-registration may be required");
- return -RT_ERROR;
- }
- /*=============================================================================
- * Maintenance Thread
- *============================================================================*/
- #include "ym310_protecl.h"
- extern SYS_INFO sys_info;
- /**
- * @brief 判断NTP时间是否已同步成功
- * @return 1=已同步, 0=未同步
- *
- * 判断逻辑:当前系统时间若为2026年5月及以前,认为未同步
- * 因为设备实际运行时间在2026年6月之后
- */
- static uint8_t is_ntp_synced(void)
- {
- extern struct rtc_time time_now;
- /* 计算当前时间的 (年*12 + 月) 值 */
- uint32_t current_value = (uint32_t)(time_now.year - 2000) * 12 + time_now.month;
- /* 2026年5月的参考值:26*12 + 5 = 317 */
- uint32_t threshold = 26 * 12 + 5;
- // rt_kprintf("current_value %d threshold %d res = %d" , current_value ,threshold, (current_value > threshold));
- /* 如果当前时间 <= 2026年5月,认为NTP未同步 */
- if (current_value <= threshold)
- {
- return 0; /* 未同步 */
- }
- return 1; /* 已同步 */
- }
- static void ym310_maintain_thread_entry(void *param)
- {
- #define MAIN_LOOP_DELAY_MS 100
- #define GPS_CYCLE_MS 600000 / 10 // 现在也就是一分钟一次
- #define MAINTAIN_CYCLE_MS 120000
- #define NTP_CYCLE_MS 600000 * 6
- #define GPS_LOOPS (GPS_CYCLE_MS / MAIN_LOOP_DELAY_MS)
- #define MAINTAIN_LOOPS (MAINTAIN_CYCLE_MS / MAIN_LOOP_DELAY_MS)
- #define NTP_LOOPS (NTP_CYCLE_MS / MAIN_LOOP_DELAY_MS)
- static rt_uint32_t loop_counter = 1;
- static char first_ntp_attempted = 1;
- rt_thread_mdelay(5000);
- if (ym310_gps_init() != RT_EOK)
- {
- LOG_W("GPS init deferred, will retry later");
- }
- while (1)
- {
- if (loop_counter % MAINTAIN_LOOPS == 0)
- {
- rt_bool_t network_connected = ym310_check_network_connected();
- s_last_network_connected = network_connected;
- if (!network_connected)
- {
- s_net_fail_count++;
- LOG_D("Network check failed (count=%d/%d)", s_net_fail_count, NET_FAIL_THRESHOLD);
- if (s_net_fail_count >= NET_FAIL_THRESHOLD)
- {
- LOG_W("Network disconnected! Attempting recovery...");
- if (ym310_module_reinit() == RT_EOK)
- {
- LOG_I("Network recovered");
- s_net_fail_count = 0;
- }
- for (int i = 0; i < MQTT_INSTANCE_MAX; i++)
- {
- if (g_mqtt_instances[i].config.enabled)
- {
- if (g_mqtt_instances[i].state == MQTT_STATE_CONNECTED)
- {
- g_mqtt_instances[i].state = MQTT_STATE_DISCONNECTED;
- }
- }
- }
- }
- }
- else
- {
- if (s_net_fail_count > 0)
- {
- LOG_D("Network check passed, resetting failure counter");
- s_net_fail_count = 0;
- }
- }
- char csq_buf[64];
- int rssi, ber;
- if (ym310_at_exec_cmd("AT+CSQ", csq_buf, sizeof(csq_buf), YM310_AT_SHORT_TIMEOUT_MS) == AT_RESP_OK)
- {
- if (ym310_parse_csq_response(csq_buf, &rssi, &ber) == 0)
- {
- LOG_D("Signal quality: RSSI=%d, BER=%d", rssi, ber);
- sys_info.csq = rssi;
- }
- }
- else
- {
- LOG_D("CSQ query failed");
- }
- }
- if (loop_counter % GPS_LOOPS == 0)
- {
- if (ym310_gps_get_info() == RT_EOK)
- {
- LOG_D("GPS updated: %s, %s", dev_info.latitude, dev_info.longitude);
- }
- }
- /* 立即 NTP 同步:当 RTC 是默认值时,第一次网络就绪后立即执行一次 */
- if (first_ntp_attempted && (is_ntp_synced() == 0))
- {
- if (ym310_check_network_connected())
- {
- LOG_I("RTC is default value, syncing time immediately...");
- if (ym310_ntp_sync_time() == RT_EOK)
- {
- first_ntp_attempted = 0;
- LOG_I("Initial NTP sync completed, RTC updated");
- }
- else
- {
- LOG_W("Initial NTP sync failed, will retry on next network check");
- }
- }
- // else
- // {
- // LOG_W("s_last_network_connected == 0");
- // }
- }
- // else
- // {
- // LOG_I("year = %d mon = %d day = %d" , time_now.year , time_now.month , time_now.date );
- // }
- if (loop_counter % NTP_LOOPS == 0)
- {
- if (s_last_network_connected)
- {
- ym310_ntp_sync_time();
- }
- }
- loop_counter++;
- if (loop_counter == 0)
- loop_counter = 1;
- rt_thread_mdelay(MAIN_LOOP_DELAY_MS);
- }
- ym310_gps_deinit();
- LOG_I("Maintenance thread stopped");
- }
- /*=============================================================================
- * Public API
- *============================================================================*/
- rt_thread_t ym310_start_maintain_thread(void)
- {
- g_maintain_thread = rt_thread_create("ym310_maint", ym310_maintain_thread_entry,
- RT_NULL, MAINTAIN_THREAD_STACK_SIZE,
- MAINTAIN_THREAD_PRIORITY, 10);
- if (g_maintain_thread == RT_NULL)
- {
- LOG_E("Failed to create maintenance thread!");
- return RT_NULL;
- }
- rt_thread_startup(g_maintain_thread);
- return g_maintain_thread;
- }
- void ym310_maintain_thread_stop(void)
- {
- s_maintain_thread_running = RT_FALSE;
- }
- /*=============================================================================
- * GCJ-02 Transform Test Command (MSH) - Integer Output Only
- *============================================================================*/
- static void transform_test(int argc, char **argv)
- {
- const char *lat_nmea, *ns, *lon_nmea, *ew;
- if (argc >= 5)
- {
- lon_nmea = argv[1];
- ew = argv[2];
- lat_nmea = argv[3];
- ns = argv[4];
- }
- else
- {
- lon_nmea = "11339.66602";
- ew = "E";
- lat_nmea = "3448.60878";
- ns = "N";
- rt_kprintf("[TEST] Using default coords: %s%s, %s%s\n", lon_nmea, ew, lat_nmea, ns);
- }
- /* Parse WGS84 for display */
- double wgs84_lat = 0.0, wgs84_lon = 0.0;
- char temp[16];
- strncpy(temp, lat_nmea, sizeof(temp) - 1);
- temp[sizeof(temp) - 1] = '\0';
- char *dot = strchr(temp, '.');
- if (dot)
- {
- char deg_str[3] = {0};
- strncpy(deg_str, temp, 2);
- int deg = atoi(deg_str);
- double minutes = atof(temp + 2);
- wgs84_lat = (double)deg + minutes / 60.0;
- if (*ns == 'S' || *ns == 's')
- wgs84_lat = -wgs84_lat;
- }
- strncpy(temp, lon_nmea, sizeof(temp) - 1);
- temp[sizeof(temp) - 1] = '\0';
- dot = strchr(temp, '.');
- if (dot)
- {
- char deg_str[4] = {0};
- strncpy(deg_str, temp, 3);
- int deg = atoi(deg_str);
- double minutes = atof(temp + 3);
- wgs84_lon = (double)deg + minutes / 60.0;
- if (*ew == 'W' || *ew == 'w')
- wgs84_lon = -wgs84_lon;
- }
- long wgs84_lat_int = (long)(wgs84_lat * 1e7 + (wgs84_lat >= 0 ? 0.5 : -0.5));
- long wgs84_lon_int = (long)(wgs84_lon * 1e7 + (wgs84_lon >= 0 ? 0.5 : -0.5));
- /* Convert to GCJ-02 */
- int gcj_lat_1e7, gcj_lon_1e7;
- nmea_pair_to_gcj02_int(lat_nmea, *ns, lon_nmea, *ew, &gcj_lat_1e7, &gcj_lon_1e7);
- /* Print results */
- rt_kprintf("\n========================================\n");
- rt_kprintf("[WGS-84] %ld.%07ld, %ld.%07ld\n",
- wgs84_lat_int / 10000000, (wgs84_lat_int % 10000000) >= 0 ? (wgs84_lat_int % 10000000) : -(wgs84_lat_int % 10000000),
- wgs84_lon_int / 10000000, (wgs84_lon_int % 10000000) >= 0 ? (wgs84_lon_int % 10000000) : -(wgs84_lon_int % 10000000));
- rt_kprintf("[GCJ-02] %d.%07d, %d.%07d\n",
- gcj_lat_1e7 / 10000000, (gcj_lat_1e7 % 10000000) >= 0 ? (gcj_lat_1e7 % 10000000) : -(gcj_lat_1e7 % 10000000),
- gcj_lon_1e7 / 10000000, (gcj_lon_1e7 % 10000000) >= 0 ? (gcj_lon_1e7 % 10000000) : -(gcj_lon_1e7 % 10000000));
- long dlat = (long)gcj_lat_1e7 - wgs84_lat_int;
- long dlon = (long)gcj_lon_1e7 - wgs84_lon_int;
- rt_kprintf("[OFFSET] dLat = %ld (1e-7 deg), dLon = %ld (1e-7 deg)\n", dlat, dlon);
- rt_kprintf("========================================\n\n");
- }
- MSH_CMD_EXPORT(transform_test, Test WGS84 to GCJ - 02 conversion)
|