feat(DLPilot): M305 实测负载功率对接(功率检测三步序列)
This commit is contained in:
+7
-5
@@ -106,18 +106,20 @@ DLPilot/
|
||||
(DLPC 未就绪时 M730/M731/M732 被拒回 0xFF)以上游 `protocols.md` 为唯一权威,
|
||||
本仓不维护协议文档副本;注意 **M7S0 是"开启"TEC 自动控温**(方向反直觉)、
|
||||
M737 在定时投光中延迟应答(CLI 等待上限 35s)。
|
||||
- **M303/M304 载荷是二进制例外**(SQ52205 电源实测):成功载荷 2 字节大端原始值,
|
||||
- **M303/M304/M305 载荷是二进制例外**(SQ52205 电源实测):成功载荷为大端原始值,
|
||||
**不是 ASCII**——Frame.payload 解出来是乱码,必须走 `payload_bytes()` 取原始字节;
|
||||
M303=u16 mV(12V 轨窗口 11400~12600),M304=s16 补码 mA(正=正向,固件原样上总线,
|
||||
上位机按有符号解析,FF 06=−250)。封装在 `payload_u16_be/payload_s16_be/format_power`,
|
||||
回归向量在 selftest_rs485.py(真机抓取帧)。
|
||||
上位机按有符号解析,FF 06=−250),**M305=u32 mW(LEN=4,勿复用双字节解析;
|
||||
恒非负,量程 0~295000,能量方向看 M304 符号;显示 mW→W 两位小数)**。
|
||||
封装在 `payload_u16_be/payload_s16_be/payload_u32_be/format_power`,
|
||||
回归向量在 selftest_rs485.py(M303/M304 真机帧,M305 算法推演帧)。
|
||||
- **电源自检序列**(M301 协议→M302 挡位最大电流→M303 实测母线电压,帧驱动状态机
|
||||
`_pd_on_frame/_pd_seq`,超时 3s/步):FPDO 判定 = 电压就近挡(标准 PD 固定挡
|
||||
5/9/12/15/20/28V,±5% 容差)+ M302 挡位电流;**12V 且 ≥3A 绿底,挡位不符红底,
|
||||
无匹配挡 ERR**。应答按 TYPE=0xF0 判成功;
|
||||
CH224Q 电压配置寄存器(0x0A)只写不可读,挡位只能实测判定。
|
||||
- **功率检测** = M303+M304 → 读数框 电压V / 电流mA;**功率值暂不计算**
|
||||
(用户要求:后续固件会提供功率命令直接返回,届时填充),显示占位"功率: —"。
|
||||
- **功率检测** = M303+M304+M305 序列 → 读数框 电压V / 电流mA / 功率W(M305 u32 mW
|
||||
换算两位小数);各步载荷长度按 kind 校验(2/2/4 字节),坏帧中止显示 ERR。
|
||||
|
||||
## 5. 构建 / 发布流水线(全部在 src/ 下执行)
|
||||
|
||||
|
||||
+2
-1
@@ -104,7 +104,7 @@ GUI"光机控制"区:选串口 → 连接 → 点快捷按钮或命令下拉/
|
||||
按实测电压就近判定 PD 固定挡(5/9/12/15/20/28V,容差 ±5%):**12V 挡且 ≥3A 绿底
|
||||
"FPDO: 12V@3A"**;挡位不符(如 9V 挡)**红底**显示实际挡位;不落在任何标准挡显示
|
||||
**ERR**(CH224Q 电压配置寄存器只写不可读,挡位只能靠实测判定)。**功率检测**依序发
|
||||
M303+M304,读数框显示 电压(V) / 电流(mA);功率暂留空(后续固件命令直接返回)。
|
||||
M303+M304+M305,读数框显示 电压(V) / 电流(mA) / 功率(W,mW 换算两位小数)。
|
||||
|
||||
| 命令 | 功能 | 响应示例 |
|
||||
|---|---|---|
|
||||
@@ -117,6 +117,7 @@ M303+M304,读数框显示 电压(V) / 电流(mA);功率暂留空(后续固
|
||||
| `M302` | 查 PD 挡位最大电流(u16 大端 **mA**,50mA/LSB 固件已换算) | 0x0BB8 = 3000 mA = 3 A |
|
||||
| `M303` | 查母线电压(SQ52205 实测,**2 字节大端二进制载荷**) | 0x2EF4 = 12020 mV = 12.02 V(12V 轨窗口 11400~12600) |
|
||||
| `M304` | 查负载电流(SQ52205 实测,**2 字节大端二进制载荷**) | s16 补码 mA:0x0034=+52;FF 06=−250(正=正向) |
|
||||
| `M305` | 查负载功率(SQ52205 实测,**4 字节大端二进制载荷** u32) | mW→显示 W 两位小数:0x00008CA0=36000 mW=36.00 W(量程 0~295000 mW) |
|
||||
| `M999` | 查固件版本 | `okv20.0.0.1` |
|
||||
| `M737` | 查投光是否结束(投光中延迟应答) | `ok` |
|
||||
| `M7S0` / `M7S1` | TEC 自动控温开 / 关(注意 S0=开) | `ok` |
|
||||
|
||||
+16
-9
@@ -997,22 +997,22 @@ class App(ctk.CTk):
|
||||
self.var_fpdo.set(f'FPDO: {gear}V@{a_txt}A')
|
||||
|
||||
def _pwr_query(self):
|
||||
"""功率检测: M303 实测电压 + M304 实测电流(按有符号); 功率值待固件功率命令"""
|
||||
"""功率检测: M303 电压 + M304 电流(按有符号) + M305 功率(u32 mW)"""
|
||||
if not self.dlpc.is_connected():
|
||||
self.lbl_dlpc_st.configure(text='未连接串口', text_color='#E07A3F')
|
||||
return
|
||||
if self._pwr_seq:
|
||||
return
|
||||
self._pwr_seq = [('M303', 'mv'), ('M304', 'ma')]
|
||||
self._pwr_seq = [('M303', 'mv'), ('M304', 'ma'), ('M305', 'mw')]
|
||||
self._pwr_values = {}
|
||||
self._dlpc_log('功率检测: 开始')
|
||||
self._pwr_step_next()
|
||||
|
||||
def _pwr_step_next(self):
|
||||
if not self._pwr_seq:
|
||||
v_mv = self._pwr_values.get('mv', 0)
|
||||
ma = self._pwr_values.get('ma', 0)
|
||||
self._pwr_update(v_mv, ma)
|
||||
self._pwr_update(self._pwr_values.get('mv'),
|
||||
self._pwr_values.get('ma'),
|
||||
self._pwr_values.get('mw'))
|
||||
self._dlpc_log('功率检测: 完成')
|
||||
return
|
||||
self.dlpc.send(self._pwr_seq[0][0])
|
||||
@@ -1025,8 +1025,10 @@ class App(ctk.CTk):
|
||||
self.after_cancel(self._pwr_timer)
|
||||
self._pwr_timer = None
|
||||
cmd, kind = self._pwr_seq.pop(0)
|
||||
# 各步载荷长度: 电压/电流 2 字节, 功率 4 字节(u32)
|
||||
want_len = {'mv': 2, 'ma': 2, 'mw': 4}[kind]
|
||||
raw = dlpc_rs485.payload_bytes(fr) if fr is not None else b''
|
||||
if fr is None or fr.type_code != 0xF0 or len(raw) != 2:
|
||||
if fr is None or fr.type_code != 0xF0 or len(raw) != want_len:
|
||||
self._pwr_seq.clear()
|
||||
self.var_pwr.set('电压: ERR 电流: — 功率: —')
|
||||
self._dlpc_log('功率检测: 应答错误/超时, 中止')
|
||||
@@ -1035,11 +1037,16 @@ class App(ctk.CTk):
|
||||
self._pwr_values['mv'] = dlpc_rs485.payload_u16_be(raw)
|
||||
elif kind == 'ma':
|
||||
self._pwr_values['ma'] = dlpc_rs485.payload_s16_be(raw)
|
||||
elif kind == 'mw':
|
||||
self._pwr_values['mw'] = dlpc_rs485.payload_u32_be(raw)
|
||||
self._pwr_step_next()
|
||||
|
||||
def _pwr_update(self, v_mv, ma):
|
||||
"""功率读数框更新: 电压 V / 电流 mA; 功率暂不计算(待固件功率命令返回后填充)"""
|
||||
self.var_pwr.set(f'电压: {v_mv / 1000:.2f} V 电流: {ma} mA 功率: —')
|
||||
def _pwr_update(self, v_mv, ma, mw):
|
||||
"""功率读数框更新: 电压 V / 电流 mA / 功率 W(mW 换算, 两位小数; 缺项显示 —)"""
|
||||
v = f'{v_mv / 1000:.2f} V' if v_mv is not None else '—'
|
||||
a = f'{ma} mA' if ma is not None else '—'
|
||||
w = f'{mw / 1000:.2f} W' if mw is not None else '—'
|
||||
self.var_pwr.set(f'电压: {v} 电流: {a} 功率: {w}')
|
||||
|
||||
def _light_entry_apply(self, _evt=None):
|
||||
"""滑条数值输入框回车: 校验并限幅 54-800, 同步回滑条"""
|
||||
|
||||
@@ -8,7 +8,7 @@ DLPC3421 光机 RS485 控制链路(板上 GD32E230 作 RS485→I2C 网关)
|
||||
物理层 RS485 半双工 115200 8N1(PC 经 USB-RS485 转换器接板, DE 由 MCU 硬件换向)
|
||||
命令帧 D5 01 LEN <ASCII命令> CRC 01=板类型, LEN=命令字节数
|
||||
响应帧 B5 TYPE LEN <payload> CRC payload 为 ASCII(ok / err:OL / okTL:246 ...),
|
||||
例外: M303/M304 载荷为 2 字节大端二进制
|
||||
例外: M303/M304/M305 载荷为大端二进制
|
||||
(SQ52205 电源实测, 见 POWER_COMMANDS)
|
||||
CRC 帧内第 2 字节(板类型)起累加到最后一个 payload 字节, 取低 8 位
|
||||
帧长 最小 6 字节, 最大 32 字节
|
||||
@@ -83,12 +83,14 @@ PRESETS = (
|
||||
Frame = collections.namedtuple('Frame', 'type_code payload raw')
|
||||
|
||||
|
||||
# --- M303/M304(SQ52205 电源实测值查询): 成功载荷为 2 字节原始二进制(非 ASCII) ---
|
||||
# --- M303/M304/M305(SQ52205 电源实测值查询): 成功载荷为原始二进制(非 ASCII) ---
|
||||
# M303 母线电压: u16 大端, 单位 mV; 12V 轨正常窗口 11400~12600(标称 ±5%)
|
||||
# M304 负载电流: s16 大端补码, 单位 mA; 正=正向, 负=反向(固件原样上总线,
|
||||
# 上位机必须按有符号解析)。例: 载荷 FF 06 = -250 mA
|
||||
# M305 负载功率: u32 大端(LEN=4, 勿复用双字节解析), 单位 mW, 恒非负;
|
||||
# 量程约 0~295000 mW; 能量方向看 M304 符号
|
||||
# 错误时 TYPE=0xFF, 载荷为错误信息字节串(走通用译码路径)
|
||||
POWER_COMMANDS = ('M303', 'M304')
|
||||
POWER_COMMANDS = ('M303', 'M304', 'M305')
|
||||
|
||||
|
||||
def payload_bytes(fr):
|
||||
@@ -105,11 +107,20 @@ def payload_s16_be(raw):
|
||||
return v - 0x10000 if v & 0x8000 else v
|
||||
|
||||
|
||||
def payload_u32_be(raw):
|
||||
return (raw[0] << 24) | (raw[1] << 16) | (raw[2] << 8) | raw[3]
|
||||
|
||||
|
||||
def format_power(cmd, fr):
|
||||
"""M303/M304 成功应答 -> 人读文本; 非 POWER 命令/失败/载荷异常返回 None"""
|
||||
"""电源实测命令成功应答 -> 人读文本; 非电源命令/失败/载荷异常返回 None"""
|
||||
if cmd not in POWER_COMMANDS:
|
||||
return None
|
||||
raw = payload_bytes(fr)
|
||||
if cmd == 'M305':
|
||||
if fr.type_code != 0xF0 or len(raw) != 4:
|
||||
return None
|
||||
mw = payload_u32_be(raw)
|
||||
return f'{mw} mW ({mw / 1000:.2f} W)'
|
||||
if fr.type_code != 0xF0 or len(raw) != 2:
|
||||
return None
|
||||
if cmd == 'M303':
|
||||
|
||||
@@ -121,7 +121,8 @@ def run_dlpc(port, baud, cmds):
|
||||
print('← (35s 超时无响应)')
|
||||
rc = 1
|
||||
else:
|
||||
print(f'← {dlpc_rs485.describe(got)} [{got.raw.hex(" ").upper()}]')
|
||||
nice = dlpc_rs485.format_power(cmd, got) # 电源命令二进制载荷译码
|
||||
print(f'← {nice or dlpc_rs485.describe(got)} [{got.raw.hex(" ").upper()}]')
|
||||
if got.type_code != 0xF0:
|
||||
rc = 1
|
||||
ser.close()
|
||||
|
||||
@@ -87,5 +87,15 @@ check('M304 应答帧', len(frames), 1)
|
||||
check('M304 电流(0x0034=+52mA)', d.format_power('M304', frames[0]), '+52 mA')
|
||||
check('M304 负值(FF06=-250mA 补码)', d.payload_s16_be(bytes.fromhex('FF 06')), -250)
|
||||
|
||||
# 9) M305(SQ52205 实测功率)回归向量: u32 大端 mW(LEN=4, 算法推演帧)
|
||||
check('build_frame(M305)', d.build_frame('M305').hex(' ').upper(),
|
||||
'D5 01 04 4D 33 30 35 EA')
|
||||
frames = d.FrameParser().feed(bytes.fromhex('B5 F0 04 00 00 8C A0 20'))
|
||||
check('M305 应答帧', len(frames), 1)
|
||||
check('M305 功率(0x8CA0=36000mW)', d.format_power('M305', frames[0]),
|
||||
'36000 mW (36.00 W)')
|
||||
check('M305 拒绝双字节载荷', d.format_power(
|
||||
'M305', d.FrameParser().feed(bytes.fromhex('B5 F0 02 8C A0 1E'))[0]), None)
|
||||
|
||||
print('RESULT:', 'FAIL:' + ','.join(fails) if fails else 'ALL PASS')
|
||||
sys.exit(1 if fails else 0)
|
||||
|
||||
Reference in New Issue
Block a user