From a8f2edd62425b13d77fdd04a4931c9693c2eea69 Mon Sep 17 00:00:00 2001 From: wrh Date: Fri, 9 Oct 2026 11:05:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9ESink=E6=9D=BFD+/D-?= =?UTF-8?q?=E6=A0=A1=E5=87=86=E5=8F=82=E6=95=B0=E5=86=99=E5=85=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增SINK_CMD_SET_DPDM_CAL命令定义及对应寄存器 2. 新增校准参数结构体及相关任务提交、查询接口 3. 修改北向帧校验逻辑适配校准写入的6字节长度要求 4. 更新协议板版本至V1.1.56,寄存器版本号更新为0x0148 5. 修改Sink电压稳定确认参数,优化5V电压确认计数 6. 新增校准参数配置比较函数,独立处理校准写入事务 7. 更新修改日志,记录本次版本新增功能详情 --- apps/chrg/applications/thread/chrg_comm.c | 45 ++++++++- apps/chrg/applications/thread/chrg_north.c | 5 +- apps/chrg/applications/thread/chrg_north.h | 2 +- apps/chrg/applications/thread/chrg_roll_nor.c | 87 ++++++++++++++++++ apps/chrg/applications/thread/chrg_roll_nor.h | 12 ++- apps/chrg/applications/utils/chrg_def.h | 3 +- apps/chrg/applications/utils/chrg_regs.h | 6 ++ apps/chrg/applications/utils/chrg_sink.c | 27 ++++++ apps/chrg/applications/utils/chrg_sink.h | 21 ++++- ...00-4多协议可编程双向电源通信协议V_1.2.xlsx | Bin 18322 -> 18778 bytes docs/修改日志.md | 10 ++ 11 files changed, 211 insertions(+), 7 deletions(-) diff --git a/apps/chrg/applications/thread/chrg_comm.c b/apps/chrg/applications/thread/chrg_comm.c index c229dcf..d442c1f 100644 --- a/apps/chrg/applications/thread/chrg_comm.c +++ b/apps/chrg/applications/thread/chrg_comm.c @@ -27,7 +27,7 @@ #include "stm32f4xx_hal.h" #define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */ -#define CHRG_FIRMWARE_VERSION 0x0147U /* 当前协议板版本:V1.1.55 */ +#define CHRG_FIRMWARE_VERSION 0x0148U /* 当前协议板版本:V1.1.56 */ rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR]; @@ -1735,6 +1735,18 @@ static void chrg_mb_write_sink(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_ case SINK_REG_DYNA_UNLOAD: // 0x1E: 卸载斜率 pSW->sink.test.change_test.k_Fall = sou_value; break; + case SINK_REG_DPDM_DZ_K: // D+ K,实际比例系数放大10000倍 + pSW->sink.dpdm_cal.dz_k = sou_value; + break; + case SINK_REG_DPDM_DZ_B: // D+ B,单位0.01V,有符号16位 + pSW->sink.dpdm_cal.dz_b = (rt_int16_t)sou_value; + break; + case SINK_REG_DPDM_DF_K: // D- K,实际比例系数放大10000倍 + pSW->sink.dpdm_cal.df_k = sou_value; + break; + case SINK_REG_DPDM_DF_B: // D- B,单位0.01V,有符号16位 + pSW->sink.dpdm_cal.df_b = (rt_int16_t)sou_value; + break; default: rt_kprintf("[SINK CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset); break; @@ -1868,6 +1880,16 @@ static rt_bool_t chrg_comm_sink_config_equal(const struct chrg_switch_t *a, sizeof(a->sink.test.change_test)) == 0); } +/* D+/D-校准参数为独立北向事务,不并入普通负载状态机配置比较。 */ +static rt_bool_t chrg_comm_sink_dpdm_cal_equal(const struct chrg_switch_t *a, + const struct chrg_switch_t *b) +{ + return (a->sink.dpdm_cal.dz_k == b->sink.dpdm_cal.dz_k) && + (a->sink.dpdm_cal.dz_b == b->sink.dpdm_cal.dz_b) && + (a->sink.dpdm_cal.df_k == b->sink.dpdm_cal.df_k) && + (a->sink.dpdm_cal.df_b == b->sink.dpdm_cal.df_b); +} + /***************************************************************** 函数名称: chrg_comm_copy_sink_config 函数描述: 将PC配置逐项应用到Sink,保留实际运行状态、旧测试模式和量测 @@ -2373,6 +2395,27 @@ static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, } status = (switch_ret == 0) ? MB_EX_NONE : MB_EX_SLAVE_BUSY; } else if (new_id == ID_SINK) { + /* + * D+/D-校准参数不是负载工作参数:上位机依次写入四个保持寄存器后, + * 必须单独写PARAM_EFFECT提交。若同时改了协议、CC或带载参数, + * 本次拒绝提交,避免校准写入抢占正在进行的负载状态机。 + */ + if (!chrg_comm_sink_dpdm_cal_equal(pReal, pSW)) { + if (!chrg_comm_sink_config_equal(pReal, pSW)) { + status = MB_EX_SLAVE_BUSY; + } else if (chrg_roll_nor_sink_dpdm_cal_submit(ch, pReal, + &pSW->sink.dpdm_cal) != 0) { + status = MB_EX_SLAVE_BUSY; + } else { + pNOR->config_version[ch]++; + status = MB_EX_NONE; + } + if (status != MB_EX_NONE) { + g_shadow_dirty[ch] = 1; + } + rt_mutex_release(pTHR_NOR->mutex); + return status; + } sink_config_changed = !chrg_comm_sink_config_equal(pReal, pSW); old_sink_sub = pReal->sub; old_sink_on = pReal->sink.On_work; diff --git a/apps/chrg/applications/thread/chrg_north.c b/apps/chrg/applications/thread/chrg_north.c index 9cf20ed..a8389b7 100644 --- a/apps/chrg/applications/thread/chrg_north.c +++ b/apps/chrg/applications/thread/chrg_north.c @@ -429,6 +429,7 @@ static rt_bool_t chrg_north_frame_shape_valid(eIDX_ID id, if (id == ID_SINK) { switch (command) { case SINK_CMD_RESET: + case SINK_CMD_SET_DPDM_CAL: case SINK_CMD_SET_CC: case SINK_CMD_SET_LEVEL: case SINK_CMD_SET_QC20: @@ -445,7 +446,9 @@ static rt_bool_t chrg_north_frame_shape_valid(eIDX_ID id, case SINK_CMD_SET_VOOC: case SINK_CMD_SET_AVS: case LOAD_PRO_NONE: - return (length == MIN_FRAME_LENGTH) ? RT_TRUE : RT_FALSE; + return (command == SINK_CMD_SET_DPDM_CAL) ? + ((length == 6U) ? RT_TRUE : RT_FALSE) : + ((length == MIN_FRAME_LENGTH) ? RT_TRUE : RT_FALSE); default: return RT_FALSE; } diff --git a/apps/chrg/applications/thread/chrg_north.h b/apps/chrg/applications/thread/chrg_north.h index 619eabf..e505e3c 100644 --- a/apps/chrg/applications/thread/chrg_north.h +++ b/apps/chrg/applications/thread/chrg_north.h @@ -16,7 +16,7 @@ #include "chrg_def.h" /* V_On启停判定电压源:切换后需重新编译固件。 */ -#define SINK_VON_VOLTAGE_FROM_PROTOCOL 6U +#define SINK_VON_VOLTAGE_FROM_PROTOCOL 1U #define SINK_VON_VOLTAGE_FROM_POWER 2U #ifndef SINK_VON_VOLTAGE_SOURCE #define SINK_VON_VOLTAGE_SOURCE SINK_VON_VOLTAGE_FROM_POWER diff --git a/apps/chrg/applications/thread/chrg_roll_nor.c b/apps/chrg/applications/thread/chrg_roll_nor.c index 9fbcd43..d0452bd 100644 --- a/apps/chrg/applications/thread/chrg_roll_nor.c +++ b/apps/chrg/applications/thread/chrg_roll_nor.c @@ -61,6 +61,17 @@ static rt_uint8_t g_sink_reset_next_sub[TOTAL_NOR_CHS] = {0}; /* 仅CC参数实际变化的通道才会断开D+/D-/CC,并在CC稳定后恢复。 */ static rt_uint8_t g_sink_cc_relay_close_mask = 0U; static rt_uint8_t g_sink_cc_relay_restore_mask = 0U; +/* D+/D-校准写入任务按通道独立保存,避免与普通0x20轮询共用参数缓存。 */ +struct sink_dpdm_cal_job_t { + struct sink_dpdm_cal_t cal; + rt_bool_t pending; + rt_uint8_t status; +}; +#define SINK_DPDM_CAL_STATUS_IDLE 0U +#define SINK_DPDM_CAL_STATUS_PENDING 1U +#define SINK_DPDM_CAL_STATUS_SUCCESS 2U +#define SINK_DPDM_CAL_STATUS_TIMEOUT 0x80U +static struct sink_dpdm_cal_job_t g_sink_dpdm_cal_job[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}; @@ -144,6 +155,29 @@ void chrg_roll_nor_sink_reset_cancel(rt_uint8_t ch) g_sink_cc_relay_restore_mask &= (rt_uint8_t)~SOURCE_CHANNEL_BIT(ch); } +rt_bool_t chrg_roll_nor_sink_dpdm_cal_pending(rt_uint8_t ch) +{ + return (ch < TOTAL_NOR_CHS) && g_sink_dpdm_cal_job[ch].pending; +} + +int chrg_roll_nor_sink_dpdm_cal_submit(rt_uint8_t ch, + struct chrg_switch_t *pSW, const struct sink_dpdm_cal_t *pCal) +{ + if ((ch >= TOTAL_NOR_CHS) || (pSW == RT_NULL) || (pCal == RT_NULL)) { + return -1; + } + /* 校准写入只抢占普通量测,不能覆盖初始化、协议/CC切换等事务。 */ + if (g_sink_dpdm_cal_job[ch].pending || (pSW->id != ID_SINK) || + (pSW->sub != IDX_GET_SINK_VC)) { + return -2; + } + g_sink_dpdm_cal_job[ch].cal = *pCal; + g_sink_dpdm_cal_job[ch].pending = RT_TRUE; + g_sink_dpdm_cal_job[ch].status = SINK_DPDM_CAL_STATUS_PENDING; + pSW->sub = IDX_SET_SINK_DPDM_CAL; + return 0; +} + void chrg_roll_nor_sink_cc_switch_prepare(rt_uint8_t ch, rt_bool_t cc_changed) { @@ -686,6 +720,8 @@ static rt_uint8_t chrg_roll_nor_expected_cmd(const struct chrg_switch_t *pSW) return SINK_CMD_SET_CC; case IDX_SET_SINK_CCLVL: return SINK_CMD_SET_LEVEL; + case IDX_SET_SINK_DPDM_CAL: + return SINK_CMD_SET_DPDM_CAL; default: return 0; } @@ -729,8 +765,12 @@ static int chrg_roll_nor_response_matches(const struct mb_msg_t *pMB, if ((expected_cmd == SRC_CMD_GET_VOLTAGE) && (pMB->length != 21U)) { return -3; } + if ((expected_cmd == SINK_CMD_SET_DPDM_CAL) && (pMB->length != 6U)) { + return -4; + } if ((expected_cmd != SRC_CMD_GET_VOLTAGE) && (expected_cmd != SRC_CMD_GET_PROTOCOL) && + (expected_cmd != SINK_CMD_SET_DPDM_CAL) && (pMB->length != MIN_FRAME_LENGTH)) { return -4; } @@ -910,6 +950,11 @@ static int chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW, 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_DPDM_CAL: + if (!g_sink_dpdm_cal_job[ch].pending) { + return -1; + } + return sink_set_dpdm_cal(&g_sink_dpdm_cal_job[ch].cal); case IDX_SET_SINK_PD: /* 只有协议回码确认后,下一轮才允许进入电压查询。 */ *next_sub = IDX_WAIT_SINK_PD_ACK; @@ -1030,6 +1075,26 @@ static int chrg_roll_nor_auto_request(rt_uint8_t idx, g_sink_reset_next_sub[idx] = 0U; advance_sub = RT_FALSE; } + } else if ((expected_id == ID_SINK) && + (request_sub == IDX_SET_SINK_DPDM_CAL)) { + /* + * 0x32回码格式:06 NC ID 32 STATUS CRC。 + * 只有STATUS为0才把任务参数提交到实时结构;否则保留原参数, + * 并回到0x20普通量测状态,避免失败写入影响负载流程。 + */ + g_sink_dpdm_cal_job[idx].pending = RT_FALSE; + g_sink_dpdm_cal_job[idx].status = pMB->payload[4]; + pSW->sub = IDX_GET_SINK_VC; + advance_sub = RT_FALSE; + if (pMB->payload[4] == 0U) { + pSW->sink.dpdm_cal = g_sink_dpdm_cal_job[idx].cal; + g_sink_dpdm_cal_job[idx].status = + SINK_DPDM_CAL_STATUS_SUCCESS; + LOG_I("sink dpdm cal write success: ch=%d", idx + 1U); + } else { + LOG_E("sink dpdm cal write failed: ch=%d status=%u", + idx + 1U, pMB->payload[4]); + } } else if ((expected_id == ID_SINK) && ((request_sub == IDX_SET_SINK_CCLINE) || (request_sub == IDX_SET_SINK_CC_BEFORE_PD) || @@ -1053,6 +1118,16 @@ static int chrg_roll_nor_auto_request(rt_uint8_t idx, 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); + if ((expected_id == ID_SINK) && + (request_sub == IDX_SET_SINK_DPDM_CAL)) { + rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER); + g_sink_dpdm_cal_job[idx].pending = RT_FALSE; + g_sink_dpdm_cal_job[idx].status = SINK_DPDM_CAL_STATUS_TIMEOUT; + if (pSW->sub == IDX_SET_SINK_DPDM_CAL) { + pSW->sub = IDX_GET_SINK_VC; + } + rt_mutex_release(pTHR->mutex); + } return -1; } @@ -1152,6 +1227,18 @@ void chrg_roll_nor_thread_entry (void *data) rt_thread_mdelay(2); continue; } + /* 校准写入任务不依赖通道运行使能,优先占用一次北向事务。 */ + if (chrg_roll_nor_sink_dpdm_cal_pending(idx)) { + if ((chrg_north_switch((eIDX_NOR_CH)idx) == 0) && + (chrg_north_request_begin((eIDX_NOR_CH)idx) != 0U)) { + 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; + } if (source_waiting || sink_waiting) { CHRG_CHANNEL_NEXT(index); rt_thread_mdelay(2); diff --git a/apps/chrg/applications/thread/chrg_roll_nor.h b/apps/chrg/applications/thread/chrg_roll_nor.h index 75ad32e..cf197ba 100644 --- a/apps/chrg/applications/thread/chrg_roll_nor.h +++ b/apps/chrg/applications/thread/chrg_roll_nor.h @@ -11,6 +11,9 @@ #include +struct chrg_switch_t; +struct sink_dpdm_cal_t; + #define THR_NAME_ROLL_NOR "thr.rollnor" #define STATE_WORKING 0x03//运行标志位 enum { @@ -41,7 +44,8 @@ enum { IDX_SET_SINK_CC_BEFORE_PD_WITH_MODE, IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE, IDX_SET_SINK_MODE_AFTER_PD, - IDX_WAIT_SINK_MODE_AFTER_PD + IDX_WAIT_SINK_MODE_AFTER_PD, + IDX_SET_SINK_DPDM_CAL // 上位机校准参数写入Sink板0x32 }; struct chrg_rollnor_t { @@ -112,6 +116,12 @@ extern void chrg_roll_nor_sink_cc_switch_prepare(rt_uint8_t ch, /* 低电流确认完成后,按登记结果断开D+/D-/CC继电器。 */ extern void chrg_roll_nor_sink_cc_relay_close(rt_uint8_t ch); +/* 提交Sink板D+/D-校准参数写入任务;仅空闲量测状态允许提交。 */ +extern int chrg_roll_nor_sink_dpdm_cal_submit(rt_uint8_t ch, + struct chrg_switch_t *pSW, const struct sink_dpdm_cal_t *pCal); +/* 查询指定通道是否存在待执行的D+/D-校准写入任务。 */ +extern rt_bool_t chrg_roll_nor_sink_dpdm_cal_pending(rt_uint8_t ch); + #define sink_time 3 #endif diff --git a/apps/chrg/applications/utils/chrg_def.h b/apps/chrg/applications/utils/chrg_def.h index f47ea70..61ca267 100644 --- a/apps/chrg/applications/utils/chrg_def.h +++ b/apps/chrg/applications/utils/chrg_def.h @@ -14,8 +14,7 @@ /* CHRG application version. Keep this value synchronized with the changelog. */ #define CHRG_VERSION_MAJOR 1U #define CHRG_VERSION_MINOR 1U -#define CHRG_VERSION_PATCH 55U -#define CHRG_VERSION_STRING "V1.1.55" + /* * Channel polling mode: diff --git a/apps/chrg/applications/utils/chrg_regs.h b/apps/chrg/applications/utils/chrg_regs.h index c18391e..8456f72 100644 --- a/apps/chrg/applications/utils/chrg_regs.h +++ b/apps/chrg/applications/utils/chrg_regs.h @@ -152,6 +152,12 @@ enum { #define SINK_REG_DYNA_TIME2 0x1C // ¸ºÔØ2±£³Öʱ¼ä (0.01ms) #define SINK_REG_DYNA_SLOPE 0x1D // ¶¯̬¼ÓÔØбÂÊ (0.001A/us) #define SINK_REG_DYNA_UNLOAD 0x1E // ¶¯̬жÔØбÂÊ (0.001A/us) +/* D+/D-У׼²ÎÊý£ºKΪÎ޷ûºÅ16루ʵ¼ʱÈÀýϵÊý¡Á10000£©£¬BΪÓзûºÅ16루0.01V£©¡£ + * ÉÏλ»úдÍêËÄÏîºó£¬д±¾ͨµÀSYS_REG_PARAM_EFFECT=1£¬ÓÉ405ת·¢Sink 0x32¡£ */ +#define SINK_REG_DPDM_DZ_K 0x1F // D+ K +#define SINK_REG_DPDM_DZ_B 0x20 // D+ B +#define SINK_REG_DPDM_DF_K 0x21 // D- K +#define SINK_REG_DPDM_DF_B 0x22 // D- B // ---- µçԴ(Source)²ÎÊýƫÒÆ (Ïà¶ÔͨµÀ»ùµØַ: HOLD_REG_SRC_BASE + ch*6) ---- #define SRC_REG_PROTOCOL 0x00 // ЭÒéÀàÐÍ diff --git a/apps/chrg/applications/utils/chrg_sink.c b/apps/chrg/applications/utils/chrg_sink.c index a9c6c17..610dfbd 100644 --- a/apps/chrg/applications/utils/chrg_sink.c +++ b/apps/chrg/applications/utils/chrg_sink.c @@ -302,6 +302,33 @@ int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf) return chrg_north_send(frame, len); } +/***************************************************************** +函数名称: sink_set_dpdm_cal +函数描述: 向Sink协议板写入D+/D-校准参数 +输入参数: pCal:四个16位校准参数 +输出参数: - +返回说明: <0:发送失败 >0:发送长度 +其它说明: 所有字段按高字节在前发送;B按int16_t补码原样发送 +*****************************************************************/ +int sink_set_dpdm_cal(const struct sink_dpdm_cal_t *pCal) +{ + rt_uint16_t len = 0U; + rt_uint8_t data[8] = {0}; + rt_uint8_t frame[16] = {0}; + + if (pCal == RT_NULL) { + return -1; + } + u16_to_u8v(pCal->dz_k, &data[0]); + u16_to_u8v((rt_uint16_t)pCal->dz_b, &data[2]); + u16_to_u8v(pCal->df_k, &data[4]); + u16_to_u8v((rt_uint16_t)pCal->df_b, &data[6]); + /* 发送帧:0D NC 01 32 DZ_K DZ_B DF_K DF_B CRC,四个16位字段均为大端。 */ + chrg_north_pkg_encode(ID_SINK, SINK_CMD_SET_DPDM_CAL, + data, sizeof(data), frame, &len); + return chrg_north_send(frame, len); +} + static rt_uint8_t chrg_sink_init_build_commands(struct chrg_switch_t *pSW, rt_uint16_t *regs, rt_uint16_t *vals) { diff --git a/apps/chrg/applications/utils/chrg_sink.h b/apps/chrg/applications/utils/chrg_sink.h index 9c3d409..426cd83 100644 --- a/apps/chrg/applications/utils/chrg_sink.h +++ b/apps/chrg/applications/utils/chrg_sink.h @@ -71,7 +71,15 @@ struct test #define SINK_CMD_GET_VOLTAGE 0x20 // 读取变电压板电压 #define SINK_CMD_RESET 0x01 // 复位Sink协议板 +#define SINK_CMD_SET_DPDM_CAL 0x32 // 写入D+/D-校准参数 +/* D+/D-校准系数:K为实际比例系数放大10000倍,B单位为0.01V。 */ +struct sink_dpdm_cal_t { + rt_uint16_t dz_k; + rt_int16_t dz_b; + rt_uint16_t df_k; + rt_int16_t df_b; +}; struct sink_vc_t { rt_uint8_t voltage; // 电压 0.01V @@ -215,7 +223,7 @@ enum { /* Sink电压稳定确认参数,供chrg_sink_volt_judge使用。 */ #define SINK_VOLT_5V_TARGET_MV 5000U #define SINK_VOLT_CONFIRM_NORMAL_COUNT 3U -#define SINK_VOLT_CONFIRM_5V_COUNT 12U +#define SINK_VOLT_CONFIRM_5V_COUNT 3U #define SINK_CURRENT_START_GRACE_MS 200U /* 主继电器闭合后的0V持续监控:由北向轮询线程每轮调用,掉电立即转掉电保护。 */ @@ -266,6 +274,7 @@ struct chrg_sink_t { rt_uint8_t change_cv_flag; rt_uint8_t change_source_flag; // 从sink切换到source标志位 rt_uint8_t work_mode; // 0=停止 1=工作 2=低电压 + struct sink_dpdm_cal_t dpdm_cal; // 上位机待写入Sink板的D+/D-校准参数 }; //纹波寄存器 @@ -408,6 +417,16 @@ extern int sink_set_cc_lvl (rt_uint8_t lvl); 其它说明: - *****************************************************************/ extern int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf); + +/***************************************************************** +函数名称: sink_set_dpdm_cal +函数描述: 向Sink协议板写入D+/D-校准参数 +输入参数: pCal:四个16位校准参数 +输出参数: - +返回说明: <0:发送失败 >0:发送长度 +其它说明: 发送0x32;K为×10000,B为0.01V有符号补码 +*****************************************************************/ +extern int sink_set_dpdm_cal(const struct sink_dpdm_cal_t *pCal); // ===================== 负载测试函数声明 ===================== extern void sink_test_short_set (struct chrg_switch_t *pSW, rt_uint8_t *pData, rt_uint8_t run_flag); extern void sink_test_ocp_set (struct chrg_switch_t *pSW, rt_uint8_t *pData, rt_uint8_t run_flag); diff --git a/docs/QMP4810300-4多协议可编程双向电源通信协议V_1.2.xlsx b/docs/QMP4810300-4多协议可编程双向电源通信协议V_1.2.xlsx index c263bf5d96f7028860d88d8e4b78af44d85abe08..9fced9df265e5f14be7d85d6034dfdb3c7636e0c 100644 GIT binary patch delta 12351 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 Mm