Files
chrg/apps/chrg/applications/thread/chrg_comm.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

2360 lines
80 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_comm.c
完成日期 :
当前版本号 : V1.0
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
版本历史 : 创建原始版本
说明 :
******************************************************************************/
#include <string.h>
#include <rtthread.h>
#include "chrg_thread.h"
#include "chrg_north.h"
#include "chrg_comm.h"
#include "chrg_utils.h"
#include "chrg_south.h"
#include "chrg_roll_sou.h"
#include "chrg_eload.h"
#include "chrg_rel.h"
#include "chrg_roll_nor.h"
#define LOG_TAG "chrg.comm"
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
#include "chrg_north_pkg.h"
#include "chrg_lcd.h"
#include "stm32f4xx_hal.h"
rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR];
rt_uint8_t ucCoilBuf[(TOTAL_COIL_REGS+BITS_UCHAR-1)/BITS_UCHAR];
rt_uint16_t usRegInBuf[TOTAL_INPUT_REGS];
rt_uint16_t usRegHoldBuf[TOTAL_HOLD_ALL_REGS] = {0}; //上位机Modbus 指令/数据保持器
rt_uint16_t usRegProBuf[TOTAL_HOLD_ALL_REGS]; //北向protcal???
//rt_uint16_t usRegTestBuf[TOTAL_TEST_REGS];
rt_uint8_t g_proto_pData[80] = {0};//上位机协议指令,控制四个通道;二维
rt_uint16_t g_proto_reqLen = 0;
rt_uint8_t mobude_ymodem_buf[MB_YMODEM_DATA_SIZE] = {0};//南向功率板升级缓冲区
rt_uint8_t mobude_ymodem_buf_2[MB_YMODEM_DATA_SIZE] = {0};//南向功率板升级缓冲区
/* Modbus 影子寄存器: 0x06/0x10 写操作暂存到此, PARAM_EFFECT 生效后复制到实际 pNOR->sw */
static struct chrg_switch_t g_shadow_sw[TOTAL_NOR_CHS];
static rt_uint8_t g_shadow_dirty[TOTAL_NOR_CHS] = {0}; /* 0=已生效 1=待生效,防止重复覆盖 */
/* 首次写入影子寄存器前,从真实结构体同步,避免覆盖运行中的关键标志位 */
static void chrg_shadow_sync(rt_uint8_t ch)
{
if (g_shadow_dirty[ch] == 0) {
rt_memcpy(&g_shadow_sw[ch], &chrgnorth.sw[ch], sizeof(struct chrg_switch_t));
}
g_shadow_dirty[ch] = 1;
}
static void chrg_shadow_init(void)
{
rt_memcpy(g_shadow_sw, chrgnorth.sw, sizeof(g_shadow_sw));
rt_memset(g_shadow_dirty, 0, sizeof(g_shadow_dirty));
}
struct chrg_comm_t chrgcomm = {
.devname = DEV_NAME_COMM,
.tty = RT_NULL,
.rx_len = 0,
.tx_len = 0,
.addr = MODBUS_ADDRESS_DEFAULT,
};
static void chrg_mb_write_sink(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW);
static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW);
static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR, struct chrg_south_t *pSOU);
/*! \brief Function to set bits in a byte buffer.
*
* This function allows the efficient use of an array to implement bitfields.
* The array used for storing the bits must always be a multiple of two
* bytes. Up to eight bits can be set or cleared in one operation.
*
* \param ucByteBuf A buffer where the bit values are stored. Must be a
* multiple of 2 bytes. No length checking is performed and if
* usBitOffset / 8 is greater than the size of the buffer memory contents
* is overwritten.
* \param usBitOffset The starting address of the bits to set. The first
* bit has the offset 0.
* \param ucNBits Number of bits to modify. The value must always be smaller
* than 8.
* \param ucValues Thew new values for the bits. The value for the first bit
* starting at <code>usBitOffset</code> is the LSB of the value
* <code>ucValues</code>
*
* \code
* ucBits[2] = {0, 0};
*
* // Set bit 4 to 1 (read: set 1 bit starting at bit offset 4 to value 1)
* mb_set_bits( ucBits, 4, 1, 1 );
*
* // Set bit 7 to 1 and bit 8 to 0.
* mb_set_bits( ucBits, 7, 2, 0x01 );
*
* // Set bits 8 - 11 to 0x05 and bits 12 - 15 to 0x0A;
* mb_set_bits( ucBits, 8, 8, 0x5A);
* \endcode
*/
void mb_set_bits (rt_uint8_t *ucByteBuf, rt_uint16_t usBitOffset,
rt_uint8_t ucNBits, rt_uint8_t ucValue)
{
rt_uint16_t usWordBuf;
rt_uint16_t usMask;
rt_uint16_t usByteOffset;
rt_uint16_t usNPreBits;
rt_uint16_t usValue = ucValue;
RT_ASSERT(ucNBits <= BITS_UCHAR);
RT_ASSERT((size_t)BITS_UCHAR == sizeof(rt_uint8_t) * 8);
/* Calculate byte offset for first byte containing the bit values starting
* at usBitOffset. */
usByteOffset = (rt_uint16_t)((usBitOffset) / BITS_UCHAR);
/* How many bits precede our bits to set. */
usNPreBits = (rt_uint16_t)(usBitOffset - usByteOffset * BITS_UCHAR);
/* Move bit field into position over bits to set */
usValue <<= usNPreBits;
/* Prepare a mask for setting the new bits. */
usMask = (rt_uint16_t)((1 << (rt_uint16_t)ucNBits) - 1);
usMask <<= usBitOffset - usByteOffset * BITS_UCHAR;
/* copy bits into temporary storage. */
usWordBuf = ucByteBuf[usByteOffset];
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
/* Zero out bit field bits and then or value bits into them. */
usWordBuf = (rt_uint16_t)((usWordBuf & (~usMask)) | usValue);
/* move bits back into storage */
ucByteBuf[usByteOffset] = (rt_uint8_t)(usWordBuf & 0xFF);
ucByteBuf[usByteOffset + 1] = (rt_uint8_t)(usWordBuf >> BITS_UCHAR);
}
/*! \brief Function to read bits in a byte buffer.
*
* This function is used to extract up bit values from an array. Up to eight
* bit values can be extracted in one step.
*
* \param ucByteBuf A buffer where the bit values are stored.
* \param usBitOffset The starting address of the bits to set. The first
* bit has the offset 0.
* \param ucNBits Number of bits to modify. The value must always be smaller
* than 8.
*
* \code
* rt_uint8_t ucBits[2] = {0, 0};
* rt_uint8_t ucResult;
*
* // Extract the bits 3 - 10.
* ucResult = mb_get_bits( ucBits, 3, 8 );
* \endcode
*/
rt_uint8_t mb_get_bits (rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset, rt_uint8_t ucNBits)
{
rt_uint16_t usWordBuf;
rt_uint16_t usMask;
rt_uint16_t usByteOffset;
rt_uint16_t usNPreBits;
/* Calculate byte offset for first byte containing the bit values starting
* at usBitOffset. */
usByteOffset = (rt_uint16_t)((usBitOffset) / BITS_UCHAR);
/* How many bits precede our bits to set. */
usNPreBits = (rt_uint16_t)(usBitOffset - usByteOffset * BITS_UCHAR);
/* Prepare a mask for setting the new bits. */
usMask = (rt_uint16_t)((1 << (rt_uint16_t)ucNBits) - 1);
/* copy bits into temporary storage. */
usWordBuf = ucByteBuf[usByteOffset];
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
/* throw away unneeded bits. */
usWordBuf >>= usNPreBits;
/* mask away bits above the requested bitfield. */
usWordBuf &= usMask;
return (rt_uint8_t)usWordBuf;
}
static void set_ymodem_update_channel(struct chrg_north_t *pNOR,struct chrg_south_t *pSOU,eIDX_SOU_CH ch)
{
for (int i = 0; i < 4; i++) {
pNOR->enable[i] = 0;
pSOU->enable[i] = 0;
}
pNOR->enable[ch] = 1;
pSOU->enable[ch] = 1;
}
static eMBException mb_error (eMBErrorCode eErrorCode)
{
eMBException eStatus;
switch (eErrorCode) {
case MB_ENOERR:
eStatus = MB_EX_NONE;
break;
case MB_ENOREG:
eStatus = MB_EX_ILLEGAL_DATA_ADDRESS;
break;
case MB_ETIMEDOUT:
eStatus = MB_EX_SLAVE_BUSY;
break;
default:
eStatus = MB_EX_SLAVE_DEVICE_FAILURE;
break;
}
return eStatus;
}
//extern eMBErrorCode Modbus_Protocal_Set(rt_uint16_t Role_value,rt_uint16_t src,rt_uint16_t pps,rt_uint16_t pro_value,rt_uint16_t volt_value,rt_uint16_t curr_value);
eMBErrorCode mb_reg_input_cb (rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress, rt_uint16_t usNRegs)
{
eMBErrorCode eStatus = MB_ENOERR;
rt_uint16_t iRegIndex;
if ((usAddress >= INPUT_REG_START)
&& (usAddress + usNRegs <= INPUT_REG_START + TOTAL_INPUT_REGS)) {
iRegIndex = usAddress - INPUT_REG_START;
while (usNRegs > 0) {
*pucRegBuffer++ = (rt_uint8_t)(usRegInBuf[iRegIndex] >> BITS_UCHAR);
*pucRegBuffer++ = (rt_uint8_t)(usRegInBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
} else {
eStatus = MB_ENOREG;
}
return eStatus;
}
/*****************************************************************
函数名称: mb_reg_holding_cb
函数描述: Modbus保持寄存器读写回调函数
输入参数: req: 写操作时指向待写入的Modbus帧数据缓冲区(高字节在前);读操作时无意义
pucRegBuffer: 读操作时指向存储返回数据的缓冲区;写操作时无意义
usAddress: 保持寄存器起始地址(16位,基于HOLD_REG_START的偏移)
usNRegs: 需要读写的保持寄存器数量(16位寄存器个数)
eMode: 寄存器操作模式(MB_REG_READ-读寄存器,MB_REG_WRITE-写寄存器)
输出参数: -
返回说明: eMBErrorCode枚举值,MB_ENOERR表示操作成功,MB_ENOREG表示地址越界
其它说明: 1. 寄存器地址需满足HOLD_REG_START ≤ usAddress + usNRegs ≤ HOLD_REG_START + TOTAL_HOLD_ALL_REGS
2. 字节序遵循Modbus RTU标准:高字节在前,低字节在后
3. usRegHoldBuf为全局保持寄存器缓冲区,存储所有可读写配置参数
*****************************************************************/
eMBErrorCode mb_reg_holding_cb (rt_uint8_t *req, rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress,
rt_uint16_t usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
rt_uint16_t iRegIndex;
rt_uint8_t highByte, lowByte; // 定义字节变量用于打印
if ((usAddress >= HOLD_REG_START)
&& (usAddress + usNRegs <= HOLD_REG_START + TOTAL_HOLD_ALL_REGS)) {
iRegIndex = usAddress - HOLD_REG_START;
switch (eMode) {
/* read current register values from the protocol stack. */
case MB_REG_READ:
while (usNRegs > 0) {
*pucRegBuffer++ = (rt_uint8_t)(usRegHoldBuf[iRegIndex] >> BITS_UCHAR);
*pucRegBuffer++ = (rt_uint8_t)(usRegHoldBuf[iRegIndex] & 0xFF);
// highByte = (rt_uint8_t)(usRegHoldBuf[iRegIndex] >> BITS_UCHAR);
// lowByte = (rt_uint8_t)(usRegHoldBuf[iRegIndex] & 0xFF);
// rt_kprintf("Reg[%d] = 0x%04X, High:0x%02X, Low:0x%02X\r\n",
// iRegIndex, usRegHoldBuf[iRegIndex], highByte, lowByte);
iRegIndex++;
usNRegs--;
}
break;
/* write current register values with new values from the protocol stack. */
case MB_REG_WRITE:
while (usNRegs > 0) {
// usRegHoldBuf[iRegIndex] = *req++ << BITS_UCHAR;
// usRegHoldBuf[iRegIndex] |= *req++;
// iRegIndex++;
usNRegs--;
}
break;
}
} else {
eStatus = MB_ENOREG;
}
return eStatus;
}
/*****************************************************************
函数名称: mb_reg_test_cb
函数描述: Modbus测试寄存器读写回调函数,实现16位保持寄存器与8位字节流的双向转换,
支持读寄存器(返回配置参数)和写寄存器(存储主机下发的配置指令)
输入参数: req: 写操作时指向待写入的Modbus帧数据缓冲区(高字节在前);读操作时无意义
pucRegBuffer: 读操作时指向存储返回数据的缓冲区;写操作时无意义
usAddress: 保持寄存器起始地址(16位,基于HOLD_REG_START的偏移)
usNRegs: 需要读写的保持寄存器数量(16位寄存器个数)
eMode: 寄存器操作模式(MB_REG_READ-读寄存器,MB_REG_WRITE-写寄存器)
输出参数: -
返回说明: eMBErrorCode枚举值,MB_ENOERR表示操作成功,MB_ENOREG表示地址越界
其它说明: 1. 寄存器地址需满足HOLD_REG_START ≤ usAddress + usNRegs ≤ HOLD_REG_START + TOTAL_HOLD_REGS
2. 字节序遵循Modbus RTU标准:高字节在前,低字节在后
3. usRegHoldBuf为全局保持寄存器缓冲区,存储所有可读写配置参数
*****************************************************************/
eMBErrorCode mb_reg_test_cb (rt_uint8_t *req, rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress,
rt_uint16_t usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
// rt_uint16_t iRegIndex;
// if ((usAddress >= TEST_REG_START)
// && (usAddress + usNRegs <= TEST_REG_START + TOTAL_TEST_REGS)) {
// iRegIndex = usAddress - TEST_REG_START;
// switch (eMode) {
// /* read current register values from the protocol stack. */
// case MB_REG_READ:
// while (usNRegs > 0) {
// *pucRegBuffer++ = (rt_uint8_t)(usRegTestBuf[iRegIndex] >> BITS_UCHAR);
// *pucRegBuffer++ = (rt_uint8_t)(usRegTestBuf[iRegIndex] & 0xFF);
// iRegIndex++;
// usNRegs--;
// }
// break;
// /* write current register values with new values from the protocol stack. */
// case MB_REG_WRITE:
// while (usNRegs > 0) {
// usRegTestBuf[iRegIndex] = *req++ << BITS_UCHAR;
// usRegTestBuf[iRegIndex] |= *req++;
// iRegIndex++;
// usNRegs--;
// }
// break;
// }
// } else {
// eStatus = MB_ENOREG;
// }
return eStatus;
}
/*****************************************************************
函数名称: mb_ymodem_updata_cb
*****************************************************************/
eMBErrorCode mb_ymodem_updata_cb (rt_uint8_t *state, rt_uint8_t *pucRegBuffer)
{
eMBErrorCode eStatus = MB_ENOERR;
switch (*state) {
/* read current register values from the protocol stack. */
case 0:
/* 返回值反映实际ymodem升级状态: ACK_C=空闲, ACK=升级中 */
pucRegBuffer[0] = (*state == Ymodem_No) ? ACK_C : ACK;
break;
case 1:
pucRegBuffer[0] = (*state == Ymodem_No) ? ACK_C : ACK;
break;
/* write current register values with new values from the protocol stack. */
}
return eStatus;
}
eMBErrorCode mb_reg_coils_cb (rt_uint8_t *req, rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress,
rt_uint16_t usNCoils, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
rt_uint16_t iRegIndex = 0, iRegBitIndex = 0, iNReg = 0;
iNReg = (usNCoils+BITS_UCHAR-1)/BITS_UCHAR;
if ((usAddress >= COIL_REG_START) && (usAddress + usNCoils <= COIL_REG_START + TOTAL_COIL_REGS)) {
iRegIndex = (rt_uint16_t)(usAddress - COIL_REG_START) / BITS_UCHAR;
iRegBitIndex = (rt_uint16_t)(usAddress - COIL_REG_START) % BITS_UCHAR;
switch (eMode) {
/* read current coil values from the protocol stack. */
case MB_REG_READ:
while (iNReg > 0) {
*pucRegBuffer++ = mb_get_bits(&ucCoilBuf[iRegIndex++], iRegBitIndex, BITS_UCHAR);
iNReg--;
}
pucRegBuffer--;
/* last coils */
usNCoils = usNCoils % BITS_UCHAR;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (BITS_UCHAR - usNCoils);
*pucRegBuffer = *pucRegBuffer >> (BITS_UCHAR - usNCoils);
break;
/* write current coil values with new values from the protocol stack. */
case MB_REG_WRITE:
while (iNReg > 1) {
mb_set_bits(&ucCoilBuf[iRegIndex++], iRegBitIndex, BITS_UCHAR, *req++);
iNReg--;
}
/* last coils */
usNCoils = usNCoils % BITS_UCHAR;
/* mb_set_bits has bug when ucNBits is zero */
if (usNCoils != 0) {
mb_set_bits(&ucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils, *req++);
}
break;
}
} else {
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode mb_reg_discrete_cb (rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress, rt_uint16_t usNDiscrete)
{
eMBErrorCode eStatus = MB_ENOERR;
rt_uint16_t iRegIndex , iRegBitIndex , iNReg;
iNReg = (usNDiscrete+BITS_UCHAR-1) / BITS_UCHAR;
if ((usAddress >= DISC_REG_START)
&& ((usAddress + usNDiscrete) <= (DISC_REG_START + TOTAL_DISC_REGS))) {
iRegIndex = (rt_uint16_t) (usAddress - DISC_REG_START) / BITS_UCHAR;
iRegBitIndex = (rt_uint16_t) (usAddress - DISC_REG_START) % BITS_UCHAR;
while (iNReg > 0) {
*pucRegBuffer++ = mb_get_bits(&ucDiscInBuf[iRegIndex++], iRegBitIndex, BITS_UCHAR);
iNReg--;
}
pucRegBuffer--;
/* last discrete */
usNDiscrete = usNDiscrete % BITS_UCHAR;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (BITS_UCHAR - usNDiscrete);
*pucRegBuffer = *pucRegBuffer >> (BITS_UCHAR - usNDiscrete);
} else {
eStatus = MB_ENOREG;
}
return eStatus;
}
/*****************************************************************
函数名称: funcReadCoils
函数描述: 读多个继电器
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
eMBException funcReadCoils (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
rt_uint16_t regAddress = 0, cntCoils = 0;
rt_uint8_t ucNBytes = 0;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
regAddress = u8v_to_u16(&reqFrame[2]);
cntCoils = u8v_to_u16(&reqFrame[4]);
if ((0 == cntCoils)||(cntCoils >= MB_PDU_FUNC_READ_COILCNT_MAX)) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
ucNBytes = (cntCoils+BITS_UCHAR-1)/BITS_UCHAR;
resFrame[1] = MB_READ_COILS;
resFrame[2] = ucNBytes;
eRegStatus = mb_reg_coils_cb(RT_NULL, &resFrame[3], regAddress, cntCoils, MB_REG_READ);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
} else {
*resLen = 3+ucNBytes;
}
return eStatus;
}
/*****************************************************************
函数名称: funcReadDiscreteInputs
函数描述: 读离散输入
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
eMBException funcReadDiscreteInputs (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
rt_uint16_t regAddress = 0, cntDisCrete = 0;
rt_uint8_t ucNBytes = 0;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
regAddress = u8v_to_u16(&reqFrame[2]);
cntDisCrete = u8v_to_u16(&reqFrame[4]);
if ((0 == cntDisCrete)||(cntDisCrete >= MB_PDU_FUNC_READ_DISCCNT_MAX)) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
ucNBytes = (cntDisCrete+BITS_UCHAR-1)/BITS_UCHAR;
resFrame[1] = MB_READ_DISCRETE_INPUTS;
resFrame[2] = ucNBytes;
eRegStatus = mb_reg_discrete_cb(&resFrame[3], regAddress, cntDisCrete);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
} else {
*resLen = 3+ucNBytes;
}
return eStatus;
}
/*****************************************************************
函数名称: funcReadHoldingRegister
函数描述: 读保持寄存器
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
eMBException funcReadHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
rt_uint16_t regAddress = 0, cntReg = 0;
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_switch_t *pSW = &pNOR->sw[0];
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
regAddress = u8v_to_u16(&reqFrame[2]);
cntReg = u8v_to_u16(&reqFrame[4]);
if ((0 == cntReg)||(cntReg >= MB_PDU_FUNC_READ_REGCNT_MAX)) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
resFrame[1] = MB_READ_HOLDING_REGISTER;
resFrame[2] = cntReg * 2;
eRegStatus = mb_reg_holding_cb(RT_NULL, &resFrame[3], regAddress, cntReg, MB_REG_READ);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
} else {
*resLen = 3+cntReg * 2;
}
rt_kprintf("------COM VOLT =%d -------\n------COM CURR =%d-------", pSW->Now_voltage,pSW->Now_current);
return eStatus;
}
/*****************************************************************
函数名称: funcReadInputRegister
函数描述: 读输入寄存器
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
eMBException funcReadInputRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
rt_uint16_t regAddress = 0, cntReg = 0;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
regAddress = u8v_to_u16(&reqFrame[2]);
cntReg = u8v_to_u16(&reqFrame[4]);
if ((0 == cntReg)||(cntReg >= MB_PDU_FUNC_READ_REGCNT_MAX)) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
resFrame[1] = MB_READ_INPUT_REGISTER;
resFrame[2] = cntReg * 2;
eRegStatus = mb_reg_discrete_cb(&resFrame[3], regAddress, cntReg);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
} else {
*resLen = 3+cntReg*2;
}
return eStatus;
}
/*****************************************************************
函数名称: funcReadTestRegister
函数描述: 读测试寄存器
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
//eMBException funcReadTestRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
// rt_uint8_t *resFrame, rt_uint16_t *resLen)
//{
// rt_uint16_t regAddress = 0,regCH=0, cntReg = 0; //读取的寄存器地址和寄存器数量
// eMBException eStatus = MB_EX_NONE;
// eMBErrorCode eRegStatus;
// if (4+MB_PDU_FUNC_READ_SIZE != reqLen) {
// return MB_EX_ILLEGAL_DATA_VALUE;
// }
// regAddress = reqFrame[3];
// regCH = reqFrame[4];
// cntReg = reqFrame[5];
// regAddress = (reqFrame[3]==1) ? 0 : 2;
//
// regAddress = regAddress+regCH*TOTAL_TEST_CH_REGS;
//
//
// if ((0 == cntReg)||(cntReg >= MB_PDU_FUNC_READ_REGCNT_MAX)) {
// return MB_EX_ILLEGAL_DATA_VALUE;
// }
// resFrame[1] = MB_READ_TEST_REGISTER;
// resFrame[2] = cntReg * 2;
// eRegStatus = mb_reg_test_cb(RT_NULL, &resFrame[3], regAddress, cntReg, MB_REG_READ);
// rt_kprintf("");
// if (eRegStatus != MB_ENOERR) {
// eStatus = mb_error(eRegStatus);
// } else {
// *resLen = 3+cntReg*2;
// }
// return eStatus;
//}
// /*****************************************************************
// 函数名称: funcWriteCoil
// 函数描述: 写单个保持继电器
// 输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
// 输出参数: -
// 返回说明: -
// 其它说明: -
// *****************************************************************/
eMBException funcWriteCoil (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
// rt_uint16_t regAddress = 0, value = 0;
// rt_uint8_t ucBuf[2] = {0};
// eMBException eStatus = MB_EX_NONE;
// eMBErrorCode eRegStatus;
// if (4+MB_PDU_FUNC_WRITE_SIZE != reqLen) {
// return MB_EX_ILLEGAL_DATA_VALUE;
// }
// regAddress = u8v_to_u16(&reqFrame[2]);
// value = u8v_to_u16(&reqFrame[4]);
// if (0x0000 == value) {
// ucBuf[0] = 0;
// ucBuf[1] = 0;
// } else if (0xFF00 == value) {
// ucBuf[0] = 1;
// ucBuf[1] = 0;
// } else {
// return MB_EX_ILLEGAL_DATA_VALUE;
// }
// //判断地址
// rt_uint16_t reg_offset = regAddress-COIL_REG_START;
// //提取通道
// eIDX_SOU_CH ch = (eIDX_SOU_CH)(reg_offset/TOTAL_COIL_CH_REGS);
// a = ch;
// //判断寄存器偏移量
// rt_uint16_t sout_reg = reg_offset%TOTAL_COIL_CH_REGS;
// if (ch > IDX_SOU_CH4) {
// rt_kprintf("[funcWriteCoil] ch out of range! ch=%d, max=%d\n", ch, IDX_SOU_CH4);
// return MB_EX_ILLEGAL_DATA_ADDRESS;
// }
// // 校验sout_reg是否在合法线圈寄存器范围
// if (sout_reg > MODBUS_COIL_SRC_CC) {
// rt_kprintf("[funcWriteCoil] sout_reg out of range! reg=%d\n", sout_reg);
// return MB_EX_ILLEGAL_DATA_ADDRESS;
// }
// //功能实现
// if(value==0x0000){
// switch(sout_reg){
// case MODBUS_COIL_PWR_SRC:
// chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_REL_ON, ALL_REL_OFF);
// rt_kprintf("THE_ALL_REL_OFF");
// break;
// case MODBUS_COIL_PWR_SINK:
// chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_REL_ON, ALL_REL_OFF);
// rt_kprintf("THE_ALL_REL_OFF");
// break;
// case MODBUS_COIL_PWR_ALL:
// chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_REL_ON, ALL_REL_OFF);
// rt_kprintf("THE_ALL_REL_OFF");
// break;
// case MODBUS_COIL_SINK_CC:
// chrg_nor_sw_rel((eIDX_NOR_CH)ch,4);
// rt_kprintf("CC_SINK_OFF");
// break;
// case MODBUS_COIL_SRC_CC:
// chrg_nor_sw_rel((eIDX_NOR_CH)ch,4);
// rt_kprintf("CC_SRC_OFF");
// break;
// default:
// return MB_EX_ILLEGAL_DATA_ADDRESS;
// break;
// }
// }
// else{
// switch(sout_reg){
// case MODBUS_COIL_PWR_SRC:
// chrg_set_sou_reg(ch, REG_REL_ON, MAIN_REL_ON);
// rt_kprintf("THE_Main_REL_ON");
// break;
// case MODBUS_COIL_PWR_SINK:
// chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_REL_ON, FU_REL_ON);
// rt_kprintf("THE_Main_REL_ON");
// break;
// case MODBUS_COIL_PWR_ALL:
// chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_REL_ON, ALL_REL_ON);
// rt_kprintf("THE_Main_REL_ON");
// break;
// case MODBUS_COIL_SINK_CC:
// chrg_nor_sw_rel((eIDX_NOR_CH)ch,ID_SINK);
// rt_kprintf("CC_SINK_ON");
// break;
// case MODBUS_COIL_SRC_CC:
// chrg_nor_sw_rel((eIDX_NOR_CH)ch,ID_SOURCE);
// rt_kprintf("CC_SRC_ON");
// break;
// default:
// return MB_EX_ILLEGAL_DATA_ADDRESS;
// break;
// }
// }
// // rt_memcpy(resFrame, reqFrame, reqLen);
// *resLen = reqLen-2;
// eRegStatus = mb_reg_coils_cb(RT_NULL, ucBuf, regAddress, 1, MB_REG_WRITE);
// if (eRegStatus != MB_ENOERR) {
// eStatus = mb_error(eRegStatus);
// }
return 0;
// return eStatus;
}
/*****************************************************************
* 负载协议映射表: Modbus寄存器值 → 内部负载协议枚举
*****************************************************************/
typedef struct {
rt_uint16_t reg_val; // Modbus寄存器写入值
rt_uint16_t sink_pro; // 内部负载协议枚举 (eLOAD_PRO)
rt_uint8_t has_group; // 是否有组号 (PDO/PPS/PD3.1/UFCS/AVS)
} SinkProtoMap_t;
static const SinkProtoMap_t sink_proto_map[] = {
{0x10, LOAD_PRO_NONE, 0}, // 无协议
{0x11, LOAD_PRO_QC20, 0}, // QC2.0
{0x12, LOAD_PRO_QC30, 0}, // QC3.0
{0x13, LOAD_PRO_FCP, 0}, // FCP
{0x14, LOAD_PRO_AFC, 0}, // AFC
{0x15, LOAD_PRO_SCP, 0}, // SCP
{0x16, LOAD_PRO_VIVO, 0}, // VIVO
{0x17, LOAD_PRO_TFC_RFC, 0}, // TFC(传音)
{0x19, LOAD_PRO_PDO_AUTO, 1}, // PDO自动
{0x1B, LOAD_PRO_PPS_AUTO, 1}, // PPS自动
{0x1C, LOAD_PRO_PD31AVS, 1}, // PD3.1
{0x1D, LOAD_PRO_UFCS, 1}, // UFCS
{0x1F, LOAD_PRO_AVS, 1}, // AVS
};
#define SINK_PROTO_MAP_NUM (sizeof(sink_proto_map) / sizeof(sink_proto_map[0]))
/*****************************************************************
* 电源协议映射表: Modbus寄存器值 → 内部电源协议枚举
*****************************************************************/
typedef struct {
rt_uint16_t reg_val;
rt_uint16_t src_pro; // 内部电源协议枚举 (eSRC_PRO)
} SrcProtoMap_t;
static const SrcProtoMap_t src_proto_map[] = {
{0x2A, PRO_PD0PSS}, // PD
{0x22, PRO_FCP}, // FCP
{0x23, PRO_SCPB}, // SCPB
{0x27, PRO_QC30}, // QC3.0
{0x28, PRO_QC20}, // QC2.0
{0x29, PRO_AFC}, // AFC
{0x2C, PRO_UFCS}, // UFCS
};
#define SRC_PROTO_MAP_NUM (sizeof(src_proto_map) / sizeof(src_proto_map[0]))
/*****************************************************************
* 查找负载协议映射
*****************************************************************/
static rt_uint16_t sink_proto_lookup(rt_uint16_t reg_val, rt_uint8_t *has_group)
{
for (int i = 0; i < SINK_PROTO_MAP_NUM; i++) {
if (sink_proto_map[i].reg_val == reg_val) {
*has_group = sink_proto_map[i].has_group;
return sink_proto_map[i].sink_pro;
}
}
return LOAD_PRO_NONE; // 默认无协议
}
/*****************************************************************
* 查找电源协议映射
*****************************************************************/
static rt_uint16_t src_proto_lookup(rt_uint16_t reg_val)
{
for (int i = 0; i < SRC_PROTO_MAP_NUM; i++) {
if (src_proto_map[i].reg_val == reg_val) {
return src_proto_map[i].src_pro;
}
}
return PRO_NONE; // 默认无协议
}
/*****************************************************************
* 查找电源类型
*****************************************************************/
static rt_uint16_t src_type_lookup(rt_uint16_t reg_val,struct chrg_switch_t *pSW)
{
switch(reg_val){
case 0:
pSW->source.src = 0;
pSW->source.pps = 0;
break;
case 1:
pSW->source.src = 0;
pSW->source.pps = 1;
break;
case 2:
pSW->source.src = 3;
pSW->source.pps = 0;
break;
case 3:
pSW->source.src = 3;
pSW->source.pps = 1;
break;
default:
return 1;
break;
}
return 0;
}
/*****************************************************************
函数名称: funcWriteHoldingRegister
函数描述: 写单个保持寄存器(0x06功能码)
根据寄存器地址自动识别负载/电源/系统区块,直接操作对应通道结构体
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: MB_EX_NONE=成功, 其他=Modbus异常码
其它说明: 新协议采用标准0x06功能码,寄存器地址区分功能区块:
0x0000~0x0073 负载, 0x0080~0x0097 电源, 0x00A0~0x00A7 系统
*****************************************************************/
eMBException funcWriteHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_switch_t *pSW = RT_NULL;
rt_uint8_t regAddress = 0;
rt_uint8_t regAddress_H = 0;
rt_uint16_t sou_value = 0;
/* ---- 提取通道号和区块内偏移 ---- */
eIDX_SOU_CH ch;
rt_uint16_t reg_offset; // 区块内寄存器偏移
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if (4 + MB_PDU_FUNC_WRITE_SIZE != reqLen) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
regAddress_H = reqFrame[2];
regAddress = reqFrame[3];
sou_value = u8v_to_u16(&reqFrame[4]);
/* ---- 特殊地址: 系统复位 ---- */
if (regAddress_H == RESET_NORTH_ADDR && sou_value == RESET_NORTH_VALUE) {
__asm__ __volatile__("cpsid i");
__asm__ __volatile__("ldr r0, =0xE000ED0C");
__asm__ __volatile__("ldr r1, =0x05FA0004");
__asm__ __volatile__("str r1, [r0]");
while (1);
}
/* ---- 特殊地址: 南向板复位 ---- */
if (regAddress_H == RESET_SOUTH_ADDR) {
if (sou_value < 4) {
chrg_set_sou_reg((eIDX_SOU_CH)sou_value, RESET_SOUTH_VALUE, 0x01);
} else {
rt_kprintf("Value_Error\n");
return MB_EX_ILLEGAL_DATA_VALUE;
}
goto build_response;
}
/* ---- 地址范围校验 ---- */
if(regAddress_H == HOLD_REG_SINK_BASE){
if (REG_IS_SINK(regAddress)) {
ch = (eIDX_SOU_CH)REG_GET_SINK_CH(regAddress);
reg_offset = REG_GET_SINK_OFFSET(regAddress);
}
}else if (regAddress_H == HOLD_REG_SRC_BASE) {
if (REG_IS_SRC(regAddress)) {
ch = (eIDX_SOU_CH)REG_GET_SRC_CH(regAddress);
reg_offset = REG_GET_SRC_OFFSET(regAddress);
}
} else if (regAddress_H == HOLD_REG_SYS_BASE) {
if (REG_IS_SYS(regAddress)) {
ch = (eIDX_SOU_CH)REG_GET_SYS_CH(regAddress);
reg_offset = REG_GET_SYS_OFFSET(regAddress);
}
} else {
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
if (ch > IDX_SOU_CH4) {
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
pSW = &g_shadow_sw[ch]; // 写入影子寄存器, 等待 PARAM_EFFECT 生效
chrg_shadow_sync(ch); // 首次写同步真实状态,防止覆盖运行标志位
/* ===== 直接根据高字节分发到对应业务函数 ===== */
if (regAddress_H == HOLD_REG_SINK_BASE)
{
chrg_mb_write_sink(ch, reg_offset, sou_value, pSW);
}
else if (regAddress_H == HOLD_REG_SRC_BASE)
{
chrg_mb_write_src(ch, reg_offset, sou_value, pSW);
}
else if (regAddress_H == HOLD_REG_SYS_BASE)
{
chrg_mb_write_sys(ch, reg_offset, sou_value, pSW, pNOR, pSOU);
}
build_response:
/* ---- 构建响应帧 ---- */
rt_memcpy(resFrame, reqFrame, reqLen);
*resLen = reqLen - 2;
/* ---- 写入保持寄存器镜像 ---- */
eRegStatus = mb_reg_holding_cb(&reqFrame[4], &resFrame[3], regAddress, 1, MB_REG_WRITE);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
}
return eStatus;
}
/*****************************************************************
函数名称: funcWriteMultipleCoils
函数描述: 写多个继电器
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
eMBException funcWriteMultipleCoils (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
rt_uint16_t regAddress = 0, cntCoils = 0;
rt_uint8_t ucByteCount;
rt_uint8_t ucByteCountVerify;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if (4+MB_PDU_FUNC_WRITE_SIZE > reqLen) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
regAddress = u8v_to_u16(&reqFrame[2]);
cntCoils = u8v_to_u16(&reqFrame[4]);
ucByteCount = reqFrame[6];
ucByteCountVerify = (cntCoils+BITS_UCHAR-1)/BITS_UCHAR;
if ((0 == cntCoils)
||(cntCoils > MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX)
||(ucByteCountVerify != ucByteCount)) {
return MB_EX_ILLEGAL_DATA_VALUE;
}
rt_memcpy(resFrame, reqFrame, reqLen);
*resLen = 6;
eRegStatus = mb_reg_coils_cb(reqFrame, &resFrame[3], regAddress, cntCoils, MB_REG_WRITE);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
}
return eStatus;
}
static void parse_load_no_group(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t reqLen, struct chrg_switch_t *pSW)
{
rt_uint16_t volt_mv = 0; // 协议请求电压(mV)
rt_uint16_t curr_ma = 0; // 负载电流(mA)
// 数据区索引:0=状态+通道,1=CC线,2,选择恒压恒流模式3-4=电压,5-6=电流,6-7=保留
volt_mv = u8v_to_u16(&pData[3]); // 电压(mV,大端)
curr_ma = u8v_to_u16(&pData[5]); // 电流(mA,大端)
// 按协议命令码赋值
switch (protoCmd)
{
case 0x11: // QC2.0
pSW->sink.protocol = LOAD_PRO_QC20;
break;
case 0x12: // QC3.0
pSW->sink.protocol = LOAD_PRO_QC30;
break;
case 0x13: // FCP
pSW->sink.protocol = LOAD_PRO_FCP;
break;
case 0x14: // AFC
pSW->sink.protocol = LOAD_PRO_AFC;
break;
case 0x15: // SCP
pSW->sink.protocol = LOAD_PRO_SCP;
break;
case 0x16: // VIVO
pSW->sink.protocol = LOAD_PRO_VIVO;
break;
case 0x17: // TFC
pSW->sink.protocol = LOAD_PRO_TFC_RFC;
break;
default:
rt_kprintf("无组号负载协议不支持:0x%02X\n", protoCmd);
return;
}
// 赋值通用参数
pSW->sink.loadv = volt_mv;
pSW->sink.loadc = curr_ma;
pSW->sink.Pro_Group = 0; // 无组号
rt_kprintf("pro=%d,volt_mv=%d,curr=%d",pSW->sink.protocol,volt_mv,curr_ma);
}
static void parse_load_with_group(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t reqLen, struct chrg_switch_t *pSW)
{
rt_uint8_t group_num = 0; // 组号
rt_uint16_t volt_mv = 0; // 协议请求电压(mV)
rt_uint16_t curr_ma = 0; // 负载电流(mA)
// 数据区索引:0=状态+通道,1=CC线,2=恒压恒流模式,3=组号
group_num = pData[3];
pSW->sink.Pro_Group = group_num;
// 按协议命令码分支
switch (protoCmd)
{
case CMD_LOAD_PD0_MAN: // PD0(手动)
pSW->sink.protocol = LOAD_PRO_PDO_MANUAL;
// PD0特殊:组号后为3个保留2字节,无电压电流
volt_mv = 0;
curr_ma = 0;
break;
case CMD_LOAD_PD0_AUTO: // PDO自动
pSW->sink.protocol = LOAD_PRO_PDO_AUTO;
volt_mv = u8v_to_u16(&pData[4]); // 4-5=电压
curr_ma = u8v_to_u16(&pData[6]); // 6-7=电流
break;
case CMD_LOAD_PPS_MAN: // PPS(手动)
pSW->sink.protocol = LOAD_PRO_PPS_MANUAL;
volt_mv = u8v_to_u16(&pData[4]);
curr_ma = u8v_to_u16(&pData[6]);
break;
case CMD_LOAD_PPS_AUTO: // PPS(自动)
pSW->sink.protocol = LOAD_PRO_PPS_AUTO;
volt_mv = u8v_to_u16(&pData[4]);
curr_ma = u8v_to_u16(&pData[6]);
break;
case CMD_LOAD_PD31: // PD3.1
pSW->sink.protocol = LOAD_PRO_PD31AVS;
volt_mv = u8v_to_u16(&pData[4]);
curr_ma = u8v_to_u16(&pData[6]);
break;
case CMD_LOAD_UFCS: // UFCS
pSW->sink.protocol = LOAD_PRO_UFCS;
volt_mv = u8v_to_u16(&pData[4]);
curr_ma = u8v_to_u16(&pData[6]);
break;
case CMD_LOAD_VOOC: // VOOC
pSW->sink.protocol = LOAD_PRO_VOOC;
volt_mv = 0;
curr_ma = 0;
break;
case CMD_LOAD_AVS: // AVS
pSW->sink.protocol = LOAD_PRO_AVS;
volt_mv = u8v_to_u16(&pData[4]);
curr_ma = u8v_to_u16(&pData[6]);
break;
default:
rt_kprintf("有组号负载协议不支持:0x%02X\n", protoCmd);
return;
}
rt_kprintf("volt_mv=%d,curr_ma=%d\n",volt_mv,curr_ma);
// 赋值通用参数
pSW->sink.loadv = volt_mv;
pSW->sink.loadc = curr_ma;
}
// //sink开机函数
// rt_uint8_t chrg_com_sink_on(rt_uint8_t ch, struct chrg_switch_t *pSW, rt_uint8_t *enable){
// *enable = 1;
// pSW->id = ID_SINK;
// pSW->sub = IDX_SET_SINK_CURR;
// pSW->change_flag = 0x01;
// pSW->sink.work_on_step = 0;
// return 0;
// }
//source开机函数
rt_uint8_t chrg_com_source_on(rt_uint8_t ch, rt_uint8_t protoCmd, struct chrg_switch_t *pSW, rt_uint8_t *enable){
*enable = 1;
pSW->id = ID_SOURCE;
pSW->source.LCD_Set_Pro_Flag=3;
pSW->sub = IDX_SET_SOURCE_ID;
pSW->change_flag = 0x01;
pSW->continue_flag = 1;
return 0;
}
/*****************************************************************
函数名称: funcWriteProtoCal
函数描述: 写入协议
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
eMBException funcWriteProtoCal (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
/************ 局部变量定义 ************/
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_switch_t *pSW = RT_NULL;
rt_uint8_t slaveAddr = 0; // 从机地址(0x01~0xFF)
rt_uint8_t protoCmd = 0; // 协议命令码(0x11~0x1F/0x22~0x2C/0x2F)
rt_uint16_t regAddress = 0; // 寄存器起始地址
rt_uint8_t *pData = RT_NULL; // 协议数据区起始指针(状态+通道字段开始)
rt_uint8_t statusChByte = 0;// 状态+通道字节(reqFrame[5])
eIDX_SOU_CH ch = IDX_SOU_CH1;// 通道号(1~4)
rt_uint8_t chNum = 0; // 通道号数值(1~4)
rt_uint8_t devStatus = 0; // 设备状态(0=不变,1=开机,2=关机)
rt_uint8_t ccSel = 0; // CC线选择(0=CC1+CC2,1=CC1,2=CC2,3=断开)
// *g_proto_pData = RT_NULL;
g_proto_reqLen = 0;
// Modbus异常码
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
rt_uint16_t reg_offset = 0;
rt_uint16_t sout_reg = 0;
rt_uint16_t sou_value = 0;
/************ 校验 ************/
// 最小帧长度:地址(1)+命令码(1)+寄存器(2)+数据区(至少1)+校验(2) = 7字节
if (reqLen < 7) {
rt_kprintf("The long error%d must more 7\n", reqLen);
return MB_EX_ILLEGAL_DATA_VALUE;
}
/************ 解析帧 ************/
slaveAddr = reqFrame[0]; // 从机地址(0x01~0xFF)
protoCmd = reqFrame[3]; // 协议命令码(负载0x11~0x1F,电源0x22~0x2C/0x2F)
rt_kprintf("pro=%04x\n",protoCmd);
pData = &reqFrame[4]; // 数据区起始(跳过地址+命令码+寄存器)
statusChByte = pData[0]; // 状态+通道字节(数据区第1字节)
/************ 地址校验 ************/
if (protoCmd < PRO_REG_START || protoCmd >= TOTAL_PROTOCAL_CNT) {
rt_kprintf("Address error0x%04X\n", protoCmd);
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
/************ 提取通道号和状态 ************/
// bit0-3:状态(0=不变,1=开机,2=关机)
devStatus = statusChByte & 0x0F;
rt_kprintf("status=%d",devStatus);
// bit4-7:通道号(1=CH1,2=CH2,3=CH3,4=CH4)
chNum = (statusChByte >> 4) & 0x0F;
ccSel = pData[1];
rt_uint8_t cv_mode = pData[2];
// 通道号合法性校验
if (chNum < 1 || chNum > 4) {
rt_kprintf("通道号非法:%d(仅支持1~4)\n", chNum);
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
ch = (eIDX_SOU_CH)(chNum - 1); // 转换为枚举类型(IDX_SOU_CH1=0)
/************ 硬件结构体绑定 ************/
if (pNOR == RT_NULL) {
rt_kprintf("ERROR: pNOR is NULL!\n");
return MB_EX_SLAVE_DEVICE_FAILURE;
}
pSW = &pNOR->sw[ch]; // 绑定当前通道的协议配置结构体
pSW->protoCmd = protoCmd; //com端协议命令码
pSW->CV_mode = cv_mode; //恒压恒流模式选择
rt_memcpy(g_proto_pData, pData, reqLen - 4);
g_proto_reqLen = reqLen;
rt_kprintf("com_recitive\n");
/************ 按「负载/电源」分支解析 ************/
// ========== 负载协议解析 (0x11~0x1F) ==========
if (protoCmd >= 0x11 && protoCmd <= 0x1F) {
pSW->sink.cc_set = ccSel; //负载CC线选择
if(pSW->source.On_Flag){ //负载切电源
pSW->source.change_sink_Flag = 1;
chrg_sou_stop(ch,pSW,pNOR);
}else{
if(devStatus==2){ //负载关机
chrg_sou_stop(ch,pSW,pNOR);
}
else if(devStatus==1){ //负载开机
//chrg_com_sink_on(ch,pSW,&pNOR->enable[ch]);
}
}
}
// ==========电源协议解析 (0x22~0x2C/0x2F) ==========
else if ((protoCmd >= 0x22 && protoCmd <= 0x2C) || protoCmd == 0x2F) {
pSW->source.cc_set = ccSel; //电源CC线选择
if(pSW->sink.On_work){ //电源切负载
pSW->sink.change_source_flag = 1;
chrg_sou_stop(ch,pSW,pNOR);
}else{
if(devStatus==2){ //电源关机
chrg_sou_stop(ch,pSW,pNOR);
}else if(devStatus==1){ //电源开机
chrg_com_source_on(ch,pSW->protoCmd,pSW,&pNOR->enable[ch]);
}
}
}
// ========== 非法命令码 ==========
else {
rt_kprintf("非法协议命令码:0x%02X\n", protoCmd);
return MB_EX_ILLEGAL_FUNCTION;
}
// /************ 配置参数写入保持寄存器 ************/
eRegStatus = mb_reg_holding_cb(&reqFrame[4], &resFrame[3], regAddress, 1, MB_REG_WRITE);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
rt_kprintf("寄存器写入失败:%d\n", eRegStatus);
}
/************ 构建响应帧 ************/
rt_memcpy(resFrame, reqFrame, reqLen);
*resLen = reqLen - 2; // 去掉CRC校验位
/************ 调试输出 ************/
// rt_kprintf("Pro Set OK:Ch=%d,Pro0x%02X,Status%d,CC Set%d\n",
// chNum, protoCmd, devStatus, ccSel);
return eStatus;
}
/*****************************************************************
函数名称: funcSinkTest
函数描述: 负载测试
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
eMBException funcSinkTest (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
/************ 局部变量定义 ************/
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_switch_t *pSW = RT_NULL;
rt_uint8_t slaveAddr = 0; // 从机地址
rt_uint8_t test_mode = 0; // 测试模式 0x01/0x02/0x03
rt_uint16_t regAddress = 0; // 寄存器地址
rt_uint8_t *pData = RT_NULL; // 数据区指针
rt_uint8_t statusChByte = 0; // 状态+通道字节
eIDX_SOU_CH ch = IDX_SOU_CH1; // 通道枚举
rt_uint8_t chNum = 0; // 通道号 1~4
rt_uint8_t devStatus = 0; // 设备状态 0=启动 1=停止,2=继续,3=结束
// Modbus异常
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
// /************ 长度校验 ************/
// if (reqLen < 11) {
// rt_kprintf("Len error:%d <11\n", reqLen);
// return MB_EX_ILLEGAL_DATA_VALUE;
// }
/************ 解析帧 ************/
slaveAddr = reqFrame[0];
test_mode = reqFrame[3]; // 测试命令:0x01短路 0x02OCP 0x03动态
pData = &reqFrame[4]; // 数据起始
statusChByte= pData[0]; // 状态通道字节
/************ 地址校验 ************/
if (test_mode < 0x01 || test_mode > 0x03) {
rt_kprintf("Test mode err:0x%02X\n", test_mode);
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
/************ 解析状态 & 通道 ************/
devStatus = statusChByte & 0x0F; // 低4位:状态
chNum = (statusChByte >> 4) & 0x0F; // 高4位:通道
/************ 通道校验 ************/
if (chNum <1 || chNum>4) {
rt_kprintf("Ch err:%d\n", chNum);
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
ch = (eIDX_SOU_CH)(chNum -1);
/************ 绑定结构体 ************/
pSW = &pNOR->sw[ch];
pSW->sink.test.test_mode = test_mode; //测试模式
pSW->sink.test.run_flag = devStatus; //设备状态
pSW->change_flag = 0x01;
struct test *pTset = &pSW->sink.test;
#if SINK_TEST_DEBUG
rt_kprintf("test_mode=%d\n",test_mode);
rt_kprintf("test_flag=%d\n",pTset->test_mode);
#endif
/*********************************************************/
switch(test_mode)
{
case 0x01:
// 短路测试(OCPC
sink_test_short_set(pSW, pData, devStatus);
break;
case 0x02:
// OCP 测试
sink_test_ocp_set(pSW, pData, devStatus);
break;
case 0x03:
// 动态测试
sink_test_dynamic_set(pSW, pData, devStatus);
break;
default:
return MB_EX_ILLEGAL_FUNCTION;
}
/************ 启动 / 停止控制 ************/
if(devStatus == 0) //启动
{
pNOR->enable[ch] = 1;
pSW->id = ID_SINK;
pSW->sink.test.work_step = 0;
pSOU->online[ch] = 1;
}
else if(devStatus == 1) //停止
{
pSW->id = ID_SINK;
pSW->sink.test.stop_step = 0;
rt_kprintf("Sink Test Stop CH%d\n", chNum);
}
/************ 响应帧 ************/
rt_memcpy(resFrame, reqFrame, reqLen-2);
*resLen = reqLen -2;
return eStatus;
}
/*****************************************************************
函数名称: funcWriteMultipleHoldingRegister
函数描述: 写多个保持寄存器(0x10)
规则:reqFrame[2] = 分区高字节(SINK/SRC/SYS)reqFrame[3] = 分区内起始偏移
不再做全局保持寄存器地址越界判断,仅做通道合法校验,写入影子寄存器
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
*****************************************************************/
eMBException funcWriteMultipleHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_switch_t *pSW = RT_NULL;
// 公共变量(两种模式共用)
rt_uint16_t cntReg = 0;
rt_uint8_t ucRegByteCount;
rt_uint8_t *pWriteData = RT_NULL;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
// 模式私有变量
#if TRIM_NORTH
rt_uint16_t regAddress = 0;
#else
rt_uint8_t regAddress_H = 0;
rt_uint16_t regBaseOffset = 0;
#endif
// ========== 公共校验逻辑(只写一遍)==========
if (4 + MB_PDU_FUNC_WRITE_MUL_SIZE_MIN > reqLen) {
rt_kprintf("LEN ERROR");
return MB_EX_ILLEGAL_DATA_VALUE;
}
cntReg = u8v_to_u16(&reqFrame[4]);
ucRegByteCount = reqFrame[6];
if ((0 == cntReg)
|| (cntReg > MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX)
|| (ucRegByteCount != cntReg * 2))
{
rt_kprintf("DATA ERROR");
return MB_EX_ILLEGAL_DATA_VALUE;
}
pWriteData = &reqFrame[7];
// ========== 分支业务逻辑 ==========
#if TRIM_NORTH
// 校准模式:旧连续地址逻辑
regAddress = u8v_to_u16(&reqFrame[2]);
if (regAddress < HOLD_REG_START || (regAddress + cntReg - 1) >= (HOLD_REG_START + TOTAL_HOLD_ALL_REGS)) {
rt_kprintf("ADDRESS ERROR");
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
for (int i = 0; i < cntReg; i++)
{
rt_uint16_t Curr_reg_addr = regAddress + i;
rt_uint16_t Curr_reg_offset = Curr_reg_addr - HOLD_REG_START;
eIDX_SOU_CH ch = (eIDX_SOU_CH)(Curr_reg_offset / TOTAL_HOLD_CH_REGS);
if (ch > IDX_SOU_CH4) {
rt_kprintf("WRITE MULTI REG: CH ERROR, ch=%d (reg=0x%04X)\n", ch, Curr_reg_addr);
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
if (pNOR == RT_NULL) {
rt_kprintf("WRITE MULTI REG: ERROR: pNOR is NULL! (reg=0x%04X)\n", Curr_reg_addr);
return MB_EX_SLAVE_DEVICE_FAILURE;
}
pSW = &pNOR->sw[ch];
rt_uint16_t sou_value = u8v_to_u16(&pWriteData[i * 2]);
rt_uint16_t sout_reg = Curr_reg_offset % TOTAL_HOLD_CH_REGS;
switch (sout_reg)
{
case REG_VOLTAGE_OUT + 1:
pSW->source.max_vol = sou_value;
pSW->sink.loadv = sou_value;
chrg_set_sou_reg(ch, sout_reg, sou_value);
rt_kprintf("voltage=%d", sou_value);
break;
case REG_CURRENT_OUT + 1:
pSW->source.protective_curr = sou_value;
pSW->sink.loadc = sou_value;
chrg_set_sou_reg(ch, sout_reg, sou_value);
break;
default:
rt_kprintf("THE SOUT_REG=%d", sout_reg);
break;
}
rt_kprintf("ch=:%d,reg=%02x,value=%02x", ch, sout_reg, sou_value);
}
#else
// 正常产品模式:分区地址逻辑
regAddress_H = reqFrame[2];
regBaseOffset = reqFrame[3];
for (int i = 0; i < cntReg; i++)
{
rt_uint16_t curr_part_offset = regBaseOffset + i;
eIDX_SOU_CH ch = (eIDX_SOU_CH)(curr_part_offset / TOTAL_HOLD_CH_REGS);
rt_uint16_t ch_reg_offset = curr_part_offset % TOTAL_HOLD_CH_REGS;
if (ch > IDX_SOU_CH4) {
//rt_kprintf("WRITE MULTI REG: CH ERROR, ch=%d (part offset=%d)\n", ch, curr_part_offset);
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
pSW = &g_shadow_sw[ch];
chrg_shadow_sync(ch); // 首次写同步真实状态
rt_uint16_t sou_value = u8v_to_u16(&pWriteData[i * 2]);
if (regAddress_H == HOLD_REG_SINK_BASE)
{
chrg_mb_write_sink(ch, ch_reg_offset, sou_value, pSW);
}
else if (regAddress_H == HOLD_REG_SRC_BASE)
{
chrg_mb_write_src(ch, ch_reg_offset, sou_value, pSW);
}
else if (regAddress_H == HOLD_REG_SYS_BASE)
{
chrg_mb_write_sys(ch, ch_reg_offset, sou_value, pSW, pNOR, pSOU);
}
else
{
//rt_kprintf("WRITE MULTI REG: INVALID PARTITION 0x%02X\n", regAddress_H);
return MB_EX_ILLEGAL_DATA_ADDRESS;
}
// rt_kprintf("ch:%d, part_offset:%d, ch_reg:%d, val:%d\n", ch, curr_part_offset, ch_reg_offset, sou_value);
}
#endif
// ========== 公共应答帧组装、回调(只写一遍)==========
rt_memcpy(resFrame, reqFrame, reqLen);
*resLen = 6;
#if TRIM_NORTH
eRegStatus = mb_reg_holding_cb(&reqFrame[7], &resFrame[3], regAddress, cntReg, MB_REG_WRITE);
#else
eRegStatus = mb_reg_holding_cb(&reqFrame[7], &resFrame[3], regBaseOffset, cntReg, MB_REG_WRITE);
#endif
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
}
return eStatus;
}
/*****************************************************************
函数名称: funcTrimELoad
函数描述: 校准源载
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -只支持协议寄存器
*****************************************************************/
eMBException funcTrimELoad (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_switch_t *pSW = RT_NULL;
rt_uint16_t regAddress = 0, cntReg = 0;
rt_uint8_t RegCount;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if (4+MB_PDU_FUNC_WRITE_MUL_SIZE_MIN > reqLen) {
rt_kprintf("LEN ERROR");
return MB_EX_ILLEGAL_DATA_VALUE;
}
//计算寄存器地址,数量和字节
eIDX_SOU_CH ch = reqFrame[2]&0x0F;
rt_uint8_t enable_flag = (reqFrame[2]>>4)&0x0F;
regAddress = reqFrame[3];
RegCount = u8v_to_u16(&reqFrame[4]);
rt_kprintf("ch=%d,enable=%d,reg=0x%02x,count=%d\n",ch+1,enable_flag,regAddress,RegCount);
if(ch<0||ch>3){
rt_kprintf("CH ERROR");
return MB_EX_ILLEGAL_DATA_VALUE;
}
if(enable_flag == 0x00 || enable_flag == 0x01){
}else{
rt_kprintf("Enable Flag ERROR");
return MB_EX_ILLEGAL_DATA_VALUE;
}
set_ymodem_update_channel(pNOR, pSOU, ch); //关掉除选定通道外的其他通道使能
//提取首指针
struct chrg_trim *pTrim = &pNOR->trim[ch];
rt_uint8_t *pWriteData = &reqFrame[7];
pNOR->north_mode = 1;
pTrim->trim_enable_flag = enable_flag;
pTrim->trim_step = 0;
//多寄存器控制操作
for(int i =0;i<RegCount;i++){
//计算当前寄存器的协议地址和本地偏移
rt_uint16_t Curr_reg_addr = regAddress + i; // 当前寄存器协议地址
rt_uint16_t Curr_write_value = u8v_to_u16(pWriteData+i*2);//寄存器数值
switch (Curr_reg_addr)
{
case ModbusRTU_Volt_CAL_K_H:
pTrim->trim_mode = MODE_VOLT_CAL;
pTrim->trim_volt_k_H = Curr_write_value;
break;
case ModbusRTU_Volt_CAL_K_L:
pTrim->trim_volt_k_L = Curr_write_value;
break;
case ModbusRTU_Volt_CAL_B:
pTrim->trim_volt_b = Curr_write_value;
break;
case ModbusRTU_Current_CAL_K_H:
pTrim->trim_mode = MODE_CURR_CAL;
pTrim->trim_curr_k_H = Curr_write_value;
break;
case ModbusRTU_Current_CAL_K_L:
pTrim->trim_curr_k_L = Curr_write_value;
break;
case ModbusRTU_Current_CAL_B:
pTrim->trim_curr_b = Curr_write_value;
break;
case ModbusRTU_SourceCurrent_CAL_K_H:
pTrim->trim_mode = MODE_SOURCE_CURR_CAL;
pTrim->trim_source_curr_k_H = Curr_write_value;
break;
case ModbusRTU_SourceCurrent_CAL_K_L:
pTrim->trim_source_curr_k_L = Curr_write_value;
break;
case ModbusRTU_SourceCurrent_CAL_B:
pTrim->trim_source_curr_b = Curr_write_value;
break;
case ModbusRTU_Trim_Zero_CAL:
pTrim->trim_mode = MODE_ZERO_CAL;
pTrim->trim_zero = Curr_write_value;
break;
default:
rt_kprintf("THE CAL REG=%d",Curr_reg_addr);
break;
}
//寄存器操作
rt_kprintf("com ch=:%d,reg=%02x,value=%d\n",ch,Curr_reg_addr,Curr_write_value);
}
rt_memcpy(resFrame, reqFrame, reqLen);
*resLen = 6;
//eRegStatus = mb_reg_holding_cb(&reqFrame[7], &resFrame[3], regAddress, cntReg, MB_REG_WRITE);
if (eRegStatus != MB_ENOERR) {
eStatus = mb_error(eRegStatus);
}
return eStatus;
}
/*****************************************************************
函数名称: funYmodemUpadata
函数描述: 南向功率板升级函数
输入参数: reqFrame: 请求数据 reqLen: 请求长度 resFrame:响应数据 resLen:响应长度
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
Ymodem_state ystate = Ymodem_No;
rt_uint8_t s_first_soh_rcvd = 0;
eMBException funYmodemUpadata (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
rt_uint8_t *resFrame, rt_uint16_t *resLen)
{
rt_uint8_t test_mode = 0; // 测试模式 0x01/0x02/0x03
eIDX_SOU_CH ch = IDX_SOU_CH1; // 通道枚举
rt_uint8_t chNum = 0; // 通道号 1~4
chNum = reqFrame[4];
ch = (eIDX_SOU_CH)(chNum);
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_rollsou_t *pROLL = &chrgrollsou;
// Modbus异常
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if(chNum<0||chNum>3){
return 0;
}
rt_kprintf("ch = %d",ch);
//解析上位机的帧头判断状态
if(reqLen==8){
if(reqFrame[5] == 0xff){
pROLL->mode = 1;
set_ymodem_update_channel(pNOR, pSOU, ch);
ystate = Ymodem_Wait;
pROLL->ch = ch;
s_first_soh_rcvd = 0;
chrg_eload_clear_ymodem_resp(); /* 进入升级时清除残留应答 */
}
if(reqFrame[5] == 0x00){
pROLL->mode = 0;
ystate = Ymodem_No;
set_ymodem_update_channel(pNOR, pSOU, ch);
s_first_soh_rcvd = 0;
chrg_eload_clear_ymodem_resp(); /* 退出升级时清除残留应答 */
}
}
#if SINK_TEST_DEBUG
rt_kprintf("test_mode=%d\n",test_mode);
//rt_kprintf("test_flag=%d\n",pTset->test_mode);
#endif
eRegStatus = mb_ymodem_updata_cb(&ystate,resFrame);
/************ 响应帧 ************/
// rt_memcpy(resFrame, reqFrame, reqLen-2);
*resLen = 1;//reqLen -2;
return eStatus;
}
static struct code_func_t funcHandlers[MB_HANDLERS_MAX] = {
{MB_READ_COILS, funcReadCoils},
{MB_READ_DISCRETE_INPUTS, funcReadDiscreteInputs},
{MB_READ_HOLDING_REGISTER, funcReadHoldingRegister},
{MB_READ_INPUT_REGISTER, funcReadInputRegister},
{MB_WRITE_SINGLE_COIL, funcWriteCoil},
{MB_WRITE_REGISTER, funcWriteHoldingRegister}, // 0x06
{MB_WRITE_MULTIPLE_COILS, funcWriteMultipleCoils},
{MB_WRITE_MULTIPLE_REGISTERS, funcWriteMultipleHoldingRegister}, // 0x10
{MB_YMODEM_UPDATAE, funYmodemUpadata}, // 0x20 Ymodem升级
{MB_TRIM_ELOAD, funcTrimELoad}, // 0x21 校准
};
/*****************************************************************
函数名称: chrg_comm_parse_msg
函数描述: 解析请求的消息
输入参数: pCOMM: 消息结构
输出参数: -
返回说明: -
其它说明: 分命令处理对应消息。地址为广播时不应答
*****************************************************************/
static int chrg_comm_parse_msg (struct chrg_comm_t *pCOMM)
{
if (RT_NULL == pCOMM) {
return -1;
}
if (pCOMM->rx_len < 8) {
return -2;
}
//校验
if (0 != mb_crc16(pCOMM->rx_buf, pCOMM->rx_len)) {
rt_uint16_t crc = mb_crc16(pCOMM->rx_buf, pCOMM->rx_len-2);
rt_uint16_t crc_r = u8v_to_u16(&pCOMM->rx_buf[pCOMM->rx_len-2]);
rt_kprintf("crc %04X vs %04X\r\n", swap_u16(crc), crc_r);
return -3;
}
int i = 0, ret = -1;
rt_uint16_t crc = 0;
eMBException eStatus = MB_EX_ILLEGAL_FUNCTION;
rt_uint8_t address = 0, functionCode = 0x00;
address = pCOMM->rx_buf[0];
functionCode = pCOMM->rx_buf[1];
//判断地址
if ((address != pCOMM->addr)&&(MB_ADDRESS_BROADCAST != address)) {
return ret;
}
struct code_func_t *pFunc = RT_NULL;
for (i = 0; i < MB_HANDLERS_MAX; i++) {
pFunc = &funcHandlers[i];
if (RT_NULL == pFunc) {
break;
}
//匹配功能码和处理函数
if ((functionCode == pFunc->code)&&(RT_NULL != pFunc->func)) {
eStatus = pFunc->func(pCOMM->rx_buf, pCOMM->rx_len,
pCOMM->tx_buf, &pCOMM->tx_len);
break;
}
}
if (MB_ADDRESS_BROADCAST != address) {
pCOMM->tx_buf[0] = address;
//异常响应
if (MB_EX_NONE != eStatus) {
pCOMM->tx_buf[1] = (functionCode | MB_FUNC_ERROR);
pCOMM->tx_buf[2] = eStatus;
pCOMM->tx_len = 3;
}
crc = mb_crc16(pCOMM->tx_buf, pCOMM->tx_len);
u16_to_u8v_com(crc, &pCOMM->tx_buf[pCOMM->tx_len]);
pCOMM->tx_len += 2;
ret = chrg_tty_send(pCOMM->tty, pCOMM->tx_buf, pCOMM->tx_len);
}
return ret;
}
///*****************************************************************
//函数名称: ymodem_send
//函数描述: 每隔一秒发一次0x43告诉上位机准备数据
//输入参数: pCOMM: 消息结构
//输出参数: -
//返回说明: -
//其它说明: 分命令处理对应消息。地址为广播时不应答
//*****************************************************************/
////返回1:需要发送数据;返回0:无需发送
//uint8_t y_time = 0;
//uint8_t ymodem_send(struct chrg_comm_t *pCOMM,uint8_t state){
//
// struct chrg_rollsou_t *pROLL = &chrgrollsou;
// static rt_uint8_t number = 4;
// uint8_t need_tx = 0;
// if(pROLL->send_flag==0)y_time++;
// pCOMM->tx_len = 0; //每次进来先清空发送长度
// /* ======== 尚未收到上位机第一个数据包: 定时发送'C'握手 ======== */
// if (!s_first_soh_rcvd) {
// if (y_time > 20) {
// pCOMM->tx_buf[0] = ACK_C;
// pCOMM->tx_len = 1;
// need_tx = 1;
// y_time = 0;
// }
// return need_tx;
// }
// if(state == Ymodem_Rec_End){
// //if (y_time > 20) {
// pCOMM->tx_buf[0] = ACK;
// pCOMM->tx_buf[1] = ACK_C;
// pCOMM->tx_len = 2;
// need_tx = 1;
// y_time = 0;
// number--;
// if(number == 0)
// {
// state = Ymodem_Wait;
// number = 4;
// }
// state = Ymodem_Wait;
// //}
// }
// /* ======== 已收到上位机数据包: 南向有应答立刻转发给上位机 ======== */
// uint8_t south_resp = chrg_eload_get_ymodem_resp();
// if (south_resp != 0) {
// switch (south_resp) {
// case ACK:
// memset(mobude_ymodem_buf_2,0,sizeof(mobude_ymodem_buf));
// switch(state){
// case Ymodem_Rec_End:
// case Ymodem_Rec_Start:
// pCOMM->tx_buf[0] = ACK;
// pCOMM->tx_buf[1] = ACK_C;
// pCOMM->tx_len = 2;
// break;
// case Ymodem_Rec_1024:
// pCOMM->tx_buf[0] = ACK;
// pCOMM->tx_len = 1;
// }
// need_tx = 1;
// /* Rec_End收到ACK → 南向已完成2次EOT握手,切到收尾阶段 */
// break;
// case NAK:
// chrg_send_sou_upadata_data(mobude_ymodem_buf_2,1029);
// break;
// default:
// break;
// }
// y_time = 0;
// rt_kprintf("REC DATA = %02x\n",south_resp);
// }
//
// return need_tx;
//}
///*****************************************************************
//函数名称: Ymodem_Process
//函数描述: 处理ymodem协议数据
//输入参数: pCOMM: 消息结构
//输出参数: -
//返回说明: -
//其它说明: 分命令处理对应消息。地址为广播时不应答
//*****************************************************************/
//uint16_t len = 0;
//eMBException Ymodem_Process(rt_uint8_t *reqFrame, rt_uint16_t reqLen,
// rt_uint8_t *resFrame, rt_uint16_t *resLen)
//{
// eMBException eStatus = MB_EX_NONE;
// struct chrg_rollsou_t *pROLL = &chrgrollsou;
// rt_kprintf("TX_LEN = %d\n",reqLen);
//// for(int i=0;i<reqLen;i++){
//// rt_kprintf("%02x ",reqFrame[i]);
//// }
// len = reqLen;
// uint8_t data = reqFrame[0];
// switch(data){
// case SOH:
// memset(mobude_ymodem_buf,0,sizeof(mobude_ymodem_buf));
// ystate = Ymodem_Rec_Start;
// memcpy(mobude_ymodem_buf,reqFrame,reqLen);
// memcpy(mobude_ymodem_buf_2,reqFrame,reqLen);
// chrg_send_sou_upadata_data(mobude_ymodem_buf,reqLen);
// pROLL->send_flag = 1;
// s_first_soh_rcvd = 1;
// break;
// case STX:
// ystate = Ymodem_Rec_1024;
// memset(mobude_ymodem_buf,0,sizeof(mobude_ymodem_buf));
// memcpy(mobude_ymodem_buf,reqFrame,reqLen);
// memcpy(mobude_ymodem_buf_2,reqFrame,reqLen);
// chrg_send_sou_upadata_data(mobude_ymodem_buf,reqLen);
// pROLL->send_flag = 1;
// break;
// case EOT:
// ystate = Ymodem_Rec_End;
// memset(mobude_ymodem_buf,0,sizeof(mobude_ymodem_buf));
// memcpy(mobude_ymodem_buf,reqFrame,reqLen);
// memcpy(mobude_ymodem_buf_2,reqFrame,reqLen);
// chrg_send_sou_upadata_data(mobude_ymodem_buf,reqLen);
// pROLL->send_flag = 1;
// break;
// }
// return eStatus;
//}
/*****************************************************************
函数名称: chrg_comm_updata_north
函数描述: 解析南向程序数据包
输入参数: pCOMM: 消息结构
输出参数: -
返回说明: -
其它说明: 分命令处理对应消息。地址为广播时不应答
*****************************************************************/
static int chrg_comm_updata_north (struct chrg_comm_t *pCOMM)
{
// if (RT_NULL == pCOMM) {
// return -1;
// }
int ret = 0;
// uint8_t need_tx = 0;
// pCOMM->tx_len = 0; //进来先清空发送缓冲区
// eMBException eStatus = MB_EX_NONE;
// //收到有效数据才解析Ymodem
// if(pCOMM->rx_len == 8 && pCOMM->rx_buf[1]==0x20){
// eStatus = funYmodemUpadata(pCOMM->rx_buf, pCOMM->rx_len, pCOMM->tx_buf, &pCOMM->tx_len);
// }
// else if(pCOMM->rx_len == 8 && pCOMM->rx_buf[1]==0x06){
// eStatus = funcWriteHoldingRegister(pCOMM->rx_buf, pCOMM->rx_len, pCOMM->tx_buf, &pCOMM->tx_len);
// }
// else if(pCOMM->rx_len != 0){
// rt_kprintf("len = %d\n",pCOMM->rx_len);
// Ymodem_Process(pCOMM->rx_buf, pCOMM->rx_len, pCOMM->tx_buf, &pCOMM->tx_len);
// }
// //统一调用定时应答生成
// need_tx = ymodem_send(pCOMM,ystate);
// //只有标志为1且长度有效才发送
// if(need_tx && pCOMM->tx_len > 0){
// ret = chrg_tty_send(pCOMM->tty, pCOMM->tx_buf, pCOMM->tx_len);
// }
return ret;
}
/*****************************************************************
函数名称: chrg_comm_thread_entry
函数描述: 对外RS485通信线程体
输入参数: *data: 本线程信息
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
void chrg_comm_thread_entry (void *data)
{
struct chrg_thread_t *pTHR = (struct chrg_thread_t *)data;
if (RT_NULL == pTHR) {
return ;
}
int len = 0;
struct chrg_tty_t *pTTY = RT_NULL;
struct chrg_comm_t *pCOMM = &chrgcomm;
struct chrg_rollsou_t *pROLL = &chrgrollsou;
pTTY = chrg_tty_create(pCOMM->devname, BAUD_RATE_115200, 0, 8, 1);
if (RT_NULL == pTTY) {
LOG_E("tty can't create.");
return ;
}
chrg_tty_set_recv_tmo(pTTY, 8);
if (chrg_tty_connect(pTTY) != RT_EOK) {
chrg_tty_destory(pTTY);
return;
}
chrg_tty_mode_set(pTTY, 0);
pCOMM->tty = pTTY;
/* 初始化影子寄存器, 与当前 chrgnorth.sw 同步 */
chrg_shadow_init();
while (1) {
rt_memset(pCOMM->rx_buf, 0, sizeof(pCOMM->rx_buf));
len = chrg_tty_recv(pTTY, pCOMM->rx_buf, sizeof(pCOMM->rx_buf));
// LOG_HEX("Num=", len, pCOMM->rx_buf, len);
if(pROLL->mode==0x01){ //升级模式走单独协议
pCOMM->rx_len = len;
pCOMM->tx_len = 0;
chrg_comm_updata_north(pCOMM);
}else{
if (len <= 0) {
rt_thread_mdelay(1);
continue;
}
pCOMM->rx_len = len;
pCOMM->tx_len = 0;
chrg_comm_parse_msg(pCOMM);
}
}
}
#if 0
int rs485snd (int argc, char **argv)
{
struct chrg_comm_t *pCOMM = &chrgcomm;
rt_uint8_t test[16] = {
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
if (RT_NULL != pCOMM->tty) {
chrg_tty_send(pCOMM->tty, test, 16);
}
return 0;
}
MSH_CMD_EXPORT(rs485snd, rs485 test send);
#endif
static void chrg_mb_write_sink(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW)
{
switch (reg_offset)
{
case SINK_REG_PROTOCOL: // 0x00: 协议类型
{
rt_uint8_t has_group = 0;
pSW->sink.protocol = sink_proto_lookup(sou_value, &has_group);
pSW->protoCmd = (rt_uint8_t)sou_value;
// rt_kprintf("[SINK CH%d] Protocol=0x%02X\n", ch + 1, pSW->sink.protocol);
}
break;
case SINK_REG_PRO_GEAR: // 0x01: 协议挡位(组号)
pSW->sink.Pro_Group = sou_value;
// rt_kprintf("[SINK CH%d] Gear=%d\n", ch + 1, sou_value);
break;
case SINK_REG_PRO_VOLT: // 0x02: 协议电压 (mV)
pSW->sink.pro_loadv = sou_value;
// rt_kprintf("[SINK CH%d] ProVolt=%d mV\n", ch + 1, sou_value);
break;
case SINK_REG_PRO_CURR: // 0x03: 协议电流 (mA)
pSW->sink.pro_loadc = sou_value;
// rt_kprintf("[SINK CH%d] ProCurr=%d mA\n", ch + 1, sou_value);
break;
case SINK_REG_CC_SEL: // 0x04: CC选择
pSW->sink.cc_set = (rt_uint8_t)sou_value;
// rt_kprintf("[SINK CH%d] CC_SEL=%d\n", ch + 1, sou_value);
break;
case SINK_REG_EMARK: // 0x05: E-Mark控制(预留)
break;
case SINK_REG_LOAD_MODE: // 0x06: 负载模式 (1=恒压, 2=恒流)
pSW->CV_mode = (rt_uint8_t)sou_value;
// rt_kprintf("[SINK CH%d] LoadMode=%d\n", ch + 1, sou_value);
break;
case SINK_REG_LOAD_VOLT: // 0x07: 负载电压 (mV)
pSW->sink.loadv = sou_value;
// rt_kprintf("[SINK CH%d] LoadVolt=%d mV\n", ch + 1, sou_value);
break;
case SINK_REG_LOAD_CURR: // 0x08: 负载电流 (mA)
pSW->sink.loadc = sou_value;
// rt_kprintf("[SINK CH%d] LoadCurr=%d mA\n", ch + 1, sou_value);
break;
case SINK_REG_TEST_MODE: // 0x09: 测试模式
pSW->sink.test.test_mode = (rt_uint8_t)sou_value;
// rt_kprintf("[SINK CH%d] TestMode=%d\n", ch + 1, sou_value);
break;
case SINK_REG_LOAD_STATUS: // 0x0A: 负载状态 (1=运行, 2=停止)
pSW->sink.Now_State = sou_value;
// rt_kprintf("[SINK CH%d] STATUS=%d\n", ch + 1, sou_value);
break;
case SINK_REG_VON_VOLT: // 0x0B: Von电压
pSW->sink.volt_on = sou_value;
// rt_kprintf("[SINK CH%d] VonVolt=%d mV\n", ch + 1, sou_value);
break;
case SINK_REG_RISE_SLOPE: // 0x0C: 加载斜率(预留)
case SINK_REG_FALL_SLOPE: // 0x0D: 卸载斜率(预留)
break;
case SINK_REG_SHORT_HOLD_TIME: // 0x0E: 保持时间(ms)
pSW->sink.test.short_test.hold_time = sou_value;
break;
case SINK_REG_SHORT_SET_MODE: // 0x0F: 设置模式
pSW->sink.test.short_test.set_mode = (rt_uint8_t)sou_value;
break;
case SINK_REG_SHORT_HAVE_CURR: // 0x10:设置是否带载
pSW->sink.test.short_test.have_curr_flag = (rt_uint8_t)sou_value;
break;
case SINK_REG_OCP_START_CURR: // 0x11: 起始电流
pSW->sink.test.OCP_test.start_curr = sou_value;
break;
case SINK_REG_OCP_END_CURR: // 0x12: 终点电流
pSW->sink.test.OCP_test.end_curr = sou_value;
break;
case SINK_REG_OCP_STEP_CURR: // 0x13: 步进电流
pSW->sink.test.OCP_test.change_curr = sou_value;
break;
case SINK_REG_OCP_STEP_TIME: // 0x14: 步进保持时间
pSW->sink.test.OCP_test.change_keep_time = sou_value;
break;
case SINK_REG_OCP_RECOV_TIME: // 0x15: 恢复时间
pSW->sink.test.OCP_test.hold_time = sou_value;
break;
case SINK_REG_OCP_STOP_VOLT: // 0x16: 截止电压
pSW->sink.test.OCP_test.stop_volt = sou_value;
break;
case SINK_REG_OCP_RECOV_LOAD: // 0x17: 恢复后带载
pSW->sink.test.OCP_test.hold_curr = (rt_uint8_t)sou_value;
break;
case SINK_REG_OCP_SET_MODE: // 0x18: 设置模式
pSW->sink.test.OCP_test.set_mode = (rt_uint8_t)sou_value;
break;
case SINK_REG_DYNA_LOAD1: // 0x19: 动态负载1
pSW->sink.test.change_test.curr1_set = sou_value;
break;
case SINK_REG_DYNA_TIME1: // 0x1A: 负载1保持时间
pSW->sink.test.change_test.time1_set = sou_value;
break;
case SINK_REG_DYNA_LOAD2: // 0x1B: 动态负载2
pSW->sink.test.change_test.curr2_set = sou_value;
break;
case SINK_REG_DYNA_TIME2: // 0x1C: 负载2保持时间
pSW->sink.test.change_test.time2_set = sou_value;
break;
case SINK_REG_DYNA_SLOPE: // 0x1D: 加载斜率
pSW->sink.test.change_test.k_Rise = sou_value;
break;
case SINK_REG_DYNA_UNLOAD: // 0x1E: 卸载斜率
pSW->sink.test.change_test.k_Fall = sou_value;
break;
default:
rt_kprintf("[SINK CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset);
break;
}
}
static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW)
{
switch (reg_offset)
{
case SRC_REG_PROTOCOL: // 0x00: 协议
pSW->source.protocol = src_proto_lookup(sou_value);
pSW->source.Set_Pro_Flag = 1;
pSW->protoCmd = (rt_uint8_t)sou_value;
// rt_kprintf("[SRC CH%d] Protocol=0x%02X -> 0x%02X\n", ch + 1, sou_value, pSW->source.protocol);
break;
case SRC_REG_PRO_GEAR: // 0x01: 协议类型
src_type_lookup(sou_value,pSW);
//rt_kprintf("[SRC CH%d] Gear=%d\n", ch + 1, sou_value);
break;
case SRC_REG_PRO_MODE: // 0x02: 输出模式 (1=恒压, 2=恒流)
pSW->CV_mode = (rt_uint8_t)sou_value;
// rt_kprintf("[SRC CH%d] Mode=%d\n", ch + 1, sou_value);
break;
case SRC_REG_MIN_VOLT: // 0x03: 最小电压 (mV)
pSW->source.min_vol = sou_value;
//rt_kprintf("[SRC CH%d] MinVolt=%d mV\n", ch + 1, sou_value);
break;
case SRC_REG_MAX_VOLT: // 0x04: 最大电压 (mV)
pSW->source.max_vol = sou_value;
// rt_kprintf("[SRC CH%d] MaxVolt=%d mV\n", ch + 1, sou_value);
break;
case SRC_REG_MAX_CURR: // 0x05: 最大电流 (mA)
pSW->source.protective_curr = sou_value;
pSW->source.vc.set_current = sou_value;
//rt_kprintf("[SRC CH%d] MaxCurr=%d mA\n", ch + 1, sou_value);
break;
case SRC_REG_CC_SEL: // 0x06: CC选择
pSW->source.cc_set = (rt_uint8_t)sou_value;
//rt_kprintf("[SRC CH%d] CC_SEL=%d\n", ch + 1, sou_value);
break;
case SRC_REG_OUTPUT_STATUS: // 0x07: 输出状态 (1=运行, 2=停止)
pSW->source.Now_State = sou_value;
break;
default:
rt_kprintf("[SRC CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset);
break;
}
//rt_kprintf("ret_offset = %d, value = %d",reg_offset,sou_value);
}
static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value,
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR, struct chrg_south_t *pSOU)
{
struct chrg_comm_t *pCOMM = &chrgcomm;
switch (reg_offset)
{
case SYS_REG_ROLE_SWITCH: // 0x00: 源/载状态切换
if (sou_value == 0x01)
{
pSW->id = ID_SINK;
}
else if (sou_value == 0x02)
{
pSW->id = ID_SOURCE;
pSW->source.Set_Pro_Flag = 1;
}
break;
case SYS_REG_PARAM_EFFECT: // 0x01: 参数生效标志
if (sou_value == 0x01)
{
g_shadow_dirty[ch] = 0; // 标记已生效
struct chrg_switch_t *pReal = &pNOR->sw[ch];
rt_uint8_t pro_change = 0;
sink_proto_diff_t diff_info;
chrg_sink_get_proto_diff(pReal, pSW, &diff_info, &pro_change);
eIDX_ID old_id = pReal->id;
eIDX_ID new_id = pReal->id;
rt_uint16_t sink_work = pSW->sink.Now_State;
rt_uint16_t source_work = pSW->source.Now_State;
//rt_uint8_t old_sink_test = pReal->sink.test.test_mode;
struct chrg_thread_t *pTHR_NOR = &chrgthr[IDX_THR_ROLL_NOR];
rt_mutex_take(pTHR_NOR->mutex, RT_WAITING_FOREVER);
rt_memcpy(pReal, &g_shadow_sw[ch], sizeof(struct chrg_switch_t));
if (new_id == ID_SINK)
{
if (sink_work == 0x01) // 负载启动
{
rt_uint8_t curr_test = pReal->sink.test.test_mode;
rt_uint8_t curr_test_old = pReal->sink.test.test_mode_old;
// 测试模式状态发生切换:0<->非0
if ((curr_test_old == 0 && curr_test != 0) || (curr_test == 0 && curr_test_old != 0))
{
if (curr_test_old == 0)
{
// 从正常模式进入测试模式
pReal->sink.work_mode = (curr_test == 3) ? SINK_WORK_ON_TEST_CHANGE : SINK_WORK_ON_TEST_SHOUT;
pReal->sink.test.test_mode_old = curr_test;
}
else
{
// 从测试模式切回正常模式
pReal->sub = IDX_SET_SINK_CCLINE;
pReal->sink.work_mode = SINK_WORK_INIT;
}
}
else
{
// 测试模式无变化,处理负载初始化/参数更新
if (pReal->sink.On_work == 0)
{
// 负载首次启动硬件初始化
pReal->sink.On_work = 1;
pReal->sub = IDX_SET_SINK_CCLINE;
pReal->sink.work_mode = SINK_WORK_INIT;
}
else
{
if (pro_change)
{
// 协议参数变更,重新初始化链路
pReal->sub = IDX_SET_SINK_CCLINE;
pReal->sink.work_mode = SINK_WORK_WAIT;
}
else
{
// 仅下发差异寄存器
chrg_sink_diff_send_reg((eIDX_SOU_CH)ch, &diff_info, pReal);
}
}
}
}
else // sink_work == 0x00 负载停止
{
pReal->sink.On_work = 0;
pReal->sink.work_mode = SINK_WORK_STOP;
}
chrg_sink_work(ch, pReal);
}
else if (new_id == ID_SOURCE && source_work == 0x01)
{
chrg_com_source_on(ch, pReal->protoCmd, pReal, &pNOR->enable[ch]);
}
else if (new_id == ID_SOURCE && source_work == 0x00)
{
chrg_sou_stop(ch, pReal, pNOR);
}
rt_mutex_release(pTHR_NOR->mutex);
}
break;
default:
rt_kprintf("[SYS CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset);
break;
}
}
void chrg_sink_get_proto_diff(struct chrg_switch_t *pReal,
struct chrg_switch_t *pShadow,
sink_proto_diff_t *pDiff,
rt_uint8_t *pChange)
{
pDiff->proto_changed = (pReal->sink.protocol != pShadow->sink.protocol) ? 1 : 0;
pDiff->group_changed = (pReal->sink.Pro_Group != pShadow->sink.Pro_Group) ? 1 : 0;
pDiff->ccset_changed = (pReal->sink.cc_set != pShadow->sink.cc_set) ? 1 : 0;
pDiff->pro_volt_changed = (pReal->sink.pro_loadv != pShadow->sink.pro_loadv) ? 1 : 0;
pDiff->pro_curr_changed = (pReal->sink.pro_loadc != pShadow->sink.pro_loadc) ? 1 : 0;
pDiff->volt_changed = (pReal->sink.loadv != pShadow->sink.loadv) ? 1 : 0;
pDiff->curr_changed = (pReal->sink.loadc != pShadow->sink.loadc) ? 1 : 0;
pDiff->cvmode_changed = (pReal->CV_mode != pShadow->CV_mode) ? 1 : 0;
// 任意一项变更则 pro_change = 0,全部不变 = 1
*pChange = (!pDiff->proto_changed && !pDiff->group_changed &&
!pDiff->pro_volt_changed && !pDiff->pro_curr_changed &&
!pDiff->ccset_changed && !pDiff->cvmode_changed) ? 0 : 1;
}
void chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal)
{
chrg_sou_com_sou_set();
if(pReal->CV_mode == 0x01){
if (pDiff->volt_changed)
{
chrg_sou_com_batch_add_reg(ch, REG_VOLTAGE_OUT+1, pReal->sink.loadv);
}
}else{
if (pDiff->curr_changed)
{
chrg_sou_com_batch_add_reg(ch, REG_CURRENT_OUT+1, pReal->sink.loadc);
}
}
if(pDiff->cvmode_changed){
chrg_sou_com_batch_add_reg(ch, REG_MODE, pReal->CV_mode);
}
}