4. J1939请求PGN报文发送与响应
任务说明
本案例实现 J1939 请求报文(PGN 59904,Request)的发送与响应解析。请求报文数据域固定 3 字节,内容为被请求 PGN 的小端表示。目标 PGN 以 0xFEF1(车速,Vehicle Speed)为例,接收方收到请求后返回对应 PGN 数据,发送方解析响应中的车速值。
报文结构
- Request PGN:PGN=59904(0x00EA00),数据域 3 字节 = 目标 PGN 小端(0xFEF1 → F1 FE 00)。
- 响应 PGN:0xFEF1,数据域第 1~2 字节为车速,分辨率 1/256 km/h,偏移 0。
- J1939 29 位 ID 组成:优先级(3) + PGN(18) + 源地址(8)。
完整实现(Python)
import struct
# J1939 29位ID构造:优先级(3) | PGN(18) | 源地址(8)
def build_id(priority, pgn, sa):
return ((priority & 0x7) << 26) | ((pgn & 0x3FFFF) << 8) | (sa & 0xFF)
def parse_id(can_id):
priority = (can_id >> 26) & 0x7
pgn = (can_id >> 8) & 0x3FFFF
sa = can_id & 0xFF
return priority, pgn, sa
REQUEST_PGN = 59904 # 0x00EA00
TARGET_PGN = 0xFEF1 # 车速
SA_SENDER = 0x80
SA_RESPONDER = 0x90
# 1. 构造 Request PGN 报文
def build_request(target_pgn, sa):
data = struct.pack("<I", target_pgn)[:3] # 小端3字节
can_id = build_id(6, REQUEST_PGN, sa)
return can_id, data
# 2. 响应方:收到请求后返回车速
def build_response(speed_kmh, sa):
raw = int(round(speed_kmh * 256)) & 0xFFFF
data = struct.pack("<H", raw)
can_id = build_id(6, TARGET_PGN, sa)
return can_id, data
# 3. 发送方:解析响应
def parse_response(can_id, data):
_, pgn, sa = parse_id(can_id)
if pgn != TARGET_PGN:
return None
if len(data) < 2:
return None
raw = struct.unpack("<H", data[:2])[0]
return {"sa": sa, "speed_kmh": raw / 256.0}
# ---- 最小闭环验证 ----
req_id, req_data = build_request(TARGET_PGN, SA_SENDER)
print("Request ID=0x%08X data=%s" % (req_id, req_data.hex()))
# 响应方解析请求
_, rpgn, rsa = parse_id(req_id)
assert rpgn == REQUEST_PGN
requested = struct.unpack("<I", req_data + b"\x00")[0]
assert requested == TARGET_PGN
print("Responder got request for PGN=0x%04X from SA=0x%02X" % (requested, rsa))
# 响应方返回 88.5 km/h
resp_id, resp_data = build_response(88.5, SA_RESPONDER)
print("Response ID=0x%08X data=%s" % (resp_id, resp_data.hex()))
# 发送方解析响应
result = parse_response(resp_id, resp_data)
print("Parsed:", result)
assert result["sa"] == SA_RESPONDER
assert abs(result["speed_kmh"] - 88.5) < 0.01
print("OK")
运行与验证
直接执行 python j1939_request.py。预期输出:Request ID 与数据 f1fe00,响应数据为 88.5×256=22656=0x5880 的小端 8058,解析结果 speed_kmh=88.5,末尾打印 OK。断言全部通过即表示请求构造、响应生成与解析闭环正确。
关键点
- Request PGN 数据域固定 3 字节,必须小端填充目标 PGN。
- 响应解析需先按 PGN 过滤,避免误处理其他报文。
- 车速分辨率 1/256 km/h,解析时除以 256 还原物理值。