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