1. 更新所有文件的版本号注释从V1.1.8到V1.1.9 2. 修改chrg_comm.c中的固件版本宏定义和注释 3. 在修改日志中新增V1.1.9版本的更新内容 4. 添加Allegro设计文件的锁定日志和工程文件
1316 lines
48 KiB
C
1316 lines
48 KiB
C
/****************************************************************************
|
||
文件名称 : chrg_source.c
|
||
完成日期 :
|
||
当前版本号 : V1.1.9
|
||
主要功能 : 北向数据source请求数据填充及发送。
|
||
版本历史 : 创建原始版本
|
||
说明 :
|
||
******************************************************************************/
|
||
|
||
#include <rtthread.h>
|
||
#include <string.h>
|
||
#include "chrg_north_pkg.h"
|
||
#include "chrg_utils.h"
|
||
#include "chrg_roll_nor.h"
|
||
#include "chrg_source.h"
|
||
#include "chrg_eload.h"
|
||
#include "chrg_roll_sou.h"
|
||
#include "chrg_rel.h"
|
||
|
||
#define SOURCE_VOLT_COMPENSATION_MV 200U
|
||
|
||
static int chrg_source_work_running(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW);
|
||
static int chrg_source_work_full_reset(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW);
|
||
static int chrg_source_work_full_reset_wait(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW);
|
||
static int chrg_source_work_full_reset_relay(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW);
|
||
static int chrg_source_work_full_reset_relay_wait(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW);
|
||
static int chrg_source_work_init_wait(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW);
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_init_submit
|
||
函数描述: 将电源模式初始化参数批量提交到南向功率板命令队列
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: -
|
||
返回说明: 0:提交成功 <0:参数错误或队列提交失败
|
||
其它说明: INIT不写电压;电压统一由RUNING状态写入,避免多个入口重复控制
|
||
*****************************************************************/
|
||
int chrg_source_init_submit(rt_uint8_t idx, struct chrg_switch_t *pSW)
|
||
{
|
||
/* Source启动参数一次入队,最后发送WORK_START使功率板开始输出。 */
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return -1;
|
||
}
|
||
rt_uint16_t regs[5] = {
|
||
REG_ELOAD,
|
||
REG_MODE,
|
||
REG_REL_ON,
|
||
REG_CURRENT_OUT + 1,
|
||
REG_WORK
|
||
};
|
||
rt_uint16_t vals[5] = {
|
||
ELOAD_SOURCE,
|
||
pSW->CV_mode,
|
||
0x03,
|
||
pSW->source.set_curr,
|
||
WORK_START
|
||
};
|
||
|
||
return chrg_sou_com_batch_submit(idx, regs, vals, 5);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_work_init
|
||
函数描述: 执行电源INIT状态,初始化功率板并打开对应北向通道
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: 更新电源运行标志、通道使能、在线状态及work_mode
|
||
返回说明: 0:初始化命令提交成功 非0:初始化失败
|
||
其它说明: 标准协议从pd_set准备目标并转入RUNING;快充协议清空旧电压后
|
||
进入WAIT,等待北向协商结果,INIT本身不写功率板电压
|
||
*****************************************************************/
|
||
static int chrg_source_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||
{
|
||
struct chrg_south_t *pSOU = &chrgsouth;
|
||
struct chrg_north_t *pNOR = &chrgnorth;
|
||
int ret;
|
||
|
||
/* 最大电流是功率板启动保护值,快充回码到达后可再更新运行目标。 */
|
||
pSW->source.set_curr = pSW->source.pd_set.mm.max_cur;
|
||
if (pSW->source.protocol == PRO_NONE) {
|
||
pSW->source.set_volt = pSW->source.pd_set.mm.max_vol;
|
||
} else {
|
||
/* 禁止快充重新启动时沿用上一次协商电压。 */
|
||
pSW->source.set_volt = 0;
|
||
}
|
||
|
||
ret = chrg_source_init_submit(idx, pSW);
|
||
if (ret != 0) {
|
||
return ret;
|
||
}
|
||
|
||
pSW->source.On_Flag = 1;
|
||
pSW->source.qc_err = 0;
|
||
pNOR->enable[idx] = 1;
|
||
pSOU->online[idx] = 1;
|
||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SOURCE);
|
||
/* 初始化批次必须全部收到南向回码后,才能继续协议设置或输出控制。 */
|
||
pSW->source.work_mode = SOURCE_WORK_INIT_WAIT;
|
||
return 0;
|
||
}
|
||
|
||
static int chrg_source_work_init_wait(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW)
|
||
{
|
||
int result;
|
||
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return -1;
|
||
}
|
||
if (chrg_sou_com_batch_is_pending(idx)) {
|
||
return 1;
|
||
}
|
||
result = chrg_sou_com_batch_get_result(idx);
|
||
if (result <= 0) {
|
||
/* 南向初始化失败时,保持北向协议不变并重发完整初始化批次。 */
|
||
pSW->source.work_mode = SOURCE_WORK_INIT;
|
||
return 1;
|
||
}
|
||
|
||
if (pSW->sub == IDX_SET_SOURCE_RESET) {
|
||
/* 复位后的初始化完成,才允许进入PD协议设置。 */
|
||
pSW->sub = IDX_SET_SOURCE_PD;
|
||
pSW->source.work_mode = SOURCE_WORK_WAIT;
|
||
return 0;
|
||
}
|
||
|
||
if (pSW->source.protocol == PRO_NONE) {
|
||
/* 标准协议不等待协商,初始化完成后直接写入目标电压。 */
|
||
pSW->source.work_mode = SOURCE_WORK_RUNING;
|
||
return chrg_source_work_running(idx, pSW);
|
||
}
|
||
pSW->source.work_mode = SOURCE_WORK_WAIT;
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_work_wait
|
||
函数描述: 执行电源WAIT状态
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: -
|
||
返回说明: 0:状态处理完成
|
||
其它说明: WAIT状态不下发命令,由北向解析函数判断目标电压是否变化
|
||
*****************************************************************/
|
||
static int chrg_source_work_wait(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||
{
|
||
/* WAIT状态不产生南向命令,等待下一帧北向电压数据。 */
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_work_running
|
||
函数描述: 执行电源RUNING状态,下发补偿后的最新目标电压
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: -
|
||
返回说明: 0:命令提交成功 非0:命令提交失败
|
||
其它说明: 功率板设定值固定比目标高200mV,防止限压导致输出进入稳流模式;
|
||
目标最大值为48000mV,无需做uint16_t饱和处理
|
||
*****************************************************************/
|
||
static int chrg_source_work_running(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||
{
|
||
/* 只对本次下发值补偿,不修改set_volt,防止多次执行时累计增加。 */
|
||
rt_uint16_t reg = REG_VOLTAGE_OUT + 1;
|
||
rt_uint16_t value = pSW->source.set_volt;
|
||
|
||
return chrg_sou_com_batch_submit(idx, ®, &value, 1);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_work_protocol_switch
|
||
函数描述: 执行电源协议或CC切换前的功率板输出清零
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: 清零source.set_volt,并在命令入队成功后进入WAIT状态
|
||
返回说明: 0:清零命令提交成功 非0:状态或命令提交失败
|
||
其它说明: COM在进入本状态前必须将sub设置为协议、CC或组合事务入口;
|
||
本状态只管理南向清零,不修改北向sub,
|
||
标准协议同时按0V、模式、电流顺序入队,保证南向命令顺序固定
|
||
*****************************************************************/
|
||
static int chrg_source_work_protocol_switch(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW)
|
||
{
|
||
rt_uint16_t regs[3];
|
||
rt_uint16_t vals[3];
|
||
rt_uint8_t count = 0;
|
||
int ret;
|
||
|
||
if ((pSW->sub != IDX_SET_SOURCE_PD) &&
|
||
(pSW->sub != IDX_SET_SOURCE_RESET)) {
|
||
return -1;
|
||
}
|
||
|
||
regs[count] = REG_VOLTAGE_OUT + 1;
|
||
vals[count++] = 0;
|
||
if (pSW->source.protocol == PRO_NONE) {
|
||
/* 标准协议切换时,模式和限流值必须排在0V命令之后生效。 */
|
||
regs[count] = REG_MODE;
|
||
vals[count++] = pSW->CV_mode;
|
||
regs[count] = REG_CURRENT_OUT + 1;
|
||
vals[count++] = pSW->source.pd_set.mm.max_cur;
|
||
}
|
||
|
||
/* 只有整批命令成功加入南向队列后,才允许北向继续协议切换。 */
|
||
ret = chrg_sou_com_batch_submit(idx, regs, vals, count);
|
||
if (ret != 0) {
|
||
return ret;
|
||
}
|
||
|
||
pSW->source.set_volt = 0;
|
||
pSW->source.work_mode = SOURCE_WORK_WAIT;
|
||
return 0;
|
||
}
|
||
|
||
static int chrg_source_work_full_reset(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW)
|
||
{
|
||
rt_uint16_t reg = REG_WORK;
|
||
rt_uint16_t value = WORK_STOP;
|
||
|
||
/* Cancel stale south commands so the reset sequence starts from a known state. */
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return -1;
|
||
}
|
||
if (chrg_sou_com_batch_cancel(idx) != 0) {
|
||
return -1;
|
||
}
|
||
if (chrg_sou_com_batch_submit(idx, ®, &value, 1) != 0) {
|
||
return -1;
|
||
}
|
||
pSW->source.set_volt = 0;
|
||
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_WAIT;
|
||
return 1;
|
||
}
|
||
|
||
static int chrg_source_work_full_reset_wait(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW)
|
||
{
|
||
int result;
|
||
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return -1;
|
||
}
|
||
if (chrg_sou_com_batch_is_pending(idx)) {
|
||
return 1;
|
||
}
|
||
result = chrg_sou_com_batch_get_result(idx);
|
||
if (result <= 0) {
|
||
pSW->source.work_mode = SOURCE_WORK_FULL_RESET;
|
||
return 1;
|
||
}
|
||
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_RELAY;
|
||
return 1;
|
||
}
|
||
|
||
static int chrg_source_work_full_reset_relay(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW)
|
||
{
|
||
rt_uint16_t reg = REG_REL_ON;
|
||
rt_uint16_t value = ALL_REL_OFF;
|
||
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return -1;
|
||
}
|
||
if (chrg_sou_com_batch_submit(idx, ®, &value, 1) != 0) {
|
||
return -1;
|
||
}
|
||
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_RELAY_WAIT;
|
||
return 1;
|
||
}
|
||
|
||
static int chrg_source_work_full_reset_relay_wait(eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW)
|
||
{
|
||
int result;
|
||
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return -1;
|
||
}
|
||
if (chrg_sou_com_batch_is_pending(idx)) {
|
||
return 1;
|
||
}
|
||
result = chrg_sou_com_batch_get_result(idx);
|
||
if (result <= 0) {
|
||
pSW->source.work_mode = SOURCE_WORK_FULL_RESET_RELAY;
|
||
return 1;
|
||
}
|
||
|
||
/* South relays are off; now disconnect D+/D- and CC before SOURCE_RESET. */
|
||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0);
|
||
pSW->sub = IDX_SET_SOURCE_RESET;
|
||
pSW->source.work_mode = SOURCE_WORK_WAIT;
|
||
return 1;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_work_stop
|
||
函数描述: 执行电源主动关机流程
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: 清除目标电压、运行标志、通道使能和在线状态
|
||
返回说明: 0:停止成功 非0:停止命令提交失败
|
||
其它说明: 依次关闭功率板两路继电器、清零电压并发送WORK_STOP;
|
||
停止命令成功入队后立即关闭北向通道,不额外发送CC_CLOSE
|
||
*****************************************************************/
|
||
static int chrg_source_work_stop(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||
{
|
||
struct chrg_south_t *pSOU = &chrgsouth;
|
||
struct chrg_north_t *pNOR = &chrgnorth;
|
||
int ret;
|
||
|
||
rt_uint16_t regs[3] = {REG_REL_ON, REG_VOLTAGE_OUT + 1, REG_WORK};
|
||
rt_uint16_t vals[3] = {ALL_REL_OFF, 0, WORK_STOP};
|
||
|
||
/* 先断开两路功率继电器,再清零输出并停止,避免关机瞬间继续向外供电。 */
|
||
ret = chrg_sou_com_batch_submit(idx, regs, vals, 3);
|
||
if (ret != 0) {
|
||
return ret;
|
||
}
|
||
|
||
pSW->source.set_volt = 0;
|
||
pSW->source.On_Flag = 0;
|
||
pSW->source.qc_err = 0;
|
||
pNOR->enable[idx] = 0;
|
||
pSOU->online[idx] = 0;
|
||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0);
|
||
pSW->sub = IDX_SET_SOURCE_STOP_STATE;
|
||
pSW->source.work_mode = SOURCE_WORK_WAIT;
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_work_switch
|
||
函数描述: 处理“负载切换到电源”的过渡状态
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: 清除旧负载运行标志,设置电源北向入口和INIT状态
|
||
返回说明: 0:停止命令成功加入队列 非0:命令入队失败
|
||
其它说明: pSW->id已由COM更新为ID_SOURCE;先关闭旧负载继电器并提交
|
||
WORK_STOP,后续电源INIT使用同一通道队列,保证停止命令先执行
|
||
*****************************************************************/
|
||
static int chrg_source_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||
{
|
||
rt_uint16_t regs[3] = {REG_REL_ON, REG_VOLTAGE_OUT + 1, REG_WORK};
|
||
rt_uint16_t vals[3] = {ALL_REL_OFF, 0, WORK_STOP};
|
||
int ret;
|
||
|
||
ret = chrg_sou_com_batch_submit(idx, regs, vals, 3);
|
||
if (ret != 0) {
|
||
return ret;
|
||
}
|
||
|
||
/* 停止成功入队后,清除旧Sink运行标志。 */
|
||
pSW->sink.On_work = 0;
|
||
pSW->source.set_volt = 0;
|
||
/* 首次进入Source按“设置协议->连接CC”启动,不能沿用Sink的sub状态。 */
|
||
pSW->sub = IDX_SET_SOURCE_PD;
|
||
/* SWITCH只负责旧角色退出,后续启动统一交给Source INIT状态。 */
|
||
pSW->source.work_mode = SOURCE_WORK_INIT;
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_work_state
|
||
函数描述: 电源工作状态机统一入口
|
||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||
输出参数: 根据source.work_mode执行对应状态动作
|
||
返回说明: 0:状态处理成功 <0:参数、状态或命令提交失败
|
||
其它说明: 支持INIT、WAIT、RUNING、STOP、SWITCH和PROTOCOL_SWITCH状态
|
||
*****************************************************************/
|
||
int chrg_source_work_state(rt_uint8_t idx, struct chrg_switch_t *pSW)
|
||
{
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return -1;
|
||
}
|
||
|
||
/* 所有Source功率板控制统一从本状态机出口执行。 */
|
||
switch (pSW->source.work_mode) {
|
||
case SOURCE_WORK_INIT:
|
||
return chrg_source_work_init(idx, pSW);
|
||
case SOURCE_WORK_WAIT:
|
||
return chrg_source_work_wait(idx, pSW);
|
||
case SOURCE_WORK_RUNING:
|
||
return chrg_source_work_running(idx, pSW);
|
||
case SOURCE_WORK_STOP:
|
||
return chrg_source_work_stop(idx, pSW);
|
||
case SOURCE_WORK_SWITCH:
|
||
return chrg_source_work_switch(idx, pSW);
|
||
case SOURCE_WORK_PROTOCOL_SWITCH:
|
||
return chrg_source_work_protocol_switch(idx, pSW);
|
||
case SOURCE_WORK_FULL_RESET:
|
||
return chrg_source_work_full_reset(idx, pSW);
|
||
case SOURCE_WORK_FULL_RESET_WAIT:
|
||
return chrg_source_work_full_reset_wait(idx, pSW);
|
||
case SOURCE_WORK_FULL_RESET_RELAY:
|
||
return chrg_source_work_full_reset_relay(idx, pSW);
|
||
case SOURCE_WORK_FULL_RESET_RELAY_WAIT:
|
||
return chrg_source_work_full_reset_relay_wait(idx, pSW);
|
||
case SOURCE_WORK_INIT_WAIT:
|
||
return chrg_source_work_init_wait(idx, pSW);
|
||
default:
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
rt_uint8_t Pro_Group_VCMM[11][8] = {
|
||
{0} // 11个挡位,8个参数(src, pps, vmin_H,vmin_L, vmax_H,vmax_L,cur_set_H,cur_set_L)
|
||
};
|
||
/*****************************************************************
|
||
函数名称: source_get_vc
|
||
函数描述: source电压电流查询请求
|
||
输入参数: vol:电压 cur:电流
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:发送长度
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int source_get_vc (rt_uint16_t vol, rt_uint16_t cur)
|
||
{
|
||
rt_uint16_t len = 0;
|
||
rt_uint8_t data[12] = {0};
|
||
rt_uint8_t frame[16] = {0};
|
||
|
||
u16_to_u8v(vol, &data[0]);
|
||
u16_to_u8v(cur, &data[2]);
|
||
data[4] = 0x00;
|
||
data[5] = 0x00;
|
||
|
||
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_GET_VOLTAGE, data, 6, frame, &len);
|
||
|
||
return chrg_north_send(frame, len);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: source_get_pd
|
||
函数描述: source pd 协议查询请求
|
||
输入参数: -
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:发送长度
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int source_get_pd (void)
|
||
{
|
||
rt_uint16_t len = 0;
|
||
rt_uint8_t frame[16] = {0};
|
||
|
||
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_GET_PROTOCOL, RT_NULL, 0, frame, &len);
|
||
|
||
return chrg_north_send(frame, len);
|
||
}
|
||
|
||
int source_reset (void)
|
||
{
|
||
rt_uint16_t len = 0;
|
||
rt_uint8_t data[8] = {0};
|
||
rt_uint8_t frame[16] = {0};
|
||
|
||
data[0] = 0x00;
|
||
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_RESET, data, 1, frame, &len);
|
||
|
||
return chrg_north_send(frame, len);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: source_set_cc_lvl
|
||
函数描述: source 设置 cc 等级
|
||
输入参数: lvl:等级
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:发送长度
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int source_set_cc_lvl (rt_uint8_t lvl)
|
||
{
|
||
rt_uint16_t len = 0;
|
||
rt_uint8_t data[8] = {0};
|
||
rt_uint8_t frame[16] = {0};
|
||
|
||
data[0] = lvl;
|
||
|
||
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_SET_CC_LEVEL, data, 1, frame, &len);
|
||
|
||
return chrg_north_send(frame, len);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: source_set_cc_lvl
|
||
函数描述: source 设置 cc 等级
|
||
输入参数: lvl:等级
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:发送长度
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int source_set_cc_choose (rt_uint8_t cc_set)
|
||
{
|
||
rt_uint16_t len = 0;
|
||
rt_uint8_t data[8] = {0};
|
||
rt_uint8_t frame[16] = {0};
|
||
|
||
data[0] = cc_set;
|
||
|
||
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_SET_CC_CHOOSE, data, 1, frame, &len);
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("source set cc frame:");
|
||
for (int i = 0; i < len; i++) {
|
||
rt_kprintf(" %02x", frame[i]);
|
||
}
|
||
rt_kprintf("\n");
|
||
#endif
|
||
return chrg_north_send(frame, len);
|
||
}
|
||
|
||
|
||
/*
|
||
填入单档
|
||
*/
|
||
rt_uint8_t parse_mulit_gear_One(rt_uint16_t min_volt_mv,rt_uint16_t max_volt_mv, rt_uint16_t max_curr_ma) {
|
||
// 清空缓冲区
|
||
rt_memset(Pro_Group_VCMM, 0, sizeof(Pro_Group_VCMM));
|
||
Pro_Group_VCMM[0][0] = 0x00; // src
|
||
Pro_Group_VCMM[0][1] = 0x00; // pps
|
||
Pro_Group_VCMM[0][2] = (min_volt_mv >> 8) & 0xFF; // vmin_H
|
||
Pro_Group_VCMM[0][3] = min_volt_mv & 0xFF; // vmin_L
|
||
Pro_Group_VCMM[0][4] = (max_volt_mv >> 8) & 0xFF; // vmax_H
|
||
Pro_Group_VCMM[0][5] = max_volt_mv & 0xFF; // vmax_L
|
||
Pro_Group_VCMM[0][6] = (max_curr_ma >> 8) & 0xFF; // cur_set_H
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("H_C=%02x",Pro_Group_VCMM[0][6]);
|
||
#endif
|
||
Pro_Group_VCMM[0][7] = max_curr_ma & 0xFF; // cur_set_L
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("L_C=%02x\n",Pro_Group_VCMM[0][7]);
|
||
#endif
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: parse_power_single_gear
|
||
函数描述: 单档电源协议解析函数(QC3.0/QC2.0/SCPB)
|
||
输入参数: protoCmd: 协议命令码(0x27/0x28/0x23)
|
||
pData: 协议数据区缓冲区(状态+通道+CC线+最大电压+最大电流)
|
||
reqLen: 帧总长度
|
||
pSW: 通道协议配置结构体指针
|
||
输出参数: -
|
||
返回说明: -
|
||
其它说明: 数据格式:状态+通道(1)+CC线(1)+最大电压(2)+最大电流(2)
|
||
*****************************************************************/
|
||
void parse_power_single_gear(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t reqLen,uint8_t *pro_gear_idx,uint8_t *pro,rt_uint16_t *protect_curr)
|
||
{
|
||
rt_uint16_t min_volt_mv = 0; // 最小输出电压(mv)
|
||
rt_uint16_t max_volt_mv = 0; // 最大输出电压(mV)
|
||
rt_uint16_t max_curr_ma = 0; // 最大输出电流(mA)
|
||
|
||
// 数据区索引:0=状态+通道,1=CV,2=CC线,3-4=最小电压,5-6=最大电压,7-8最大电流
|
||
|
||
min_volt_mv = u8v_to_u16(&pData[3]); // 大端
|
||
max_volt_mv = u8v_to_u16(&pData[5]); // 大端
|
||
max_curr_ma = u8v_to_u16(&pData[7]); // 大端
|
||
*protect_curr = u8v_to_u16(&pData[9]); // 大端
|
||
// rt_kprintf("\n");
|
||
// for(int i=0;i<10;i++){
|
||
// rt_kprintf("%0x",pData[i]);
|
||
// }
|
||
// rt_kprintf("\n");
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("one_gear");
|
||
rt_kprintf("min_volt_mv = %d\n",min_volt_mv);
|
||
rt_kprintf("max_volt_mv = %d\n",max_volt_mv);
|
||
rt_kprintf("prtect_curr= %04x",*protect_curr);
|
||
#endif
|
||
*pro_gear_idx = 1; // 单档协议固定1
|
||
// 按协议命令码赋值
|
||
switch (protoCmd)
|
||
{
|
||
case 0x27: // QC3.0
|
||
*pro = PRO_QC30;
|
||
break;
|
||
case 0x28: // QC2.0
|
||
*pro = PRO_QC20;
|
||
break;
|
||
case 0x23: // SCPB
|
||
*pro = PRO_SCPB;
|
||
break;
|
||
default:
|
||
rt_kprintf("单档电源协议不支持:0x%02X\n", protoCmd);
|
||
return;
|
||
}
|
||
|
||
parse_mulit_gear_One(min_volt_mv,max_volt_mv,max_curr_ma);
|
||
return;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: parse_pd_11group_pdo
|
||
函数描述: 解析PD协议11组PDO数据,填充8参数高低字节缓冲区
|
||
输入参数: pdoData: 11组PDO数据缓冲区(小端序,44字节)
|
||
pdo_group_num: 实际PDO组数
|
||
pSW: 通道协议配置结构体指针(仅校验)
|
||
输出参数: -
|
||
返回说明: -
|
||
其它说明: 1. type映射:0→src=0/pps=0;1→src=03/pps=00;2→src=03/pps=00;3→src=03/pps=01
|
||
2. 所有16位参数拆分为高/低字节填充
|
||
*****************************************************************/
|
||
void parse_pd_11group_pdo(rt_uint8_t *pdoData, rt_uint8_t pdo_group_num) {
|
||
rt_uint32_t pdo_val = 0;
|
||
rt_uint8_t pdo_type = 0;
|
||
rt_uint16_t vmin_mv = 0, vmax_mv = 0, cur_power = 0; // 16位原始值
|
||
|
||
// 清空缓冲区
|
||
rt_memset(Pro_Group_VCMM, 0, sizeof(Pro_Group_VCMM));
|
||
|
||
for (rt_uint8_t i = 0; i < pdo_group_num; i++) {
|
||
|
||
// 1. 拼接32位PDO值(低字节在前)
|
||
pdo_val = (rt_uint32_t)pdoData[i*4 + 3] << 24 |
|
||
(rt_uint32_t)pdoData[i*4 + 2] << 16 |
|
||
(rt_uint32_t)pdoData[i*4 + 1] << 8 |
|
||
(rt_uint32_t)pdoData[i*4];
|
||
|
||
// 2. 提取PDO类型(Bit30-31)
|
||
pdo_type = (pdo_val >> 30) & 0x03;
|
||
// 3. 按type映射src和pps
|
||
switch (pdo_type) {
|
||
case 0: // FPDO → src=0x00, pps=0x00
|
||
Pro_Group_VCMM[i][0] = 0x00;
|
||
Pro_Group_VCMM[i][1] = 0x00;
|
||
break;
|
||
case 1: // EPRPDO → src=0x03, pps=0x00
|
||
Pro_Group_VCMM[i][0] = 0x00;
|
||
Pro_Group_VCMM[i][1] = 0x01;
|
||
break;
|
||
case 2: // PPS → src=0x03, pps=0x00
|
||
Pro_Group_VCMM[i][0] = 0x03;
|
||
Pro_Group_VCMM[i][1] = 0x00;
|
||
break;
|
||
case 3: // EPR AVS → src=0x03, pps=0x01
|
||
Pro_Group_VCMM[i][0] = 0x03;
|
||
Pro_Group_VCMM[i][1] = 0x01;
|
||
break;
|
||
default:
|
||
rt_kprintf("parse_pd_11group_pdo: unknown PDO type=%d (index=%d)\n", pdo_type, i);
|
||
continue;
|
||
}
|
||
|
||
// 4. 解析电压/电流/功率(16位值)
|
||
switch (pdo_type) {
|
||
case 0: // FPDO(固定电源)
|
||
case 1: // EPRPDO(固定电源)
|
||
vmin_mv = vmax_mv = ((pdo_val >> 10) & 0x03FF) * 50; // 电压(mV)
|
||
cur_power = (pdo_val & 0x03FF) * 10; // 电流(mA)
|
||
break;
|
||
case 2: // PPS(可编程电源)
|
||
vmin_mv = ((pdo_val >> 8) & 0x00FF) * 100; // 最小电压(mV)
|
||
vmax_mv = ((pdo_val >> 17) & 0x00FF) * 100; // 最大电压(mV)
|
||
cur_power = (pdo_val & 0x7F) * 50; // 电流(mA)
|
||
break;
|
||
case 3: // EPR AVS(功率型)
|
||
vmin_mv = ((pdo_val >> 8) & 0x00FF) * 100; // 最小电压(mV)
|
||
vmax_mv = ((pdo_val >> 17) & 0x1FF) * 100; // 最大电压(mV)
|
||
cur_power = (pdo_val & 0xFF) * 1; // 功率(W)
|
||
break;
|
||
default:
|
||
vmin_mv = vmax_mv = cur_power = 0;
|
||
break;
|
||
}
|
||
|
||
// 5. 拆分高低字节填充缓冲区(核心)
|
||
// 最小电压拆分
|
||
Pro_Group_VCMM[i][2] = (vmin_mv >> 8) & 0xFF; // vmin_H
|
||
Pro_Group_VCMM[i][3] = vmin_mv & 0xFF; // vmin_L
|
||
// 最大电压拆分
|
||
Pro_Group_VCMM[i][4] = (vmax_mv >> 8) & 0xFF; // vmax_H
|
||
Pro_Group_VCMM[i][5] = vmax_mv & 0xFF; // vmax_L
|
||
// 电流/功率拆分
|
||
Pro_Group_VCMM[i][6] = (cur_power >> 8) & 0xFF; // cur_set_H
|
||
Pro_Group_VCMM[i][7] = cur_power & 0xFF; // cur_set_L
|
||
#if NORTH_SOURCE_DEBUG
|
||
// 调试打印
|
||
rt_kprintf("max_H=%d",Pro_Group_VCMM[i][4]);
|
||
rt_kprintf("max_L=%d",Pro_Group_VCMM[i][5]);
|
||
rt_kprintf("min_H=%d",Pro_Group_VCMM[i][2]);
|
||
rt_kprintf("min_L=%d",Pro_Group_VCMM[i][3]);
|
||
if (pdo_type == 3) { // EPR AVS 打印功率
|
||
rt_kprintf("PDO[%d]:src=0x%02X, pps=0x%02X, V_MIN=%dmV(0x%02X%02X),V_MAX=%dmV(0x%02X%02X),C/P=%dW(0x%02X%02X)\n",
|
||
i, Pro_Group_VCMM[i][0], Pro_Group_VCMM[i][1],
|
||
vmin_mv, Pro_Group_VCMM[i][2], Pro_Group_VCMM[i][3],
|
||
vmax_mv, Pro_Group_VCMM[i][4], Pro_Group_VCMM[i][5],
|
||
cur_power, Pro_Group_VCMM[i][6], Pro_Group_VCMM[i][7]);
|
||
} else { // 其他类型打印电流
|
||
rt_kprintf("PDO[%d]: src=0x%02X, pps=0x%02X, V_MIN=%dmV(0x%02X%02X), V_MAX=%dmV(0x%02X%02X),C/P=%dmA(0x%02X%02X)\n",
|
||
i, Pro_Group_VCMM[i][0], Pro_Group_VCMM[i][1],
|
||
vmin_mv, Pro_Group_VCMM[i][2], Pro_Group_VCMM[i][3],
|
||
vmax_mv, Pro_Group_VCMM[i][4], Pro_Group_VCMM[i][5],
|
||
cur_power, Pro_Group_VCMM[i][6], Pro_Group_VCMM[i][7]);
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
|
||
/*****************************************************************
|
||
函数名称: parse_power_pdo_gear
|
||
函数描述: PDO档电源协议解析函数(PD协议)
|
||
输入参数: protoCmd: 协议命令码(0x2A)
|
||
pData: 协议数据区缓冲区(状态+通道+CC线+PDO组数+11组PDO+保留+保护电流+补偿电压)
|
||
reqLen: 帧总长度
|
||
pSW: 通道协议配置结构体指针
|
||
输出参数: -
|
||
返回说明: -
|
||
其它说明: 数据格式:状态+通道(1)+CC线(1)+PDO组数(1)+11组PDO(44)+保留(20)+保护电流(2)+补偿电压(2)
|
||
*****************************************************************/
|
||
void parse_power_pdo_gear(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t reqLen,uint8_t *pro_gear_idx,uint8_t *pro,rt_uint16_t *protect_ma)
|
||
{
|
||
rt_uint8_t pdo_group_num = 0; // PDO组数
|
||
rt_int16_t comp_volt_mv = 0; // 补偿电压(mV)
|
||
|
||
// 数据区索引:0=状态+通道,1=CC线,2=恒压恒流模式,3=PDO组数(bit12-15)
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("pdata=%04x",pData[3]);
|
||
#endif
|
||
pdo_group_num = (pData[3] >> 4) & 0x0F; // Bit12-15提取组数
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("num=%d\n",pdo_group_num);
|
||
#endif
|
||
*pro = PRO_PD0PSS;
|
||
*pro_gear_idx = pdo_group_num;
|
||
// 解析11组PDO(小端序,44字节)
|
||
parse_pd_11group_pdo(&pData[4], pdo_group_num);
|
||
|
||
// 解析保留字段(20字节) + 保护电流 + 补偿电压
|
||
*protect_ma = u8v_to_u16(&pData[4 + 44 + 20]); // 67-68字节
|
||
comp_volt_mv = (rt_int16_t)u8v_to_u16(&pData[4 + 44 + 22]); // 69-70字节
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("project_curr=%d mA, add_volt=%d mV\n", *protect_ma, comp_volt_mv);
|
||
#endif
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: parse_mulit_gear_more
|
||
函数描述: 解析三-四挡位原始数据,填充8参数高低字节缓冲区(同步修改)
|
||
输入参数: pData: PDO原始数据缓冲区 gear_num: 有效PDO组数
|
||
输出参数: -
|
||
返回说明: 0:成功 1:参数错误
|
||
其它说明: 同步适配新缓冲区格式和src/pps映射规则
|
||
*****************************************************************/
|
||
rt_uint8_t parse_mulit_gear_more(rt_uint8_t *pData, rt_uint8_t gear_num) {
|
||
// 入参合法性校验
|
||
if (pData == RT_NULL || gear_num == 0 || gear_num > 11) {
|
||
rt_kprintf("parse_mulit_gear_pd0:invalid params (gear_num=%d)\n", gear_num);
|
||
return 1;
|
||
}
|
||
|
||
// 清空缓冲区
|
||
rt_memset(Pro_Group_VCMM, 0, sizeof(Pro_Group_VCMM));
|
||
|
||
rt_uint32_t pdo_val = 0;
|
||
rt_uint8_t pdo_type = 0;
|
||
rt_uint16_t vmin_mv = 0, vmax_mv = 0, cur_power = 0;
|
||
|
||
for (rt_uint8_t i = 0; i < gear_num; i++) {
|
||
// 终止条件:PDO电压字段为0则停止
|
||
|
||
// 1. 拼接32位PDO值(低字节在前)
|
||
pdo_val = (rt_uint32_t)pData[i*4 + 3] << 24 |
|
||
(rt_uint32_t)pData[i*4 + 2] << 16 |
|
||
(rt_uint32_t)pData[i*4 + 1] << 8 |
|
||
(rt_uint32_t)pData[i*4];
|
||
|
||
// 2. 提取PDO类型(Bit30-31)
|
||
pdo_type = (pdo_val >> 30) & 0x03;
|
||
|
||
// 3. 按type映射src和pps
|
||
switch (pdo_type) {
|
||
case 0: // FPDO → src=0x00, pps=0x00
|
||
Pro_Group_VCMM[i][0] = 0x00;
|
||
Pro_Group_VCMM[i][1] = 0x00;
|
||
break;
|
||
case 1: // EPRPDO → src=0x03, pps=0x00
|
||
Pro_Group_VCMM[i][0] = 0x00;
|
||
Pro_Group_VCMM[i][1] = 0x01;
|
||
break;
|
||
case 2: // PPS → src=0x03, pps=0x00
|
||
Pro_Group_VCMM[i][0] = 0x03;
|
||
Pro_Group_VCMM[i][1] = 0x00;
|
||
break;
|
||
case 3: // EPR AVS → src=0x03, pps=0x01
|
||
Pro_Group_VCMM[i][0] = 0x03;
|
||
Pro_Group_VCMM[i][1] = 0x01;
|
||
break;
|
||
default:
|
||
rt_kprintf("parse_mulit_gear_pd0:unknown PDO type=%d\n", pdo_type);
|
||
continue;
|
||
}
|
||
|
||
// 4. 解析电压/电流/功率(16位值)
|
||
switch (pdo_type) {
|
||
case 0: // FPDO(固定电源)
|
||
case 1: // EPRPDO(固定电源)
|
||
vmin_mv = vmax_mv = ((pdo_val >> 10) & 0x03FF) * 50; // 电压(mV)
|
||
cur_power = (pdo_val & 0x03FF) * 10; // 电流(mA)
|
||
break;
|
||
case 2: // PPS(可编程电源)
|
||
vmin_mv = ((pdo_val >> 8) & 0x00FF) * 100; // 最小电压(mV)
|
||
vmax_mv = ((pdo_val >> 17) & 0x00FF) * 100; // 最大电压(mV)
|
||
cur_power = (pdo_val & 0x7F) * 50; // 电流(mA)
|
||
break;
|
||
case 3: // EPR AVS(功率型)
|
||
vmin_mv = ((pdo_val >> 8) & 0x00FF) * 100; // 最小电压(mV)
|
||
vmax_mv = ((pdo_val >> 17) & 0x1FF) * 100; // 最大电压(mV)
|
||
cur_power = (pdo_val & 0xFF) * 1; // 功率(W)
|
||
break;
|
||
default:
|
||
vmin_mv = vmax_mv = cur_power = 0;
|
||
break;
|
||
}
|
||
// 5. 拆分高低字节填充缓冲区
|
||
Pro_Group_VCMM[i][2] = (vmin_mv >> 8) & 0xFF; // vmin_H
|
||
Pro_Group_VCMM[i][3] = vmin_mv & 0xFF; // vmin_L
|
||
Pro_Group_VCMM[i][4] = (vmax_mv >> 8) & 0xFF; // vmax_H
|
||
Pro_Group_VCMM[i][5] = vmax_mv & 0xFF; // vmax_L
|
||
Pro_Group_VCMM[i][6] = (cur_power >> 8) & 0xFF; // cur_set_H
|
||
Pro_Group_VCMM[i][7] = cur_power & 0xFF; // cur_set_L
|
||
#if NORTH_SOURCE_DEBUG
|
||
// 调试打印
|
||
rt_kprintf("parse_mulit_gear_pd0 PDO[%d]:rc=0x%02X, pps=0x%02X,V_Min=%dmV,V_MAX=%dmV,C/P=%d\n",
|
||
i, Pro_Group_VCMM[i][0], Pro_Group_VCMM[i][1], vmin_mv, vmax_mv, cur_power);
|
||
#endif
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: parse_power_multi_gear_more
|
||
函数描述: 三-四档电源协议解析函数(FCP/AFC/SCPA)
|
||
输入参数: protoCmd: 协议命令码(0x22/0x29/0x2C/0x2F)
|
||
pData: 协议数据区缓冲区(状态+通道+CC线+挡位数量+PDO组+保护电流+补偿电压)
|
||
reqLen: 帧总长度
|
||
pSW: 通道协议配置结构体指针
|
||
输出参数: -
|
||
返回说明: -
|
||
其它说明: 1. FCP/AFC/SCPA:挡位数量(1)+PDO组(4*N)+保护电流(2)+补偿电压(2)
|
||
2. UFCS:挡位数量(1)+PDO组(4*3)+保护电流(2)+补偿电压(2)
|
||
*****************************************************************/
|
||
void parse_multi_gear_more(rt_uint8_t protoCmd, rt_uint8_t *pData, rt_uint16_t reqLen,uint8_t *pro_gear_idx,uint8_t *pro,rt_uint16_t *protect_ma)
|
||
{
|
||
rt_uint8_t gear_num = 0; // 挡位数量
|
||
rt_int16_t comp_volt_mv = 0;// 补偿电压(mV)
|
||
|
||
// 数据区索引:0=状态+通道,1=CC线,2=恒压恒流模式,3=挡位数量
|
||
gear_num = pData[3];
|
||
//挡位数量
|
||
if(gear_num > 11) {
|
||
rt_kprintf("THE GEARNUM MORE 11 GEAR_NUM=%d\n", gear_num);
|
||
return;
|
||
}
|
||
*pro_gear_idx = gear_num;
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("pro_gear_idx = %d\n",gear_num);
|
||
#endif
|
||
// 解析保护电流和补偿电压(不同协议偏移不同)
|
||
switch (protoCmd)
|
||
{
|
||
case 0x22: // FCP (挡位数量+PDO组(4*4)+保护电流+补偿电压)
|
||
*pro = PRO_FCP;
|
||
break;
|
||
case 0x29: // AFC (同FCP)
|
||
*pro = PRO_AFC;
|
||
break;
|
||
case 0x2F: // SCPA (同FCP)
|
||
*pro = PRO_SCPA;
|
||
break;
|
||
default:
|
||
rt_kprintf("THE PRO NO MORE PRO PRO=%02X\n", protoCmd);
|
||
return;
|
||
}
|
||
*protect_ma = u8v_to_u16(&pData[4 + 16]); // 19-20字节
|
||
comp_volt_mv = (rt_int16_t)u8v_to_u16(&pData[4 + 18]);
|
||
#if NORTH_SOURCE_DEBUG
|
||
for(int i = 0;i<30;i++){
|
||
rt_kprintf("data[%d]=%02x",i,pData[i]);
|
||
}
|
||
rt_kprintf("protect_curr=%d\n",*protect_ma);
|
||
#endif
|
||
// 解析PDO组(小端序)
|
||
parse_mulit_gear_more(&pData[4],gear_num);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: parse_ufcs_gear
|
||
函数描述: 解析UFCS协议单组PDO数据(EPR AVS类型),填充8参数高低字节缓冲区
|
||
输入参数: pData: UFCS单组PDO原始数据缓冲区(4字节)
|
||
gear_idx: 当前挡位索引(0开始)
|
||
输出参数: -
|
||
返回说明: 0:成功 1:参数错误
|
||
其它说明: UFCS协议固定为EPR AVS类型(Bit30-31=3),规则:
|
||
Bit0-7:功率(1=1W) Bit8-15:最小电压(1=100mV) Bit17-25:最大电压(1=100mV)
|
||
缓冲区前两位固定为0(类型+PPS值)
|
||
*****************************************************************/
|
||
rt_uint8_t parse_ufcs_gear_more(rt_uint8_t *pData, rt_uint8_t gear_num) {
|
||
// 入参合法性校验
|
||
if (pData == RT_NULL || gear_num == 0 || gear_num > 11) {
|
||
rt_kprintf("parse_ufcs_gear_more:invalid params (gear_num=%d)\n", gear_num);
|
||
return 1;
|
||
}
|
||
|
||
// 清空缓冲区
|
||
rt_memset(Pro_Group_VCMM, 0, sizeof(Pro_Group_VCMM));
|
||
|
||
rt_uint32_t pdo_val = 0;
|
||
rt_uint16_t vmin_mv = 0, vmax_mv = 0, cur_ma = 0;
|
||
|
||
for (rt_uint8_t i = 0; i < gear_num; i++) {
|
||
// 1. 拼接32位PDO
|
||
pdo_val = (rt_uint32_t)pData[i*4 + 3] << 24 |
|
||
(rt_uint32_t)pData[i*4 + 2] << 16 |
|
||
(rt_uint32_t)pData[i*4 + 1] << 8 |
|
||
(rt_uint32_t)pData[i*4];
|
||
|
||
// ================= 固定 =================
|
||
Pro_Group_VCMM[i][0] = 0x00;
|
||
Pro_Group_VCMM[i][1] = 0x00;
|
||
|
||
// ================= 位规则 =================
|
||
// Bit0-6 电流 1=50mA
|
||
cur_ma = (pdo_val & 0x3F) * 100;//原50,乘2了
|
||
|
||
// Bit8-15 最小电压 1=100mV
|
||
vmin_mv = ((pdo_val >> 8) & 0xFF) * 100;
|
||
|
||
// Bit17-25 最大电压 1=100mV
|
||
vmax_mv = ((pdo_val >> 17) & 0x1FF) * 100;
|
||
|
||
// ================= 填充缓冲区 =================
|
||
Pro_Group_VCMM[i][2] = (vmin_mv >> 8) & 0xFF;
|
||
Pro_Group_VCMM[i][3] = vmin_mv & 0xFF;
|
||
Pro_Group_VCMM[i][4] = (vmax_mv >> 8) & 0xFF;
|
||
Pro_Group_VCMM[i][5] = vmax_mv & 0xFF;
|
||
Pro_Group_VCMM[i][6] = (cur_ma >> 8) & 0xFF;
|
||
Pro_Group_VCMM[i][7] = cur_ma & 0xFF;
|
||
#if NORTH_SOURCE_DEBUG
|
||
// ================= 打印格式 =================
|
||
rt_kprintf("parse_ufcs_gear_more PDO[%d]:PPS/AVS,V_Min=%dmV,V_MAX=%dmV,Max_Current=%dmA\n",
|
||
i, vmin_mv, vmax_mv, cur_ma);
|
||
#endif
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: parse_power_ufcs
|
||
函数描述: UFCS协议专属解析函数(独立于多档位通用函数)
|
||
输入参数: pData: 协议数据区缓冲区(状态+通道+CC线+挡位数量+PDO组+保护电流+补偿电压)
|
||
reqLen: 帧总长度
|
||
pro_gear_idx: 输出有效挡位数量
|
||
pro: 输出协议类型(赋值为PRO_UFCS)
|
||
输出参数: -
|
||
返回说明: -
|
||
其它说明: UFCS固定格式:挡位数量(1)+PDO组(4*3)+保护电流(2)+补偿电压(2)
|
||
仅解析UFCS协议,不兼容其他多档位协议
|
||
*****************************************************************/
|
||
void parse_power_ufcs(rt_uint8_t *pData, rt_uint16_t reqLen, uint8_t *pro_gear_idx, uint8_t *pro,rt_uint16_t *protect_ma)
|
||
{
|
||
rt_uint8_t gear_num = 0;
|
||
rt_int16_t comp_volt_mv = 0;
|
||
|
||
gear_num = pData[3];
|
||
|
||
if(gear_num > 11) {
|
||
rt_kprintf("parse_power_ufcs: gear_num >11, set=3\n");
|
||
gear_num = 3;
|
||
}
|
||
|
||
*pro_gear_idx = gear_num;
|
||
*pro = PRO_UFCS;
|
||
|
||
// UFCS偏移
|
||
|
||
*protect_ma = u8v_to_u16(&pData[4 + 12]);
|
||
// for(int i = 0;i<24;i++){
|
||
// rt_kprintf("data[%d]=%02x",i,pData[i]);
|
||
// }
|
||
comp_volt_mv = 0;//(rt_int16_t)u8v_to_u16(&pData[3 + 14]);
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("parse_power_ufcs:gear=%d,protect=%dmA,comp=%dmV\n",
|
||
gear_num,*protect_ma, comp_volt_mv);
|
||
#endif
|
||
|
||
// 调用下面的循环解析
|
||
parse_ufcs_gear_more(&pData[4], gear_num);
|
||
}
|
||
|
||
static rt_uint8_t pd_fill_single_group(rt_uint8_t *data, rt_uint8_t start_idx, rt_uint8_t group_idx,rt_uint16_t max_cur)
|
||
{
|
||
// 校验索引合法性
|
||
if (group_idx >= PD_VOLTAGE_CNT) {
|
||
rt_kprintf("ERROR GROUP IDX EXCEED IDX=%d)\n", group_idx);
|
||
return 0;
|
||
}
|
||
|
||
rt_uint8_t idx = start_idx;
|
||
const Pro_Group *target_group = &pd_voltage_map[group_idx]; // 仅取目标挡位
|
||
|
||
|
||
// 1. 填充pro + src(2字节)
|
||
data[idx++] = target_group->src;
|
||
data[idx++] = target_group->pps;
|
||
|
||
// 2. 填充电压最小值(2字节,高8位+低8位)
|
||
data[idx++] = (target_group->v_min >> 8) & 0xff;
|
||
data[idx++] = target_group->v_min & 0xff;
|
||
|
||
// 3. 填充电压最大值(2字节,高8位+低8位)
|
||
data[idx++] = (target_group->v_max >> 8) & 0xff;
|
||
data[idx++] = target_group->v_max & 0xff;
|
||
|
||
// 4. 填充电流设置值(2字节,高8位+低8位)
|
||
data[idx++] = (max_cur >> 8) & 0xff;
|
||
data[idx++] = max_cur & 0xff;
|
||
|
||
// 5. 填充保留位(6字节全0)
|
||
for (rt_uint8_t j = 0; j < 6; j++) {
|
||
data[idx++] = 0x00;
|
||
}
|
||
return idx - start_idx; // 返回填充的总字节数
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: source_set_pd
|
||
函数描述: source 设置PD协议
|
||
输入参数: pro:协议 src:源 pps: PPS vmax:最大电压 vmin:最小电压 max_cur:最大电流
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:发送长度
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int source_set_pd (rt_uint8_t pro, rt_uint8_t src, rt_uint8_t pps,
|
||
rt_uint16_t vmax, rt_uint16_t vmin, rt_int16_t max_cur)
|
||
{
|
||
|
||
rt_uint16_t len = 0;
|
||
rt_uint8_t data[80] = {0};
|
||
rt_uint8_t frame[80] = {0};
|
||
rt_uint8_t send_len = 0; //数据长度
|
||
rt_uint8_t max_group_idx = 0; //挡位索引
|
||
data[0] = pro; //协议
|
||
//rt_kprintf("cur_pro=%d",max_cur);
|
||
if(pro==0x07||pro==0x08||pro==0x03){
|
||
data[1] = 0;//src
|
||
data[2] = 0;//pps
|
||
data[3] = 0x13;//固定电压最小值为5V
|
||
data[4] = 0x88;
|
||
data[5] = (vmax>>8)&0xff;//电压最大值为设定电压
|
||
data[6] = vmax&0xff;
|
||
data[7] = (max_cur>>8)&0xff;//电流输出为设置值
|
||
data[8] = max_cur&0xff;
|
||
for (rt_uint8_t j = 9; j < 14; j++) {
|
||
data[j] = 0x00;
|
||
}
|
||
send_len=15;
|
||
}
|
||
else{
|
||
switch (vmax)
|
||
{
|
||
case 5000: max_group_idx = 0; break;
|
||
case 9000: max_group_idx = 1; break;
|
||
case 12000: max_group_idx = 2; break;
|
||
case 20000: max_group_idx = 3; break;
|
||
case 48000: max_group_idx = 4; break;
|
||
default:rt_kprintf("VOLT ERROR");break;
|
||
}
|
||
rt_uint8_t idx = 1; //从data[1]开始填充
|
||
// 循环填充从0到max_group_idx的所有挡位
|
||
for (rt_uint8_t i = 0; i <= max_group_idx; i++) {
|
||
rt_uint8_t fill_len = pd_fill_single_group(data, idx, i,max_cur);
|
||
if (fill_len == 0) {
|
||
rt_kprintf("Error: fill group %d failed\n", i);
|
||
return -1;
|
||
}
|
||
idx += fill_len; // 偏移到下一组起始位置
|
||
}
|
||
send_len = idx; // 总填充字节数
|
||
}
|
||
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_SET_PROTOCOL, data, send_len, frame, &len);
|
||
return chrg_north_send(frame, len);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: pd_fill_single_group
|
||
函数描述: 填充单个PD挡位的协议数据
|
||
输入参数: data:目标字节数组 start_idx:数组起始填充位置 group_idx:要调用的挡位索引(0=5V,1=9V...4=PPS)
|
||
输出参数: -
|
||
返回说明: 0:索引越界/错误 >0:填充的字节数(固定14字节)
|
||
其它说明: -
|
||
*****************************************************************/
|
||
rt_uint8_t pd_fill_single_group_com(rt_uint8_t *data, rt_uint8_t start_idx, rt_uint8_t gear)
|
||
{
|
||
// 核心:直接索引已拆分好的高低位缓冲区,按位填充(无任何多余运算)
|
||
rt_uint8_t idx = start_idx;
|
||
// 1. src + pps(2字节)
|
||
data[idx++] = Pro_Group_VCMM[gear][0];
|
||
data[idx++] = Pro_Group_VCMM[gear][1];
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = Pro_Group_VCMM[gear][2];
|
||
data[idx++] = Pro_Group_VCMM[gear][3];
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = Pro_Group_VCMM[gear][4];
|
||
data[idx++] = Pro_Group_VCMM[gear][5];
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = Pro_Group_VCMM[gear][6];
|
||
data[idx++] = Pro_Group_VCMM[gear][7];
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
return idx - start_idx; // 返回填充的总字节数
|
||
}
|
||
|
||
rt_uint8_t pd_fill_single_group_need_src_com(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
|
||
|
||
rt_uint8_t idx = start_idx;
|
||
struct chrg_src_t *source = &psw->source;
|
||
const struct vc_pd_t *pd = &source->pd_set;
|
||
const struct vc_mm_t *mm = &pd->mm;
|
||
// 1. src + pps(2字节)
|
||
data[idx++] = 0x00;
|
||
data[idx++] = 0x00;
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = 0x13;
|
||
data[idx++] = 0x88;
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = 0x13;
|
||
data[idx++] = 0x88;
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
data[idx++] = pd->src_type;
|
||
data[idx++] = pd->pps_type;
|
||
//rt_kprintf("src = %d pps = %d\n", pd->src_type, pd->pps_type);
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->min_vol >> 8;
|
||
data[idx++] = mm->min_vol & 0xFF;
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_vol >> 8;
|
||
data[idx++] = mm->max_vol & 0xFF;
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
return idx - start_idx; // 返回填充的总字节数
|
||
}
|
||
|
||
rt_uint8_t pd_fill_single_group_no_src_com(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
|
||
|
||
rt_uint8_t idx = start_idx;
|
||
struct chrg_src_t *source = &psw->source;
|
||
const struct vc_mm_t *mm = &source->pd_set.mm;
|
||
// 1. src + pps(2字节)
|
||
data[idx++] = 0x00;
|
||
data[idx++] = 0x00;
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = 0x13;//mm->min_vol >> 8;
|
||
data[idx++] = 0x18;//mm->min_vol & 0xFF;
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_vol >> 8;
|
||
data[idx++] = mm->max_vol & 0xFF;
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
return idx - start_idx; // 返回填充的总字节数
|
||
}
|
||
|
||
rt_uint8_t pd_fill_single_group_AFC(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
|
||
|
||
rt_uint8_t idx = start_idx;
|
||
struct chrg_src_t *source = &psw->source;
|
||
const struct vc_mm_t *mm = &source->pd_set.mm;
|
||
// 1. src + pps(2字节)
|
||
data[idx++] = 0x00;
|
||
data[idx++] = 0x00;
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = 0x13;
|
||
data[idx++] = 0x88;
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = 0x13;
|
||
data[idx++] = 0x88;
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
// 1. src + pps(2字节)
|
||
data[idx++] = 0x00;
|
||
data[idx++] = 0x00;
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_vol >> 8;
|
||
data[idx++] = mm->max_vol & 0xFF;
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_vol >> 8;
|
||
data[idx++] = mm->max_vol & 0xFF;
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
return idx - start_idx; // 返回填充的总字节数
|
||
}
|
||
|
||
rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
|
||
|
||
rt_uint8_t idx = start_idx;
|
||
struct chrg_src_t *source = &psw->source;
|
||
const struct vc_mm_t *mm = &source->pd_set.mm;
|
||
// 1. src + pps(2字节)
|
||
data[idx++] = 0x00;
|
||
data[idx++] = 0x00;
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = 0x13;
|
||
data[idx++] = 0x88;
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = 0x13;
|
||
data[idx++] = 0x88;
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
// 1. src + pps(2字节)
|
||
data[idx++] = 0x00;
|
||
data[idx++] = 0x00;
|
||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->min_vol >> 8;
|
||
data[idx++] = mm->min_vol & 0xFF;
|
||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_vol >> 8;
|
||
data[idx++] = mm->max_vol & 0xFF;
|
||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
// 5. 保留位6字节(直接填0)
|
||
memset(&data[idx], 0x00, 6);
|
||
idx+=6;
|
||
return idx - start_idx; // 返回填充的总字节数
|
||
}
|
||
|
||
static rt_uint8_t chrg_source_fill_AFC_three_gears(rt_uint8_t *data,
|
||
rt_uint8_t start_idx, struct chrg_switch_t *psw)
|
||
{
|
||
static const rt_uint16_t fixed_voltages[] = {5000U, 9000U, 12000U, 20000U};
|
||
const struct vc_mm_t *mm = &psw->source.pd_set.mm;
|
||
rt_uint8_t idx = start_idx;
|
||
rt_uint8_t gear;
|
||
|
||
for (gear = 0; gear < (sizeof(fixed_voltages) / sizeof(fixed_voltages[0]));
|
||
gear++) {
|
||
/* FCP固定电压档不使用PD源类型和PPS类型。 */
|
||
data[idx++] = 0x00;
|
||
data[idx++] = 0x00;
|
||
data[idx++] = fixed_voltages[gear] >> 8;
|
||
data[idx++] = fixed_voltages[gear] & 0xFF;
|
||
data[idx++] = fixed_voltages[gear] >> 8;
|
||
data[idx++] = fixed_voltages[gear] & 0xFF;
|
||
data[idx++] = mm->max_cur >> 8;
|
||
data[idx++] = mm->max_cur & 0xFF;
|
||
memset(&data[idx], 0x00, 6);
|
||
idx += 6;
|
||
}
|
||
|
||
return idx - start_idx;
|
||
}
|
||
|
||
int source_set_pro(rt_uint8_t pro, struct chrg_switch_t *pSW)
|
||
{
|
||
rt_uint16_t len = 0;
|
||
rt_uint8_t data[150] = {0};
|
||
rt_uint8_t frame[150] = {0};
|
||
rt_uint8_t send_len = 0; //数据长度
|
||
rt_uint8_t max_group_idx = 0; //挡位索引
|
||
data[0] = pro; //协议
|
||
rt_uint8_t idx = 1; //从data[1]开始填充
|
||
rt_uint8_t fill_len = 0;
|
||
rt_uint8_t protocal = pSW->source.protocol;
|
||
if(protocal == PRO_PD0PSS){
|
||
fill_len = pd_fill_single_group_need_src_com(data, idx, pSW);
|
||
}else if(protocal == PRO_SCPB||protocal == PRO_QC30||protocal == PRO_QC20 ||protocal == PRO_FCP ){
|
||
fill_len = pd_fill_single_group_no_src_com(data, idx, pSW);
|
||
}else if(protocal == PRO_UFCS){
|
||
fill_len = pd_fill_single_group_UFCS(data, idx, pSW);
|
||
}else{
|
||
fill_len = chrg_source_fill_AFC_three_gears(data, idx, pSW);
|
||
}
|
||
idx += fill_len;
|
||
send_len = idx; // 总填充字节数
|
||
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_SET_PROTOCOL, data, send_len, frame, &len);
|
||
#if NORTH_SOURCE_DEBUG
|
||
rt_kprintf("source protocol frame:");
|
||
for (rt_uint16_t i = 0; i < len; i++) {
|
||
rt_kprintf(" %02x", frame[i]);
|
||
}
|
||
rt_kprintf("\n");
|
||
#endif
|
||
// for(rt_uint8_t i=0;i<idx;i++){
|
||
// rt_kprintf("%02x",data[i]);
|
||
// }
|
||
// rt_kprintf("idx=%d",idx);
|
||
return chrg_north_send(frame, len);
|
||
}
|
||
|