#include #include #include #include "ql_rtos.h" #include "ql_rtc.h" #include "ql_uart.h" #include "factory_protocol.h" #define FT_PROTOCOL_LINE_MAX 1024 typedef struct { char session[32]; char imei[32]; char iccid[32]; char nfc_uid[32]; char start_time[40]; u32 start_ms; u32 seq; ft_state_t nodes[FT_NODE_COUNT]; int cdc_open; } ft_protocol_context_t; static ft_protocol_context_t g_protocol; u32 ft_now_ms(void) { return ql_rtos_get_systicks() * 5U; } const char *ft_node_name(ft_node_t node) { static const char *names[FT_NODE_COUNT] = { "BOOT_AUDIO", "POWER_ADC", "AUDIO_LOOPBACK", "KEY_TRIPLE", "ESIM", "DATA_CALL", "PING", "NFC" }; if (node < 0 || node >= FT_NODE_COUNT) { return "UNKNOWN"; } return names[node]; } static const char *ft_state_name(ft_state_t state) { if (state == FT_STATE_PASS) return "PASS"; if (state == FT_STATE_FAIL) return "FAIL"; return "WAIT"; } static void ft_emit(const char *fmt, ...) { char payload[FT_PROTOCOL_LINE_MAX - 16]; char line[FT_PROTOCOL_LINE_MAX]; va_list args; int len; va_start(args, fmt); vsnprintf(payload, sizeof(payload), fmt, args); va_end(args); len = snprintf(line, sizeof(line), "FT1 %s\r\n", payload); if (len < 0) return; if (len >= (int)sizeof(line)) len = sizeof(line) - 1; printf("%s", line); if (g_protocol.cdc_open) { ql_uart_write(QL_USB_CDC_PORT, (unsigned char *)line, len); } } static void ft_make_session(void) { ql_rtc_time_t rtc = {0}; u32 now = ft_now_ms(); g_protocol.start_ms = now; if (ql_rtc_get_time(&rtc) == 0 && rtc.tm_year >= 2024) { snprintf(g_protocol.start_time, sizeof(g_protocol.start_time), "%04d-%02d-%02dT%02d:%02d:%02d", rtc.tm_year, rtc.tm_mon, rtc.tm_mday, rtc.tm_hour, rtc.tm_min, rtc.tm_sec); snprintf(g_protocol.session, sizeof(g_protocol.session), "%04d%02d%02d-%02d%02d%02d", rtc.tm_year, rtc.tm_mon, rtc.tm_mday, rtc.tm_hour, rtc.tm_min, rtc.tm_sec); } else { strcpy(g_protocol.start_time, ""); snprintf(g_protocol.session, sizeof(g_protocol.session), "BOOT-%010lu", (unsigned long)now); } } void ft_protocol_init(void) { memset(&g_protocol, 0, sizeof(g_protocol)); g_protocol.cdc_open = (ql_uart_open(QL_USB_CDC_PORT, QL_UART_BAUD_115200, QL_FC_NONE) == 0); ft_make_session(); } static void ft_copy(char *dst, unsigned int dst_size, const char *src) { if (!dst || dst_size == 0) return; if (!src) src = ""; snprintf(dst, dst_size, "%s", src); } void ft_protocol_set_imei(const char *imei) { ft_copy(g_protocol.imei, sizeof(g_protocol.imei), imei); } void ft_protocol_set_iccid(const char *iccid) { ft_copy(g_protocol.iccid, sizeof(g_protocol.iccid), iccid); } void ft_protocol_set_nfc_uid(const char *uid) { ft_copy(g_protocol.nfc_uid, sizeof(g_protocol.nfc_uid), uid); } const char *ft_protocol_imei(void) { return g_protocol.imei; } const char *ft_protocol_iccid(void) { return g_protocol.iccid; } const char *ft_protocol_nfc_uid(void) { return g_protocol.nfc_uid; } void ft_protocol_session_start(void) { ft_emit("{\"v\":%d,\"type\":\"session_start\",\"seq\":%lu," "\"session\":\"%s\",\"uptime_ms\":%lu,\"imei\":\"%s\"," "\"iccid\":\"%s\",\"nfc_uid\":\"%s\",\"fw\":\"%s\"," "\"ping_host\":\"%s\",\"start_time\":%s%s%s}", FT_PROTOCOL_VERSION, (unsigned long)++g_protocol.seq, g_protocol.session, (unsigned long)ft_now_ms(), g_protocol.imei, g_protocol.iccid, g_protocol.nfc_uid, FT_FIRMWARE_VERSION, FT_PING_HOST, g_protocol.start_time[0] ? "\"" : "null", g_protocol.start_time, g_protocol.start_time[0] ? "\"" : ""); } void ft_protocol_node_start(ft_node_t node) { ft_emit("{\"v\":%d,\"type\":\"node_start\",\"seq\":%lu," "\"session\":\"%s\",\"uptime_ms\":%lu,\"imei\":\"%s\"," "\"iccid\":\"%s\",\"nfc_uid\":\"%s\",\"node\":%d," "\"name\":\"%s\"}", FT_PROTOCOL_VERSION, (unsigned long)++g_protocol.seq, g_protocol.session, (unsigned long)ft_now_ms(), g_protocol.imei, g_protocol.iccid, g_protocol.nfc_uid, node, ft_node_name(node)); } void ft_protocol_node_progress(ft_node_t node, int current, int required) { ft_emit("{\"v\":%d,\"type\":\"node_progress\",\"seq\":%lu," "\"session\":\"%s\",\"uptime_ms\":%lu,\"imei\":\"%s\"," "\"iccid\":\"%s\",\"nfc_uid\":\"%s\",\"node\":%d," "\"name\":\"%s\",\"result\":\"PASS\"," "\"data\":{\"current\":%d,\"required\":%d}}", FT_PROTOCOL_VERSION, (unsigned long)++g_protocol.seq, g_protocol.session, (unsigned long)ft_now_ms(), g_protocol.imei, g_protocol.iccid, g_protocol.nfc_uid, node, ft_node_name(node), current, required); } void ft_protocol_node_result(ft_node_t node, int passed, ft_error_t code, u32 elapsed_ms, const char *data_json) { const char *result = passed ? "PASS" : "FAIL"; if (node >= 0 && node < FT_NODE_COUNT) { g_protocol.nodes[node] = passed ? FT_STATE_PASS : FT_STATE_FAIL; } if (!data_json || !data_json[0]) data_json = "{}"; ft_emit("{\"v\":%d,\"type\":\"node_result\",\"seq\":%lu," "\"session\":\"%s\",\"uptime_ms\":%lu,\"imei\":\"%s\"," "\"iccid\":\"%s\",\"nfc_uid\":\"%s\",\"node\":%d," "\"name\":\"%s\",\"result\":\"%s\",\"code\":%d," "\"elapsed_ms\":%lu,\"data\":%s}", FT_PROTOCOL_VERSION, (unsigned long)++g_protocol.seq, g_protocol.session, (unsigned long)ft_now_ms(), g_protocol.imei, g_protocol.iccid, g_protocol.nfc_uid, node, ft_node_name(node), result, code, (unsigned long)elapsed_ms, data_json); } void ft_protocol_session_result(int passed, ft_error_t code) { ft_emit("{\"v\":%d,\"type\":\"session_result\",\"seq\":%lu," "\"session\":\"%s\",\"uptime_ms\":%lu,\"result\":\"%s\"," "\"fail_code\":%d,\"imei\":\"%s\",\"iccid\":\"%s\"," "\"nfc_uid\":\"%s\",\"start_time\":%s%s%s," "\"duration_ms\":%lu,\"nodes\":{" "\"BOOT_AUDIO\":\"%s\",\"POWER_ADC\":\"%s\"," "\"AUDIO_LOOPBACK\":\"%s\",\"KEY_TRIPLE\":\"%s\"," "\"ESIM\":\"%s\",\"DATA_CALL\":\"%s\"," "\"PING\":\"%s\",\"NFC\":\"%s\"}}", FT_PROTOCOL_VERSION, (unsigned long)++g_protocol.seq, g_protocol.session, (unsigned long)ft_now_ms(), passed ? "PASS" : "FAIL", code, g_protocol.imei, g_protocol.iccid, g_protocol.nfc_uid, g_protocol.start_time[0] ? "\"" : "null", g_protocol.start_time, g_protocol.start_time[0] ? "\"" : "", (unsigned long)(ft_now_ms() - g_protocol.start_ms), ft_state_name(g_protocol.nodes[0]), ft_state_name(g_protocol.nodes[1]), ft_state_name(g_protocol.nodes[2]), ft_state_name(g_protocol.nodes[3]), ft_state_name(g_protocol.nodes[4]), ft_state_name(g_protocol.nodes[5]), ft_state_name(g_protocol.nodes[6]), ft_state_name(g_protocol.nodes[7])); } void ft_protocol_power_off(void) { ft_emit("{\"v\":%d,\"type\":\"power_off\",\"seq\":%lu," "\"session\":\"%s\",\"uptime_ms\":%lu,\"imei\":\"%s\"," "\"iccid\":\"%s\",\"nfc_uid\":\"%s\",\"code\":0}", FT_PROTOCOL_VERSION, (unsigned long)++g_protocol.seq, g_protocol.session, (unsigned long)ft_now_ms(), g_protocol.imei, g_protocol.iccid, g_protocol.nfc_uid); }