2. J1939 PGN数据库查询工具

任务说明

实现一个命令行 PGN 查询工具:输入 PGN 号(十进制或 0x 十六进制),输出该 PGN 的名称、数据长度(字节)、发送频率和所属子系统。数据以本地字典形式内置,覆盖 J1939 常用 PGN。

环境与依赖

  • Python 3.8+,仅用标准库,无需安装第三方包。
  • 文件:pgn_db.py(数据库与查询函数)、query.py(命令行入口)。

查询流程

输入 PGN 字符串 parse_pgn() 十进制/0x → int lookup_pgn() 查 PGN_DB 字典 格式化输出 名称/长度/频率/子系统

核心代码

pgn_db.py:内置 PGN 元数据字典与查询函数。

PGN_DB = {
    0xE800: {"name": "ECU1", "length": 8, "rate_ms": 100, "system": "Engine"},
    0xE801: {"name": "ECU2", "length": 8, "rate_ms": 100, "system": "Engine"},
    0xF004: {"name": "EngineSpeed", "length": 8, "rate_ms": 20, "system": "Engine"},
    0xFEF1: {"name": "VehicleSpeed", "length": 8, "rate_ms": 100, "system": "Powertrain"},
    0xFEE5: {"name": "AmbientConditions", "length": 8, "rate_ms": 1000, "system": "Cab"},
    0xFEF2: {"name": "FuelConsumption", "length": 8, "rate_ms": 100, "system": "Powertrain"},
    0xFECA: {"name": "DM1_ActiveDTC", "length": 8, "rate_ms": 1000, "system": "Diagnostics"},
    0xFEDF: {"name": "SoftwareIdentification", "length": 8, "rate_ms": 0, "system": "Diagnostics"},
    0xEA00: {"name": "TransmissionOilTemp", "length": 8, "rate_ms": 1000, "system": "Transmission"},
    0xFEE9: {"name": "DashDisplay", "length": 8, "rate_ms": 100, "system": "Cab"},
}

def parse_pgn(text):
    """把用户输入解析为整数 PGN。支持十进制与 0x 前缀十六进制。"""
    text = text.strip()
    if text.lower().startswith("0x"):
        return int(text, 16)
    return int(text, 10)

def lookup_pgn(pgn):
    """返回元数据字典;未收录返回 None。"""
    return PGN_DB.get(pgn)

def format_result(pgn, meta):
    if meta is None:
        return f"PGN 0x{pgn:04X} ({pgn}) 未收录于本地数据库。"
    rate = "事件触发" if meta["rate_ms"] == 0 else f"{meta['rate_ms']} ms"
    return (
        f"PGN        : 0x{pgn:04X} ({pgn})\n"
        f"名称       : {meta['name']}\n"
        f"数据长度   : {meta['length']} 字节\n"
        f"发送频率   : {rate}\n"
        f"所属子系统 : {meta['system']}"
    )

query.py:命令行入口,支持参数或交互式输入。

import sys
from pgn_db import parse_pgn, lookup_pgn, format_result

def run(text):
    try:
        pgn = parse_pgn(text)
    except ValueError:
        print(f"无法解析 PGN: {text!r},请输入十进制或 0x 十六进制。")
        return 1
    print(format_result(pgn, lookup_pgn(pgn)))
    return 0

if __name__ == "__main__":
    if len(sys.argv) > 1:
        sys.exit(run(sys.argv[1]))
    print("输入 PGN(十进制或 0x 十六进制),空行退出:")
    for line in sys.stdin:
        line = line.strip()
        if not line:
            break
        run(line)

运行与验证

# 命令行方式
python query.py 0xF004
python query.py 65262

# 交互方式
python query.py

通过条件:

  • python query.py 0xF004 输出名称 EngineSpeed、长度 8 字节、频率 20 ms、子系统 Engine。
  • python query.py 65262(即 0xFEEE)输出“未收录于本地数据库”。
  • 输入非法字符串(如 abc)时打印解析失败提示并返回退出码 1。

扩展方式:向 PGN_DB 追加键值即可新增 PGN,键为整数 PGN 号,值为含 name/length/rate_ms/system 的字典;rate_ms=0 表示事件触发型报文。