Files
chrg/apps/chrg/applications/thread/chrg_comm.c
T
wrh 660aaa5a7a refactor: 重构电源通道控制逻辑,引入状态机管理
1. 删除apps/chrg/applications/thread/chrg_lcd.h中的chrg_sou_work函数声明
2. 移除chrg_source.h中冗余的状态标志定义,新增电源工作状态机枚举
3. 重构chrg_lcd.c,删除旧的启动/停止流程代码和冗余标志位操作
4. 重写chrg_roll_nor.c的协议设置和通道控制逻辑,替换为状态机处理
5. 重写chrg_source.c,新增统一的电源工作状态机实现,替换旧的协议设置函数
6. 重构chrg_north.c的电源解析逻辑,移除旧的停止流程和冗余标志位
7. 简化chrg_comm.c的Modbus协议处理逻辑,改为通过状态机控制电源通道
2026-07-21 20:56:36 +08:00

2032 lines
68 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 eMBException 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;
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 READ addr=%d count=%d-------\n", regAddress, cntReg);
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)
{
eStatus = chrg_mb_write_sys(ch, reg_offset, sou_value, pSW, pNOR, pSOU);
if (eStatus != MB_EX_NONE) {
return eStatus;
}
}
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;
}
/*****************************************************************
函数名称: 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)
{
eStatus = chrg_mb_write_sys(ch, ch_reg_offset, sou_value, pSW, pNOR, pSOU);
if (eStatus != MB_EX_NONE) {
return eStatus;
}
}
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->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 eMBException 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;
}
break;
case SYS_REG_PARAM_EFFECT: // 0x01: 参数生效标志
if (sou_value == 0x01)
{
struct chrg_switch_t *pReal = &pNOR->sw[ch];
rt_uint8_t pro_change = 0;
sink_proto_diff_t diff_info;
struct chrg_thread_t *pTHR_NOR = &chrgthr[IDX_THR_ROLL_NOR];
rt_mutex_take(pTHR_NOR->mutex, RT_WAITING_FOREVER);
eIDX_ID old_id = pReal->id;
eIDX_ID new_id = pSW->id;
rt_bool_t old_active = RT_FALSE;
if (old_id == ID_SOURCE) {
old_active = (pReal->source.On_Flag || pReal->source.Now_State);
} else if (old_id == ID_SINK) {
old_active = (pReal->sink.On_work || pReal->sink.Now_State);
}
if ((old_id != new_id) && old_active) {
rt_mutex_release(pTHR_NOR->mutex);
LOG_W("CH%d direction change rejected while active: %d -> %d",
ch + 1, old_id, new_id);
return MB_EX_SLAVE_BUSY;
}
g_shadow_dirty[ch] = 0;
chrg_sink_get_proto_diff(pReal, pSW, &diff_info, &pro_change);
rt_uint16_t sink_work = pSW->sink.Now_State;
rt_uint16_t source_work = pSW->source.Now_State;
rt_uint8_t old_cv_mode = pReal->CV_mode;
rt_uint16_t old_loadv = pReal->sink.loadv;
rt_uint16_t old_loadc = pReal->sink.loadc;
//rt_uint8_t old_sink_test = pReal->sink.test.test_mode;
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_DYNA : SINK_WORK_ON_TEST_SHORT;
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
{
// 仅下发差异寄存器
if (chrg_sink_diff_send_reg((eIDX_SOU_CH)ch, &diff_info, pReal) != 0) {
pReal->CV_mode = old_cv_mode;
pReal->sink.loadv = old_loadv;
pReal->sink.loadc = old_loadc;
g_shadow_dirty[ch] = 1;
rt_mutex_release(pTHR_NOR->mutex);
return MB_EX_SLAVE_BUSY;
}
}
}
}
}
else // sink_work == 0x00 负载停止
{
pReal->sink.On_work = 0;
pReal->sink.work_mode = SINK_WORK_STOP;
}
if (chrg_sink_work(ch, pReal) != 0) {
g_shadow_dirty[ch] = 1;
rt_mutex_release(pTHR_NOR->mutex);
return MB_EX_SLAVE_BUSY;
}
}
else if (new_id == ID_SOURCE && source_work == 0x01)
{
/* COM只触发状态,初始化命令由Source状态机统一下发。 */
pReal->source.On_Flag = 1;
pReal->source.work_mode = SOURCE_WORK_INIT;
}
else if (new_id == ID_SOURCE && source_work == 0x00)
{
/* 停止动作同样交给状态机处理,避免COM直接控制硬件。 */
pReal->source.On_Flag = 0;
pReal->source.work_mode = SOURCE_WORK_STOP;
}
rt_mutex_release(pTHR_NOR->mutex);
}
break;
default:
rt_kprintf("[SYS CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset);
break;
}
return MB_EX_NONE;
}
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;
}
int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal)
{
rt_uint16_t regs[2];
rt_uint16_t vals[2];
rt_uint8_t count = 0;
if (pReal->CV_mode == 0x01) {
if (pDiff->volt_changed) {
regs[count] = REG_VOLTAGE_OUT + 1;
vals[count++] = pReal->sink.loadv;
}
} else if (pDiff->curr_changed) {
regs[count] = REG_CURRENT_OUT + 1;
vals[count++] = pReal->sink.loadc;
}
if (pDiff->cvmode_changed) {
regs[count] = REG_MODE;
vals[count++] = pReal->CV_mode;
}
if ((count > 0) && (chrg_sou_com_batch_submit(ch, regs, vals, count) != 0)) {
LOG_E("CH%d sink diff batch submit failed", ch + 1);
return -1;
}
return 0;
}