Files
chrg/apps/chrg/applications/utils/chrg_source.c
T
wrh 06dbecfeb6 chore: 升级版本到V1.1.9,下一版本开始调试新协议板
1.  更新所有文件的版本号注释从V1.1.8到V1.1.9
2.  修改chrg_comm.c中的固件版本宏定义和注释
3.  在修改日志中新增V1.1.9版本的更新内容
4.  添加Allegro设计文件的锁定日志和工程文件
2026-08-25 19:54:40 +08:00

1316 lines
48 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_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, &reg, &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, &reg, &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, &reg, &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);
}