Files
chrg/apps/chrg/applications/thread/chrg_roll_nor.c
T
wrh e56830fc86 chore: 版本升级至V1.1.10并优化批量通信逻辑
1. 更新所有文件的版本号注释从V1.1.9到V1.1.10
2. 修改chrg_comm.c中的固件版本宏定义为0x011A
3. 新增短路保活命令优先调度逻辑,避免挤占保活窗口
4. 优化批量通信的通道轮转和重试机制
5. 改为按通道维护重试计数,避免全局计数异常
6. 新增批量通信突发计数和通道状态管理
2026-09-09 11:08:51 +08:00

1314 lines
45 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_roll_nor.c
完成日期 :
当前版本号 : V1.1.10
主要功能 : 实现北向通信轮巡请求命令。以独立线程处理。
版本历史 : 创建原始版本
说明 :
******************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <rtthread.h>
#include "chrg_gpio.h"
#include "chrg_led.h"
#include "chrg_thread.h"
#include "chrg_sink.h"
#include "chrg_source.h"
#include "chrg_roll_nor.h"
#include "chrg_roll_sou.h"
#include "chrg_comm.h"
#include "chrg_north.h"
#include "chrg_switch.h"
#include "chrg_utils.h"
#include "chrg_rel.h"
#include "chrg_wdt.h"
#define LOG_TAG "chrg.rollnor"
#include <rtdbg.h>
#define NORTH_RESPONSE_TIMEOUT_MS 50U // 单次北向请求等待匹配回码的总时间
#define NORTH_REQUEST_MAX_RETRIES 2U // 首次发送失败后最多重发2次,总发送次数为3次
#define NORTH_MEASURE_MAX_ATTEMPTS 1U // 0x20量测查询失败后直接留给下一轮轮询重发
#define NORTH_RETRY_INTERVAL_MS 5U // 相同请求两次发送之间的保护间隔
#define NORTH_POLL_INTERVAL_MS 10U // 一个通道事务结束后到下一通道的轮询间隔
#define SOURCE_PROTOCOL_WAIT_MS 100U // 每通道0xD0应答后的协议生效保护时间
#define SINK_CC_WAIT_MS 50U // Sink设置目标CC应答后的非阻塞保护时间
#define SINK_HANDSHAKE_FIRST_QUERY_DELAY_MS 50U // 协议/CC回码后首条0x20的等待时间
#define SINK_HANDSHAKE_QUERY_INTERVAL_MS 50U // 握手未完成时后续0x20查询间隔
#define SOURCE_CHANNEL_BIT(ch) ((rt_uint8_t)(1U << (ch)))
const rt_base_t sw_uart[TOTAL_NOR_CHS] = {
IDX_GPO_UART_SW1,
IDX_GPO_UART_SW2,
IDX_GPO_UART_SW3,
IDX_GPO_UART_SW4
};
struct chrg_rollnor_t chrgrollnor = {
.run = RUN_CONSOLE, // RUN_AUTO,
.ch = IDX_NOR_CH1,
// .Set_Role = ID_SINK,
// .group = 0,
};
/* 所有参与CC_CLOSE的通道共享300ms屏障;协议等待仍按通道独立计时。 */
static rt_uint8_t g_source_protocol_wait_mask = 0U;
static rt_tick_t g_source_protocol_wait_start[TOTAL_NOR_CHS] = {0};
static rt_uint8_t g_sink_cc_wait_mask = 0U;
static rt_tick_t g_sink_cc_wait_start[TOTAL_NOR_CHS] = {0};
/* Sink协议/CC握手期间的0x20查询节流记录,按通道独立计时。 */
static rt_bool_t g_sink_query_throttle[TOTAL_NOR_CHS] = {RT_FALSE};
static rt_bool_t g_sink_query_first_pending[TOTAL_NOR_CHS] = {RT_FALSE};
static rt_tick_t g_sink_query_tick[TOTAL_NOR_CHS] = {0};
/*****************************************************************
函数名称: chrg_roll_nor_sink_query_is_slow
函数描述: 判断当前Sink状态是否仍处于协议握手量测阶段
输入参数: pSW:当前负载通道控制结构体
输出参数: -
返回说明: RT_TRUE:0x20查询按握手节奏发送 RT_FALSE:使用正常轮询周期
其它说明: 只有协议/CC设置后等待协商电压的阶段限速;RUNING和低电流
待机不受影响,避免影响正常量测刷新速度
*****************************************************************/
static rt_bool_t chrg_roll_nor_sink_query_is_slow(
const struct chrg_switch_t *pSW)
{
if (pSW == RT_NULL) {
return RT_FALSE;
}
return (pSW->sink.work_mode == SINK_WORK_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_LOW_MONITOR);
}
/*****************************************************************
函数名称: chrg_roll_nor_sink_query_wait_start
函数描述: 启动Sink握手阶段的0x20查询节流计时
输入参数: ch:北向通道编号
输出参数: 记录当前tick并开启节流
返回说明: -
其它说明: 协议或CC回码成功后调用,避免下一轮立即查询协议板
*****************************************************************/
static void chrg_roll_nor_sink_query_wait_start(rt_uint8_t ch)
{
if (ch >= TOTAL_NOR_CHS) {
return;
}
g_sink_query_throttle[ch] = RT_TRUE;
g_sink_query_first_pending[ch] = RT_TRUE;
g_sink_query_tick[ch] = rt_tick_get();
}
/*****************************************************************
函数名称: chrg_roll_nor_source_switch_reset
函数描述: 清理指定Source通道的CC_CLOSE及协议等待记录
输入参数: ch:北向通道编号
输出参数: 清除对应通道的屏障位和协议等待计时
返回说明: -
其它说明: 调用者必须持有北向轮询线程互斥锁
*****************************************************************/
void chrg_roll_nor_source_switch_reset(rt_uint8_t ch)
{
if (ch >= TOTAL_NOR_CHS) {
return;
}
g_source_protocol_wait_mask &=
(rt_uint8_t)~SOURCE_CHANNEL_BIT(ch);
g_source_protocol_wait_start[ch] = 0U;
}
/*****************************************************************
函数名称: chrg_roll_nor_source_cc_close_register
函数描述: 将Source通道登记到本轮共享CC_CLOSE等待屏障
输入参数: ch:北向通道编号
输出参数: 设置pending位并清除该通道旧ACK和等待状态
返回说明: -
其它说明: 新通道加入已经开始的屏障时重新等待,保证所有登记通道共享完整保护时间
*****************************************************************/
static void chrg_roll_nor_source_protocol_wait_start(rt_uint8_t ch)
{
if (ch >= TOTAL_NOR_CHS) {
return;
}
g_source_protocol_wait_mask |= SOURCE_CHANNEL_BIT(ch);
g_source_protocol_wait_start[ch] = rt_tick_get();
}
/*****************************************************************
函数名称: chrg_roll_nor_source_wait_process
函数描述: 处理Source共享CC_CLOSE等待和每通道协议生效等待
输入参数: ch:北向通道编号 pSW:通道状态
输出参数: CC_CLOSE等待到期进入0xD0,协议等待到期进入目标CC设置
返回说明: RT_TRUE:本轮仍处于等待,不发送命令 RT_FALSE:可继续发送
其它说明: CC_CLOSE使用共享300ms屏障,协议ACK后每通道独立等待100ms
*****************************************************************/
static rt_bool_t chrg_roll_nor_source_wait_process(rt_uint8_t ch,
struct chrg_switch_t *pSW)
{
rt_uint8_t bit;
rt_tick_t elapsed;
if ((ch >= TOTAL_NOR_CHS) || (pSW == RT_NULL)) {
return RT_FALSE;
}
bit = SOURCE_CHANNEL_BIT(ch);
if ((pSW->id != ID_SOURCE) || !pSW->source.On_Flag) {
chrg_roll_nor_source_switch_reset(ch);
return RT_FALSE;
}
if (pSW->source.work_mode == SOURCE_WORK_INIT_WAIT) {
/* 南向初始化批次未完成时,禁止发送北向协议命令。 */
return RT_TRUE;
}
if (pSW->sub == IDX_WAIT_SOURCE_PROTOCOL) {
if ((g_source_protocol_wait_mask & bit) == 0U) {
pSW->sub = IDX_SET_SOURCE_CC_SET;
return RT_FALSE;
}
elapsed = (rt_tick_t)(rt_tick_get() -
g_source_protocol_wait_start[ch]);
if (elapsed < rt_tick_from_millisecond(SOURCE_PROTOCOL_WAIT_MS)) {
return RT_TRUE;
}
g_source_protocol_wait_mask &= (rt_uint8_t)~bit;
g_source_protocol_wait_start[ch] = 0U;
pSW->sub = IDX_SET_SOURCE_CC_SET;
return RT_FALSE;
}
return RT_FALSE;
}
/*****************************************************************
函数名称: chrg_roll_nor_sink_cc_wait_start
函数描述: Sink目标CC设置收到有效应答后启动该通道的稳定计时
输入参数: ch:北向通道编号
输出参数: 记录通道等待标志和起始tick
返回说明: -
其它说明: 每个通道独立计时,多个通道切换CC时等待时间不会串行累加
*****************************************************************/
static void chrg_roll_nor_sink_cc_wait_start(rt_uint8_t ch)
{
if (ch >= TOTAL_NOR_CHS) {
return;
}
g_sink_cc_wait_mask |= SOURCE_CHANNEL_BIT(ch);
g_sink_cc_wait_start[ch] = rt_tick_get();
}
/*****************************************************************
函数名称: chrg_roll_nor_sink_wait_process
函数描述: 管理Sink安全卸载、南北并行握手和CC设置后的稳定等待
输入参数: ch:北向通道编号 pSW:通道实时控制结构体
输出参数: 南向批次完成后允许协议/CC;低电流和CC均满足后允许查询
返回说明: RT_TRUE:本轮仍需等待,不发送北向命令 RT_FALSE:可继续发送
其它说明: 完整重握手中,南向批次完成后协议/CC与低电流确认并行;
进入GET_SINK_VC后,必须等低电流确认完成才允许发送0x20
*****************************************************************/
static rt_bool_t chrg_roll_nor_sink_wait_process(rt_uint8_t ch,
struct chrg_switch_t *pSW)
{
rt_uint8_t bit;
rt_tick_t elapsed;
if ((ch >= TOTAL_NOR_CHS) || (pSW == RT_NULL)) {
return RT_FALSE;
}
bit = SOURCE_CHANNEL_BIT(ch);
/* 关机必须先完成南向低电流确认和继电器批次,期间禁止北向发送。 */
if ((pSW->sink.work_mode == SINK_WORK_STOP_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_STOP_RELAY) ||
(pSW->sink.work_mode == SINK_WORK_STOP_RELAY_WAIT)) {
return RT_TRUE;
}
if ((pSW->id != ID_SINK) || !pSW->sink.On_work) {
g_sink_cc_wait_mask &= (rt_uint8_t)~bit;
g_sink_cc_wait_start[ch] = 0U;
g_sink_query_throttle[ch] = RT_FALSE;
g_sink_query_first_pending[ch] = RT_FALSE;
g_sink_query_tick[ch] = 0U;
return RT_FALSE;
}
/* 普通软卸载和低电流恢复仍禁止北向;INIT_AUX_WAIT允许南北向并行。 */
if ((pSW->sink.work_mode == SINK_WORK_UNLOAD_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT)) {
return RT_TRUE;
}
/* 协议或CC切换必须先完成低电流确认;该过程保持南向继电器状态不变。 */
if (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT) {
return RT_TRUE;
}
/* D0回码确认后先经过一个非发送状态,禁止把协议回码当成量测回码。 */
if (pSW->sub == IDX_WAIT_SINK_PD_ACK) {
pSW->sub = IDX_GET_SINK_VC;
chrg_roll_nor_sink_query_wait_start(ch);
return RT_TRUE;
}
if (pSW->sub == IDX_SET_SINK_MODE_AFTER_PD) {
rt_uint16_t reg = REG_MODE;
rt_uint16_t value = pSW->CV_mode;
if (chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, &reg, &value, 1U) != 0) {
return RT_TRUE;
}
pSW->sub = IDX_WAIT_SINK_MODE_AFTER_PD;
return RT_TRUE;
}
if (pSW->sub == IDX_WAIT_SINK_MODE_AFTER_PD) {
if (chrg_sou_com_batch_is_pending((eIDX_SOU_CH)ch)) {
return RT_TRUE;
}
if (chrg_sou_com_batch_get_result((eIDX_SOU_CH)ch) != 1) {
pSW->sub = IDX_SET_SINK_MODE_AFTER_PD;
return RT_TRUE;
}
pSW->sub = IDX_GET_SINK_VC;
chrg_roll_nor_sink_query_wait_start(ch);
return RT_TRUE;
}
if ((pSW->sub != IDX_WAIT_SINK_CC) &&
(pSW->sub != IDX_WAIT_SINK_CC_BEFORE_PD) &&
(pSW->sub != IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE)) {
/* COM在等待期间提交新配置时,清理旧事务留下的CC计时记录。 */
g_sink_cc_wait_mask &= (rt_uint8_t)~bit;
g_sink_cc_wait_start[ch] = 0U;
if (!chrg_roll_nor_sink_query_is_slow(pSW)) {
g_sink_query_throttle[ch] = RT_FALSE;
g_sink_query_first_pending[ch] = RT_FALSE;
g_sink_query_tick[ch] = 0U;
}
} else {
if ((g_sink_cc_wait_mask & bit) == 0U) {
if ((pSW->sub == IDX_WAIT_SINK_CC_BEFORE_PD) ||
(pSW->sub == IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE)) {
pSW->sub = (pSW->sub == IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE) ?
IDX_SET_SINK_PD_WITH_MODE : IDX_SET_SINK_PD;
} else {
pSW->sub = IDX_GET_SINK_VC;
chrg_roll_nor_sink_query_wait_start(ch);
}
return RT_TRUE;
}
elapsed = (rt_tick_t)(rt_tick_get() - g_sink_cc_wait_start[ch]);
if (elapsed < rt_tick_from_millisecond(SINK_CC_WAIT_MS)) {
return RT_TRUE;
}
if ((pSW->sub == IDX_WAIT_SINK_CC_BEFORE_PD) ||
(pSW->sub == IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE)) {
/* CC先设置完成后进入协议设置,不立即查询电压。 */
g_sink_query_throttle[ch] = RT_FALSE;
g_sink_query_first_pending[ch] = RT_FALSE;
g_sink_query_tick[ch] = 0U;
g_sink_cc_wait_mask &= (rt_uint8_t)~bit;
g_sink_cc_wait_start[ch] = 0U;
pSW->sub = (pSW->sub == IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE) ?
IDX_SET_SINK_PD_WITH_MODE : IDX_SET_SINK_PD;
return RT_TRUE;
}
/* 协议已先设置;CC应答并完成保护等待后进入电压查询。 */
g_sink_query_throttle[ch] = RT_TRUE;
g_sink_query_first_pending[ch] = RT_TRUE;
g_sink_query_tick[ch] = g_sink_cc_wait_start[ch];
g_sink_cc_wait_mask &= (rt_uint8_t)~bit;
g_sink_cc_wait_start[ch] = 0U;
pSW->sub = IDX_GET_SINK_VC;
return RT_TRUE;
}
/* 首条0x20等待200ms;握手未稳定时,后续查询间隔缩短为100ms。 */
if (chrg_roll_nor_sink_query_is_slow(pSW) &&
(pSW->sub == IDX_GET_SINK_VC)) {
rt_uint32_t query_interval_ms;
if (!g_sink_query_throttle[ch]) {
chrg_roll_nor_sink_query_wait_start(ch);
return RT_TRUE;
}
query_interval_ms = g_sink_query_first_pending[ch] ?
SINK_HANDSHAKE_FIRST_QUERY_DELAY_MS :
SINK_HANDSHAKE_QUERY_INTERVAL_MS;
elapsed = (rt_tick_t)(rt_tick_get() - g_sink_query_tick[ch]);
if (elapsed < rt_tick_from_millisecond(query_interval_ms)) {
return RT_TRUE;
}
g_sink_query_first_pending[ch] = RT_FALSE;
g_sink_query_tick[ch] = rt_tick_get();
}
return RT_FALSE;
}
/*****************************************************************
函数名称: sink_fill_pd_buf
函数描述: 根据快充协议类型填充PD指令的5字节数据缓冲区
输入参数:
pd_val: 快充协议类型(如0xC1/0xF8/0xFB等)
pd_volt: 电压值(mV,16位)
pd_curr: 电流值(mA,16位)
buf: 输出缓冲区
输出参数: buf: 填充后的5字节协议数据
返回说明: 0:成功 -1:参数错误
*****************************************************************/
int sink_fill_pd_buf(rt_uint8_t group,rt_uint8_t pd_val, rt_uint16_t pd_volt, rt_uint16_t pd_curr,rt_uint8_t *buf)
{
// 参数合法性校验
if (buf == RT_NULL) {
rt_kprintf("sink_fill_pd_buf: buf is a null pointer!\n");
return -1;
}
// 先清空缓冲区(默认全0)
rt_memset(buf, 0, 5);
// 按协议类型填充buf
switch(pd_val) {
// 标准/QC2.0/QC3.0/FCP(仅电压,第五位=电压)
case 0xFE: // 标准协议
case 0xF8: // QC2.0协议
case 0xF6: // QC3.0协议
case 0xF2: // FCP协议
buf[0] = pd_volt / 100; // 第5字节=电压(0.1V)
buf[1] = 0x00;//pd_curr / 100; // 第6字节=电流(0.1A)
#if NORTH_SINK_DEBUG
rt_kprintf("type: %02X, Voltage(0.1V)=%d\n", pd_val, pd_volt/100);
rt_kprintf("type: %02x, Curr(0.1A)=%d\n",pd_curr,pd_curr/100);
#endif
break;
// PDO/PPS/PD3.1/UFCS/AVS(组号+电压+电流)
case 0xFC: // PPS手动/自动
case 0xE3: // AVS协议
buf[0] = group; // 第5字节=组号(默认0)
buf[1] = (pd_volt >> 8) & 0xFF; // 第6字节=电压高8位(mV)
buf[2] = pd_volt & 0xFF; // 第7字节=电压低8位(mV)
buf[3] = (pd_curr >> 8) & 0xFF; // 第8字节=电流高8位(mA)
buf[4] = pd_curr & 0xFF; // 第9字节=电流低8位(mA)
#if NORTH_SINK_DEBUG
rt_kprintf("type: %02X, Group=0, Voltage=%d mV, Current=%d mA\n", pd_val, pd_volt, pd_curr);
#endif
break;
case 0xE0: // UFCS协议
case 0xE1: // PD3.1协议
case 0xFB: // PDO手动
buf[0] = 0x00; // 第5字节=组号(默认0)
buf[1] = (pd_volt >> 8) & 0xFF; // 第6字节=电压高8位(mV)
buf[2] = pd_volt & 0xFF; // 第7字节=电压低8位(mV)
buf[3] = (pd_curr >> 8) & 0xFF; // 第8字节=电流高8位(mA)
buf[4] = pd_curr & 0xFF; // 第9字节=电流低8位(mA)
#if NORTH_SINK_DEBUG
rt_kprintf("type: %02X, Group=0, Voltage=%d mV, Current=%d mA\n", pd_val, pd_volt, pd_curr);
#endif
break;
// SCP/VIVO/传音(电压+电流)
case 0xF3: // SCP协议
case 0xFD: // VIVO协议
case 0xF7: // 传音/TFC协议
buf[0] = (pd_volt >> 8) & 0xFF; // 第6字节=电压高8位(mV)
buf[1] = pd_volt & 0xFF; // 第7字节=电压低8位(mV)
buf[2] = (pd_curr >> 8) & 0xFF; // 第8字节=电流高8位(mA)
buf[3] = pd_curr & 0xFF; // 第9字节=电流低8位(mA)
buf[4] = 0x00;
#if NORTH_SINK_DEBUG
rt_kprintf("type: %02X, Voltage=%d mV, Current=%d mA\n", pd_val, pd_volt, pd_curr);
#endif
break;
// VOOC(无参数)
case 0xE2: // VOOC协议
#if NORTH_SINK_DEBUG
rt_kprintf("type: VOOC(0xE2), No parameters\n");
#endif
break;
case 0xF9: // AFC协议
{
// 1. 电压转HEX
rt_uint8_t volt_hex = 0;
if (pd_volt >= 5000 && pd_volt <= 20000) { // 电压范围:5V(5000mV)~20V(20000mV)
rt_uint8_t volt_v = pd_volt / 1000; // 转成V(5000mV→5V)
volt_hex = volt_v - 5; // 5V对应0,20V对应15(0xF)
} else {
#if NORTH_SINK_DEBUG
rt_kprintf("AFC VOLT ERROR VOLT=:%d mV Set 5000~20000\n", pd_volt);
#endif
return -1;
}
// 2. 电流转HEX
rt_uint8_t curr_hex = 0;
if (pd_curr >= 750 && pd_curr <= 3000) { // 电流范围:0.75A(750mA)~3.0A(3000mA)
rt_uint16_t curr_ma_step = (pd_curr - 750) / 150; // 步长150mA(0.75→1.5→...→3.0)
curr_hex = curr_ma_step; // 0.75A对应0,3.0A对应15(0xF)
#if NORTH_SINK_DEBUG
rt_kprintf("curr_ma_step = %d",curr_ma_step);
#endif
} else {
#if NORTH_SINK_DEBUG
rt_kprintf("AFC CURR ERROR%d mA SET 750~3000 \n", pd_curr);
#endif
return -1;
}
// 3. 合并电压Hex(高4位)和电流Hex(低4位)→ 填充第五字节
buf[0] = (volt_hex << 4) | curr_hex;
#if NORTH_SINK_DEBUG
rt_kprintf("type: AFC(0xF9), Voltage=%d V, Current=%.2f A, volaue=0x%X\n",
pd_volt/1000, pd_curr/1000.0, buf[0]);
#endif
}
break;
// 未知类型
default:
// rt_kprintf("Unknown fast charge type: %02X, Parameters cleared\n", pd_val);
break;
}
return 0;
}
/*****************************************************************
函数名称: chrg_roll_nor_sw_uart
函数描述: 北向通道切换 sink/source 串口
输入参数: ch: 通道 id: sink/source
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
static void chrg_roll_nor_sw_uart (eIDX_NOR_CH ch, eIDX_ID id)
{
if (ch >= TOTAL_NOR_CHS) {
return ;
}
if (ID_SOURCE == id) {
rt_pin_write(chrgios[sw_uart[ch]].base, PIN_HIGH);
} else if (ID_SINK == id) {
rt_pin_write(chrgios[sw_uart[ch]].base, PIN_LOW);
}
}
/*****************************************************************
函数名称: chrg_roll_nor_sink_pro_set
函数描述: 根据当前负载协议参数组帧并下发负载协议设置命令
输入参数: pSW:当前通道控制结构体
输出参数: -
返回说明: >0:发送长度 <0:参数组帧或串口发送失败
其它说明: 本函数只负责发送,不修改pSW->sub,状态由有效回码确认后推进
*****************************************************************/
static int chrg_roll_nor_sink_pro_set(struct chrg_switch_t *pSW)
{
rt_uint8_t buf[6] = {0};
if (sink_fill_pd_buf(pSW->sink.Pro_Group, pSW->sink.protocol,
pSW->sink.pro_loadv, pSW->sink.pro_loadc, buf) != 0) {
return -1;
}
#if NORTH_SINK_DEBUG
rt_kprintf("set_pro\r\n");
#endif
return sink_set_pd(pSW->sink.protocol, buf);
}
/*****************************************************************
函数名称: chrg_roll_nor_source_pro_set
函数描述: 根据当前电源协议参数组帧并下发电源协议设置命令
输入参数: pSW:当前通道控制结构体
输出参数: -
返回说明: >0:发送长度 <0:参数组帧或串口发送失败
其它说明: 本函数只负责发送,不修改pSW->sub,状态由有效回码确认后推进
*****************************************************************/
static int chrg_roll_nor_source_pro_set(struct chrg_switch_t *pSW)
{
return source_set_pro(pSW->source.protocol, pSW);
}
/*****************************************************************
函数名称: chrg_roll_nor_expected_cmd
函数描述: 根据当前角色和sub状态取得本次北向请求期望的回码命令
输入参数: pSW:当前通道控制结构体
输出参数: -
返回说明: 非0:期望命令码 0:当前状态没有可识别的北向请求
其它说明: 必须在chrg_roll_nor_set发送命令前调用,确保保存的期望命令
与实际发送命令一致
*****************************************************************/
static rt_uint8_t chrg_roll_nor_expected_cmd(const struct chrg_switch_t *pSW)
{
if (pSW == RT_NULL) {
return 0;
}
if (pSW->id == ID_SOURCE) {
switch (pSW->sub) {
case IDX_GET_SOURCE_VC:
return SRC_CMD_GET_VOLTAGE;
case IDX_GET_SOURCE_PD:
return SRC_CMD_GET_PROTOCOL;
case IDX_SET_SOURCE_PD:
return SRC_CMD_SET_PROTOCOL;
case IDX_SET_SOURCE_RESET:
return SRC_CMD_RESET;
case IDX_SET_SOURCE_CC_SET:
return SRC_CMD_SET_CC_CHOOSE;
case IDX_SET_SOURCE_CCLVL:
return SRC_CMD_SET_CC_LEVEL;
default:
return 0;
}
}
if (pSW->id == ID_SINK) {
switch (pSW->sub) {
case IDX_GET_SINK_VC:
return SINK_CMD_GET_VOLTAGE;
case IDX_GET_SINK_PD:
return SINK_CMD_GET_PD;
case IDX_SET_SINK_PD:
case IDX_SET_SINK_PD_ONLY:
case IDX_SET_SINK_PD_WITH_MODE:
#if 0
case IDX_SET_SINK_PD_BEFORE_CC:
#endif
return pSW->sink.protocol;
case IDX_SET_SINK_CCLINE:
case IDX_SET_SINK_CC_BEFORE_PD:
case IDX_SET_SINK_CC_BEFORE_PD_WITH_MODE:
return SINK_CMD_SET_CC;
case IDX_SET_SINK_CCLVL:
return SINK_CMD_SET_LEVEL;
default:
return 0;
}
}
return 0;
}
/*****************************************************************
函数名称: chrg_roll_nor_response_matches
函数描述: 校验北向回码与当前请求的通道角色、命令和固定长度是否匹配
输入参数: pMB:已通过north.c结构及CRC校验的回码 expected_idx:请求通道
expected_id:请求角色 expected_cmd:请求命令
输出参数: -
返回说明: 0:回码匹配 <0:参数错误或回码与请求不匹配
其它说明: 本函数只判断请求归属,业务解析在配置版本复核通过后执行
*****************************************************************/
static int chrg_roll_nor_response_matches(const struct mb_msg_t *pMB,
rt_uint8_t expected_idx, eIDX_ID expected_id, rt_uint8_t expected_cmd)
{
if ((pMB == RT_NULL) || (pMB->payload == RT_NULL) ||
(pMB->length < MIN_FRAME_LENGTH) ||
(expected_idx >= TOTAL_NOR_CHS) || (expected_cmd == 0U)) {
return -1;
}
if ((pMB->payload[2] != (rt_uint8_t)expected_id) ||
(pMB->payload[3] != expected_cmd)) {
LOG_W("north response mismatch: ch=%d id=%02x/%02x cmd=%02x/%02x",
expected_idx + 1U, pMB->payload[2], expected_id,
pMB->payload[3], expected_cmd);
return -2;
}
if ((expected_cmd == SRC_CMD_GET_VOLTAGE) && (pMB->length != 21U)) {
return -3;
}
if ((expected_cmd != SRC_CMD_GET_VOLTAGE) &&
(expected_cmd != SRC_CMD_GET_PROTOCOL) &&
(pMB->length != MIN_FRAME_LENGTH)) {
return -4;
}
return 0;
}
/*****************************************************************
函数名称: chrg_roll_nor_free_response
函数描述: 释放北向邮箱回码及其payload
输入参数: pMB:待释放邮箱消息
输出参数: -
返回说明: -
其它说明: 统一匹配成功、失配和手动模式下的消息释放路径
*****************************************************************/
static void chrg_roll_nor_free_response(struct mb_msg_t *pMB)
{
if (pMB == RT_NULL) {
return;
}
if (pMB->payload != RT_NULL) {
rt_free(pMB->payload);
}
rt_free(pMB);
}
/*****************************************************************
函数名称: chrg_roll_nor_drain_mailbox
函数描述: 非阻塞清理上一事务遗留在北向邮箱中的回码
输入参数: pTN:北向接收线程信息
输出参数: -
返回说明: -
其它说明: 必须在发送新请求前调用,避免旧回码被误认为本次请求回码
*****************************************************************/
static void chrg_roll_nor_drain_mailbox(struct chrg_thread_t *pTN)
{
struct mb_msg_t *pMB = RT_NULL;
if ((pTN == RT_NULL) || (pTN->mb == RT_NULL)) {
return;
}
while (rt_mb_recv(pTN->mb, (rt_uint32_t *)&pMB, 0) == RT_EOK) {
chrg_roll_nor_free_response(pMB);
pMB = RT_NULL;
}
}
/*****************************************************************
函数名称: chrg_roll_nor_wait_response
函数描述: 在统一截止时间内等待与当前角色和命令匹配的北向回码
输入参数: pTN:北向接收线程 expected_idx:请求通道 expected_id:请求角色
expected_cmd:请求命令 matched_response:匹配回码输出指针
输出参数: matched_response返回匹配消息,所有权交给调用者
返回说明: 0:收到匹配回码 <0:参数错误或等待超时
其它说明: 不匹配但CRC正确的旧回码会释放,并继续等待至本次总超时
*****************************************************************/
static int chrg_roll_nor_wait_response(struct chrg_thread_t *pTN,
rt_uint8_t expected_idx, eIDX_ID expected_id, rt_uint8_t expected_cmd,
struct mb_msg_t **matched_response)
{
rt_tick_t start_tick;
rt_tick_t timeout_tick;
rt_tick_t elapsed;
rt_tick_t remaining;
rt_err_t ret;
struct mb_msg_t *pMB = RT_NULL;
if ((pTN == RT_NULL) || (pTN->mb == RT_NULL) ||
(matched_response == RT_NULL)) {
return -1;
}
*matched_response = RT_NULL;
start_tick = rt_tick_get();
timeout_tick = rt_tick_from_millisecond(NORTH_RESPONSE_TIMEOUT_MS);
while (1) {
elapsed = (rt_tick_t)(rt_tick_get() - start_tick);
if (elapsed >= timeout_tick) {
return -1;
}
remaining = timeout_tick - elapsed;
ret = rt_mb_recv(pTN->mb, (rt_uint32_t *)&pMB, remaining);
if (ret != RT_EOK) {
return -1;
}
if (pMB == RT_NULL) {
continue;
}
if (chrg_roll_nor_response_matches(pMB, expected_idx,
expected_id, expected_cmd) == 0) {
*matched_response = pMB;
return 0;
}
/* CRC正确但不属于本次请求的旧回码不能结束当前等待。 */
chrg_roll_nor_free_response(pMB);
pMB = RT_NULL;
}
}
/*****************************************************************
函数名称: chrg_roll_nor_cmd
函数描述: 执行北向手动插入命令的入口检查
输入参数: pROLL:北向轮询控制结构体
输出参数: -
返回说明: 0:参数有效 <0:参数为空
其它说明: 当前仅保留入口,具体手动命令由后续功能扩展
*****************************************************************/
static int chrg_roll_nor_cmd (struct chrg_rollnor_t *pROLL)
{
if (RT_NULL == pROLL) {
return -1;
}
return 0;
}
/*****************************************************************
函数名称: chrg_roll_nor_set
函数描述: 按当前角色和sub状态发送一条北向协议命令
输入参数: ch:北向通道编号 pSW:通道控制结构体 next_sub:候选下一状态输出指针
输出参数: next_sub保存正确回码后应进入的状态,不直接修改pSW->sub
返回说明: >0:发送长度 <0:发送失败或状态不支持
其它说明: Source按差异执行协议、CC或组合命令;涉及PD的运行中切换先发送CC_CLOSE;
停止状态启动和主动停止均不额外发送CC_CLOSE;
Sink完整握手依次执行协议设置、目标CC线选择、稳定等待和VC查询
*****************************************************************/
static int chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW,
rt_uint8_t *next_sub)
{
if ((pSW == RT_NULL) || (next_sub == RT_NULL)) {
return -1;
}
*next_sub = pSW->sub;
if(pSW->id==ID_SOURCE){ //电源
chrg_roll_nor_sw_uart((eIDX_NOR_CH)ch, ID_SOURCE);
switch(pSW->sub){
case IDX_SET_SOURCE_RESET:
*next_sub = IDX_SET_SOURCE_PD;
return source_reset();
case IDX_SET_SOURCE_PD:
*next_sub = IDX_WAIT_SOURCE_PROTOCOL;
return chrg_roll_nor_source_pro_set(pSW);
case IDX_SET_SOURCE_CC_SET:
*next_sub = IDX_GET_SOURCE_VC;
return source_set_cc_choose(pSW->source.CC_Set);
case IDX_GET_SOURCE_VC:
return source_get_vc(pSW->source.set_volt,
pSW->source.set_curr);
case IDX_GET_SOURCE_PD:
*next_sub = IDX_GET_SOURCE_VC;
return source_get_pd();
default:
return -1;
}
}
else if (pSW->id == ID_SINK) {
chrg_roll_nor_sw_uart((eIDX_NOR_CH)ch, ID_SINK);
switch(pSW->sub){
case IDX_GET_SINK_VC: //查询
return sink_get_vc(pSW->sink.pro_loadv,
pSW->sink.pro_loadc);
case IDX_GET_SINK_PD:
*next_sub = IDX_GET_SINK_VC;
return sink_get_pd();
case IDX_SET_SINK_CCLINE: //CC线选择
*next_sub = IDX_WAIT_SINK_CC;
return sink_set_cc_line(pSW->sink.cc_set);
case IDX_SET_SINK_CC_BEFORE_PD:
*next_sub = IDX_WAIT_SINK_CC_BEFORE_PD;
return sink_set_cc_line(pSW->sink.cc_set);
case IDX_SET_SINK_CC_BEFORE_PD_WITH_MODE:
*next_sub = IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE;
return sink_set_cc_line(pSW->sink.cc_set);
case IDX_SET_SINK_CCLVL: //CC电平
return sink_set_cc_lvl(pSW->sink.cc_lvl);
case IDX_SET_SINK_PD:
/* 只有协议回码确认后,下一轮才允许进入电压查询。 */
*next_sub = IDX_WAIT_SINK_PD_ACK;
return chrg_roll_nor_sink_pro_set(pSW);
case IDX_SET_SINK_PD_ONLY:
*next_sub = IDX_WAIT_SINK_PD_ACK;
return chrg_roll_nor_sink_pro_set(pSW);
case IDX_SET_SINK_PD_WITH_MODE:
*next_sub = IDX_SET_SINK_MODE_AFTER_PD;
return chrg_roll_nor_sink_pro_set(pSW);
#if 0
case IDX_SET_SINK_PD_BEFORE_CC:
/* 协议回码确认后再设置CC,不提前查询电压。 */
*next_sub = IDX_SET_SINK_CCLINE;
return chrg_roll_nor_sink_pro_set(pSW);
#endif
default:
return -1;
}
}
return -1;
}
/*****************************************************************
函数名称: chrg_roll_nor_auto_request
函数描述: 执行一次自动北向请求事务,并在超时后有限次数重发
输入参数: idx:通道 pSW:通道状态 pTHR:轮询线程 pTN:北向接收线程
pNOR:北向共享状态
输出参数: -
返回说明: 0:请求成功 1:等待期间COM配置变化,旧事务已取消 <0:重试后失败
其它说明: 匹配回码有效且配置版本未变化时解析量测值并提交next_sub;
发送时不修改实时sub,CRC错误帧由north.c丢弃并表现为本次等待超时
*****************************************************************/
static int chrg_roll_nor_auto_request(rt_uint8_t idx,
struct chrg_switch_t *pSW, struct chrg_thread_t *pTHR,
struct chrg_thread_t *pTN, struct chrg_north_t *pNOR)
{
rt_bool_t advance_sub = RT_TRUE;
rt_uint8_t attempt; // 当前发送序号:0为首次,1~2为重发
rt_uint8_t request_sub = 0; // 本次请求实际使用的sub快照
rt_uint8_t next_sub = 0; // 正确回码后准备提交的候选sub
rt_uint8_t expected_cmd = 0; // 本次请求期望收到的命令码
rt_uint8_t max_attempts; // 本次请求允许的总发送次数
eIDX_ID expected_id = ID_SINK; // 本次请求发送时的角色快照
rt_uint32_t request_version = 0; // 本次请求发送时的COM配置版本
int send_ret; // 当前命令的串口发送结果
int wait_ret; // 当前命令的回码等待结果
struct mb_msg_t *pMB = RT_NULL; // 已匹配回码,处理后统一释放
if ((idx >= TOTAL_NOR_CHS) || (pSW == RT_NULL) ||
(pTHR == RT_NULL) || (pTN == RT_NULL) || (pNOR == RT_NULL)) {
return -1;
}
/* 默认保留设置命令的3次发送;首轮取得实际命令码后,0x20会改为
* 单次发送并留给下一轮轮询重试,避免量测无回码时长期占用通道。 */
max_attempts = NORTH_REQUEST_MAX_RETRIES + 1U;
for (attempt = 0; attempt < max_attempts; attempt++) {
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
if (attempt == 0U) {
/* 首次发送固定请求状态,后续重发必须继续使用同一份请求上下文。 */
request_sub = pSW->sub;
expected_id = pSW->id;
expected_cmd = chrg_roll_nor_expected_cmd(pSW);
if (expected_cmd == SRC_CMD_GET_VOLTAGE) {
max_attempts = NORTH_MEASURE_MAX_ATTEMPTS;
}
request_version = pNOR->config_version[idx];
/* 新事务发送前清理已结束或已超时事务遗留的邮箱回码。 */
chrg_roll_nor_drain_mailbox(pTN);
} else if ((pNOR->config_version[idx] != request_version) ||
(pSW->id != expected_id) || (pSW->sub != request_sub)) {
/* COM或其它控制入口已修改配置,禁止继续重发旧命令。 */
rt_mutex_release(pTHR->mutex);
return 1;
}
if (expected_cmd == 0U) {
rt_mutex_release(pTHR->mutex);
return -1;
}
send_ret = chrg_roll_nor_set(idx, pSW, &next_sub);
rt_mutex_release(pTHR->mutex);
if (send_ret > 0) {
wait_ret = chrg_roll_nor_wait_response(pTN, idx,
expected_id, expected_cmd, &pMB);
if ((wait_ret == 0) && (pMB != RT_NULL)) {
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
if ((pNOR->config_version[idx] != request_version) ||
(pSW->id != expected_id) || (pSW->sub != request_sub)) {
/* 回码到达前配置已变化,该回码属于旧事务,只释放不解析。 */
rt_mutex_release(pTHR->mutex);
chrg_roll_nor_free_response(pMB);
return 1;
}
/* 只有固定21字节的0x20量测回码需要进入Source/Sink业务解析。 */
if ((expected_cmd == SRC_CMD_GET_VOLTAGE) &&
(pMB->length == 21U)) {
if (expected_id == ID_SOURCE) {
(void)chrg_source_parse(pMB->payload,
(eIDX_SOU_CH)idx, pSW, pNOR);
} else {
chrg_sink_parse(pMB->payload,
(eIDX_SOU_CH)idx, pSW, pNOR);
}
}
/* ID、命令、CRC和配置版本均确认有效后,才正式推进实时sub。 */
if ((expected_id == ID_SOURCE) &&
(request_sub == IDX_SET_SOURCE_RESET)) {
/* 复位回码后重新执行Source INIT,初始化完成后再推进到PD。 */
pSW->source.work_mode = SOURCE_WORK_INIT;
advance_sub = RT_FALSE;
/* INIT完成前保持当前sub,禁止通用逻辑提前推进到PD。 */
} else if ((expected_id == ID_SOURCE) &&
(request_sub == IDX_SET_SOURCE_PD)) {
/* 0xD0应答后每通道独立等待100ms,再连接目标CC。 */
chrg_roll_nor_source_protocol_wait_start(idx);
chrg_comm_source_protocol_ack(idx,
(rt_uint8_t)pSW->source.protocol);
} else if ((expected_id == ID_SINK) &&
((request_sub == IDX_SET_SINK_CCLINE) ||
(request_sub == IDX_SET_SINK_CC_BEFORE_PD) ||
(request_sub == IDX_SET_SINK_CC_BEFORE_PD_WITH_MODE))) {
/* 北向Sink继电器保持接通,仅等待目标CC配置稳定。 */
chrg_roll_nor_sink_cc_wait_start(idx);
} else if ((expected_id == ID_SINK) &&
(request_sub == IDX_SET_SINK_PD_ONLY)) {
/* 仅重发协议时没有CC回码作为节流入口,直接启动200ms计时。 */
chrg_roll_nor_sink_query_wait_start(idx);
}
/* 业务解析可能主动切换sub,例如掉电恢复后要求重新设置协议。
* 只有sub仍属于本次请求时,才应用请求函数计算出的next_sub。 */
if (advance_sub && (pSW->sub == request_sub)) {
pSW->sub = next_sub;
}
rt_mutex_release(pTHR->mutex);
chrg_roll_nor_free_response(pMB);
return 0;
}
}
if ((attempt + 1U) < max_attempts) {
/* 本次发送失败或等待超时,保持request_sub并准备重发同一命令。 */
rt_thread_mdelay(NORTH_RETRY_INTERVAL_MS);
}
}
LOG_W("north request failed: ch=%d id=%02x cmd=%02x sub=%d attempts=%d",
idx + 1U, expected_id, expected_cmd, request_sub,
max_attempts);
return -1;
}
/*****************************************************************
函数名称: chrg_roll_nor_thread_entry
函数描述: 北向通道轮巡请求数据线程体
输入参数: *data: 本线程信息
输出参数: -
返回说明: -
其它说明: -
*****************************************************************/
void chrg_roll_nor_thread_entry (void *data)
{
struct chrg_thread_t *pTHR = (struct chrg_thread_t *)data;
if (RT_NULL == pTHR) {
return ;
}
rt_uint8_t index = 0, idx = 0, i = 0;
rt_uint8_t run = 0;
rt_bool_t source_waiting = RT_FALSE;
rt_bool_t sink_waiting = RT_FALSE;
int state_work_ret = 0;
rt_err_t ret = RT_EOK;
struct chrg_rollnor_t *pROLL = &chrgrollnor;
struct chrg_thread_t *pTN = &chrgthr[IDX_THR_NORTH];
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_switch_t *pSW = RT_NULL;
struct mb_msg_t *pMB_R = RT_NULL;
for (i = 0; i < TOTAL_NOR_CHS; i++) {
chrg_roll_nor_sw_uart((eIDX_NOR_CH)i, ID_SINK);
}
while (1) {
chrg_wdt_feed();
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
run = pROLL->run;
rt_mutex_release(pTHR->mutex);
switch (run) {
case RUN_AUTO: {
idx = index%TOTAL_NOR_CHS;
pSW = &pNOR->sw[idx];
source_waiting = RT_FALSE;
sink_waiting = RT_FALSE;
state_work_ret = 0;
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
/*
* INIT/STOP必须在enable过滤前执行:STOP会把enable清零,而COM
* 启动时只改变work_mode。若先判断enable,停机通道会直接continue,
* INIT永远没有机会把enable重新置1,也就无法恢复北向轮询。
* Source->Sink切换后的SINK_WORK_INIT同样从这里首次执行。
*/
if ((pSW->id == ID_SOURCE) &&
((pSW->source.work_mode == SOURCE_WORK_INIT) ||
(pSW->source.work_mode == SOURCE_WORK_STOP) ||
(pSW->source.work_mode == SOURCE_WORK_PROTOCOL_SWITCH) ||
(pSW->source.work_mode == SOURCE_WORK_FULL_RESET) ||
(pSW->source.work_mode == SOURCE_WORK_FULL_RESET_WAIT) ||
(pSW->source.work_mode == SOURCE_WORK_FULL_RESET_RELAY) ||
(pSW->source.work_mode == SOURCE_WORK_FULL_RESET_RELAY_WAIT) ||
(pSW->source.work_mode == SOURCE_WORK_INIT_WAIT))) {
state_work_ret = chrg_source_work_state(idx, pSW);
} else if ((pSW->id == ID_SINK) &&
((pSW->sink.work_mode == SINK_WORK_INIT) ||
(pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_UNLOAD_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_LOW) ||
(pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_HANDSHAKE_PREPARE) ||
(pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_STOP_WAIT) ||
(pSW->sink.work_mode == SINK_WORK_STOP_RELAY) ||
(pSW->sink.work_mode == SINK_WORK_STOP_RELAY_WAIT))) {
state_work_ret = chrg_sink_work((eIDX_SOU_CH)idx, pSW);
}
/*
* 协议切换等待只推进时间状态,不发送串口命令。该检查位于enable
* 过滤前,使停止或角色切换后的通道也能及时清理残留事务记录。
*/
source_waiting = chrg_roll_nor_source_wait_process(idx, pSW);
sink_waiting = chrg_roll_nor_sink_wait_process(idx, pSW);
/* 全通道Sink电压判定:使用eload实际电压Now_voltage与V_On比较,
* 判定后统一由chrg_sink_work执行;短路测试由该入口负责WORK_START保活。 */
for (i = 0; i < TOTAL_NOR_CHS; i++) {
struct chrg_switch_t *psw = &pNOR->sw[i];
if ((psw->id == ID_SINK) && psw->sink.On_work) {
(void)chrg_sink_volt_judge((eIDX_SOU_CH)i, psw);
}
}
rt_mutex_release(pTHR->mutex);
if (state_work_ret != 0) {
/* 南向状态动作未成功入队时保留原状态,下轮重试且禁止北向先行。 */
CHRG_CHANNEL_NEXT(index);
rt_thread_mdelay(2);
continue;
}
if (source_waiting || sink_waiting) {
CHRG_CHANNEL_NEXT(index);
rt_thread_mdelay(2);
continue;
}
if (0 == pNOR->enable[idx]) {
CHRG_CHANNEL_NEXT(index);
rt_thread_mdelay(2);
continue;
} else {
chrg_led_flashing(IDX_LED2, TIMES_ONE, PULSE_TIME*2, PULSE_TIME*2);
chrg_north_switch((eIDX_NOR_CH)idx);
chrgnorth.idx = idx;
pROLL->idx = idx;
(void)chrg_roll_nor_auto_request(idx, pSW,
pTHR, pTN, pNOR);
}
CHRG_CHANNEL_NEXT(index);
rt_thread_mdelay(NORTH_POLL_INTERVAL_MS);
continue;
}
break;
case RUN_LCD: {
chrg_roll_nor_cmd(pROLL);
}
break;
case RUN_CONSOLE: {
chrg_roll_nor_cmd(pROLL);
}
break;
case RUN_COM:
// {
// chrg_roll_nor_cmd(pROLL);
// }
break;
case RUN_NONE:
default:
rt_thread_mdelay(5);
continue;
break;
}
ret = rt_mb_recv(pTN->mb, (rt_uint32_t *)&pMB_R, 50); // 1kHz tick下超时约50ms
if ((RT_EOK == ret)&&(RT_NULL != pMB_R)) { // 存在返回数据
/* north.c只会向邮箱提交已经通过结构和CRC校验的完整帧。 */
if (RUN_AUTO != run) { // 恢复自动轮巡
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
pROLL->run = RUN_AUTO;
rt_mutex_release(pTHR->mutex);
}
chrg_roll_nor_free_response(pMB_R);
pMB_R = RT_NULL;
rt_thread_mdelay(10); // 相邻北向请求间隔50ms
} else {
if (RUN_AUTO != run) { // 非自动轮巡
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
//todo
pROLL->run = RUN_AUTO; // 切换会自动轮巡
rt_mutex_release(pTHR->mutex);
}
}
}
}
#if 1
static int sink (int argc, char **argv)
{
int ret = 0;
if (argc < 4) {
rt_kprintf("help : %s get|set [0-3] vc|pd|ccline|cclvl <data>\r\n", argv[0]);
return -1;
}
int gset = 0;
struct chrg_rollnor_t *pROLL = &chrgrollnor;
if (strcmp(argv[1], "get") == 0) {
gset = 0;
} else if (strcmp(argv[1], "set") == 0) {
gset = 1;
} else {
rt_kprintf("help : %s get|set [0-3] vc|pd|ccline|cclvl <data>\r\n", argv[0]);
return -1;
}
rt_uint8_t ch = (rt_uint8_t)atoi(argv[2]);
if ((ch < 0)||(ch >= TOTAL_NOR_CHS)) {
rt_kprintf("help : %s get|set [0-3] vc|pd|ccline|cclvl <data>\r\n", argv[0]);
return -1;
}
if (strcmp(argv[3], "vc") == 0) {
if (0 == gset) {
pROLL->sub = IDX_SET_SINK_WORK_STATE;
} else {
ret = -1;
rt_kprintf("sink vc can't set.\r\n");
return -1;
}
} else if (strcmp(argv[3], "pd") == 0) {
if (0 == gset) {
pROLL->sub = IDX_GET_SINK_PD;
} else {
//长度
if (argc != 5) {
rt_kprintf("help : %s set 0-3 ccline 0-3.\r\n", argv[0]);
return -1;
// sink_set_pd
} else { // sink set 0 pd 0
int type = atoi(argv[4]);
pROLL->pd = (rt_uint8_t)type;
pROLL->sub = IDX_SET_SINK_PD;
}
}
} else if (strcmp(argv[3], "ccline") == 0) {
if (1 == gset) {
if (argc != 5) {
rt_kprintf("help : %s set 0-3 ccline 0-3.\r\n", argv[0]);
return -1;
} else { // sink set 0 ccline 0-3
int line = atoi(argv[4]);
if ((line >= 0)&&(line <= 3)) {
pROLL->sub = IDX_SET_SINK_CCLINE;
pROLL->cc_line = (rt_uint8_t)line;
} else {
rt_kprintf("help : %s set 0-3 ccline 0-3.\r\n", argv[0]);
return -1;
}
}
} else {
ret = -1;
rt_kprintf("sink cc line can't get.\r\n");
}
} else if (strcmp(argv[3], "cclvl") == 0) {
if (1 == gset) {
if (argc != 5) {
rt_kprintf("help : %s set 0-3 cclvl 0-3.\r\n", argv[0]);
return -1;
} else { // sink set 0 cclvl 0-3
int line = atoi(argv[4]);
if ((line >= 0)&&(line <= 3)) {
pROLL->sub = IDX_SET_SINK_CCLVL;
pROLL->cc_line = (rt_uint8_t)line;
} else {
rt_kprintf("help : %s set 0-3 cclvl 0-3.\r\n", argv[0]);
return -1;
}
}
} else {
ret = -1;
rt_kprintf("sink cc level can't get.\r\n");
}
} else {
ret = -1;
}
if (0 == ret) {
pROLL->ch = ch;
pROLL->type = 0; // sink
pROLL->run = RUN_CONSOLE;
} else {
rt_kprintf("help : %s get|set [0-3] vc|pd|ccline|cclvl\r\n", argv[0]);
}
return ret;
}
MSH_CMD_EXPORT(sink, north sink test);
static int source (int argc, char **argv)
{
int ret = 0;
if (argc < 4) {
rt_kprintf("help : %s get|set [0-3] vc|pd|cclvl <data>\r\n", argv[0]);
return -1;
}
int gset = 0;
struct chrg_rollnor_t *pROLL = &chrgrollnor;
if (strcmp(argv[1], "get") == 0) {
gset = 0;
} else if (strcmp(argv[1], "set") == 0) {
gset = 1;
} else {
rt_kprintf("help : %s get|set [0-3] vc|pd|cclvl <data>\r\n", argv[0]);
return -1;
}
rt_uint8_t ch = (rt_uint8_t)atoi(argv[2]);
if ((ch < 0)||(ch >= TOTAL_NOR_CHS)) {
rt_kprintf("help : %s get|set [0-3] vc|pd|cclvl <data>\r\n", argv[0]);
return -1;
}
if (strcmp(argv[3], "vc") == 0) {
if (0 == gset) {
pROLL->sub = IDX_GET_SOURCE_VC;
} else {
ret = -1;
rt_kprintf("sink vc can't set.\r\n");
return -1;
}
} else if (strcmp(argv[3], "pd") == 0) {
if (0 == gset) {
pROLL->sub = IDX_GET_SOURCE_PD;
} else {
if (argc != 5) {
//if (argc != 5) {
rt_kprintf("help : %s set 0-3 pd 0-.\r\n", argv[0]);
return -1;
// sink_set_pd
} else { // sink set 0 pd 0
int type = atoi(argv[4]);
//协议
pROLL->pd = (rt_uint8_t)type;
//子命令
pROLL->sub = IDX_SET_SOURCE_PD;
}
}
} else if (strcmp(argv[3], "cclvl") == 0) {
if (1 == gset) {
if (argc != 5) {
rt_kprintf("help : %s set 0-3 cclvl 0-3.\r\n", argv[0]);
return -1;
} else { // sink set 0 cclvl 0-3
int line = atoi(argv[4]);
if ((line >= 0)&&(line <= 3)) {
pROLL->sub = IDX_SET_SOURCE_CCLVL;
pROLL->cc_line = (rt_uint8_t)line;
} else {
rt_kprintf("help : %s set 0-3 cclvl 0-3.\r\n", argv[0]);
return -1;
}
}
} else {
ret = -1;
rt_kprintf("sink cc level can't get.\r\n");
}
} else {
ret = -1;
}
if (0 == ret) {
pROLL->ch = ch;
pROLL->type = 1; // source
pROLL->run = RUN_CONSOLE;
} else {
rt_kprintf("help : %s get|set [0-3] vc|pd|cclvl\r\n", argv[0]);
}
return ret;
}
MSH_CMD_EXPORT(source, north source test);
#endif