feat: add VCU status feedback and map DEBUG safety inputs
This commit is contained in:
@@ -127,7 +127,7 @@ def export(font_path):
|
||||
canvas.line(40, 31, page_width-40, 31)
|
||||
canvas.setFont('AMIChinese', 8)
|
||||
canvas.setFillColor(colors.HexColor('#506775'))
|
||||
canvas.drawString(40, 19, 'AMI-2.2 | 2026-10-03 | CAN1 500K / CAN2 250K')
|
||||
canvas.drawString(40, 19, 'AMI-2.4 | 2026-10-03 | CAN1 500K / CAN2 250K')
|
||||
canvas.drawRightString(page_width-40, 19, f'{doc.page}')
|
||||
canvas.restoreState()
|
||||
|
||||
@@ -136,7 +136,7 @@ def export(font_path):
|
||||
leftMargin=40, rightMargin=40,
|
||||
topMargin=36, bottomMargin=44,
|
||||
title='AMI CAN 报文说明', author='AMI / YMR',
|
||||
subject='AMI CAN DBC v2.2: CAN1 500K / CAN2 250K')
|
||||
subject='AMI CAN DBC v2.4: CAN1 500K / CAN2 250K')
|
||||
document.build(story, onFirstPage=footer, onLaterPages=footer)
|
||||
print(OUTPUT)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ def can2_dbc_text():
|
||||
return text
|
||||
|
||||
PURPOSE = {
|
||||
0x183: 'VCU -> AMI:实际当前任务、锁定状态、EBS 状态',
|
||||
0x182: 'VCU / 测试器 -> AMI:扭矩千分、电机温度、MCU 温度',
|
||||
0x300: 'AMI -> VCU:用户确认后的任务选择请求',
|
||||
0x6A0: 'SDC -> AMI:板标识、版本、序号、上电时间',
|
||||
@@ -50,7 +51,7 @@ def render():
|
||||
'| --- | --- | --- | --- |',
|
||||
'| CAN1 | 500 kbit/s | PA11 / PA12 | [AMI.dbc](../AMI.dbc) |',
|
||||
'| CAN2 | 250 kbit/s | PB0 / PB1 | [AMI_CAN2_250k.dbc](../AMI_CAN2_250k.dbc) |', '',
|
||||
'DBC 的 `Baudrate` / `AMIPort` 分别标注所属总线。每份 DBC 均含 11 条报文、40 个信号;'
|
||||
'DBC 的 `Baudrate` / `AMIPort` 分别标注所属总线。每份 DBC 均含 12 条报文、49 个信号;'
|
||||
'同一份报文表适用于两路。CAN 工具必须按接入端口设置速率,导入 DBC 不一定自动改硬件速率。'
|
||||
'实际接法:SDC 500 kbit/s 接 CAN1,BMS 250 kbit/s 接 CAN2。', '',
|
||||
'FDCAN 时钟 64 MHz,时钟分频为 1;NominalPrescaler 为 CAN1=8、CAN2=16,'
|
||||
@@ -59,7 +60,7 @@ def render():
|
||||
'本 DBC 包含 AMI 唯一发送的 `0x300` 任务请求,以及 AMI 当前识别的 SDC / BMS 和自定义显示输入。'
|
||||
'SDC `0x6A3` DAC 控制、`0x6A5` ASSI 控制、BMS 其他电芯/故障字段不属于此接口子集。'
|
||||
'`0x182` 新增扭矩千分、电机温度和电机控制器 MCU 温度的仪表显示输入;'
|
||||
'发送者负责转换实际电机控制器协议。未定义标定后的车速、AMI 周期心跳或 VCU 执行反馈。'
|
||||
'发送者负责转换实际电机控制器协议。`0x183` 为新增 VCU 状态反馈,需 VCU 按此自定义接口发送;未定义标定后的车速或 AMI 周期心跳。'
|
||||
'旧 `0x180 / 0x181 / 0x280` 输入已停用。', '',
|
||||
'SDC 字段依据 `SDC_ACQ_DAC.dbc` VERSION 1.1,保持其信号名、位布局、缩放和单位;'
|
||||
'仅将输入接收节点设为 AMI。BMS 字段依据 '
|
||||
@@ -96,7 +97,7 @@ def render():
|
||||
lines.append(f'| `{s.name}` | {s.start} | {s.length} | '
|
||||
f'{"Intel" if s.byte_order=="little_endian" else "Motorola"} | '
|
||||
f'{s.scale:g} | {s.offset:g} | {s.unit or "-"} | '
|
||||
f'{s.minimum:g}..{s.maximum:g} |')
|
||||
f'{"0(固定)" if s.name == "Reserved" else f"{s.minimum:g}..{s.maximum:g}"} |')
|
||||
choices = [f'`{s.name}`:' + ','.join(f'{value} = {name}' for value,name in s.choices.items())
|
||||
for s in m.signals if s.choices]
|
||||
if choices:
|
||||
@@ -112,7 +113,7 @@ def render():
|
||||
'| 2..3 | 电机温度 | 小端 int16 × 0.1 ℃,仪表四舍五入到整数 ℃ |',
|
||||
'| 4..5 | MCU 温度 | 小端 int16 × 0.1 ℃,仪表四舍五入到整数 ℃ |',
|
||||
'| 6 | 有效标志 | bit0 扭矩、bit1 电机温度、bit2 MCU 温度;1 有效,0 无效;bit3..7 必须为 0 |',
|
||||
'| 7 | 帧版本 | 固定 1,与整体接口 v2.2 版本号独立 |', '',
|
||||
'| 7 | 帧版本 | 固定 1,与整体接口 v2.4 版本号独立 |', '',
|
||||
'有效值更新并显示白色;标志为 0 时立即变灰并保留历史数字。'
|
||||
'扭矩超出 -1000..1000 时仅扭矩无效,两个温度仍按各自标志处理。'
|
||||
'温度的 int16 编码范围为 -3276.8..3276.7 ℃;显示正负半值均向远离零方向取整。'
|
||||
@@ -125,6 +126,46 @@ def render():
|
||||
'# PCAN 当前接 CAN2,速率 250000;其他适配器按 python-can 接口参数设置',
|
||||
'python scripts/send_drivetrain_can.py --interface pcan --channel PCAN_USBBUS1 --bitrate 250000 --torque 500 --motor-temp 45 --mcu-temp 40 --duration 10',
|
||||
'```', '',
|
||||
'## VCU 状态反馈 0x183', '',
|
||||
'新增自定义标准数据帧,DLC 必须为 8,建议周期 100 ms;CAN1 500K 与 CAN2 250K 共用布局。'
|
||||
'只有该帧更新当前任务、锁定、EBS 主页面显示。AMI 发出任务请求后保留 VCU 上次反馈,等待新的实际状态。', '',
|
||||
'| 字节 | 字段 | 编码与规则 |', '| --- | --- | --- |',
|
||||
'| 0 | 当前任务 | 0 无;1 八字绕环;2 直线加速;3 高速循迹;4 车检测试;5 EBS 测试;6 手动驾驶 |',
|
||||
'| 1 | 锁定 | 0 已解锁(红);1 已锁定(绿) |',
|
||||
'| 2 | EBS 正常 | 0 故障(红底);1 正常(绿底) |',
|
||||
'| 3 | 有效标志 | bit0 当前任务,bit1 锁定,bit2 EBS;1 有效,0 未知;bit3..7 为 0 |',
|
||||
'| 4 | 反馈计数 | 0..255,供观察;不去重,不作为请求 ACK |',
|
||||
'| 5..6 | 保留 | 必须为 0 |',
|
||||
'| 7 | 帧版本 | 固定 1 |', '',
|
||||
'例:`02 01 01 07 00 00 00 01` 表示当前直线加速、已锁定、EBS 正常。'
|
||||
'`00 00 00 07 01 00 00 01` 表示无任务、已解锁、EBS 故障。任务 1..6 为绿字,0 无任务为红字。'
|
||||
'各有效标志为 0 时,对应项立即灰色未知;连续超过 500 ms 无合规帧后三项均未知,其他 CAN 流量不能续期。'
|
||||
'错误 DLC、版本、枚举值、保留位或扩展/远程/FD 格式整帧拒绝,不改变状态、不续期。'
|
||||
'该反馈只驱动显示,EBS 安全动作及车辆任务裁决由 VCU 实现。', '',
|
||||
'### 当前任务发送对照', '',
|
||||
'下表第 1、2 字节均为 01,只用于展示已锁定、EBS 正常;VCU 必须填写实际状态。'
|
||||
'每条合规帧同时更新三项及其有效性,不能只改任务有效位而期望另外两项继续保留。', '',
|
||||
'| 任务号 | 当前任务 | 标准 0x183 / DLC 8 数据 |', '| --- | --- | --- |',
|
||||
'| 0 | 无(红) | `00 01 01 07 00 00 00 01` |',
|
||||
'| 1 | 八字绕环 | `01 01 01 07 00 00 00 01` |',
|
||||
'| 2 | 直线加速 | `02 01 01 07 00 00 00 01` |',
|
||||
'| 3 | 高速循迹 | `03 01 01 07 00 00 00 01` |',
|
||||
'| 4 | 车检测试 | `04 01 01 07 00 00 00 01` |',
|
||||
'| 5 | EBS 测试 | `05 01 01 07 00 00 00 01` |',
|
||||
'| 6 | 手动驾驶 | `06 01 01 07 00 00 00 01` |', '',
|
||||
'任务未知通过 byte3 的 bit0=0 编码。例如 `00 01 01 06 00 00 00 01`'
|
||||
'显示任务未知、已锁定、EBS 正常;不要发送任务号 7,7 是屏内未知状态而不是 CAN 枚举。'
|
||||
'任务号、锁定、EBS 的数值范围始终校验,有效标志为 0 时也不能发送越界值。', '',
|
||||
'发送顺序:AMI 确认按钮 -> UART 任务帧 -> MCU CAN `0x300` 请求 -> VCU 裁决 -> '
|
||||
'VCU 周期 CAN `0x183` 实际状态 -> AMI 显示。确认发送后可继续显示此前实际任务,'
|
||||
'直到 VCU 更新或反馈超时。', '',
|
||||
'发送工具预览和实发示例:', '', '```powershell',
|
||||
'python scripts/send_vcu_status_can.py --task 2 --locked 1 --ebs-normal 1 --dry-run',
|
||||
'python scripts/send_vcu_status_can.py --interface pcan --channel PCAN_USBBUS1 --bitrate 500000 --task 2 --locked 1 --ebs-normal 1 --duration 10',
|
||||
'# CAN2 改为 --bitrate 250000;Windows 适配器需要时添加 --dll-dir 指定 DLL 目录',
|
||||
'```', '',
|
||||
'屏内全局变量:`current_task=0..6`(7 未知)、`lock_state=0/1/2`、`ebs_state=0/1/2`'
|
||||
'(0 未知、1 绿、2 红)。MCU 更新这些变量,dash 后初始化和 100 ms 定时器更新文案、颜色和任务按钮;切页保留反馈。', '',
|
||||
'## AMI 任务请求语义', '',
|
||||
'| Task_ID | 任务 |', '| --- | --- |',
|
||||
'| 1 | 八字绕环 |', '| 2 | 直线加速 |', '| 3 | 高速循迹 |',
|
||||
@@ -136,7 +177,7 @@ def render():
|
||||
'优先发送到最近 500 ms 内收到过有效协议报文的 CAN 口;两路活跃则发送两路;'
|
||||
'没有活跃口时尝试两路。若未连接端口自动重发导致 TX FIFO 填满,现有队列可能等待。'
|
||||
'该策略沿用当前固件。任务表示操作员请求,VCU 负责裁决和安全互锁;'
|
||||
'未定义应用层执行确认、运行完成、故障回传,也不把任务号换成 ASSI 灯状态。', '',
|
||||
'当前实际任务由 `0x183` 反馈,不按请求立即显示;未定义逐请求 ACK 或运行完成报文,也不把任务号换成 ASSI 灯状态。', '',
|
||||
'## 显示缩放与失效规则', '',
|
||||
'| 显示项 | 输入和显示规则 | 失效条件 |', '| --- | --- | --- |',
|
||||
'| 低压电池 | `0x6A1` uint16 mV;`lvbat.val=(mV+5)/10`,显示两位小数 V | 1500 ms 无有效 ADC |',
|
||||
@@ -152,13 +193,17 @@ def render():
|
||||
'第 9/10 路虚拟温度没有总线字段,最高温度也属于 MCU 派生结果,不新增虚构信号。', '',
|
||||
'BMS 扩展帧的其他字段没有纳入本 DBC,尤其字节 6..7 的低压电压不覆盖 SDC ADC。'
|
||||
'两类温度帧共用最高温度显示,后收到的温度帧更新该显示及有效性。'
|
||||
'SDC GPIO 原始电平尚无具名安全信号映射和正常极性,因此 debug 保持未知;'
|
||||
'SDC GPIO PD0..PD14 按顺序映射到 d0、d5、d2、d6、d7、d1、d3、d4、d8..d14;'
|
||||
'全部低电平正常、高电平故障,d15 无来源保持未知。心跳维持已有采样,'
|
||||
'用户最新纠正 PD1 / Safe_S 为左电机互锁(d5),屏幕已删除 BSPD/TSMS。'
|
||||
'心跳和 GPIO 均停止超过 500 ms 后全部未知,恢复需要新的 GPIO 采样;'
|
||||
'轮频 Hz 尚无周长和每圈脉冲数,不能直接当 km/h。', '',
|
||||
'有效值显示白色;未知、无效、超时显示深灰色,历史数值保留但不作为有效测量。'
|
||||
'各源独立超时,其他流量不续期。每 5 秒重新同步界面,刚连接需等待首轮同步。', '',
|
||||
'## 报文样例', '',
|
||||
'| ID / DLC | 数据(十六进制) | 解码及仪表显示 |', '| --- | --- | --- |',
|
||||
'| `0x300 / 8` | `01 02 00 01 E8 03 00 00` | 直线加速请求、序号 0、来源 AMI、上电 1000 ms |',
|
||||
'| `0x183 / 8` | `02 01 01 07 00 00 00 01` | 当前直线加速、已锁定、EBS 正常,三项有效 |',
|
||||
'| `0x182 / 8` | `F4 01 C2 01 90 01 07 01` | 500‰、45.0 ℃、40.0 ℃,三个值有效 |',
|
||||
'| `0x182 / 8` | `0C FE 9B FF 33 FF 07 01` | -500‰、-10.1 ℃、-20.5 ℃;显示 -500 / -10 / -21 |',
|
||||
'| `0x6A1 / 2` | `0C 30` | ADC 12300 mV;低压 12.30 V |',
|
||||
@@ -175,8 +220,8 @@ def render():
|
||||
'# 若同时检出 SDC 仓库,可额外比较五条输入帧的原始布局:',
|
||||
'python scripts/verify_dbc.py --sdc-dbc ../SDC_ACQ_DAC/SDC_ACQ_DAC.dbc',
|
||||
'```', '',
|
||||
'校验覆盖严格 DBC 解析(长度、信号越界与重叠)、11 个 ID 与固件宏对应、'
|
||||
'标准/扩展格式、40 个信号、发送/接收节点、SDC / 自定义帧周期、已知报文解码、'
|
||||
'校验覆盖严格 DBC 解析(长度、信号越界与重叠)、12 个 ID 与固件宏对应、'
|
||||
'标准/扩展格式、49 个信号、发送/接收节点、SDC / 自定义帧周期、已知报文解码、'
|
||||
'六个任务号与计数边界编码、大端偏置电流、无效温度枚举、全负温度和截短 DLC。'
|
||||
'已安装并验证 cantools 44.1.0,接口参考 [cantools 官方文档](https://cantools.readthedocs.io/en/latest/)。', '',
|
||||
'上述是静态及软件编解码验证,另校验两份 DBC 的速率、相同信号布局及源码 / CubeMX 位时序一致。'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
//以下代码只在上电时运行一次,一般用于全局变量定义和上电初始化数据
|
||||
int sys0=0,sys1=0,sys2=0 //全局变量定义目前仅支持4字节有符号整形(int),不支持其他类型的全局变量声明,如需使用字符串类型可以在页面中使用变量控件来实现
|
||||
int pending_task=0,current_task=7
|
||||
int lock_state=0,ebs_state=0
|
||||
int shown_task=-1,shown_lock=-1,shown_ebs=-1
|
||||
int d0=0,d1=0,d2=0,d3=0,d4=0,d5=0,d6=0,d7=0,d8=0,d9=0,d10=0,d11=0,d12=0,d13=0,d14=0,d15=0
|
||||
baud=9600//配置波特率
|
||||
dim=100//配置屏幕背光
|
||||
recmod=0//串口协议模式:0-字符串指令协议;1-主动解析协议
|
||||
printh 00 00 00 ff ff ff 88 ff ff ff//输出上电信息到串口
|
||||
page 0 //上电刷新第0页
|
||||
@@ -0,0 +1,29 @@
|
||||
if(pending_task>=1&&pending_task<=6)
|
||||
{
|
||||
if(pending_task==1)
|
||||
{
|
||||
printh AA 55 01 01 0D 0A
|
||||
}
|
||||
if(pending_task==2)
|
||||
{
|
||||
printh AA 55 01 02 0D 0A
|
||||
}
|
||||
if(pending_task==3)
|
||||
{
|
||||
printh AA 55 01 03 0D 0A
|
||||
}
|
||||
if(pending_task==4)
|
||||
{
|
||||
printh AA 55 01 04 0D 0A
|
||||
}
|
||||
if(pending_task==5)
|
||||
{
|
||||
printh AA 55 01 05 0D 0A
|
||||
}
|
||||
if(pending_task==6)
|
||||
{
|
||||
printh AA 55 01 06 0D 0A
|
||||
}
|
||||
pending_task=0
|
||||
page dash
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
shown_task=-1
|
||||
shown_lock=-1
|
||||
shown_ebs=-1
|
||||
if(current_task!=shown_task)
|
||||
{
|
||||
rw.txt="未知"
|
||||
rw.pco=33840
|
||||
if(current_task==0)
|
||||
{
|
||||
rw.txt="无"
|
||||
rw.pco=63488
|
||||
}
|
||||
if(current_task>=1&¤t_task<=6)
|
||||
{
|
||||
rw.pco=2016
|
||||
}
|
||||
if(current_task==1)
|
||||
{
|
||||
rw.txt="八字绕环"
|
||||
}
|
||||
if(current_task==2)
|
||||
{
|
||||
rw.txt="直线加速"
|
||||
}
|
||||
if(current_task==3)
|
||||
{
|
||||
rw.txt="高速循迹"
|
||||
}
|
||||
if(current_task==4)
|
||||
{
|
||||
rw.txt="车检测试"
|
||||
}
|
||||
if(current_task==5)
|
||||
{
|
||||
rw.txt="EBS测试"
|
||||
}
|
||||
if(current_task==6)
|
||||
{
|
||||
rw.txt="手动驾驶"
|
||||
}
|
||||
bt0.val=0
|
||||
if(current_task==1)
|
||||
{
|
||||
bt0.val=1
|
||||
}
|
||||
bt1.val=0
|
||||
if(current_task==2)
|
||||
{
|
||||
bt1.val=1
|
||||
}
|
||||
bt2.val=0
|
||||
if(current_task==3)
|
||||
{
|
||||
bt2.val=1
|
||||
}
|
||||
bt3.val=0
|
||||
if(current_task==4)
|
||||
{
|
||||
bt3.val=1
|
||||
}
|
||||
bt4.val=0
|
||||
if(current_task==5)
|
||||
{
|
||||
bt4.val=1
|
||||
}
|
||||
bt5.val=0
|
||||
if(current_task==6)
|
||||
{
|
||||
bt5.val=1
|
||||
}
|
||||
shown_task=current_task
|
||||
}
|
||||
if(lock_state!=shown_lock)
|
||||
{
|
||||
sd.txt="锁定未知"
|
||||
sd.pco=33840
|
||||
if(lock_state==1)
|
||||
{
|
||||
sd.txt="已锁定"
|
||||
sd.pco=2016
|
||||
}
|
||||
if(lock_state==2)
|
||||
{
|
||||
sd.txt="已解锁"
|
||||
sd.pco=63488
|
||||
}
|
||||
shown_lock=lock_state
|
||||
}
|
||||
if(ebs_state!=shown_ebs)
|
||||
{
|
||||
EBS.txt="EBS 未知"
|
||||
EBS.pco=33840
|
||||
EBS.bco=0
|
||||
if(ebs_state==1)
|
||||
{
|
||||
EBS.txt="EBS 正常"
|
||||
EBS.pco=65535
|
||||
EBS.bco=2016
|
||||
}
|
||||
if(ebs_state==2)
|
||||
{
|
||||
EBS.txt="EBS 故障"
|
||||
EBS.pco=65535
|
||||
EBS.bco=63488
|
||||
}
|
||||
shown_ebs=ebs_state
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
if(current_task!=shown_task)
|
||||
{
|
||||
rw.txt="未知"
|
||||
rw.pco=33840
|
||||
if(current_task==0)
|
||||
{
|
||||
rw.txt="无"
|
||||
rw.pco=63488
|
||||
}
|
||||
if(current_task>=1&¤t_task<=6)
|
||||
{
|
||||
rw.pco=2016
|
||||
}
|
||||
if(current_task==1)
|
||||
{
|
||||
rw.txt="八字绕环"
|
||||
}
|
||||
if(current_task==2)
|
||||
{
|
||||
rw.txt="直线加速"
|
||||
}
|
||||
if(current_task==3)
|
||||
{
|
||||
rw.txt="高速循迹"
|
||||
}
|
||||
if(current_task==4)
|
||||
{
|
||||
rw.txt="车检测试"
|
||||
}
|
||||
if(current_task==5)
|
||||
{
|
||||
rw.txt="EBS测试"
|
||||
}
|
||||
if(current_task==6)
|
||||
{
|
||||
rw.txt="手动驾驶"
|
||||
}
|
||||
bt0.val=0
|
||||
if(current_task==1)
|
||||
{
|
||||
bt0.val=1
|
||||
}
|
||||
bt1.val=0
|
||||
if(current_task==2)
|
||||
{
|
||||
bt1.val=1
|
||||
}
|
||||
bt2.val=0
|
||||
if(current_task==3)
|
||||
{
|
||||
bt2.val=1
|
||||
}
|
||||
bt3.val=0
|
||||
if(current_task==4)
|
||||
{
|
||||
bt3.val=1
|
||||
}
|
||||
bt4.val=0
|
||||
if(current_task==5)
|
||||
{
|
||||
bt4.val=1
|
||||
}
|
||||
bt5.val=0
|
||||
if(current_task==6)
|
||||
{
|
||||
bt5.val=1
|
||||
}
|
||||
shown_task=current_task
|
||||
}
|
||||
if(lock_state!=shown_lock)
|
||||
{
|
||||
sd.txt="锁定未知"
|
||||
sd.pco=33840
|
||||
if(lock_state==1)
|
||||
{
|
||||
sd.txt="已锁定"
|
||||
sd.pco=2016
|
||||
}
|
||||
if(lock_state==2)
|
||||
{
|
||||
sd.txt="已解锁"
|
||||
sd.pco=63488
|
||||
}
|
||||
shown_lock=lock_state
|
||||
}
|
||||
if(ebs_state!=shown_ebs)
|
||||
{
|
||||
EBS.txt="EBS 未知"
|
||||
EBS.pco=33840
|
||||
EBS.bco=0
|
||||
if(ebs_state==1)
|
||||
{
|
||||
EBS.txt="EBS 正常"
|
||||
EBS.pco=65535
|
||||
EBS.bco=2016
|
||||
}
|
||||
if(ebs_state==2)
|
||||
{
|
||||
EBS.txt="EBS 故障"
|
||||
EBS.pco=65535
|
||||
EBS.bco=63488
|
||||
}
|
||||
shown_ebs=ebs_state
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
xstr 8,2,160,24,0,2047,0,1,1,1,"DEBUG 安全回路"
|
||||
xstr 170,2,235,24,0,33840,0,1,1,1,"灰未知 绿正常 红故障"
|
||||
draw 8,34,111,79,10565
|
||||
xstr 9,36,102,18,0,65535,0,1,1,1,"配电箱"
|
||||
draw 128,34,231,79,10565
|
||||
xstr 129,36,102,18,0,65535,0,1,1,1,"左电机互锁"
|
||||
draw 248,34,351,79,10565
|
||||
xstr 249,36,102,18,0,65535,0,1,1,1,"左急停"
|
||||
draw 368,34,471,79,10565
|
||||
xstr 369,36,102,18,0,65535,0,1,1,1,"电池箱"
|
||||
draw 128,84,231,129,10565
|
||||
xstr 129,86,102,18,0,65535,0,1,1,1,"回路末端"
|
||||
draw 248,84,351,129,10565
|
||||
xstr 249,86,102,18,0,65535,0,1,1,1,"驾舱/右急停"
|
||||
draw 368,84,471,129,10565
|
||||
xstr 369,86,102,18,0,65535,0,1,1,1,"行程/惯性"
|
||||
line 112,56,128,56,2047
|
||||
line 124,53,128,56,2047
|
||||
line 124,59,128,56,2047
|
||||
line 232,56,248,56,2047
|
||||
line 244,53,248,56,2047
|
||||
line 244,59,248,56,2047
|
||||
line 352,56,368,56,2047
|
||||
line 364,53,368,56,2047
|
||||
line 364,59,368,56,2047
|
||||
line 472,56,478,56,2047
|
||||
line 478,56,478,106,2047
|
||||
line 478,106,472,106,2047
|
||||
line 352,106,368,106,2047
|
||||
line 356,103,352,106,2047
|
||||
line 356,109,352,106,2047
|
||||
line 232,106,248,106,2047
|
||||
line 236,103,232,106,2047
|
||||
line 236,109,232,106,2047
|
||||
draw 8,137,231,182,10565
|
||||
xstr 9,139,222,19,0,50712,0,1,1,1,"RES"
|
||||
draw 248,137,471,182,10565
|
||||
xstr 249,139,222,19,0,50712,0,1,1,1,"主控盒"
|
||||
draw 8,188,111,229,10565
|
||||
xstr 9,190,102,19,0,2047,0,1,1,1,"EBS 舵机"
|
||||
draw 128,188,231,229,10565
|
||||
xstr 129,190,102,19,0,2047,0,1,1,1,"EBS 电磁阀"
|
||||
draw 248,188,351,229,10565
|
||||
xstr 249,190,102,19,0,2047,0,1,1,1,"EBS 气压"
|
||||
draw 368,188,471,229,10565
|
||||
xstr 369,190,102,19,0,2047,0,1,1,1,"EBS 油压"
|
||||
draw 8,232,111,271,10565
|
||||
xstr 9,234,102,19,0,2047,0,1,1,1,"无人驾驶惯导"
|
||||
draw 128,232,231,271,10565
|
||||
xstr 129,234,102,19,0,2047,0,1,1,1,"无人驾驶轮速"
|
||||
draw 248,232,351,271,10565
|
||||
xstr 249,234,102,19,0,2047,0,1,1,1,"无人驾驶相机"
|
||||
draw 368,232,471,271,10565
|
||||
xstr 369,234,102,19,0,2047,0,1,1,1,"主控盒12V"
|
||||
if(d0==1)
|
||||
{
|
||||
t0.txt="正常"
|
||||
t0.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d0==2)
|
||||
{
|
||||
t0.txt="故障"
|
||||
t0.pco=63488
|
||||
}else
|
||||
{
|
||||
t0.txt="未知"
|
||||
t0.pco=33840
|
||||
}
|
||||
}
|
||||
if(d1==1)
|
||||
{
|
||||
t1.txt="正常"
|
||||
t1.pco=2016
|
||||
t3.txt="正常"
|
||||
t3.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d1==2)
|
||||
{
|
||||
t1.txt="故障"
|
||||
t1.pco=63488
|
||||
t3.txt="故障"
|
||||
t3.pco=63488
|
||||
}else
|
||||
{
|
||||
t1.txt="未知"
|
||||
t1.pco=33840
|
||||
t3.txt="未知"
|
||||
t3.pco=33840
|
||||
}
|
||||
}
|
||||
if(d2==1)
|
||||
{
|
||||
t2.txt="正常"
|
||||
t2.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d2==2)
|
||||
{
|
||||
t2.txt="故障"
|
||||
t2.pco=63488
|
||||
}else
|
||||
{
|
||||
t2.txt="未知"
|
||||
t2.pco=33840
|
||||
}
|
||||
}
|
||||
if(d3==1)
|
||||
{
|
||||
t4.txt="正常"
|
||||
t4.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d3==2)
|
||||
{
|
||||
t4.txt="故障"
|
||||
t4.pco=63488
|
||||
}else
|
||||
{
|
||||
t4.txt="未知"
|
||||
t4.pco=33840
|
||||
}
|
||||
}
|
||||
if(d4==1)
|
||||
{
|
||||
t5.txt="正常"
|
||||
t5.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d4==2)
|
||||
{
|
||||
t5.txt="故障"
|
||||
t5.pco=63488
|
||||
}else
|
||||
{
|
||||
t5.txt="未知"
|
||||
t5.pco=33840
|
||||
}
|
||||
}
|
||||
if(d5==1)
|
||||
{
|
||||
t6.txt="正常"
|
||||
t6.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d5==2)
|
||||
{
|
||||
t6.txt="故障"
|
||||
t6.pco=63488
|
||||
}else
|
||||
{
|
||||
t6.txt="未知"
|
||||
t6.pco=33840
|
||||
}
|
||||
}
|
||||
if(d6==1)
|
||||
{
|
||||
t7.txt="正常"
|
||||
t7.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d6==2)
|
||||
{
|
||||
t7.txt="故障"
|
||||
t7.pco=63488
|
||||
}else
|
||||
{
|
||||
t7.txt="未知"
|
||||
t7.pco=33840
|
||||
}
|
||||
}
|
||||
if(d7==1)
|
||||
{
|
||||
t8.txt="正常"
|
||||
t8.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d7==2)
|
||||
{
|
||||
t8.txt="故障"
|
||||
t8.pco=63488
|
||||
}else
|
||||
{
|
||||
t8.txt="未知"
|
||||
t8.pco=33840
|
||||
}
|
||||
}
|
||||
if(d8==1)
|
||||
{
|
||||
t9.txt="正常"
|
||||
t9.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d8==2)
|
||||
{
|
||||
t9.txt="故障"
|
||||
t9.pco=63488
|
||||
}else
|
||||
{
|
||||
t9.txt="未知"
|
||||
t9.pco=33840
|
||||
}
|
||||
}
|
||||
if(d9==1)
|
||||
{
|
||||
t10.txt="正常"
|
||||
t10.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d9==2)
|
||||
{
|
||||
t10.txt="故障"
|
||||
t10.pco=63488
|
||||
}else
|
||||
{
|
||||
t10.txt="未知"
|
||||
t10.pco=33840
|
||||
}
|
||||
}
|
||||
if(d10==1)
|
||||
{
|
||||
t11.txt="正常"
|
||||
t11.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d10==2)
|
||||
{
|
||||
t11.txt="故障"
|
||||
t11.pco=63488
|
||||
}else
|
||||
{
|
||||
t11.txt="未知"
|
||||
t11.pco=33840
|
||||
}
|
||||
}
|
||||
if(d11==1)
|
||||
{
|
||||
t12.txt="正常"
|
||||
t12.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d11==2)
|
||||
{
|
||||
t12.txt="故障"
|
||||
t12.pco=63488
|
||||
}else
|
||||
{
|
||||
t12.txt="未知"
|
||||
t12.pco=33840
|
||||
}
|
||||
}
|
||||
if(d12==1)
|
||||
{
|
||||
t13.txt="正常"
|
||||
t13.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d12==2)
|
||||
{
|
||||
t13.txt="故障"
|
||||
t13.pco=63488
|
||||
}else
|
||||
{
|
||||
t13.txt="未知"
|
||||
t13.pco=33840
|
||||
}
|
||||
}
|
||||
if(d13==1)
|
||||
{
|
||||
t14.txt="正常"
|
||||
t14.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d13==2)
|
||||
{
|
||||
t14.txt="故障"
|
||||
t14.pco=63488
|
||||
}else
|
||||
{
|
||||
t14.txt="未知"
|
||||
t14.pco=33840
|
||||
}
|
||||
}
|
||||
if(d14==1)
|
||||
{
|
||||
t15.txt="正常"
|
||||
t15.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d14==2)
|
||||
{
|
||||
t15.txt="故障"
|
||||
t15.pco=63488
|
||||
}else
|
||||
{
|
||||
t15.txt="未知"
|
||||
t15.pco=33840
|
||||
}
|
||||
}
|
||||
if(d15==1)
|
||||
{
|
||||
t16.txt="正常"
|
||||
t16.pco=2016
|
||||
}else
|
||||
{
|
||||
if(d15==2)
|
||||
{
|
||||
t16.txt="故障"
|
||||
t16.pco=63488
|
||||
}else
|
||||
{
|
||||
t16.txt="未知"
|
||||
t16.pco=33840
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Send custom AMI 0x183 VCU display feedback; no vehicle actuation."""
|
||||
import argparse
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
def build_payload(task, locked, ebs_normal, valid=7, sequence=0):
|
||||
if task not in range(7) or locked not in (0, 1) or ebs_normal not in (0, 1):
|
||||
raise ValueError('task must be 0..6; locked and ebs-normal must be 0 or 1')
|
||||
if valid not in range(8) or sequence not in range(256):
|
||||
raise ValueError('valid must be 0..7 and sequence must be 0..255')
|
||||
return bytes([task, locked, ebs_normal, valid, sequence, 0, 0, 1])
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--task', type=int, required=True, choices=range(7))
|
||||
parser.add_argument('--locked', type=int, required=True, choices=(0, 1))
|
||||
parser.add_argument('--ebs-normal', type=int, required=True, choices=(0, 1))
|
||||
parser.add_argument('--valid', type=int, default=7)
|
||||
parser.add_argument('--sequence', type=int, default=0)
|
||||
parser.add_argument('--interface', default='pcan')
|
||||
parser.add_argument('--channel', default='PCAN_USBBUS1')
|
||||
parser.add_argument('--bitrate', type=int, choices=(250000, 500000), default=500000)
|
||||
parser.add_argument('--period', type=float, default=.1)
|
||||
parser.add_argument('--duration', type=float, default=10)
|
||||
parser.add_argument('--dll-dir')
|
||||
parser.add_argument('--dry-run', action='store_true')
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
payload = build_payload(args.task, args.locked, args.ebs_normal, args.valid, args.sequence)
|
||||
except ValueError as exc:
|
||||
parser.error(str(exc))
|
||||
if not (0 < args.period <= .5 and 0 < args.duration and math.isfinite(args.duration)):
|
||||
parser.error('period must be >0 and <=0.5 seconds; duration must be finite and positive')
|
||||
print(f'Standard ID 0x183, DLC 8, data {payload.hex(" ").upper()}, bitrate {args.bitrate}', flush=True)
|
||||
if args.dry_run:
|
||||
return
|
||||
dll_handle = None
|
||||
if args.dll_dir:
|
||||
directory = os.path.abspath(args.dll_dir)
|
||||
os.environ['PATH'] = directory + os.pathsep + os.environ['PATH']
|
||||
dll_handle = os.add_dll_directory(directory)
|
||||
import can
|
||||
count = 0
|
||||
try:
|
||||
with can.Bus(interface=args.interface, channel=args.channel, bitrate=args.bitrate) as bus:
|
||||
started = time.monotonic()
|
||||
deadline = started
|
||||
while time.monotonic() < started + args.duration:
|
||||
payload = build_payload(args.task, args.locked, args.ebs_normal,
|
||||
args.valid, (args.sequence + count) & 255)
|
||||
bus.send(can.Message(arbitration_id=0x183, is_extended_id=False, data=payload), timeout=.2)
|
||||
count += 1
|
||||
deadline += args.period
|
||||
time.sleep(max(0, min(deadline, started + args.duration) - time.monotonic()))
|
||||
finally:
|
||||
if dll_handle is not None:
|
||||
dll_handle.close()
|
||||
print(f'Sent {count} frames. Display becomes unknown over 500 ms after feedback stops.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+25
-6
@@ -12,6 +12,7 @@ import re
|
||||
import cantools
|
||||
from export_dbc_docs import can2_dbc_text
|
||||
from send_drivetrain_can import build_payload
|
||||
from send_vcu_status_can import build_payload as build_vcu_payload
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
@@ -72,24 +73,24 @@ def main():
|
||||
header = (ROOT / 'firmware/Core/Inc/ami_protocol.h').read_text(encoding='utf-8')
|
||||
identifiers = {int(value, 16) for value in re.findall(
|
||||
r'^#define\s+AMI_CAN_ID_\w+\s+(0x[\dA-Fa-f]+)', header, re.MULTILINE)}
|
||||
expected = {0x182:(False,8), 0x300:(False,8), 0x6A0:(False,8), 0x6A1:(False,2),
|
||||
expected = {0x182:(False,8), 0x183:(False,8), 0x300:(False,8), 0x6A0:(False,8), 0x6A1:(False,2),
|
||||
0x6A2:(False,8), 0x6A4:(False,4), 0x6A6:(False,8),
|
||||
0x140:(False,8), 0x156:(False,8),
|
||||
0x186040F3:(True,8), 0x186140F3:(True,8)}
|
||||
actual = {m.frame_id:(m.is_extended_frame,m.length) for m in db.messages}
|
||||
assert actual == expected, actual
|
||||
assert set(actual) == identifiers, (actual, identifiers)
|
||||
assert len(db.messages) == 11
|
||||
assert sum(len(m.signals) for m in db.messages) == 40
|
||||
assert len(db.messages) == 12
|
||||
assert sum(len(m.signals) for m in db.messages) == 49
|
||||
for m in db.messages:
|
||||
if m.frame_id == 0x300:
|
||||
assert m.senders == ['AMI'] and m.receivers == {'VCU'}
|
||||
else:
|
||||
assert m.receivers == {'AMI'}
|
||||
assert m.senders == (['VCU'] if m.frame_id == 0x182 else
|
||||
assert m.senders == (['VCU'] if m.frame_id in (0x182,0x183) else
|
||||
['SDC_ACQ_DAC'] if 0x6A0 <= m.frame_id <= 0x6A6 else ['BMS'])
|
||||
assert db.dbc.attributes['Baudrate'].value == 500000
|
||||
for ident, cycle in [(0x182,100), (0x6A0,100), (0x6A1,500), (0x6A2,20)]:
|
||||
for ident, cycle in [(0x182,100), (0x183,100), (0x6A0,100), (0x6A1,500), (0x6A2,20)]:
|
||||
assert db.get_message_by_frame_id(ident).cycle_time == cycle
|
||||
for ident in [0x300,0x6A4,0x6A6,0x140,0x156,0x186040F3,0x186140F3]:
|
||||
assert db.get_message_by_frame_id(ident).cycle_time in (None,0)
|
||||
@@ -100,6 +101,24 @@ def main():
|
||||
return db.decode_message(ident, bytes.fromhex(data), decode_choices=False)
|
||||
|
||||
display = db.get_message_by_frame_id(0x182)
|
||||
status = db.get_message_by_frame_id(0x183)
|
||||
for task_id in range(7):
|
||||
for flags in range(8):
|
||||
raw=bytes([task_id,task_id&1,(task_id+1)&1,flags,255,0,0,1])
|
||||
values=decode(0x183,raw.hex(' '))
|
||||
assert values['Current_Task']==task_id and values['Locked']==(task_id&1)
|
||||
assert values['EBS_Normal']==((task_id+1)&1)
|
||||
assert status.encode(values)==raw
|
||||
assert db2.get_message_by_frame_id(0x183).encode(values)==raw
|
||||
assert build_vcu_payload(task_id,task_id&1,(task_id+1)&1,flags,255)==raw
|
||||
for arguments in ((7,1,1,7,0), (2,2,1,7,0), (2,1,2,7,0),
|
||||
(2,1,1,8,0), (2,1,1,7,256)):
|
||||
try:
|
||||
build_vcu_payload(*arguments)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError(f'Invalid VCU sender arguments accepted: {arguments}')
|
||||
for raw, torque, motor, mcu, flags in [
|
||||
('F4 01 C2 01 90 01 07 01',500,45,40,7),
|
||||
('0C FE 9B FF 33 FF 07 01',-500,-10.1,-20.5,7),
|
||||
@@ -218,7 +237,7 @@ def main():
|
||||
for decode_choices in (False, True):
|
||||
assert db.decode_message(ident, payload, decode_choices=decode_choices) == \
|
||||
db2.decode_message(ident, payload, decode_choices=decode_choices)
|
||||
print(json.dumps({'result':'passed','messages':len(db.messages),'signals':40,
|
||||
print(json.dumps({'result':'passed','messages':len(db.messages),'signals':sum(len(m.signals) for m in db.messages),
|
||||
'known_payload_checks':len(checks),'all_task_ids_and_counter_edges':True,
|
||||
'ports_bitrate':bitrates,'both_dbc_layouts_and_payloads_match':True,
|
||||
'firmware_and_ioc_bit_timing_match':True,
|
||||
|
||||
Reference in New Issue
Block a user