/* * Copyright (c) 2006-2026, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2026-02-03 RT-Thread first version */ /*********************↓ define ↓************************/ #define DBG_TAG "main" #define DBG_LVL DBG_LOG #define VALID 0x9D /*********************↑ define ↑************************/ /*********************↓ include ↓************************/ #include #include #include "main.h" #include "ym310_mqtt.h" /*********************↑ include ↑************************/ /*********************↓ extern ↓************************/ extern SYS_INFO sys_info; extern DEV_INFO dev_info; extern LIMIT limit; /*********************↑ extern ↑************************/ /********************↓ declaration ↓***********************/ static void load_from_ef(void); void Read_para(void); void RESET_ALL_PARA(void); static void validate_and_fix_params(void); /********************↑ declaration ↑***********************/ /*********************↓ global variables ↓************************/ volatile char ef_cfged = 0; volatile char up_flag = 0; volatile char upload_ecode = 0; volatile char update_res = 0; volatile char upload_res = 0; /*********************↑ global variables ↑************************/ /* 打印系统参数的函数 */ static void print_system_params(void) { LOG_I("========== System Parameters =========="); LOG_I(" VERSION : %s", version_with_time()); rt_kprintf("\n"); LOG_I(" [SYS_INFO]"); LOG_I(" imei : %s", sys_info.imei[0] ? sys_info.imei : "(empty)"); LOG_I(" iccid : %s", sys_info.iccid[0] ? sys_info.iccid : "(empty)"); LOG_I(" csq : %u", sys_info.csq); LOG_I(" update_url : %s", sys_info.update_url); LOG_I(" customer_cfg :"); LOG_I(" sub_topic : %s", sys_info.customer_cfg.sub_topic[0] ? sys_info.customer_cfg.sub_topic : "(empty)"); LOG_I(" pub_topic : %s", sys_info.customer_cfg.pub_topic[0] ? sys_info.customer_cfg.pub_topic : "(empty)"); LOG_I(" host : %s", sys_info.customer_cfg.host[0] ? sys_info.customer_cfg.host : "(empty)"); LOG_I(" port : %u", sys_info.customer_cfg.port); LOG_I(" qos : %u", sys_info.customer_cfg.qos); LOG_I(" enable : 0x%02X %s", sys_info.customer_cfg.enable, (sys_info.customer_cfg.enable == VALID) ? "(开启)" : "(关闭)"); LOG_I(" lastwill : %s", sys_info.customer_cfg.lastwill[0] ? sys_info.customer_cfg.lastwill : "(empty)"); LOG_I(" username : %s", sys_info.customer_cfg.username[0] ? sys_info.customer_cfg.username : "(empty)"); LOG_I(" password : %s", sys_info.customer_cfg.password[0] ? "(已设置)" : "(empty)"); if (strstr(sys_info.customer_cfg.client_id, "USE_IMEI") != NULL) { LOG_I(" client_id : %s", sys_info.imei[0] ? sys_info.imei : "(empty)"); } else { LOG_I(" client_id : %s", sys_info.customer_cfg.client_id[0] ? sys_info.customer_cfg.client_id : "(empty)"); } rt_kprintf("\n"); LOG_I(" [DEV_INFO]"); // LOG_I(" work_state : %u %s", dev_info.work_state, // dev_info.work_state == 0 ? "(待机)" : dev_info.work_state == 1 ? "(工作)" // : dev_info.work_state == 2 ? "(充电)" // : ""); LOG_I(" power_state : %u %s", dev_info.power_state, dev_info.power_state ? "(开机)" : "(关机)"); LOG_I(" light_work_duration : %u", dev_info.light_work_duration); LOG_I(" time_ctrl_enable : %u", dev_info.time_ctrl_enable); LOG_I(" time_start : %u", dev_info.time_start); LOG_I(" time_end : %u", dev_info.time_end); // LOG_I(" undervolt_protect : %u", dev_info.undervolt_protect); // LOG_I(" temp_protect : %u", dev_info.temp_protect); // LOG_I(" tilt_protect : %u", dev_info.tilt_protect); // LOG_I(" rain_protect : %u", dev_info.rain_protect); LOG_I(" light_flag : %u", dev_info.light_flag); // LOG_I(" hv_count : %u", dev_info.hv_count); // LOG_I(" charge_voltage : %u mV (%d.%03d V)", // dev_info.charge_voltage, // dev_info.charge_voltage / 1000, // dev_info.charge_voltage % 1000); // LOG_I(" battery_voltage : %u mV (%d.%03d V)", // dev_info.battery_voltage, // dev_info.battery_voltage / 1000, // dev_info.battery_voltage % 1000); // // LOG_I(" board_temp : %d (°C)", dev_info.board_temp); // LOG_I(" lamp_fault : %u %s", dev_info.lamp_fault, dev_info.lamp_fault ? "(故障)" : "(正常)"); // LOG_I(" idle_flag : %u", dev_info.idle_flag); LOG_I(" data_interval : %u min", dev_info.data_interval); LOG_I(" clean_interval : %u min", dev_info.clean_interval); LOG_I(" clean_enable : %u %s", dev_info.clean_enable, dev_info.clean_enable ? "(开启)" : "(关闭)"); LOG_I(" gps_mode : %u", dev_info.GPS_MODE); LOG_I(" longitude : %s", dev_info.longitude[0] ? dev_info.longitude : "(empty)"); LOG_I(" latitude : %s", dev_info.latitude[0] ? dev_info.latitude : "(empty)"); rt_kprintf("\n"); LOG_I(" [LIMIT]"); LOG_I(" vsunrise : %u", limit.vsunrise); LOG_I(" vsunset : %u", limit.vsunset); LOG_I(" vcutof : %u", limit.vcutof); LOG_I(" vfloat : %u", limit.vfloat); LOG_I(" vrecharge : %u", limit.vrecharge); LOG_I(" uvstart : %u", limit.uvstart); LOG_I(" uvoff : %u", limit.uvoff); LOG_I(" uvon : %u", limit.uvon); LOG_I(" overtemp : %u", limit.overtemp); LOG_I(" lowtemp : %u", limit.lowtemp); LOG_I(" unovert : %u", limit.unovert); LOG_I(" unlowt : %u", limit.unlowt); LOG_I(" battype : %u", limit.battype); } void save_sys_info(void) { int ret = ef_set_env_blob(EF_SYS_INFO, &sys_info, sizeof(sys_info)); LOG_W("sys_info save %d ", ret); if (ret == EF_NO_ERR) { parabak_backup(PARABAK_ID_SYS_INFO); } } void save_dev_info(void) { int ret = ef_set_env_blob(EF_DEV_INFO, &dev_info, sizeof(dev_info)); LOG_W("dev_info save %d ", ret); if (ret == EF_NO_ERR) { parabak_backup(PARABAK_ID_DEV_INFO); } } void save_limit(void) { int ret = ef_set_env_blob(EF_LIMIT, &limit, sizeof(limit)); LOG_W("limit save %d ", ret); if (ret == EF_NO_ERR) { parabak_backup(PARABAK_ID_LIMIT); } } static sys_info_reset(void) { rt_memset(&sys_info, 0, sizeof(sys_info)); rt_strncpy(sys_info.customer_cfg.sub_topic, "/yfkj/scd/sub", sizeof(sys_info.customer_cfg.sub_topic) - 1); rt_strncpy(sys_info.customer_cfg.pub_topic, "/yfkj/scd/pub", sizeof(sys_info.customer_cfg.pub_topic) - 1); rt_strncpy(sys_info.customer_cfg.host, "120.27.222.26", sizeof(sys_info.customer_cfg.host) - 1); sys_info.customer_cfg.port = 1883; sys_info.customer_cfg.qos = 0; sys_info.customer_cfg.enable = 0; /* 默认关闭 */ save_sys_info(); } static dev_info_reset(void) { rt_memset(&dev_info, 0, sizeof(dev_info)); dev_info.light_work_duration = 4; dev_info.data_interval = 10; dev_info.clean_interval = 30; dev_info.clean_enable = 0; // 自清虫 dev_info.power_state = 1; dev_info.time_start = 20; dev_info.time_end = 2; dev_info.light_flag = 0; dev_info.GPS_MODE = 1; save_dev_info(); } static limit_reset(void) { rt_memset(&limit, 0, sizeof(limit)); limit.uvoff = 3700; // 欠压恢复 = 3.7V limit.uvon = 3500; // 欠压开启 = 3.5V limit.overtemp = 700; // 高温保护 = 70度 limit.unovert = 500; // 高温恢复 = 50 limit.lowtemp = 100; // 低温保护 = 10 limit.unlowt = 150; // 低温恢复 = 15 limit.vsunrise = 3300; // 日出电压=3.3V limit.vsunset = 1500; // 日落电压=1.5V save_limit(); } static void load_from_ef(void) { size_t read_len; read_len = ef_get_env_blob(EF_SYS_INFO, &sys_info, sizeof(sys_info), NULL); if (read_len != sizeof(sys_info)) { int bak_state = parabak_self_check(PARABAK_ID_SYS_INFO, NULL); if (bak_state == 1) { LOG_I("sys_info EF read failed but backup valid, will restore later"); } else { LOG_W("No valid sys_info in EF, use default > read_len %d ", read_len); Recode_e_code(e_para_setdef, 1, "sys_info使用默认参数"); sys_info_reset(); } } read_len = ef_get_env_blob(EF_DEV_INFO, &dev_info, sizeof(dev_info), NULL); if (read_len != sizeof(dev_info)) { int bak_state = parabak_self_check(PARABAK_ID_DEV_INFO, NULL); if (bak_state == 1) { LOG_I("dev_info EF read failed but backup valid, will restore later"); } else { LOG_W("No valid dev_info in EF, use default > read_len %d ", read_len); Recode_e_code(e_para_setdef, 2, "dev_info使用默认参数"); dev_info_reset(); } } read_len = ef_get_env_blob(EF_LIMIT, &limit, sizeof(limit), NULL); if (read_len != sizeof(limit)) { int bak_state = parabak_self_check(PARABAK_ID_LIMIT, NULL); if (bak_state == 1) { LOG_I("limit EF read failed but backup valid, will restore later"); } else { LOG_W("No valid limit in EF, use default > read_len %d ", read_len); Recode_e_code(e_para_setdef, 3, "limit使用默认参数"); limit_reset(); } } LOG_I("Loaded from EasyFlash"); } void RESET_ALL_PARA(void) { ef_env_set_default(); sys_info_reset(); dev_info_reset(); limit_reset(); Recode_e_code(e_para_setdef, 0, "强制恢复默认参数"); } void Read_para(void) { uint32_t start_time = 0; ef_get_env_blob("start_time", &start_time, sizeof(start_time), NULL); start_time++; ef_set_env_blob("start_time", &start_time, sizeof(start_time)); LOG_I("System started on %d times.", start_time); ef_get_env_blob("up_flag", &up_flag, sizeof(up_flag), NULL); ef_get_env_blob("upload_ecode", &upload_ecode, sizeof(upload_ecode), NULL); ef_get_env_blob("update_res", &update_res, sizeof(update_res), NULL); ef_get_env_blob("upload_res", &upload_res, sizeof(upload_res), NULL); } /*********************↓ parameter validation ↓***********************/ /** * @brief 校验并修正设备参数和限制参数的范围 * * 默认值参考 dev_info_reset() 和 limit_reset() * 只校验这两个函数中出现的参数 */ static void validate_and_fix_params(void) { uint8_t need_save_dev = 0; uint8_t need_save_limit = 0; char ecode_buf[50]; LOG_I("========== Parameter Validation Started =========="); /* ========== DEV_INFO 参数校验(默认值参考 dev_info_reset) ========== */ /* 1. data_interval: 数据上报间隔 (5-180分钟),默认10 */ if (dev_info.data_interval < 5 || dev_info.data_interval > 180) { uint16_t old_val = dev_info.data_interval; LOG_W("data_interval out of range [5,180]: %u, reset to default 10", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "上报间隔非法值=%u 恢复默认=10", old_val); Recode_e_code(e_para_setdef, 10, ecode_buf); dev_info.data_interval = 10; need_save_dev = 1; } /* 2. light_work_duration: 光控工作时长 (0-10小时),默认4 */ if (dev_info.light_work_duration > 10) { uint16_t old_val = dev_info.light_work_duration; LOG_W("light_work_duration out of range [0,10]: %u, reset to default 4", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "工作时长非法值=%u 恢复默认=4", old_val); Recode_e_code(e_para_setdef, 11, ecode_buf); dev_info.light_work_duration = 4; need_save_dev = 1; } /* 3. clean_interval: 清扫间隔 (5-180分钟),默认30 */ if (dev_info.clean_interval < 5 || dev_info.clean_interval > 180) { uint16_t old_val = dev_info.clean_interval; LOG_W("clean_interval out of range [5,180]: %u, reset to default 30", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "清扫间隔非法值=%u 恢复默认=30", old_val); Recode_e_code(e_para_setdef, 12, ecode_buf); dev_info.clean_interval = 30; need_save_dev = 1; } /* 4. clean_enable: 自清虫标志 (0-1),默认0 */ if (dev_info.clean_enable > 1) { uint8_t old_val = dev_info.clean_enable; LOG_W("clean_enable out of range [0,1]: %u, reset to default 0", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "自清虫标志非法值=%u 恢复默认=0", old_val); Recode_e_code(e_para_setdef, 13, ecode_buf); dev_info.clean_enable = 0; need_save_dev = 1; } /* 5. power_state: 开关机状态 (0-1),默认1 */ if (dev_info.power_state > 1) { uint8_t old_val = dev_info.power_state; LOG_W("power_state out of range [0,1]: %u, reset to default 1", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "开关机状态非法值=%u 恢复默认=1", old_val); Recode_e_code(e_para_setdef, 14, ecode_buf); dev_info.power_state = 1; need_save_dev = 1; } /* 6. time_start: 时控开始小时 (0-23),默认20 */ if (dev_info.time_start > 23) { uint8_t old_val = dev_info.time_start; LOG_W("time_start out of range [0,23]: %u, reset to default 20", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "时控开始非法值=%u 恢复默认=20", old_val); Recode_e_code(e_para_setdef, 15, ecode_buf); dev_info.time_start = 20; need_save_dev = 1; } /* 7. time_end: 时控结束小时 (0-23),默认2 */ if (dev_info.time_end > 23) { uint8_t old_val = dev_info.time_end; LOG_W("time_end out of range [0,23]: %u, reset to default 2", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "时控结束非法值=%u 恢复默认=2", old_val); Recode_e_code(e_para_setdef, 16, ecode_buf); dev_info.time_end = 2; need_save_dev = 1; } /* 8. light_flag: 光控切换标志位 (0-1),默认0 */ if (dev_info.light_flag > 1) { uint8_t old_val = dev_info.light_flag; LOG_W("light_flag out of range [0,1]: %u, reset to default 0", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "光控源非法值=%u 恢复默认=0", old_val); Recode_e_code(e_para_setdef, 17, ecode_buf); dev_info.light_flag = 0; need_save_dev = 1; } /* 9. GPS_MODE: GPS模式 (0-1),默认1 */ if ((dev_info.GPS_MODE > 1) || (((strlen(dev_info.latitude_FORCE) < 5) || (strlen(dev_info.longitude_FORCE) < 5)) && (dev_info.GPS_MODE == 0))) { uint8_t old_val = dev_info.GPS_MODE; LOG_W("GPS_MODE out of range [0,1]: %u, reset to default 1", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "GPS模式非法值=%u 恢复默认=1", old_val); Recode_e_code(e_para_setdef, 18, ecode_buf); dev_info.GPS_MODE = 1; need_save_dev = 1; } /* ========== LIMIT 参数校验(默认值参考 limit_reset) ========== */ /* 10. uvoff: 欠压恢复电压 (1000-5000 mV),默认3700 */ if (limit.uvoff < 1000 || limit.uvoff > 5000) { uint16_t old_val = limit.uvoff; LOG_W("uvoff out of range [1000,5000]: %u, reset to default 3700", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "欠压恢复非法值=%u 恢复默认=3700", old_val); Recode_e_code(e_para_setdef, 20, ecode_buf); limit.uvoff = 3700; need_save_limit = 1; } /* 11. uvon: 欠压保护电压 (1000-5000 mV),默认3500 */ if (limit.uvon < 1000 || limit.uvon > 5000) { uint16_t old_val = limit.uvon; LOG_W("uvon out of range [1000,5000]: %u, reset to default 3500", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "欠压开启非法值=%u恢复默认=3500", old_val); Recode_e_code(e_para_setdef, 21, ecode_buf); limit.uvon = 3500; need_save_limit = 1; } /* 12. overtemp: 高温保护温度 (300-800, 即30-80°C),默认700 */ if (limit.overtemp < 300 || limit.overtemp > 800) { uint16_t old_val = limit.overtemp; LOG_W("overtemp out of range [300,800]: %u, reset to default 700", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "高温保护非法值=%u 恢复默认=700", old_val); Recode_e_code(e_para_setdef, 22, ecode_buf); limit.overtemp = 700; need_save_limit = 1; } /* 13. unovert: 高温恢复温度 (200-700, 即20-70°C),默认500 */ if (limit.unovert < 200 || limit.unovert > 700) { uint16_t old_val = limit.unovert; LOG_W("unovert out of range [200,700]: %u, reset to default 500", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "高温恢复非法值=%u 恢复默认=500", old_val); Recode_e_code(e_para_setdef, 23, ecode_buf); limit.unovert = 500; need_save_limit = 1; } /* 14. lowtemp: 低温保护温度 (-200-100, 即-20-10°C),默认100 (10°C) */ if ((int16_t)limit.lowtemp < -200 || (int16_t)limit.lowtemp > 100) { int16_t old_val = (int16_t)limit.lowtemp; LOG_W("lowtemp out of range [-200,100]: %d, reset to default 100", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "低温保护非法值=%d 恢复默认=100", old_val); Recode_e_code(e_para_setdef, 24, ecode_buf); limit.lowtemp = 100; need_save_limit = 1; } /* 15. unlowt: 低温恢复温度 (-150-150, 即-15-15°C),默认150 (15°C) */ if ((int16_t)limit.unlowt < -150 || (int16_t)limit.unlowt > 150) { int16_t old_val = (int16_t)limit.unlowt; LOG_W("unlowt out of range [-150,150]: %d, reset to default 150", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "低温恢复非法值=%d 恢复默认=150", old_val); Recode_e_code(e_para_setdef, 25, ecode_buf); limit.unlowt = 150; need_save_limit = 1; } /* 16. vsunrise: 日出电压 (1000-5000 mV),默认3300 */ if (limit.vsunrise < 1000 || limit.vsunrise > 5000) { uint16_t old_val = limit.vsunrise; LOG_W("vsunrise out of range [1000,5000]: %u, reset to default 3300", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "日出电压非法值=%u 恢复默认=3300", old_val); Recode_e_code(e_para_setdef, 26, ecode_buf); limit.vsunrise = 3300; need_save_limit = 1; } /* 17. vsunset: 日落电压 (1000-5000 mV),默认1500 */ if (limit.vsunset < 1000 || limit.vsunset > 5000) { uint16_t old_val = limit.vsunset; LOG_W("vsunset out of range [1000,5000]: %u, reset to default 1500", old_val); rt_snprintf(ecode_buf, sizeof(ecode_buf), "日落电压非法值=%u 恢复默认=1500", old_val); Recode_e_code(e_para_setdef, 27, ecode_buf); limit.vsunset = 1500; need_save_limit = 1; } /* ========== 保存修正后的参数 ========== */ if (need_save_dev) { save_dev_info(); LOG_I("DEV_INFO validation completed: parameters fixed and saved"); } if (need_save_limit) { save_limit(); LOG_I("LIMIT validation completed: parameters fixed and saved"); } if (!need_save_dev && !need_save_limit) { LOG_I("Parameter validation completed: all parameters are valid"); } LOG_I("========== Parameter Validation Finished =========="); } /*********************↑ parameter validation ↑***********************/ /* App工程 - 打印SCD APP花字 */ static void print_app_logo(void) { rt_kprintf("\033[38;5;37m"); rt_kprintf("╔══════════════════════════════════════════════════════════╗\n"); rt_kprintf("║ ║\n"); rt_kprintf("║ ███████╗ ██████╗██████╗ █████╗ ██████╗ ██████╗ ║\n"); rt_kprintf("║ ██╔════╝██╔════╝██╔══██╗ ██╔══██╗██╔══██╗██╔══██╗ ║\n"); rt_kprintf("║ ███████╗██║ ██║ ██║ ███████║██████╔╝██████╔╝ ║\n"); rt_kprintf("║ ╚════██║██║ ██║ ██║ ██╔══██║██╔═══╝ ██╔═══╝ ║\n"); rt_kprintf("║ ███████║╚██████╗██████╔╝ ██║ ██║██║ ██║ ║\n"); rt_kprintf("║ ╚══════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ║\n"); rt_kprintf("║ ║\n"); rt_kprintf("║ APP V%s ║\n", version_with_time()); rt_kprintf("╚══════════════════════════════════════════════════════════╝\n"); rt_kprintf("\033[0m\n"); } int main(void) { // rt_thread_mdelay(10); print_app_logo(); rt_thread_mdelay(1000); int countdown = 0; if (easyflash_init() == EF_NO_ERR) { Read_para(); load_from_ef(); validate_and_fix_params(); // 添加参数范围校验 ef_cfged = 1; parabak_auto_check(); print_system_params(); // 打印所有参数 } if ((up_flag != VALID) && (upload_ecode != VALID)) // 初始化联网 { if (ym310_driver_init() != RT_EOK) { LOG_E("YM310 init failed!"); return -1; } } else if (up_flag == VALID) // 开始执行升级操作 { while (1) { countdown++; rt_thread_mdelay(1000); if (countdown > 10 * 60) { break; } } rt_kprintf("wait for upguard time out ! %d\n", countdown); up_flag = 0; ef_set_env_blob("up_flag", &up_flag, sizeof(up_flag)); Recode_e_code(e_update_timeout, countdown, "MAIN:等待升级完成超时"); rt_thread_mdelay(500); rt_hw_cpu_reset(); } else if (upload_ecode == VALID) // 开始执行升级操作 { while (1) { countdown++; rt_thread_mdelay(1000); if (countdown > 10 * 60) { break; } } rt_kprintf("wait for upguard time out ! %d\n", countdown); upload_ecode = 0; ef_set_env_blob("upload_ecode", &upload_ecode, sizeof(upload_ecode)); Recode_e_code(e_update_timeout, countdown, "MAIN:等待上报EC完成超时"); rt_thread_mdelay(500); rt_hw_cpu_reset(); } // while(1) // { // Recode_e_code(e_test_fun, 6, "3-6是一条msh测试数据123456789"); // rt_thread_mdelay(1000); // } return RT_EOK; }