1. 新增sqlite文件、协议文档、调试截图、配置ini等各类辅助文件 2. 更新Keil开发包版本与工程配置,调整编译优化等级 3. 重构继电器控制逻辑、串口收发逻辑与线程优先级 4. 新增Modbus寄存器映射、校准结构体与Ymodem升级相关代码 5. 完善南北向协议解析、快充挡位配置与调试日志 6. 修复注释格式、数组越界与线程邮箱溢出问题 7. 新增屏幕控制、功率板调试与协议格式说明文档
394 lines
14 KiB
C
394 lines
14 KiB
C
/****************************************************************************
|
||
文件名称 : 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);
|
||
} |