From 8a5a32b139fdf1d56f70553cb2a6260692c10aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B7=AF=E6=80=80=E5=B8=85?= <1144983626@qq.com> Date: Fri, 8 May 2026 18:17:26 +0800 Subject: [PATCH] =?UTF-8?q?add:=E5=A2=9E=E5=8A=A0=E4=B8=8A=E4=BD=8D?= =?UTF-8?q?=E6=9C=BA=E4=BA=A4=E4=BA=92=E6=A1=86=E6=9E=B6=E3=80=81Flash=20R?= =?UTF-8?q?/W=20=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/9e12a2e4a7f3dc87fa034aecf79e893c.png | Bin 0 -> 5517 bytes Core/Core/Inc/FreeRTOSConfig.h | 4 +- Core/LWIP/Target/lwipopts.h | 4 +- Core/MDK-ARM/.eide/eide.yml | 2 + .../Third_Party/Ykc/charger_to_server.c | 157 ++-- .../Third_Party/Ykc/charger_to_server.h | 11 +- .../Third_Party/Ykc/server_common.c | 31 +- .../Third_Party/Ykc/server_common.h | 8 +- .../Third_Party/Ykc/server_to_charger.c | 89 ++- Core/README.md | 1 + Core/User/Driver/drv_flash.c | 166 ++++ Core/User/Driver/drv_flash.h | 70 ++ Core/User/Driver/drv_init.c | 3 + Core/User/Driver/flash_config.c | 150 ++++ Core/User/Driver/flash_config.h | 13 + Core/User/Global/g_dcpile.c | 12 +- Core/User/Global/g_dcpile.h | 5 +- Core/User/Global/global.h | 4 + Core/User/Os/os_task.c | 4 +- Core/User/Task/ChargerTask.c | 727 ++++++++++++------ Core/User/Task/YkcTask.c | 51 +- 21 files changed, 1131 insertions(+), 381 deletions(-) create mode 100644 Core/9e12a2e4a7f3dc87fa034aecf79e893c.png create mode 100644 Core/User/Driver/drv_flash.c create mode 100644 Core/User/Driver/drv_flash.h create mode 100644 Core/User/Driver/flash_config.c create mode 100644 Core/User/Driver/flash_config.h diff --git a/Core/9e12a2e4a7f3dc87fa034aecf79e893c.png b/Core/9e12a2e4a7f3dc87fa034aecf79e893c.png new file mode 100644 index 0000000000000000000000000000000000000000..fcc8331edeb5b2bba679ebb5ab69295b05b05c71 GIT binary patch literal 5517 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 qT-`nqzNO0LH{(x7VxdA5REaw0)%8P!Klpx literal 0 HcmV?d00001 diff --git a/Core/Core/Inc/FreeRTOSConfig.h b/Core/Core/Inc/FreeRTOSConfig.h index 80e5239..766cf02 100644 --- a/Core/Core/Inc/FreeRTOSConfig.h +++ b/Core/Core/Inc/FreeRTOSConfig.h @@ -67,8 +67,8 @@ #define configCPU_CLOCK_HZ ( SystemCoreClock ) #define configTICK_RATE_HZ ((TickType_t)1000) #define configMAX_PRIORITIES ( 7 ) -#define configMINIMAL_STACK_SIZE ((uint16_t)128) -#define configTOTAL_HEAP_SIZE ((size_t)40960) +#define configMINIMAL_STACK_SIZE ((uint16_t)512) +#define configTOTAL_HEAP_SIZE ((size_t)81920) #define configMAX_TASK_NAME_LEN ( 16 ) #define configGENERATE_RUN_TIME_STATS 1 #define configUSE_TRACE_FACILITY 1 diff --git a/Core/LWIP/Target/lwipopts.h b/Core/LWIP/Target/lwipopts.h index 8ac429d..6d4df3f 100644 --- a/Core/LWIP/Target/lwipopts.h +++ b/Core/LWIP/Target/lwipopts.h @@ -94,7 +94,7 @@ /*----- Value in opt.h for DEFAULT_THREAD_PRIO: 1 -----*/ #define DEFAULT_THREAD_PRIO 3 /*----- Value in opt.h for DEFAULT_UDP_RECVMBOX_SIZE: 0 -----*/ -#define DEFAULT_UDP_RECVMBOX_SIZE 20 +#define DEFAULT_UDP_RECVMBOX_SIZE 40 /*----- Value in opt.h for DEFAULT_TCP_RECVMBOX_SIZE: 0 -----*/ #define DEFAULT_TCP_RECVMBOX_SIZE 20 /*----- Value in opt.h for DEFAULT_ACCEPTMBOX_SIZE: 0 -----*/ @@ -107,7 +107,7 @@ #define LWIP_CHECKSUM_CTRL_PER_NETIF 1 /*-----------------------------------------------------------------------------*/ /* USER CODE BEGIN 1 */ -#define MEMP_NUM_NETBUF 48 +#define MEMP_NUM_NETBUF 80 /* USER CODE END 1 */ diff --git a/Core/MDK-ARM/.eide/eide.yml b/Core/MDK-ARM/.eide/eide.yml index c23d15a..db63140 100644 --- a/Core/MDK-ARM/.eide/eide.yml +++ b/Core/MDK-ARM/.eide/eide.yml @@ -90,6 +90,8 @@ virtualFolder: - name: Driver files: - path: ../User/Driver/drv_init.c + - path: ../User/Driver/drv_flash.c + - path: ../User/Driver/flash_config.c folders: [] - name: Task files: diff --git a/Core/Middlewares/Third_Party/Ykc/charger_to_server.c b/Core/Middlewares/Third_Party/Ykc/charger_to_server.c index 9d50948..23e0b99 100644 --- a/Core/Middlewares/Third_Party/Ykc/charger_to_server.c +++ b/Core/Middlewares/Third_Party/Ykc/charger_to_server.c @@ -1,54 +1,44 @@ -#if 1 - #include "global.h" #include "charger_to_server.h" - -/************参数修改****************/ - -#define GUN_NUM 2 // 枪数量 -#define TELE_FACTORY 0 // 0x00,移动,02:电信,03:联通,04:其他 -const uint8_t SERVER_PROTOCOL_VER = 0x10; // 协议版本BCD 0x16 => V1.6 -const char iccid_ascii[10] = {0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}; // SIM卡号BCD uint16_t pack_serial = 0; // 充电桩登录认证 void charger_to_server_0X01(uint8_t stake_index) { PACK_DATA_0X01 data = {0}; - load_charger_serial(stake_index,data.charger_serial); // 加载充电桩序列号 - data.charger_type = CHARGER_TYPE_DC; - data.gun_num = GUN_NUM; + load_charger_serial(stake_index, data.charger_serial); // 加载充电桩序列号 + data.charger_type = g_charger_manager.charger_piles[stake_index - 1].login_info.charger_type; + data.gun_num = g_charger_manager.charger_piles[stake_index - 1].login_info.gun_num; data.protocol_ver = g_charger_manager.charger_piles[stake_index - 1].login_info.protocol_ver; - memcpy(data.software_ver, SOFTWARE_VERSION, strlen(SOFTWARE_VERSION)); - data.net_conn_type = NET_CONN_TYPE; - data.tele_factory = TELE_FACTORY; - memcpy(data.sim, iccid_ascii, strlen(iccid_ascii)); - printf("北向:对电桩 %d 发送登录认证,序列号:%s\r\n", stake_index,data.charger_serial); - pack_and_send_server_data(FRAME_TYPE_0X01, stake_index, 0, (uint8_t *)&data, sizeof(PACK_DATA_0X01),stake_index); + memcpy(data.software_ver, g_charger_manager.charger_piles[stake_index - 1].login_info.software_ver, 8); + data.net_conn_type = g_charger_manager.charger_piles[stake_index - 1].login_info.net_conn_type; + data.tele_factory = g_charger_manager.charger_piles[stake_index - 1].login_info.tele_factory; + memcpy(data.sim, g_charger_manager.charger_piles[stake_index - 1].login_info.sim, 10); + printf("北向:对电桩 %d 发送登录认证,序列号:%s\r\n", stake_index, data.charger_serial); + pack_and_send_server_data(FRAME_TYPE_0X01, (uint8_t *)&data, sizeof(PACK_DATA_0X01), stake_index); } - -void charger_to_server_0X03(uint8_t stake_index,uint8_t gun_index, uint8_t gun_status) +void charger_to_server_0X03(uint8_t stake_index, uint8_t gun_index, uint8_t gun_status) { PACK_DATA_0X03 data = {0}; - load_charger_serial(stake_index,data.charger_serial); // 加载充电桩序列号 + load_charger_serial(stake_index, data.charger_serial); // 加载充电桩序列号 data.gun_index = gun_index; data.gun_status = gun_status; - printf("北向:对电桩 %d 发送心跳请求,枪号:%d,状态:%d\r\n", stake_index,gun_index,gun_status); - pack_and_send_server_data(FRAME_TYPE_0X03, stake_index, 0, (uint8_t *)&data, sizeof(PACK_DATA_0X03),stake_index); + printf("北向:对电桩 %d 发送心跳请求,枪号:%d,状态:%d\r\n", stake_index, gun_index, gun_status); + pack_and_send_server_data(FRAME_TYPE_0X03, (uint8_t *)&data, sizeof(PACK_DATA_0X03), stake_index); } -// 计费模型验证请求 -void charger_to_server_0X05(uint16_t num,uint8_t stake_index) +// 计费模型验证请求 +void charger_to_server_0X05(uint16_t num, uint8_t stake_index) { PACK_DATA_0X05 data = {0}; - load_charger_serial(stake_index,data.charger_serial); // 加载充电桩序列号 + load_charger_serial(stake_index, data.charger_serial); // 加载充电桩序列号 data.fee_model_no = num; - printf("北向:对电桩 %d 计费模型验证请求,模型号:%d\r\n", stake_index,num); - pack_and_send_server_data(FRAME_TYPE_0X05, stake_index, 0, (uint8_t *)&data, sizeof(PACK_DATA_0X05),stake_index); + printf("北向:对电桩 %d 计费模型验证请求,模型号:%d\r\n", stake_index, num); + pack_and_send_server_data(FRAME_TYPE_0X05, (uint8_t *)&data, sizeof(PACK_DATA_0X05), stake_index); } // 充电桩计费模型请求 @@ -56,60 +46,103 @@ void charger_to_server_0X09(uint8_t stake_index) { PACK_DATA_0X09 data = {0}; - load_charger_serial(stake_index,data.charger_serial); // 加载充电桩序列号 - printf("北向:对电桩 %d 计费模型请求,序列号:%s\r\n", stake_index,data.charger_serial); - pack_and_send_server_data(FRAME_TYPE_0X09, stake_index, 0, (uint8_t *)&data, sizeof(PACK_DATA_0X09),stake_index); + load_charger_serial(stake_index, data.charger_serial); // 加载充电桩序列号 + printf("北向:对电桩 %d 计费模型请求,序列号:%s\r\n", stake_index, data.charger_serial); + pack_and_send_server_data(FRAME_TYPE_0X09, (uint8_t *)&data, sizeof(PACK_DATA_0X09), stake_index); } - // 上传实时监测数据 -void charger_to_server_0X13(uint8_t stake_index,uint8_t gun_index) +void charger_to_server_0X13(uint8_t stake_index, uint8_t gun_index) { - const unsigned char trade_data[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 - }; PACK_DATA_0X13 data = {0}; - load_charger_serial(stake_index,data.charger_serial); // 加载充电桩序列号 - + ChargerGun *gun = &g_charger_manager.charger_piles[stake_index - 1].guns[gun_index - 1]; // 获取枪指针 + data = gun->real_time_data;// 复制结构体 + // 覆盖需要重新加载的字段 + load_charger_serial(stake_index, data.charger_serial); + load_trade_serial(stake_index, gun_index, data.trade_serial); data.gun_index = gun_index; - //data.gun_back = getGunBack(All_status[gun_index-1]); - // data.gun_is_insert = getGunIsInsert(All_status[gun_index-1]); - data.gun_back = g_charger_manager.charger_piles[stake_index - 1].guns[gun_index - 1].real_time_data.gun_back; - data.gun_is_insert = 1; - - //Serial.printf("data.gun_is_insert====%d\n",data.gun_is_insert); - data.status =2; - if(data.status ==0x01 || data.status==0X02 ) - { - memcpy(data.trade_serial, trade_data,16); - data.out_voltage = 0; - data.charge_energy = 0; - data.out_current = 0; + // 根据状态清零特定字段 + if (data.status == 0x01 || data.status == 0x02||data.status == 0x00) + { + memset(data.trade_serial, 0, sizeof(data.trade_serial)); + data.out_voltage = 0; + data.out_current = 0; + data.charge_energy = 0; data.charge_time = 0; data.charge_money = 0; data.hard_fault = 0; } - printf("北向:对电桩 %d 上传实时监测数据,枪号:%d,状态:%d,返回:%d,是否插入:%d\r\n", stake_index,gun_index,data.status,data.gun_back,data.gun_is_insert); - pack_and_send_server_data(FRAME_TYPE_0X13, stake_index, 0, (uint8_t *)&data, sizeof(PACK_DATA_0X13),stake_index); + pack_and_send_server_data(FRAME_TYPE_0X13, (uint8_t *)&data, sizeof(PACK_DATA_0X13), stake_index); } +// 充电结束上报 +void charger_to_server_0X19(uint8_t stake_index, uint8_t gun_index) +{ + PACK_DATA_0X19 data = {0}; + load_charger_serial(stake_index, data.charger_serial); + load_trade_serial(stake_index, gun_index, data.trade_serial); + pack_and_send_server_data(FRAME_TYPE_0X19, (uint8_t *)&data, sizeof(PACK_DATA_0X19), stake_index); +} -//平台启动回复 -void charger_to_server_0X33(uint8_t stake_mark,uint8_t gun_index,uint8_t result,uint8_t err_code) +// 平台启动回复 +void charger_to_server_0X33(uint8_t stake_index, uint8_t gun_index, uint8_t result, uint8_t err_code) { PACK_DATA_0X33 data = {0}; - load_charger_serial(stake_mark,data.charger_serial); - load_trade_serial(stake_mark,gun_index,data.trade_serial); + load_charger_serial(stake_index, data.charger_serial); + load_trade_serial(stake_index, gun_index, data.trade_serial); data.gun_index = gun_index; data.result = result; data.err_code = err_code; - printf("北向:对电桩 %d 的平台启动回复,结果:%d,错误码:%d\r\n", stake_mark,result,err_code); - pack_and_send_server_data(FRAME_TYPE_0X33, stake_mark, 0, (uint8_t *)&data, sizeof(PACK_DATA_0X33), stake_mark); + uint8_t *trade_serial = g_charger_manager.charger_piles[stake_index - 1].guns[data.gun_index - 1].real_time_data.trade_serial; + + printf("回复订单ID: "); + for (int i = 0; i < 16; i++) + { + printf("%02X", trade_serial[i]); + } + printf("\r\n"); + + printf("北向:对电桩 %d 的平台启动回复,结果:%d,错误码:%d\r\n", stake_index, result, err_code); + pack_and_send_server_data(FRAME_TYPE_0X33, (uint8_t *)&data, sizeof(PACK_DATA_0X33), stake_index); +} +// 平台停机回复 +void charger_to_server_0X35(uint8_t stake_index, uint8_t gun_index, uint8_t result, uint8_t err_code) +{ + PACK_DATA_0X35 data = {0}; + load_charger_serial(stake_index, data.charger_serial); + data.gun_index = gun_index; + data.result = result; + data.err_code = err_code; + + printf("北向:对电桩 %d 的平台停机回复,结果:%d,错误码:%d\r\n", stake_index, result, err_code); + pack_and_send_server_data(FRAME_TYPE_0X35, (uint8_t *)&data, sizeof(PACK_DATA_0X35), stake_index); } -#endif \ No newline at end of file + +// 上传交易记录 +void charger_to_server_0X3B(uint8_t stake_index, uint8_t gun_index) +{ + PACK_DATA_0X3B data = {0}; + load_charger_serial(stake_index, data.charger_serial); + load_trade_serial(stake_index, gun_index, data.trade_serial); + data.gun_index = gun_index; + + + + + pack_and_send_server_data(FRAME_TYPE_0X3B, (uint8_t *)&data, sizeof(PACK_DATA_0X3B), stake_index); +} + +// 计费模型主动更新回复 +void charger_to_server_0x57(uint8_t stake_index) +{ + PACK_DATA_0X57 data = {0}; + load_charger_serial(stake_index, data.charger_serial); + data.result = 0x01; + + printf("北向:对电桩 %d 的计费模型主动更新回复\r\n", stake_index); + pack_and_send_server_data(FRAME_TYPE_0X57, (uint8_t *)&data, sizeof(PACK_DATA_0X57), stake_index); +} \ No newline at end of file diff --git a/Core/Middlewares/Third_Party/Ykc/charger_to_server.h b/Core/Middlewares/Third_Party/Ykc/charger_to_server.h index 50dbc07..c889207 100644 --- a/Core/Middlewares/Third_Party/Ykc/charger_to_server.h +++ b/Core/Middlewares/Third_Party/Ykc/charger_to_server.h @@ -5,6 +5,7 @@ #include "server_common.h" extern uint16_t pack_serial; + uint32_t get_current_rtc_sec(); //׮¼֤ @@ -23,13 +24,11 @@ extern void charger_to_server_0X09(uint8_t stake_index); extern void charger_to_server_0X13(uint8_t stake_index,uint8_t gun_index); // -extern void charger_to_server_0X19(uint8_t gun_index); +extern void charger_to_server_0X19(uint8_t stake_index,uint8_t gun_index); // ıΪA5A8 -extern void charger_to_server_0X31(uint8_t gun_index,uint32_t card_id); //0x31-0x34Ϊ0xA5-0xA8 -extern void charger_to_server_0X33(uint8_t stake_index,uint8_t gun_index,uint8_t result,uint8_t err_code); //0x310x33 - -extern void charger_to_server_0X35(uint8_t gun_index,uint8_t err_code,uint8_t result); +extern void charger_to_server_0X33(uint8_t stake_index,uint8_t gun_index,uint8_t result,uint8_t err_code); +extern void charger_to_server_0X35(uint8_t stake_index, uint8_t gun_index, uint8_t result, uint8_t err_code); extern void charger_to_server_0x3B(uint8_t gun_index,uint32_t card_id,uint8_t trade_flag,uint8_t stop_reason); //3BΪ3D @@ -41,7 +40,7 @@ extern void charger_to_server_0X55(uint32_t time); //ƷģӦ -extern void charger_to_server_0X57(uint8_t result); +extern void charger_to_server_0X57(uint8_t stake_index); extern uint8_t get_real_status_for_server(uint8_t idx); //Զظ diff --git a/Core/Middlewares/Third_Party/Ykc/server_common.c b/Core/Middlewares/Third_Party/Ykc/server_common.c index e0e25e3..4c5be9c 100644 --- a/Core/Middlewares/Third_Party/Ykc/server_common.c +++ b/Core/Middlewares/Third_Party/Ykc/server_common.c @@ -1,6 +1,7 @@ #if 1 #include "global.h" #include "server_common.h" +#include "time.h" #include @@ -210,7 +211,7 @@ uint8_t unpack_server_data(uint8_t *buf, uint8_t len, SERVER_PACK *pack) return ret; } -void pack_and_send_server_data(uint8_t type, uint8_t encrypt, uint16_t serial, uint8_t *pdata, uint8_t len, uint8_t stake_mark) +void pack_and_send_server_data(uint8_t type, uint8_t *pdata, uint8_t len, uint8_t stake_mark) { uint8_t index = 0; uint16_t crc = 0; @@ -223,10 +224,10 @@ void pack_and_send_server_data(uint8_t type, uint8_t encrypt, uint16_t serial, u } /* 原子获取全局包序号,避免多任务竞争 */ - taskENTER_CRITICAL(); + // taskENTER_CRITICAL(); current_serial = pack_serial; pack_serial++; - taskEXIT_CRITICAL(); + // taskEXIT_CRITICAL(); buf[index++] = 0x55; buf[index++] = 0xAA; @@ -238,7 +239,7 @@ void pack_and_send_server_data(uint8_t type, uint8_t encrypt, uint16_t serial, u buf[index++] = (current_serial >> 8) & 0xFF; buf[index++] = current_serial & 0xFF; - buf[index++] = encrypt; + buf[index++] = 0x00; buf[index++] = type; if ((len > 0) && (pdata)) { @@ -250,11 +251,6 @@ void pack_and_send_server_data(uint8_t type, uint8_t encrypt, uint16_t serial, u buf[index++] = (crc >> 8) & 0xFF; buf[index++] = 0xAA; buf[index++] = 0x55; - - // for (int i = 4; i < index - 2; i++) - // { - // printf("%02X", buf[i]); - // } Air724_Message_Send(buf, index); vPortFree(buf); } @@ -285,13 +281,16 @@ int get_num_from_string(const char *str, int *num) void get_cp56time_from_sec(uint8_t *buff, uint32_t sec) { - st_cp56time2a cp56time; - cp56time.Compts.year = 25; - cp56time.Compts.month = 9; - cp56time.Compts.mday = 23; - cp56time.Compts.hour = 15; - cp56time.Compts.min = 56; - cp56time.Compts.msec = 47 * 1000; + struct tm timeinfo; + st_cp56time2a cp56time = {0}; + time_t rawtime = sec; + localtime_r(&rawtime, &timeinfo); + cp56time.Compts.year = timeinfo.tm_year % 100; // 获取年份的最后两位数 + cp56time.Compts.month = timeinfo.tm_mon + 1; // tm_mon是从0开始的,所以需要加1 + cp56time.Compts.mday = timeinfo.tm_mday; + cp56time.Compts.hour = timeinfo.tm_hour; + cp56time.Compts.min = timeinfo.tm_min; + cp56time.Compts.msec = timeinfo.tm_sec * 1000; buff[0] = cp56time.time & 0xFF; buff[1] = (cp56time.time >> 8) & 0xFF; buff[2] = (cp56time.time >> 16) & 0xFF; diff --git a/Core/Middlewares/Third_Party/Ykc/server_common.h b/Core/Middlewares/Third_Party/Ykc/server_common.h index c12d4ce..03626b8 100644 --- a/Core/Middlewares/Third_Party/Ykc/server_common.h +++ b/Core/Middlewares/Third_Party/Ykc/server_common.h @@ -47,7 +47,7 @@ #define FRAME_TYPE_0X36 0x36 // Ӫƽ̨Զͣ //--------------------------------------- -#define FRAME_TYPE_0X3D 0x3D // ׼¼ +#define FRAME_TYPE_0X3B 0x3B // ׼¼ #define FRAME_TYPE_0X40 0x40 // ׼¼ȷ #define FRAME_TYPE_0X41 0x41 // ׸Ӧ #define FRAME_TYPE_0X42 0x42 // Զ˻ @@ -291,7 +291,7 @@ typedef struct { uint8_t charger_serial[CHARGER_SERIAL_LENGTH]; // ׮ uint8_t gun_index; // ǹ - uint8_t reseut; // ֹͣ,0x00ʧ 0x01ɹ + uint8_t result; // ֹͣ,0x00ʧ 0x01ɹ uint8_t err_code; // ʧԭ,0x0 } __attribute__((packed)) PACK_DATA_0X35; // 0x35 @@ -343,7 +343,7 @@ typedef struct uint8_t trade_data[7]; // uint8_t stop_reason; // ֹͣԭ uint8_t phy_cardid[8]; // -} __attribute__((packed)) PACK_DATA_0X3D; // 0x3D +} __attribute__((packed)) PACK_DATA_0X3B; // 0x3B typedef struct { @@ -460,7 +460,7 @@ extern void increase_heart_beat_cnt(void); extern void reset_heart_beat_cnt(void); extern uint32_t get_heart_beat_cnt(void); extern uint8_t unpack_server_data(uint8_t *buf, uint8_t len, SERVER_PACK *pack); -extern void pack_and_send_server_data(uint8_t type, uint8_t encrypt, uint16_t serial, uint8_t *data, uint8_t len, uint8_t stake_mark); +extern void pack_and_send_server_data(uint8_t type, uint8_t *data, uint8_t len, uint8_t stake_mark); extern int get_num_from_string(const char *str, int *num); extern uint32_t get_card_logic_num(uint8_t idx); extern uint32_t get_card_phy_num(uint8_t idx); diff --git a/Core/Middlewares/Third_Party/Ykc/server_to_charger.c b/Core/Middlewares/Third_Party/Ykc/server_to_charger.c index 53f6656..175f08d 100644 --- a/Core/Middlewares/Third_Party/Ykc/server_to_charger.c +++ b/Core/Middlewares/Third_Party/Ykc/server_to_charger.c @@ -53,7 +53,7 @@ void on_cmd_frame_type_0X0A(uint8_t stake_index, SERVER_PACK *pack) g_charger_manager.charger_piles[stake_index - 1].get_model = true; #ifdef DEBUG - + printf("北向:接收到计费模型应答,模型ID:%d\r\n", g_charger_manager.fee_model_global.fee_model_no); printf("尖电费率:%d 服务费:%d\r\n", g_charger_manager.fee_model_global.shark_fee_ratio, g_charger_manager.fee_model_global.shark_service_ratio); printf("峰电费率:%d 服务费:%d\r\n", g_charger_manager.fee_model_global.peak_fee_ratio, g_charger_manager.fee_model_global.peak_service_ratio); @@ -116,7 +116,6 @@ void on_cmd_frame_type_0X0A(uint8_t stake_index, SERVER_PACK *pack) end_hour, end_min, fee_name); - i = j; // 跳到下一个不同费率段 } printf("================================================================\r\n"); @@ -200,57 +199,73 @@ void on_cmd_frame_type_0X58(uint8_t stake_index, SERVER_PACK *pack) i = j; // 跳到下一个不同费率段 } printf("================================================================\r\n"); + charger_to_server_0x57(stake_index); #endif } } -// 平台控制充电 +// 平台控制充电 void on_cmd_frame_type_0X34(uint8_t stake_index, SERVER_PACK *pack) { PACK_DATA_0X34 data; - uint8_t result = 1; - uint8_t err_code = 0; + uint8_t result = TRUE; // 默认启动结果成功 + uint8_t err_code = 0; // 默认错误码为0 memcpy(&data, pack->data, sizeof(PACK_DATA_0X34)); - set_trade_serial(stake_index,data.gun_index, data.trade_serial); + set_trade_serial(stake_index, data.gun_index, data.trade_serial); printf("北向:平台控制充电,桩ID:%d, 枪ID:%d, 金额:%d\r\n", stake_index, data.gun_index, data.remain_money); - + + uint8_t *trade_serial = data.trade_serial; + + memcpy(g_charger_manager.charger_piles[stake_index - 1].guns[data.gun_index - 1].real_time_data.trade_serial, data.trade_serial, 16); + if (!is_my_charger_serial(stake_index, data.charger_serial)) { result = 0; err_code = 0x1; // 桩编号不匹配 } - // else if (get_user_current_action(data.gun_index - 1)) - // { - // result = 0; - // err_code = 0x2; // 枪在使用 - // } - // else if (is_gun_fault_occur(data.gun_index - 1)) - // { - // result = 0; - // err_code = 0x3; // 设备故障 - // } - // else if (get_gun_status(data.gun_index - 1) == GUN_STATUS_UN_INSERT) - // { - // result = 0; - // err_code = 0x5; // 未插枪 - // } - // else - // { - // Serial.print("In %s\r\n", __func__); - // uint32_t id = *(uint32_t *)&data.trade_serial[12]; - // pack_cmd_to_charge_task(data.gun_index - 1, CHARGE_TASK_CMD_USER_START_CHARGE, id); - // set_charge_start_mode(data.gun_index - 1, CAHRGE_START_MODE_APP); - // update_remain_money_to_gun(data.gun_index - 1, data.remain_money); - // } + else if (g_charger_manager.charger_piles[stake_index - 1].guns[data.gun_index - 1].real_time_data.status == 3) + { + result = 0; + err_code = 0x2; // 枪在使用 + } + else if (g_charger_manager.charger_piles[stake_index - 1].guns[data.gun_index - 1].real_time_data.status == 1) + { + result = 0; + err_code = 0x3; // 枪故障 + } + else if (g_charger_manager.charger_piles[stake_index - 1].guns[data.gun_index - 1].real_time_data.status == 0) + { + result = 0; + err_code = 0x4; // 枪离线 + } + else if (g_charger_manager.charger_piles[stake_index - 1].guns[data.gun_index - 1].real_time_data.gun_is_insert == FALSE) + { + result = 0; + err_code = 0x5; // 未插枪 + } charger_to_server_0X33(stake_index, data.gun_index, result, err_code); } -#if 0 +// 平台控制停止充电 +void on_cmd_frame_type_0X36(uint8_t stake_index, SERVER_PACK *pack) +{ + PACK_DATA_0X36 data; + uint8_t result = TRUE; // 默认启动结果成功 + uint8_t err_code = 0; // 默认错误码为0 + memcpy(&data, pack->data, sizeof(PACK_DATA_0X36)); + printf("北向:平台控制停止充电,桩ID:%d, 枪ID:%d\r\n", stake_index, data.gun_index); - - - -//计费模型应答 - -#endif \ No newline at end of file + if (!is_my_charger_serial(stake_index, data.charger_serial)) + { + result = 0; + err_code = 0x1; // 桩编号不匹配 + } + else if (g_charger_manager.charger_piles[stake_index - 1].guns[data.gun_index - 1].real_time_data.status != 3) + { + result = 0; + err_code = 0x2; // 枪未在使用 + } + + charger_to_server_0X33(stake_index, data.gun_index, result, err_code); +} diff --git a/Core/README.md b/Core/README.md index 710c9c3..60ded7d 100644 --- a/Core/README.md +++ b/Core/README.md @@ -1,2 +1,3 @@ ### 生产代码设置 - /User/Global/g_decpile -> void init_chargers(void) 需要修改预设 ,从电桩全局结构体拿 +![alt text](9e12a2e4a7f3dc87fa034aecf79e893c.png) \ No newline at end of file diff --git a/Core/User/Driver/drv_flash.c b/Core/User/Driver/drv_flash.c new file mode 100644 index 0000000..4dacad5 --- /dev/null +++ b/Core/User/Driver/drv_flash.c @@ -0,0 +1,166 @@ +#include "drv_flash.h" + +/* flash数据帧格式 */ +/* 帧头, 同时表示当前帧状态 */ +/* 整帧大小, 5~65536 */ +/* 帧类型, 用于区分不同存储数据, 0~255*/ +/* 帧数据 */ +/* 帧尾, 同时表示当前帧状态 */ + +/* 可读帧表,存放不同帧类型的第一个可读帧的地址与大小 */ +type_readable_frame_t data_form[255] = {0}; +/* 首个可写地址 */ +uint32_t writeable_addr = 0; +uint8_t erase_flag = 0; + +/* 地址对齐向高地址取整 */ +#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) + +uint32_t i = 0; + +int8_t flash_manage_init(flash_manage_t *flash_manage) +{ + uint8_t buff[4] = {0}; /* 存放帧头,帧大小,帧类型 */ + + if (flash_manage->manage_sector_num == 0 || flash_manage->sector_size == 0 || flash_manage->read_flash == 0 || + flash_manage->write_flash == 0 || flash_manage->erase_sector == 0) { + return -1; + } + + /* 遍历管理的空间以更新地址 */ + for (; i < flash_manage->manage_sector_num * flash_manage->sector_size; ) { + /* 取出帧信息 */ + flash_manage->read_flash(buff, ALIGN_UP(flash_manage->flash_start_address + i, flash_manage->align_num), 4); + /* 只获取该类帧类型的首个可读帧地址 */ + if (buff[0] == FLASH_READABLE_HEAD) { + if (data_form[buff[3]].state == 0) { + uint8_t frame_tail = 0; + flash_manage->read_flash(&frame_tail, ALIGN_UP(flash_manage->flash_start_address + i, flash_manage->align_num) + (buff[2] << 8 | buff[1]) - 1, 1); + if (frame_tail == FLASH_READABLE_TAIL) { + /* 只有帧头帧尾均为可读, 才把对齐后的地址填入 */ + data_form[buff[3]].addr = ALIGN_UP(flash_manage->flash_start_address + i, flash_manage->align_num); + /* 帧大小按小端排列 */ + data_form[buff[3]].size = buff[2] << 8 | buff[1]; + data_form[buff[3]].state = 1; + } + } + i = i + ALIGN_UP(buff[2] << 8 | buff[1], flash_manage->align_num); + } else if ((buff[0] & buff[1] & buff[2] & buff[3]) == FLASH_WRITABLE) { + /* 遍历提前结束 */ + writeable_addr = ALIGN_UP(flash_manage->flash_start_address + i, flash_manage->align_num); + return 1; + } else { + i += flash_manage->align_num; + } + } + erase_flag = 1; + + return 1; +} + +void update_readable_frame(flash_manage_t *flash_manage, uint32_t addr, uint8_t frame_type) +{ + uint8_t buff[4] = {0}; /* 存放帧头,帧大小,帧类型 */ + + /* 从当前位置遍历剩余空间 */ + for (uint32_t i = 0; i < flash_manage->manage_sector_num * flash_manage->sector_size - (addr - flash_manage->flash_start_address);) { + /* 取出帧信息 */ + flash_manage->read_flash(buff, ALIGN_UP(addr + i, flash_manage->align_num), 4); + /* 寻找相同类型的帧数据 */ + if (buff[0] == FLASH_READABLE_HEAD) { + if (buff[3] == frame_type) { + uint8_t frame_tail = 0; + flash_manage->read_flash(&frame_tail, ALIGN_UP(addr + i, flash_manage->align_num) + (buff[2] << 8 | buff[1]) - 1, 1); + if (frame_tail == FLASH_READABLE_TAIL) { + /* 只有帧头帧尾均为可读, 才把地址填入 */ + data_form[buff[3]].addr = ALIGN_UP(addr + i, flash_manage->align_num); + data_form[buff[3]].size = buff[2] << 8 | buff[1]; + data_form[buff[3]].state = 1; + return; + } + } + i += ALIGN_UP(buff[2] << 8 | buff[1], flash_manage->align_num); + } else if ((buff[0] | buff[1] | buff[2] | buff[3]) == FLASH_WRITABLE) { + return; + } else { + i += flash_manage->align_num; + } + } +} + +int8_t flash_manage_read(flash_manage_t *flash_manage, uint8_t *pbuf, uint8_t frame_type) +{ + if (flash_manage->manage_sector_num == 0 || flash_manage->sector_size == 0 || flash_manage->read_flash == 0 || + flash_manage->write_flash == 0 || flash_manage->erase_sector == 0) { + return -1; + } + + /* 可读表存在数据 */ + if (data_form[frame_type].state != 0) { + flash_manage->read_flash(pbuf, data_form[frame_type].addr + 4, data_form[frame_type].size - 5); + if (flash_manage->flash_read_mode == FLASH_CLEAR_MODE) { + /* 将flash内部数据帧头尾置为无效数据 */ + uint8_t frame_head[flash_manage->align_num]; + memset(frame_head, FLASH_NULL, flash_manage->align_num); + flash_manage->write_flash(frame_head, data_form[frame_type].addr, flash_manage->align_num); + flash_manage->write_flash(frame_head, data_form[frame_type].addr + data_form[frame_type].size - 32, flash_manage->align_num); + /* 将对应类型的可读表置0 */ + data_form[frame_type].state = 0; + if (flash_manage->flash_write_mode == FLASH_NO_OVERWRITING_MODE) { + /* flash处于覆写模式下, 可读帧是唯一的,故无需更新可读表, 而非覆写模式, 需要更新可读表 */ + update_readable_frame(flash_manage, ALIGN_UP(data_form[frame_type].addr + data_form[frame_type].size, flash_manage->align_num), frame_type); + } + } + return 1; + } + return 0; +} + +int8_t flash_manage_write(flash_manage_t *flash_manage, uint8_t *pbuf, uint16_t size, uint8_t frame_type) +{ + uint8_t buff[size + 5]; + uint16_t len = 0; + + memset(buff, 0, size + 5); + len = size + 5; + + if (flash_manage->manage_sector_num == 0 || flash_manage->sector_size == 0 || flash_manage->read_flash == 0 || + flash_manage->write_flash == 0 || flash_manage->erase_sector == 0) { + return -1; + } + + if (writeable_addr > flash_manage->flash_start_address + flash_manage->manage_sector_num * flash_manage->sector_size - len || erase_flag == 1) { + erase_flag = 0; + flash_manage->erase_sector(flash_manage->flash_start_address); + writeable_addr = ALIGN_UP(flash_manage->flash_start_address, flash_manage->align_num); + /* 重置可读表 */ + for (uint8_t i = 0; i < 255; i++) { + data_form[i].state = 0; + } + } + + buff[0] = FLASH_READABLE_HEAD; + buff[1] = len & 0xff; + buff[2] = len >> 8 & 0xff; + buff[3] = frame_type; + buff[len - 1] = FLASH_READABLE_TAIL; + memcpy(buff + 4, pbuf, size); + flash_manage->write_flash(buff, writeable_addr, len); + + if (data_form[frame_type].state == 0) { + /* 可读表为空时更新 */ + data_form[frame_type].addr = writeable_addr; + data_form[frame_type].size = len; + data_form[frame_type].state = 1; + } else if (flash_manage->flash_write_mode == FLASH_OVERWRITING_MODE && data_form[frame_type].state == 1) { + /* 将flash内部上一个相同类型的数据帧头置为无效数据 */ + uint8_t frame_head[flash_manage->align_num]; + memset(frame_head, FLASH_NULL, flash_manage->align_num); + flash_manage->write_flash(frame_head, data_form[frame_type].addr, flash_manage->align_num); + data_form[frame_type].addr = writeable_addr; + data_form[frame_type].size = len; + } + writeable_addr = ALIGN_UP(writeable_addr + len, flash_manage->align_num); + + return 1; +} diff --git a/Core/User/Driver/drv_flash.h b/Core/User/Driver/drv_flash.h new file mode 100644 index 0000000..403026e --- /dev/null +++ b/Core/User/Driver/drv_flash.h @@ -0,0 +1,70 @@ +#ifndef __DRV_FLASH_H__ +#define __DRV_FLASH_H__ + +#include +#include + +enum flash_state { + /* 数据无效帧头/帧尾,等于flash擦除后的值取反 */ + FLASH_NULL = 0x00, + /* 数据可读帧头 */ + FLASH_READABLE_HEAD = 0xa5, + /* 数据可读帧尾 */ + FLASH_READABLE_TAIL = 0x5a, + /* 数据可写帧头/帧尾,等于flash擦除后的值 */ + FLASH_WRITABLE = 0xff, +}; + +typedef enum { + /* 不覆写模式 */ + FLASH_NO_OVERWRITING_MODE = 0x00, + /* 覆写模式, 即写入数据后将先前同类型数据置为无效 */ + FLASH_OVERWRITING_MODE, + /* 读取不清空模式 */ + FLASH_NO_CLEAR_MODE, + /* 读取清空模式,即读取数据所在的flash位置0 */ + FLASH_CLEAR_MODE, +} flash_write_read_mode_t; + +typedef struct { + /* 可读表标志位,表示当前是否存在可读数据 */ + uint8_t state; + /* 可读数据大小, 包含帧头帧尾 */ + uint16_t size; + /* 可读数据起始地址, 包含帧头 */ + uint32_t addr; +} type_readable_frame_t; + +typedef struct +{ + /* 地址对齐数, 1-2^5 */ + uint8_t align_num; + /* flash写入模式 */ + flash_write_read_mode_t flash_write_mode; + /* flashdu'q'b模式 */ + flash_write_read_mode_t flash_read_mode; + /* 管理的flash起始地址,按扇区对齐 */ + uint32_t flash_start_address; + /* 管理的flash扇区数量 */ + uint32_t manage_sector_num; + /* flash的扇区大小 */ + uint32_t sector_size; + + /* 开启flash */ + void (*open_flash)(void); + /* 关闭flash */ + void (*close_flash)(void); + /* 读flash */ + void (*read_flash)(uint8_t *pbuf, uint32_t addr, uint16_t datalen); + /* 写flash */ + void (*write_flash)(uint8_t *pbuf, uint32_t addr, uint16_t datalen); + /* 擦除flash */ + uint8_t (*erase_sector)(uint32_t addr); +} flash_manage_t; + +int8_t flash_manage_init(flash_manage_t *flash_manage); +int8_t flash_manage_read(flash_manage_t *flash_manage, uint8_t *pbuf, uint8_t frame_type); +int8_t flash_manage_write(flash_manage_t *flash_manage, uint8_t *pbuf, uint16_t size, uint8_t frame_type); + + +#endif /* _FLASH_MANAGE_H__ */ diff --git a/Core/User/Driver/drv_init.c b/Core/User/Driver/drv_init.c index 4af922c..8d04ab7 100644 --- a/Core/User/Driver/drv_init.c +++ b/Core/User/Driver/drv_init.c @@ -10,6 +10,7 @@ /* Includes -------------------------------------------------------------------*/ #include "drv_init.h" #include +#include "flash_config.h" /* code -----------------------------------------------------------------------*/ void send_cmd_to_air724(uint8_t *cmd, uint16_t len) @@ -37,6 +38,7 @@ void send_server_address_to_air724(void) pos = 0; memset(config_cmd, 0, sizeof(config_cmd)); } + /** * @brief drv_all_Init:所有传感器、外设芯片、外部设备初始化 * @@ -50,4 +52,5 @@ void send_server_address_to_air724(void) void drv_all_Init(void) { AIR724_RESET(); /* AIR724 复位 */ + stm_flash_init();/* 初始化flash */ } diff --git a/Core/User/Driver/flash_config.c b/Core/User/Driver/flash_config.c new file mode 100644 index 0000000..74792fd --- /dev/null +++ b/Core/User/Driver/flash_config.c @@ -0,0 +1,150 @@ +#include "flash_config.h" +#include "stm32h7xx_hal.h" +#include "FreeRTOS.h" +#include "task.h" + +void stmflash_read_data(uint8_t *pbuf, uint32_t addr, uint16_t datalen) +{ + if (pbuf == NULL || datalen == 0) { + return; + } + memcpy(pbuf, (const void *)addr, datalen); +} + +/* ============================================================ + * 写 Flash + * 函数指针原型: void (*write_flash)(uint8_t *pbuf, uint32_t addr, uint16_t datalen) + * + * H743 写入规则: + * - 每次必须写 32字节 (FLASH_TYPEPROGRAM_FLASHWORD) + * - 写入地址必须 32字节对齐 + * - 不满 32字节的部分用 0xFF 填充 + * ============================================================ */ +void stmflash_write_data(uint8_t *pbuf, uint32_t addr, uint16_t datalen) +{ + if (pbuf == NULL || datalen == 0) { + return; + } + + /* 地址必须32字节对齐 */ + if ((addr % 32) != 0) { + return; + } + + /* 计算对齐后的长度 */ + uint16_t aligned_len = (datalen + 31) & ~31U; + + /* 构建对齐缓冲区, 多余部分填 0xFF */ + uint8_t buf[aligned_len]; + memset(buf, 0xFF, aligned_len); + memcpy(buf, pbuf, datalen); + + HAL_FLASH_Unlock(); + + uint32_t address = addr; + uint8_t *writePtr = buf; + uint16_t remain = aligned_len; + + while (remain >= 32) + { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, + address, + (uint32_t)writePtr) != HAL_OK) + { + /* 写入失败,退出 */ + break; + } + address += 32; + writePtr += 32; + remain -= 32; + } + + HAL_FLASH_Lock(); +} + +/* ============================================================ + * 擦除 Flash Sector + * 函数指针原型: uint8_t (*erase_sector)(uint32_t addr) + * + * H743 参数: + * - Bank2, Sector0 起始地址 0x08100000 + * - 每个 Sector = 128KB + * - VoltageRange = FLASH_VOLTAGE_RANGE_3 (2.7V ~ 3.6V) + * ============================================================ */ +uint8_t flash_sector_erase(uint32_t addr) +{ + FLASH_EraseInitTypeDef EraseInitStruct = {0}; + uint32_t SECTORError = 0; + + /* 根据地址计算 Sector 编号 */ + /* Bank2: 0x08100000 ~ 0x081FFFFF, 共8个Sector, 每个128KB */ + uint32_t sector = (addr - 0x08100000) / (128 * 1024); + + if (sector > 7) { + return 0; + } + + HAL_FLASH_Unlock(); + + EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; + EraseInitStruct.Banks = FLASH_BANK_2; + EraseInitStruct.Sector = sector; + EraseInitStruct.NbSectors = 1; + + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK) + { + HAL_FLASH_Lock(); + return 0; + } + + HAL_FLASH_Lock(); + return 1; +} + + +flash_manage_t stm_flash_manage = {0}; + +/* demo */ +// stm_flash_read(data[0], 1); +// stm_flash_read(data[1], 0); +// stm_flash_read(data[0], 1); +// stm_flash_read(data[1], 0); +// stm_flash_write("12345678912345678912345678912345678912345", 41, 1); +// stm_flash_write("abcdef", 6, 0); +// stm_flash_write("12345678912345678912345678912345678912345", 41, 1); +// stm_flash_write("abcdef", 6, 0); + +void stm_flash_init(void) +{ + stm_flash_manage.align_num = 32; + stm_flash_manage.flash_write_mode = FLASH_OVERWRITING_MODE; + stm_flash_manage.flash_read_mode = FLASH_NO_CLEAR_MODE; + stm_flash_manage.flash_start_address = 0x08180000; + stm_flash_manage.manage_sector_num = 1; + stm_flash_manage.sector_size = 128 * 1024; + stm_flash_manage.open_flash = NULL; + stm_flash_manage.close_flash = NULL; + stm_flash_manage.read_flash = stmflash_read_data; + stm_flash_manage.write_flash = stmflash_write_data; + stm_flash_manage.erase_sector = flash_sector_erase; + + // stm_flash_manage.open_flash(); + flash_manage_init(&stm_flash_manage); +} + +int8_t stm_flash_read(uint8_t *pbuf, uint8_t frame_type) +{ + taskENTER_CRITICAL(); + int8_t flag = flash_manage_read(&stm_flash_manage, pbuf, frame_type); + taskEXIT_CRITICAL(); + return flag; +} + +int8_t stm_flash_write(uint8_t *pbuf, uint16_t size, uint8_t frame_type) +{ + taskENTER_CRITICAL(); + int8_t flag = flash_manage_write(&stm_flash_manage, pbuf, size, frame_type); + taskEXIT_CRITICAL(); + return flag; +} diff --git a/Core/User/Driver/flash_config.h b/Core/User/Driver/flash_config.h new file mode 100644 index 0000000..15ebacb --- /dev/null +++ b/Core/User/Driver/flash_config.h @@ -0,0 +1,13 @@ +#ifndef _FLASH_CONFIG_H__ +#define _FLASH_CONFIG_H__ + +#include "drv_flash.h" + + +void stm_flash_init(void); +int8_t stm_flash_read(uint8_t *pbuf, uint8_t frame_type); +int8_t stm_flash_write(uint8_t *pbuf, uint16_t size, uint8_t frame_type); + +extern flash_manage_t stm_flash_manage; // 声明flash管理结构体 + +#endif /* _FLASH_CONFIG_H__ */ diff --git a/Core/User/Global/g_dcpile.c b/Core/User/Global/g_dcpile.c index 7a17402..8f98854 100644 --- a/Core/User/Global/g_dcpile.c +++ b/Core/User/Global/g_dcpile.c @@ -5,7 +5,10 @@ ChargerManager g_charger_manager = {0}; /*充电桩序列号*/ const uint8_t piles_serial[6][7] = { + // {0x88, 0x26, 0x01, 0x13, 0x12, 0x00, 0x01}, + {0x32, 0x01, 0x06, 0x01, 0x11, 0x15, 0x58}, + {0x32, 0x01, 0x06, 0x01, 0x11, 0x16, 0x54}, {0x88, 0x26, 0x01, 0x13, 0x12, 0x00, 0x01}, {0x88, 0x26, 0x01, 0x13, 0x12, 0x00, 0x02}, @@ -19,7 +22,7 @@ const uint8_t piles_serial[6][7] = { * @note 初始化充电桩管理器,设置充电桩数量和每个充电桩的初始状态 */ void init_chargers(void) { - g_charger_manager.charger_count = 6; + g_charger_manager.charger_count = MAX_CHARGER_COUNT; for (int i = 0; i < g_charger_manager.charger_count; i++) { ChargerPile *ctx = &g_charger_manager.charger_piles[i]; @@ -28,7 +31,7 @@ void init_chargers(void) { ctx->get_model = false; ctx->is_udp_online = false; ctx->login_info.charger_type = CHARGER_TYPE_DC; - ctx->login_info.gun_num = 2; + ctx->login_info.gun_num = MAX_GUN_PER_CHARGER; ctx->login_info.protocol_ver = 0x10; // V1.6 strcpy((char*)ctx->login_info.software_ver, "V4.1.50"); ctx->login_info.net_conn_type = 0; // SIM @@ -36,10 +39,9 @@ void init_chargers(void) { ctx->login_info.tele_factory = 0x00; // 移动 // 初始化枪 - for (int g = 0; g < ctx->login_info.gun_num && g < MAX_GUN_PER_CHARGER; g++) { + for (int g = 0; g < ctx->login_info.gun_num; g++) { ctx->guns[g].gun_index = g + 1; - ctx->guns[g].status = 0; // 正常 + ctx->guns[g].real_time_data.status = 0; // 离线 } - } } \ No newline at end of file diff --git a/Core/User/Global/g_dcpile.h b/Core/User/Global/g_dcpile.h index 5dde9ff..764108e 100644 --- a/Core/User/Global/g_dcpile.h +++ b/Core/User/Global/g_dcpile.h @@ -12,10 +12,7 @@ typedef struct { uint8_t gun_index; // 枪索引 - bool is_changing; // 是否正在充电 - bool is_plugged; // 是否已插入枪 - bool is_gun_returned; // 是否已返回枪 - uint8_t status; // 状态 + PACK_DATA_0X13 real_time_data; // 实时数据 } ChargerGun; diff --git a/Core/User/Global/global.h b/Core/User/Global/global.h index 46f3374..ce99bd5 100644 --- a/Core/User/Global/global.h +++ b/Core/User/Global/global.h @@ -61,6 +61,9 @@ #define TRUE 1 #define FALSE 0 + + + #define PI 3.1415926f #define SOFTWARE_VERSION "JSBRv1.2" // 软件版本 @@ -115,6 +118,7 @@ #define get_sys_time_msec() HAL_GetTick() + #define CONSTRAIN(x, max, min) (x > max ? max : (x < min ? min : x)) #endif /* __GLOBAL_H */ diff --git a/Core/User/Os/os_task.c b/Core/User/Os/os_task.c index a0dfb59..dafde1c 100644 --- a/Core/User/Os/os_task.c +++ b/Core/User/Os/os_task.c @@ -56,10 +56,10 @@ void Os_Task_Init(void) /*任务入口函数、任务名字、任务栈大小、 xReturn = xTaskCreate((TaskFunction_t)DownLinkTask_Function, "DownLinkTask", 1024, NULL, osPriorityAboveNormal, &DownLinkTaskHandle); /* UDP 消息队列接受任务 */ - xReturn = xTaskCreate((TaskFunction_t)UDPTask_Function, "UDPTask", 512, NULL, osPriorityAboveNormal, &UDPTaskHandle); + xReturn = xTaskCreate((TaskFunction_t)UDPTask_Function, "UDPTask", 1536, NULL, osPriorityHigh, &UDPTaskHandle); /* UDP 消息解析任务 */ - xReturn = xTaskCreate((TaskFunction_t)UDP_ParseTask_Function, "UDPParseTask", 1024, NULL, osPriorityAboveNormal, &UDP_ParseTaskHandle); + xReturn = xTaskCreate((TaskFunction_t)UDP_ParseTask_Function, "UDPParseTask", 2048, NULL, osPriorityAboveNormal, &UDP_ParseTaskHandle); /* 云快充平台交互任务 */ xReturn = xTaskCreate((TaskFunction_t)YkcTask_Function, "YKCTask", 1024, NULL, osPriorityAboveNormal, &YkcTaskHandle); diff --git a/Core/User/Task/ChargerTask.c b/Core/User/Task/ChargerTask.c index 8bb0974..4bb88fa 100644 --- a/Core/User/Task/ChargerTask.c +++ b/Core/User/Task/ChargerTask.c @@ -15,6 +15,34 @@ ip4_addr_t stake_ip_4 = IPADDR4_INIT_BYTES(10, 12, 19, 104); // 桩 4 IP地址 ip4_addr_t stake_ip_5 = IPADDR4_INIT_BYTES(10, 12, 19, 105); // 桩 5 IP地址 ip4_addr_t stake_ip_6 = IPADDR4_INIT_BYTES(10, 12, 19, 106); // 桩 6 IP地址 +ip4_addr_t server_ip = IPADDR4_INIT_BYTES(10, 12, 19, 107); // 上位机管理地址 + +/** + * @brief 将十六进制字符串转换为字节数组 + * @note 输入字符串长度必须为偶数 + */ +int hex_string_to_bytes(const char *hex_str, uint8_t *bytes, int len) +{ + for (int i = 0; i < len; i++) + { + unsigned int val; + sscanf(hex_str + i * 2, "%02x", &val); + bytes[i] = (uint8_t)val; + } + return 0; +} + +/** + * @brief 将字节数组转换为十六进制字符串 + * @note 输出字符串长度必须为32 + */ +void bytes_to_hex_string(const uint8_t *bytes, char *hex_str) +{ + for (int i = 0; i < 16; i++) + { + sprintf(hex_str + i * 2, "%02X", bytes[i]); + } +} /** * @brief UDP发送 * @note 发送数据到指定桩 @@ -26,31 +54,49 @@ ip4_addr_t stake_ip_6 = IPADDR4_INIT_BYTES(10, 12, 19, 106); // 桩 6 IP地址 err_t udp_send_response(uint8_t stake_index, uint8_t *data, u16_t len) { struct netbuf *buf = netbuf_new(); - if (!buf) { + if (!buf) + { return ERR_MEM; } - + ip4_addr_t *dst_ip = NULL; - switch (stake_index) { - case 1: dst_ip = &stake_ip_1; break; - case 2: dst_ip = &stake_ip_2; break; - case 3: dst_ip = &stake_ip_3; break; - case 4: dst_ip = &stake_ip_4; break; - case 5: dst_ip = &stake_ip_5; break; - case 6: dst_ip = &stake_ip_6; break; + switch (stake_index) + { + case 1: + dst_ip = &stake_ip_1; + break; + case 2: + dst_ip = &stake_ip_2; + break; + case 3: + dst_ip = &stake_ip_3; + break; + case 4: + dst_ip = &stake_ip_4; + break; + case 5: + dst_ip = &stake_ip_5; + break; + case 6: + dst_ip = &stake_ip_6; + break; + case 7: + dst_ip = &server_ip; + break; default: printf("Invalid stake index\r\n"); netbuf_delete(buf); - return ERR_VAL; // ← 修复 return 无返回值 + return ERR_VAL; // ← 修复 return 无返回值 } - - void *buf_data = netbuf_alloc(buf, len); // ← 在 netbuf 内部分配内存 - if (!buf_data) { + + void *buf_data = netbuf_alloc(buf, len); // ← 在 netbuf 内部分配内存 + if (!buf_data) + { netbuf_delete(buf); return ERR_MEM; } - memcpy(buf_data, data, len); // ← 拷贝数据,不再依赖外部指针 - + memcpy(buf_data, data, len); // ← 拷贝数据,不再依赖外部指针 + err_t err = netconn_sendto(datalink_conn, buf, dst_ip, LINK_STAKE_PORT); netbuf_delete(buf); return err; @@ -166,7 +212,7 @@ void UDPTask_Function(void const *argument) */ void local_on_cmd_callback_power_on(uint8_t stake_index, cJSON *json_pack) { - if (stake_index > 6) + if (stake_index > MAX_CHARGER_COUNT) { return; } @@ -203,7 +249,7 @@ void local_on_cmd_callback_power_on(uint8_t stake_index, cJSON *json_pack) */ void local_on_cmd_callback_heartbeat_response(uint8_t stake_index, cJSON *json_pack) { - if (stake_index > 6) + if (stake_index > MAX_CHARGER_COUNT) { return; } @@ -258,6 +304,432 @@ void local_on_cmd_callback_heartbeat_response(uint8_t stake_index, cJSON *json_p printf("南向:对电桩 %d 心跳回复成功\r\n", stake_index); } +/** + * @brief 解析充电桩实时数据指令 + * @note 回复实时数据应答 + * @param stake_index 桩索引 + * @param json_pack json数据包 + */ +void local_on_cmd_callback_realtime_data_response(uint8_t stake_index, cJSON *json_pack) +{ + if (stake_index > MAX_CHARGER_COUNT) + { + return; + } + + cJSON *transaction_id = cJSON_GetObjectItem(json_pack, "transaction_id"); // 提取交易序列号 + cJSON *gun_id = cJSON_GetObjectItem(json_pack, "gun_id"); // 提取枪号 + cJSON *state = cJSON_GetObjectItem(json_pack, "state"); // 提取枪状态 + cJSON *gun_back = cJSON_GetObjectItem(json_pack, "gun_back"); // 提取枪归位状态 + cJSON *gun_insert = cJSON_GetObjectItem(json_pack, "gun_insert"); // 提取枪插入状态 + cJSON *voltage = cJSON_GetObjectItem(json_pack, "voltage"); // 提取电压 + cJSON *current = cJSON_GetObjectItem(json_pack, "current"); // 提取电流 + cJSON *cable_temp = cJSON_GetObjectItem(json_pack, "cable_temp"); // 提取电缆温度 + cJSON *cable_code = cJSON_GetObjectItem(json_pack, "cable_code"); // 提取电缆编码 + cJSON *soc = cJSON_GetObjectItem(json_pack, "soc"); // 提取SOC + cJSON *battery_temp = cJSON_GetObjectItem(json_pack, "battery_temp"); // 提取电池温度 + cJSON *charge_time = cJSON_GetObjectItem(json_pack, "charge_time"); // 提取充电时间 + cJSON *remain_time = cJSON_GetObjectItem(json_pack, "remain_time"); // 提取剩余时间 + cJSON *charge_kwh = cJSON_GetObjectItem(json_pack, "charge_kwh"); // 提取充电量 + cJSON *loss_kwh = cJSON_GetObjectItem(json_pack, "loss_kwh"); // 提取损失量 + cJSON *charge_amount = cJSON_GetObjectItem(json_pack, "charge_amount"); // 提取充电金额 + cJSON *fault = cJSON_GetObjectItem(json_pack, "fault"); // 提取故障状态 + // 检查交易序列号、枪号、状态字段是否存在 + if (!transaction_id || !gun_id || !state) + { + printf(" └── [error] 缺少必要字段 transaction_id/gun_id/state\r\n"); + return; + } + // 检查交易序列号长度是否为32位 + if (strlen(transaction_id->valuestring) != 32) + { + printf(" └── [error] transaction_id长度错误: %d\r\n", (int)strlen(transaction_id->valuestring)); + return; + } + // 检查枪号是否有效 + uint8_t gun_idx = (uint8_t)gun_id->valueint; + if (gun_idx == 0 || gun_idx > MAX_GUN_PER_CHARGER) + { + printf(" └── [error] 无效的gun_id: %d\r\n", gun_idx); + return; + } + + ChargerPile *pile = &g_charger_manager.charger_piles[stake_index - 1]; + ChargerGun *gun = &pile->guns[gun_idx - 1]; + + // 更新枪状态 + gun->real_time_data.status = (uint8_t)state->valueint; + // 更新枪归位状态 + gun->real_time_data.gun_back = (uint8_t)gun_back->valueint; + // 更新枪插入状态 + gun->real_time_data.gun_is_insert = (uint8_t)gun_insert->valueint; + // 更新电压 + gun->real_time_data.out_voltage = (uint16_t)(voltage->valuedouble * 10); + // 更新电流 + gun->real_time_data.out_current = (uint16_t)(current->valuedouble * 10); + // 更新电缆温度 + gun->real_time_data.gun_line_temp = (uint8_t)cable_temp->valueint; + // 更新SOC + gun->real_time_data.soc = (uint8_t)soc->valueint; + // 更新电池温度 + gun->real_time_data.battery_temp = (uint8_t)battery_temp->valueint; + // 更新累计充电时间 + gun->real_time_data.charge_time = (uint16_t)charge_time->valueint; + // 更新剩余时间 + gun->real_time_data.remain_time = (uint16_t)remain_time->valueint; + // 更新充电量 + gun->real_time_data.charge_energy = (uint32_t)(charge_kwh->valuedouble * 10000); + // 更新损失量 + gun->real_time_data.loss_energy = (uint32_t)(loss_kwh->valuedouble * 10000); + // 更新充电金额 + gun->real_time_data.charge_money = (uint32_t)(charge_amount->valuedouble * 10000); + // 更新故障状态 + gun->real_time_data.hard_fault = (uint16_t)fault->valueint; + + // 回复实时数据应答 + cJSON *root = NULL; + char *str = NULL; + + root = cJSON_CreateObject(); + if (root == NULL) + { + printf("Failed to create JSON object for stake %d\r\n", stake_index); + return; + } + + /* 添加一条字符串类型的JSON数据(添加一个链表节点) */ + cJSON_AddNumberToObject(root, "id", stake_index); + cJSON_AddStringToObject(root, "cmd", "realtime data"); + cJSON_AddStringToObject(root, "type", "response"); + + str = cJSON_Print(root); + udp_send_response(stake_index, str, strlen(str)); + free(str); + cJSON_Delete(root); + + printf("南向:对电桩 %d 实时数据回复成功\r\n", stake_index); +} + +/** + * @brief 主动下发启动指令 + * @note 发送启动指令到充电桩,符合协议格式要求 + * @param stake_index 桩索引 (1~6) + * @param gun_id 枪编码 (1~N) + */ +void local_on_cmd_send_start_charging(uint8_t stake_index, uint8_t gun_id) +{ + if (stake_index > 6 || stake_index == 0) + { + printf("Invalid stake index: %d\r\n", stake_index); + return; + } + + if (gun_id == 0 || gun_id > MAX_GUN_PER_CHARGER) + { + printf("Invalid gun id: %d\r\n", gun_id); + return; + } + + // 检查是否已获取费率模型 + if (!g_charger_manager.charger_piles[stake_index - 1].get_model) + { + printf("Stake %d fee model not ready\r\n", stake_index); + return; + } + + cJSON *root = NULL; + cJSON *billing_array = NULL; + cJSON *billing_item = NULL; + char *str = NULL; + + // 转换交易ID:16位数组转字符串 + char transaction_id_str[33] = {0}; // 32位 + 结束符 + uint8_t *trade_serial = g_charger_manager.charger_piles[stake_index - 1].guns[gun_id - 1].real_time_data.trade_serial; + trade_serial_to_string(trade_serial, transaction_id_str); + + root = cJSON_CreateObject(); + if (root == NULL) + { + printf("Failed to create JSON object for stake %d\r\n", stake_index); + return; + } + + /* 添加基本字段 */ + cJSON_AddNumberToObject(root, "id", stake_index); + cJSON_AddStringToObject(root, "cmd", "start charging"); + cJSON_AddStringToObject(root, "transaction_id", transaction_id_str); // 使用转换后的32位字符串 + cJSON_AddNumberToObject(root, "gun_id", gun_id); + cJSON_AddStringToObject(root, "type", "request"); + + /* 添加限制金额(根据实际业务设置)*/ + cJSON_AddNumberToObject(root, "limit_amount", 00.00); + + /* 创建计费模型数组 */ + billing_array = cJSON_CreateArray(); + if (billing_array == NULL) + { + printf("Failed to create billing array\r\n"); + cJSON_Delete(root); + return; + } + + /* 计费时段:生成简化格式 [start_time, end_time, electricity_fee, service_fee] */ + int i = 0; + + while (i < 48) // 48个半小时时段 + { + uint8_t current_type = g_charger_manager.fee_model_global.fee_num[i]; + + // 跳过无效费率 + if (current_type == 0xFF) + { + i++; + continue; + } + + // 查找连续相同费率的结束位置 + int j = i; + while (j < 48 && g_charger_manager.fee_model_global.fee_num[j] == current_type) + { + j++; + } + + // 计算起始时间(小时.半小时:6.0=6:00, 6.5=6:30) + float start_time = i * 0.5f; + float end_time = j * 0.5f; + + // 跨天处理:24.0显示为0.0 + if (end_time == 24.0f) + { + end_time = 0.0f; + } + + // 根据费率类型设置电费和服务费 + float electricity_fee = 0.0f; + float service_fee = 0.0f; + + switch (current_type) + { + case 0x00: // 尖时 + electricity_fee = g_charger_manager.fee_model_global.shark_fee_ratio / 100000.0f; + service_fee = g_charger_manager.fee_model_global.shark_service_ratio / 100000.0f; + break; + case 0x01: // 峰时 + electricity_fee = g_charger_manager.fee_model_global.peak_fee_ratio / 100000.0f; + service_fee = g_charger_manager.fee_model_global.peak_service_ratio / 100000.0f; + break; + case 0x02: // 平时 + electricity_fee = g_charger_manager.fee_model_global.flat_fee_ratio / 100000.0f; + service_fee = g_charger_manager.fee_model_global.flat_service_ratio / 100000.0f; + break; + case 0x03: // 谷时 + electricity_fee = g_charger_manager.fee_model_global.valley_fee_ratio / 100000.0f; + service_fee = g_charger_manager.fee_model_global.valley_service_ratio / 100000.0f; + break; + default: + electricity_fee = 0.0f; + service_fee = 0.0f; + break; + } + + // 创建计费时段数组 [start_time, end_time, electricity_fee, service_fee] + if (electricity_fee > 0 || service_fee > 0) + { + billing_item = cJSON_CreateArray(); + if (billing_item != NULL) + { + cJSON_AddNumberToObject(billing_item, NULL, start_time); + cJSON_AddNumberToObject(billing_item, NULL, end_time); + cJSON_AddNumberToObject(billing_item, NULL, electricity_fee); + cJSON_AddNumberToObject(billing_item, NULL, service_fee); + cJSON_AddItemToArray(billing_array, billing_item); + } + } + + i = j; // 跳到下一个不同费率段 + } + + // 将数组添加到根对象 + cJSON_AddItemToObject(root, "billing_model", billing_array); + + // 转换为JSON字符串并发送 + str = cJSON_Print(root); + if (str != NULL) + { + // #ifdef DEBUG + // printf("Send start command JSON: %s\r\n", str); + // #endif + + udp_send_response(stake_index, str, strlen(str)); + + free(str); + } + else + { + printf("Failed to print JSON for stake %d\r\n", stake_index); + } + + cJSON_Delete(root); + printf("Southbound: Start command sent to stake %d, gun %d, total %d billing periods\r\n", + stake_index, gun_id, (int)cJSON_GetArraySize(billing_array)); +} + +void local_on_cmd_callback_server_login_response(cJSON *json_pack) +{ + + cJSON *request_id = cJSON_GetObjectItem(json_pack, "request_id"); + cJSON *username = cJSON_GetObjectItem(json_pack, "username"); + cJSON *password = cJSON_GetObjectItem(json_pack, "password"); + + cJSON *root = NULL; + char *str = NULL; + + root = cJSON_CreateObject(); + if (root == NULL) + { + printf("Failed to create JSON object for server login\r\n"); + return; + } + + /* 添加一条字符串类型的JSON数据(添加一个链表节点) */ + cJSON_AddStringToObject(root, "request_id", request_id->valuestring); + + if (strcmp(username->valuestring, "admin") != 0 || strcmp(password->valuestring, "123456") != 0) + { + cJSON_AddStringToObject(root, "error", "用户或密码错误 "); + cJSON_AddBoolToObject(root, "success", cJSON_False); + printf("登录失败\r\n"); + } + else + { + cJSON_AddBoolToObject(root, "success", cJSON_True); + printf("登录成功\r\n"); + } + str = cJSON_Print(root); + udp_send_response(7, str, strlen(str)); + free(str); + cJSON_Delete(root); + +} + +// 处理获取状态查询指令 +void local_on_cmd_callback_server_get_status_response(cJSON *json_pack) +{ + cJSON *request_id = cJSON_GetObjectItem(json_pack, "request_id"); + + cJSON *root = NULL; + cJSON *piles = NULL; + cJSON *pile = NULL; + cJSON *guns = NULL; + cJSON *gun = NULL; + char *str = NULL; + + root = cJSON_CreateObject(); + if (root == NULL) + { + printf("Failed to create JSON object for get_status\r"); + return; + } + + cJSON_AddStringToObject(root, "request_id", request_id->valuestring); + cJSON_AddBoolToObject(root, "success", cJSON_True); + + /* ── piles 数组 ── */ + piles = cJSON_CreateArray(); + + /* 桩 1 */ + pile = cJSON_CreateObject(); + cJSON_AddStringToObject(pile, "serial", "32010601111558"); + cJSON_AddBoolToObject(pile, "is_online", cJSON_True); + guns = cJSON_CreateArray(); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 1); + cJSON_AddItemToArray(guns, gun); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + cJSON_AddItemToObject(pile, "guns", guns); + cJSON_AddItemToArray(piles, pile); + + /* 桩 2 */ + pile = cJSON_CreateObject(); + cJSON_AddStringToObject(pile, "serial", "32010601111559"); + cJSON_AddBoolToObject(pile, "is_online", cJSON_True); + guns = cJSON_CreateArray(); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 1); + cJSON_AddItemToArray(guns, gun); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 1); + cJSON_AddItemToArray(guns, gun); + cJSON_AddItemToObject(pile, "guns", guns); + cJSON_AddItemToArray(piles, pile); + + /* 桩 3 */ + pile = cJSON_CreateObject(); + cJSON_AddStringToObject(pile, "serial", "32010601111560"); + cJSON_AddBoolToObject(pile, "is_online", cJSON_True); + guns = cJSON_CreateArray(); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + cJSON_AddItemToObject(pile, "guns", guns); + cJSON_AddItemToArray(piles, pile); + + /* 桩 4 */ + pile = cJSON_CreateObject(); + cJSON_AddStringToObject(pile, "serial", "32010601111561"); + cJSON_AddBoolToObject(pile, "is_online", cJSON_False); + guns = cJSON_CreateArray(); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + cJSON_AddItemToObject(pile, "guns", guns); + cJSON_AddItemToArray(piles, pile); + + /* 桩 5 */ + pile = cJSON_CreateObject(); + cJSON_AddStringToObject(pile, "serial", "32010601111562"); + cJSON_AddBoolToObject(pile, "is_online", cJSON_True); + guns = cJSON_CreateArray(); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 1); + cJSON_AddItemToArray(guns, gun); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + cJSON_AddItemToObject(pile, "guns", guns); + cJSON_AddItemToArray(piles, pile); + + /* 桩 6 */ + pile = cJSON_CreateObject(); + cJSON_AddStringToObject(pile, "serial", "32010601111563"); + cJSON_AddBoolToObject(pile, "is_online", cJSON_False); + guns = cJSON_CreateArray(); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + gun = cJSON_CreateObject(); + cJSON_AddNumberToObject(gun, "status", 0); + cJSON_AddItemToArray(guns, gun); + cJSON_AddItemToObject(pile, "guns", guns); + cJSON_AddItemToArray(piles, pile); + + cJSON_AddItemToObject(root, "piles", piles); + + /* ── 发送 ── */ + str = cJSON_Print(root); + udp_send_response(7, str, strlen(str)); + free(str); + cJSON_Delete(root); + printf("get_status 回复已发送 \r\n"); +} void handle_udp_downlink(uint8_t id, const char *cmd, cJSON *json_pack) { @@ -275,6 +747,26 @@ void handle_udp_downlink(uint8_t id, const char *cmd, cJSON *json_pack) printf("南向:收到电桩 %d 心跳指令\r\n", id); local_on_cmd_callback_heartbeat_response(id, json_pack); } + // 处理实时数据指令 + else if (strcmp(cmd, "realtime data") == 0) + { + printf("南向:收到电桩 %d 实时数据指令 \r\n", id); + local_on_cmd_callback_realtime_data_response(id, json_pack); + } + + /*处理上位机指令 */ + // 处理登录指令 + else if (strcmp(cmd, "server_login") == 0) + { + printf("上位机:收到登录指令 \r\n"); + local_on_cmd_callback_server_login_response(json_pack); + } + // 处理获取状态查询指令 + else if (strcmp(cmd, "server_get_status") == 0) + { + printf("上位机:收到获取状态查询指令 \r\n"); + local_on_cmd_callback_server_get_status_response(json_pack); + } else { printf("Unknown CMD: '%s' from ID %d\r\n", cmd, id); @@ -292,209 +784,10 @@ void trade_serial_to_string(uint8_t *trade_serial, char *output_str) { return; } - + for (int i = 0; i < 16; i++) { sprintf(&output_str[i * 2], "%02X", trade_serial[i]); } output_str[32] = '\0'; } - -/** - * @brief 主动下发启动指令 - * @note 发送启动指令到充电桩,符合协议格式要求 - * @param stake_index 桩索引 (1~6) - * @param gun_id 枪编码 (1~N) - */ -void local_on_cmd_send_start_charging(uint8_t stake_index, uint8_t gun_id) -{ - if (stake_index > 6 || stake_index == 0) - { - printf("Invalid stake index: %d\r\n", stake_index); - return; - } - - if (gun_id == 0 || gun_id > MAX_GUN_PER_CHARGER) - { - printf("Invalid gun id: %d\r\n", gun_id); - return; - } - - // 检查是否已获取费率模型 - if (!g_charger_manager.charger_piles[stake_index - 1].get_model) - { - printf("Stake %d fee model not ready\r\n", stake_index); - return; - } - - cJSON *root = NULL; - cJSON *billing_array = NULL; - cJSON *billing_item = NULL; - char *str = NULL; - - // 转换交易ID:16位数组转字符串 - char transaction_id_str[33] = {0}; // 32位 + 结束符 - uint8_t *trade_serial = g_charger_manager.charger_piles[stake_index - 1].guns[gun_id - 1].real_time_data.trade_serial; - trade_serial_to_string(trade_serial, transaction_id_str); - - root = cJSON_CreateObject(); - if (root == NULL) - { - printf("Failed to create JSON object for stake %d\r\n", stake_index); - return; - } - - /* 添加基本字段 */ - cJSON_AddNumberToObject(root, "id", stake_index); - cJSON_AddStringToObject(root, "cmd", "start charging"); - cJSON_AddStringToObject(root, "transaction_id", transaction_id_str); // 使用转换后的32位字符串 - cJSON_AddNumberToObject(root, "gun_id", gun_id); - cJSON_AddStringToObject(root, "type", "request"); - - /* 添加限制金额(根据实际业务设置)*/ - cJSON_AddNumberToObject(root, "limit_amount", 30.00); - - /* 创建计费模型数组 */ - billing_array = cJSON_CreateArray(); - if (billing_array == NULL) - { - printf("Failed to create billing array\r\n"); - cJSON_Delete(root); - return; - } - - /* 计费时段:根据费率表生成 period_id 1:尖 2:峰 3:平 4:谷 */ - int period_id = 1; - int i = 0; - - while (i < 48) // 48个半小时时段 - { - uint8_t current_type = g_charger_manager.fee_model_global.fee_num[i]; - - // 跳过无效费率 - if (current_type == 0xFF) - { - i++; - continue; - } - - // 查找连续相同费率的结束位置 - int j = i; - while (j < 48 && g_charger_manager.fee_model_global.fee_num[j] == current_type) - { - j++; - } - - // 计算起始时间(第i个半小时段) - int start_hour = i / 2; - int start_min = (i % 2) * 30; - - // 计算结束时间(第j个半小时段的起始时间) - int end_hour = j / 2; - int end_min = (j % 2) * 30; - - // 格式化时间字符串 "HH:MM" - char start_time[6]; - char end_time[6]; - sprintf(start_time, "%02d:%02d", start_hour, start_min); - - if (end_hour == 24 && end_min == 0) - { - sprintf(end_time, "00:00"); // 跨天显示为00:00 - } - else - { - sprintf(end_time, "%02d:%02d", end_hour, end_min); - } - - // 根据费率类型设置电费和服务费 - float electricity_fee = 0.0f; - float service_fee = 0.0f; - int mapped_period_id = 0; // 映射到协议要求的period_id - - switch (current_type) - { - case 0x00: // 尖时 - electricity_fee = g_charger_manager.fee_model_global.shark_fee_ratio / 100000.0f; - service_fee = g_charger_manager.fee_model_global.shark_service_ratio / 100000.0f; - mapped_period_id = 1; // 1:尖 - break; - case 0x01: // 峰时 - electricity_fee = g_charger_manager.fee_model_global.peak_fee_ratio / 100000.0f; - service_fee = g_charger_manager.fee_model_global.peak_service_ratio / 100000.0f; - mapped_period_id = 2; // 2:峰 - break; - case 0x02: // 平时 - electricity_fee = g_charger_manager.fee_model_global.flat_fee_ratio / 100000.0f; - service_fee = g_charger_manager.fee_model_global.flat_service_ratio / 100000.0f; - mapped_period_id = 3; // 3:平 - break; - case 0x03: // 谷时 - electricity_fee = g_charger_manager.fee_model_global.valley_fee_ratio / 100000.0f; - service_fee = g_charger_manager.fee_model_global.valley_service_ratio / 100000.0f; - mapped_period_id = 4; // 4:谷 - break; - default: - electricity_fee = 0.0f; - service_fee = 0.0f; - mapped_period_id = 0; - break; - } - - // 创建计费时段对象(只有有效费率类型才添加) - if (mapped_period_id > 0) - { - billing_item = cJSON_CreateObject(); - if (billing_item != NULL) - { - cJSON_AddNumberToObject(billing_item, "period_id", mapped_period_id); - cJSON_AddStringToObject(billing_item, "start_time", start_time); - cJSON_AddStringToObject(billing_item, "end_time", end_time); - cJSON_AddNumberToObject(billing_item, "electricity_fee", electricity_fee); - cJSON_AddNumberToObject(billing_item, "service_fee", service_fee); - - cJSON_AddItemToArray(billing_array, billing_item); - - // 调试打印 - #ifdef DEBUG - const char *period_name = ""; - switch(mapped_period_id) - { - case 1: period_name = "Sharp"; break; - case 2: period_name = "Peak"; break; - case 3: period_name = "Flat"; break; - case 4: period_name = "Valley"; break; - } - printf("Period %d: %s-%s [%s] electricity:%.3f service:%.3f\r\n", - mapped_period_id, start_time, end_time, period_name, - electricity_fee, service_fee); - #endif - } - } - - i = j; // 跳到下一个不同费率段 - } - - // 将数组添加到根对象 - cJSON_AddItemToObject(root, "billing_model", billing_array); - - // 转换为JSON字符串并发送 - str = cJSON_Print(root); - if (str != NULL) - { - #ifdef DEBUG - printf("Send start command JSON: %s\r\n", str); - #endif - - udp_send_response(stake_index, str, strlen(str)); - free(str); - } - else - { - printf("Failed to print JSON for stake %d\r\n", stake_index); - } - - cJSON_Delete(root); - printf("Southbound: Start command sent to stake %d, gun %d, total %d billing periods\r\n", - stake_index, gun_id, (int)cJSON_GetArraySize(billing_array)); -} \ No newline at end of file diff --git a/Core/User/Task/YkcTask.c b/Core/User/Task/YkcTask.c index 4685800..9000cfd 100644 --- a/Core/User/Task/YkcTask.c +++ b/Core/User/Task/YkcTask.c @@ -24,13 +24,12 @@ */ uint8_t SETP = 0; - void YkcTask_Function(void const *argument) { init_chargers(); /* 初始化桩结构体*/ ulTaskNotifyTake(pdTRUE, portMAX_DELAY); /* 等待桩通讯协议层完成*/ osDelay(5000); - // send_server_address_to_air724(); + // send_server_address_to_air724(); while (1) { TaskRunTimeStat.YkcTask.threads_runtime = GetTask_RunTime(YkcTaskID); @@ -39,52 +38,56 @@ void YkcTask_Function(void const *argument) switch (SETP) { - case 0: - { - - if (g_charger_manager.charger_piles[1 - 1].is_udp_online) - { - uint8_t open_cmd[] = { 0x55, 0xAA, 0x3, 0x01, 0x01, 0xAA, 0x55}; - Air724_Message_Send(open_cmd, sizeof(open_cmd)); - osDelay(3000); - SETP = 1; - } - else - { - printf("网关:等待桩上电指令\r\n"); - osDelay(1000); - SETP = 0; - } - + case 0: + { + // 等待桩上电 + if (!g_charger_manager.charger_piles[1 - 1].is_udp_online) + { + uint8_t open_cmd[] = {0x55, 0xAA, 0x3, 0x01, 0x01, 0xAA, 0x55}; + Air724_Message_Send(open_cmd, sizeof(open_cmd)); + osDelay(3000); + SETP = 1; } - break; + else + { + printf("网关:等待桩上电指令\r\n"); + osDelay(1000); + SETP = 0; + } + } + break; + // 云快充登录认证 case 1: { if (!g_charger_manager.charger_piles[1 - 1].is_online) { charger_to_server_0X01(1); - } else { SETP = 2; + charger_to_server_0X05(1,1); } - osDelay(5000); + osDelay(5000); } break; + // 云快充计费模型请求 case 2: { if (!g_charger_manager.charger_piles[1 - 1].get_model) + + charger_to_server_0X09(1); // 桩1计费模型请求 else SETP = 3; osDelay(3000); } break; + case 3: { charger_to_server_0X13(1, 1); // 上传状态 - local_on_cmd_send_start_charging(1,1); + // local_on_cmd_send_start_charging(1, 1); osDelay(3000); } break; @@ -92,7 +95,7 @@ void YkcTask_Function(void const *argument) break; } - //osDelay(2000); + // osDelay(2000); } }