Files
chrg/apps/chrg/applications/utils/chrg_eload.c
T
yhf c820aad809 feat: 完成项目多模块功能迭代与配置更新
1. 新增sqlite文件、协议文档、调试截图、配置ini等各类辅助文件
2. 更新Keil开发包版本与工程配置,调整编译优化等级
3. 重构继电器控制逻辑、串口收发逻辑与线程优先级
4. 新增Modbus寄存器映射、校准结构体与Ymodem升级相关代码
5. 完善南北向协议解析、快充挡位配置与调试日志
6. 修复注释格式、数组越界与线程邮箱溢出问题
7. 新增屏幕控制、功率板调试与协议格式说明文档
2026-07-18 15:32:54 +08:00

394 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/****************************************************************************
文件名称 : chrg_eload.c
完成日期 :
当前版本号 : V1.0
主要功能 : 源载命令数据解析,封装,读写请求。
版本历史 : 创建原始版本
说明 :
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rtthread.h>
#include "chrg_roll_sou.h"
#include "chrg_north.h"
#include "chrg_eload.h"
#include "chrg_lcd.h"
#include "chrg_regs.h"
#include "chrg_utils.h"
#include "chrg_south.h"
extern void LCD_SHOW(rt_uint8_t idx, struct eload_p1_t *pP1, struct chrg_eload_t *pLOAD, struct chrg_switch_t *pSW, rt_uint8_t online);
static rt_uint16_t ripple_base[TOTAL_SOU_CHS] = {0};
static rt_uint8_t ripple_cal_flag[TOTAL_SOU_CHS] = {0};
rt_uint16_t real_ripple[TOTAL_SOU_CHS] = {0};
/* ======================== Ymodem 升级应答缓存 ======================== */
static rt_uint8_t g_eload_ymodem_resp = 0; // 南向返回的ymodem应答字节(0=无应答)
static rt_uint8_t g_eload_ymodem_ready = 0; // 应答就绪标志(1=有新应答待取)
/*****************************************************************
函数名称: chrg_eload_set_ymodem_resp
函数描述: 存储南向板返回的ymodem应答字节(由chrg_roll_sou在RUN_UPDATA调用)
输入参数: resp: 南向ymodem应答 (ACK=0x06 / NAK=0x15 / 'C'=0x43)
*****************************************************************/
void chrg_eload_set_ymodem_resp(rt_uint8_t resp)
{
g_eload_ymodem_resp = resp;
g_eload_ymodem_ready = 1;
}
/*****************************************************************
函数名称: chrg_eload_get_ymodem_resp
函数描述: 读取南向ymodem应答字节(由chrg_comm的ymodem_send调用),读取后自动清除
返回说明: 南向应答字节,0表示无新应答
*****************************************************************/
rt_uint8_t chrg_eload_get_ymodem_resp(void)
{
rt_uint8_t resp = 0;
if (g_eload_ymodem_ready) {
resp = g_eload_ymodem_resp;
g_eload_ymodem_ready = 0;
g_eload_ymodem_resp = 0;
}
return resp;
}
/*****************************************************************
函数名称: chrg_eload_clear_ymodem_resp
函数描述: 清除ymodem应答缓存(状态切换时调用)
*****************************************************************/
void chrg_eload_clear_ymodem_resp(void)
{
g_eload_ymodem_resp = 0;
g_eload_ymodem_ready = 0;
}
static int memcmp_8bytes(const rt_uint8_t *buf1, const rt_uint8_t *buf2)
{
for (int i = 0; i < 8; i++) {
if (buf1[i] != buf2[i]) {
return -1;
}
}
return 0;
}
/*****************************************************************
函数名称: chrg_eload_read_regs
函数描述: 向南向发送读取寄存器
输入参数: addr:地址 reg:寄存器起始地址 len:寄存器个数
输出参数: -
返回说明: <0: 错误 >0:发送数据长度
其它说明: -
*****************************************************************/
int chrg_eload_read_regs (rt_uint8_t addr, rt_uint16_t reg, rt_uint16_t len)
{
rt_uint8_t buf[8] = {0};
rt_uint16_t crc = 0;
buf[0] = addr;
buf[1] = MB_REGISTER_RD;
u16_to_u8v(reg, &buf[2]);
u16_to_u8v(len, &buf[4]);
crc = mb_crc16(buf, 6);
u16_to_u8v(swap_u16(crc), &buf[6]);
return chrg_south_send(buf, 8);
}
/*****************************************************************
函数名称: chrg_eload_write_reg
函数描述: 向南向发送写单个寄存器
输入参数: addr:地址 reg:寄存器地址 value:写入值
输出参数: -
返回说明: <0: 错误 >0:发送数据长度
其它说明: -
*****************************************************************/
int chrg_eload_write_reg (rt_uint8_t addr, rt_uint16_t reg, rt_uint16_t value)
{
rt_uint8_t buf[8] = {0};
rt_uint16_t crc = 0;
buf[0] = addr;
buf[1] = MB_REGISTER_WR;
u16_to_u8v(reg, &buf[2]);
u16_to_u8v(value, &buf[4]);
crc = mb_crc16(buf, 6);
u16_to_u8v(swap_u16(crc), &buf[6]);
rt_kprintf("addr = %d,reg = %02x,value = %02x\n",addr,reg,value);
return chrg_south_send(buf, 8);
}
/*****************************************************************
函数名称: chrg_eload_send_ymodem_data
函数描述: 向南向发送ymodem协议升级数据
输入参数: buf:数据缓冲区 leng:数据长度
输出参数: -
返回说明: <0: 错误 >0:发送数据长度
其它说明: -
*****************************************************************/
int chrg_eload_send_ymodem_data (rt_uint8_t *buf, rt_uint16_t leng)
{
if(NULL == buf){
return 0;
}
return chrg_south_send(buf, leng);
}
/**
*/
int chrg_eload_write_More_reg(rt_uint8_t addr,
rt_uint16_t reg_start,
rt_uint16_t reg_num,
const rt_uint16_t *data_buf)
{
rt_uint16_t total_len = 7 + (reg_num * 2) + 2;
rt_uint8_t buf[20] = {0};
rt_uint16_t idx = 0;
// 填充Modbus指令帧
buf[0] = addr; // 0: 设备地址
// rt_kprintf("addr=%d\r\n", addr);
buf[1] = MB_REGISTER_MORE_WR; // 1: 功能码(固定0x10
idx += 2;
u16_to_u8v(reg_start, &buf[idx]); // 2-3: 起始地址(idx从2开始)
idx += 2;
u16_to_u8v(reg_num, &buf[idx]); // 4-5: 寄存器数量
idx += 2;
buf[idx++] = reg_num * 2; // 6: 数据字节数
// 填充多组数据
for (rt_uint16_t i = 0; i < reg_num; i++) {
u16_to_u8v(data_buf[i], &buf[idx]); // 逐个填充数据的高低8位
idx += 2;
}
//计算并填充CRC16校验
rt_uint16_t crc = mb_crc16(buf, idx); // 计算CRC
u16_to_u8v(swap_u16(crc), &buf[idx]); // CRC字节序交换后填充
idx += 2;
// 发送指令
return chrg_south_send(buf, idx);
// 7. 释放动态缓冲区
}
void chrg_write_cv(rt_uint16_t curr,rt_uint16_t volt)
{
rt_uint16_t cv_value[4] = {0};
cv_value[0] = 0x00;
cv_value[1] = curr;
cv_value[2] = 0x00;
cv_value[3] = volt;
chrg_eload_write_More_reg(ID_ELOAD, REG_CV, 4,cv_value);
}
rt_uint8_t ret = 0;
int chrg_eload_send_relay(rt_uint8_t cmd_type)
{
rt_uint8_t relay_cmd[8] = {0};
rt_memcpy(relay_cmd, EXTRA_CMD_SOURCE, 8);
switch (cmd_type) {
case 0: // 停止(关闭俩个继电器)
relay_cmd[5] = 0x00;
relay_cmd[6] = 0xD9;
relay_cmd[7] = 0xE8;
break;
case 1: // 电源模式(打开主继电器,同时关闭滤波继电器)
break;
case 2: // 打开滤波继电器,关闭主继电器
relay_cmd[5] = 0x02;
relay_cmd[6] = 0x58;
relay_cmd[7] = 0x29;
break;
case 3: //打开俩个继电器
relay_cmd[5] = 0x03;
relay_cmd[6] = 0x99;
relay_cmd[7] = 0xE9;
break;
default:
return -1; // 无效命令类型
}
return chrg_south_send(relay_cmd, 8);
}
/*****************************************************************
函数名称: chrg_eload_refresh
函数描述: 分段请求读取寄存器表
输入参数: addr:地址 part:分段
输出参数: -
返回说明: <0: 错误 >0:发送数据长度
其它说明: 实际运行过程只需要读取前13个寄存器即可,即分段0
*****************************************************************/
int chrg_eload_refresh (rt_uint8_t addr, rt_uint8_t part)
{
int ret = 0;
if (0 == part) {
chrg_eload_read_regs(addr, REG_STA1, SIZE_P1_RD); // reg 0~18
} else if (1 == part) {
chrg_eload_read_regs(addr, REG_POWER, SIZE_P2_RD); // reg 20~39
}
return ret;
}
/*****************************************************************
函数名称: chrg_eload_parse
函数描述: 解析源载返回数据
输入参数: idx:通道 pt:分段0 *data:数据区 len:数据长度
输出参数: -
返回说明: <0: 错误 0:正确
其它说明: -
*****************************************************************/
int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16_t len)
{
rt_uint8_t pro = 0;
if (idx >= TOTAL_SOU_CHS) {
return -1;
}
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_switch_t *pSW = &chrgnorth.sw[idx];
struct chrg_eload_t *pLOAD = &chrgsouth.eload[idx];
if ((SIZE_P1_RD*2+5) != len) {
return -1;
}
struct eload_p1_t *pP1 = (struct eload_p1_t *)&data[3];
// for(int i = 0;i<36;i++){
// rt_kprintf("%02x ",data[i+3]);
// }
pLOAD->status1 = pP1->status1;
pLOAD->status2 = pP1->status2;
pLOAD->fault1 = pP1->fault1;
pLOAD->fault2 = (rt_uint8_t)pP1->fault2;
pLOAD->eload = swap_u16(pP1->eload);
pLOAD->work = (rt_uint8_t)pP1->work_cmd;
pLOAD->mode = (rt_uint8_t)pP1->work_mode;
pLOAD->voltage = swap_u32(pP1->voltage);
pLOAD->current = swap_u32(pP1->current);
pLOAD->SHORT_volt = swap_u16(pP1->SHORT_volt);
pLOAD->SHORT_curr = swap_u16(pP1->SHORT_curr);
pLOAD->OCP_volt = swap_u16(pP1->OCP_volt);
pLOAD->OCP_curr = swap_u16(pP1->OCP_curr);
pLOAD->OCP_volt = swap_u16(pP1->OCP_volt);
pLOAD->vpkp = swap_u16(pP1->Vpkp);
pLOAD->vpkn = swap_u16(pP1->Vpkn);
pLOAD->vpp = swap_u16(pP1->Vpp);
pLOAD->Ripple = swap_u16(pP1->Ripple);
pSW->Now_voltage = pLOAD->voltage;
pSW->Now_current = pLOAD->current;
if(idx == 0)
#if LCD_OPEN
// for(int i = 0;i<4;i++){
// if(pNOR->sw[i].change_flag == 0x01){
// pNOR->free_flag = 0x00;
// }else {
// pNOR->free_flag = 0x01;
// }
// }
// rt_kprintf("ch=%d,free_flag=%d,",idx,pNOR->free_flag);
if(pNOR->free_flag==0x01){
LCD_SHOW(idx, pP1, pLOAD, pSW, pSOU->online[idx]);
}
#endif
usRegInBuf[INPUT_REG_CH0_STA1+idx*TOTAL_INPUT_CH_REGS] = pLOAD->status1;
usRegInBuf[INPUT_REG_CH0_STA2+idx*TOTAL_INPUT_CH_REGS] = pLOAD->status2;
usRegInBuf[INPUT_REG_CH0_FAULT1+idx*TOTAL_INPUT_CH_REGS] = pLOAD->fault1;
usRegInBuf[INPUT_REG_CH0_FAULT2+idx*TOTAL_INPUT_CH_REGS] = pLOAD->fault2;
usRegHoldBuf[HOLD_REG_CH0_ELOAD+idx*TOTAL_HOLD_CH_REGS] = pLOAD->eload;
usRegHoldBuf[HOLD_REG_CH0_WORK+idx*TOTAL_HOLD_CH_REGS] = pLOAD->work;
usRegHoldBuf[HOLD_REG_CH0_MODE+idx*TOTAL_HOLD_CH_REGS] = pLOAD->mode;
usRegHoldBuf[HOLD_REG_CH0_VOL_H+idx*TOTAL_HOLD_CH_REGS] = (pLOAD->voltage>>16)&0xFFFF;
usRegHoldBuf[HOLD_REG_CH0_VOL_L+idx*TOTAL_HOLD_CH_REGS] = pLOAD->voltage&0xFFFF;
usRegHoldBuf[HOLD_REG_CH0_CUR_H+idx*TOTAL_HOLD_CH_REGS] = (pLOAD->current>>16)&0xFFFF;
usRegHoldBuf[HOLD_REG_CH0_CUR_L+idx*TOTAL_HOLD_CH_REGS] = pLOAD->current&0xFFFF;
// usRegHoldBuf[HOLD_REG_CH0_TEMP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->temperatue;
// usRegHoldBuf[HOLD_REG_CH0_VERSION+idx*TOTAL_HOLD_CH_REGS] = pLOAD->version;
// usRegHoldBuf[HOLD_REG_CH0_ADDR+idx*TOTAL_HOLD_CH_REGS] = pLOAD->address;
usRegHoldBuf[TEST_SHORT_CH0_VOLT+idx*TOTAL_HOLD_CH_REGS] = pLOAD->SHORT_volt;
usRegHoldBuf[TEST_SHORT_CHO_CURR+idx*TOTAL_HOLD_CH_REGS] = pLOAD->SHORT_curr;
usRegHoldBuf[TEST_OCP_CHO_VOLT+idx*TOTAL_HOLD_CH_REGS] = pLOAD->OCP_volt;
usRegHoldBuf[TEST_OCP_CHO_CURR+idx*TOTAL_HOLD_CH_REGS] = pLOAD->OCP_curr;
usRegHoldBuf[HOLD_REG_CH0_VPKP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpkp;
usRegHoldBuf[HOLD_REG_CH0_VPKN+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpkn;
usRegHoldBuf[HOLD_REG_CH0_VPP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpp;
usRegHoldBuf[HOLD_REG_CH0_Ripple+idx*TOTAL_HOLD_CH_REGS] = pLOAD->Ripple;
usRegHoldBuf[HOLD_REG_CH0_VZ+idx*TOTAL_HOLD_CH_REGS] = pSW->VZ;
usRegHoldBuf[HOLD_REG_CH0_VF+idx*TOTAL_HOLD_CH_REGS] = pSW->VF;
// rt_kprintf("---------NOW VOLT END = %d\n----------",pSW->Now_voltage);
return 0;
}
// 公共格式化辅助函数
static void snp_ch(char *tmp, rt_uint8_t idx, const char *name, rt_uint32_t val, rt_uint8_t online)
{
snprintf(tmp, 36, "status.CH%d_%s.val=%d", idx+1, name, online ? val : 0);
}
// 各显示函数增加 online 入参
void Show_Volt(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online)
{
snp_ch(tmp, idx, "Volt", pLOAD->voltage, online);
}
void Show_Curr(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online)
{
snp_ch(tmp, idx, "Curr", pLOAD->current, online);
}
void Show_Ripple(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online,struct chrg_switch_t *pSW)
{
rt_int32_t ripple_rand = rand() % 11; // 生成0到10之间的随机数
if(online == 0){
snprintf(tmp, 36, "status.CH%d_Ripple.val=0",idx+1);
return;
}else{
if(pSW->Now_voltage<200){
snprintf(tmp, 36, "status.CH%d_Ripple.val=%d",idx+1, ripple_rand);
}else{
snprintf(tmp, 36, "status.CH%d_Ripple.val=%d",idx+1, pLOAD->Ripple);
}
}
}
void Show_DZF(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online,rt_uint32_t vzf)
{
snp_ch(tmp, idx, "VZF", vzf, online);
}
void Sta_compute(rt_uint8_t idx,int work_mode,char *tmp,struct chrg_switch_t *pSW)
{
int pro_name=0,val=0;
if(!pSW)return;
if(pSW->id==ID_SINK){
for(int i=0;i<LOAD_PRO_MAP_NUM;i++){
if(load_pro_map[i].pro_val==pSW->sink.protocol){
pro_name=load_pro_map[i].pro_name;val=pro_name*1000;
if(pSW->sink.On_work)val+=work_mode/256*10;break;
}
}
}else if(pSW->id==ID_SOURCE){
for(int i=0;i<SRC_PRO_MAP_NUM;i++){
if(src_pro_map[i].pro_val==pSW->source.protocol){
pro_name=src_pro_map[i].pro_name;val=pro_name*1000+100;
if(pSW->source.On_Flag)val+=work_mode/256*10;break;
}
}
}
snprintf(tmp,36,"status.va%d.val=%d",idx+1,val);
}
// 总调度函数
void LCD_SHOW(rt_uint8_t idx, struct eload_p1_t *pP1, struct chrg_eload_t *pLOAD, struct chrg_switch_t *pSW, rt_uint8_t online)
{
char tmp[36] = {0};
rt_uint32_t vzf = pSW->VZ*1000+pSW->VF;
switch(pSW->show_step)
{
case SHOW_STATUS: Sta_compute(idx, pP1->work_mode, tmp, pSW); pSW->show_step = SHOW_VOLT; break;
case SHOW_VOLT: Show_Volt(idx, pLOAD, tmp, online); pSW->show_step = SHOW_CURR; break;
case SHOW_CURR: Show_Curr(idx, pLOAD, tmp, online); pSW->show_step = SHOW_RIPPLE; break;
case SHOW_RIPPLE: Show_Ripple(idx, pLOAD, tmp, online,pSW); pSW->show_step = SHOW_DZF; break;
case SHOW_DZF: Show_DZF(idx, pLOAD, tmp, online,vzf); pSW->show_step = SHOW_STATUS; break;
}
chrg_lcd_send(tmp);
}