feat(set-protocol): добавь порт F407 для DevBoard_V1

This commit is contained in:
2026-09-07 08:32:02 +03:00
parent c9cf797132
commit daa3466a41
12 changed files with 516 additions and 1 deletions

View File

@@ -0,0 +1,60 @@
"""CAN485 DevBoard_V1 USB command and frame helpers (no GUI/serial dependency)."""
from __future__ import annotations
import re
from dataclasses import dataclass
FRAME_RE = re.compile(
r"^\[\s*(\d+)\.(\d{3})\]\s+(?:(RS485)\s+)?"
r"(EXT|STD)\s+0x([0-9A-Fa-f]+)\s+"
r"(RTR\s+)?DLC=(\d)(?:\s+DATA=([0-9A-Fa-f ]*))?"
)
@dataclass(frozen=True, slots=True)
class BoardFrame:
timestamp: float
extended: bool
can_id: int
data: bytes
rtr: bool = False
source: str = "CAN"
def parse_frame_line(line: str) -> BoardFrame | None:
match = FRAME_RE.match(line.strip())
if match is None:
return None
seconds, millis, source, frame_type, raw_id, raw_rtr, raw_dlc, raw_data = match.groups()
dlc = int(raw_dlc)
data = bytes.fromhex(raw_data or "")
rtr = bool(raw_rtr)
if (not rtr and len(data) != dlc) or (rtr and data):
return None
extended = frame_type == "EXT"
can_id = int(raw_id, 16)
if can_id > (0x1FFFFFFF if extended else 0x7FF):
return None
return BoardFrame(int(seconds) + int(millis) / 1000.0, extended, can_id,
data, rtr, source or "CAN")
def command_transmit(frame: BoardFrame) -> bytes:
if len(frame.data) > 8:
raise ValueError("DLC cannot exceed 8")
kind = "E" if frame.extended else "S"
return f"T,{kind},{frame.can_id:X},{len(frame.data)},{frame.data.hex().upper()}\n".encode("ascii")
def command_setup(*, can_bitrate: int = 500, rs485_baud: int = 512000,
route: int = 3) -> tuple[bytes, ...]:
if can_bitrate not in (25, 50, 100, 125, 250, 500, 800, 1000):
raise ValueError("unsupported CAN bitrate")
if not 1200 <= rs485_baud <= 4_000_000:
raise ValueError("unsupported RS485 baud")
if route not in range(4):
raise ValueError("route must be 0..3")
return (f"S{can_bitrate}\n".encode("ascii"), b"M0\n",
f"B{rs485_baud}\n".encode("ascii"), f"Q{route}\n".encode("ascii"))

View File

@@ -0,0 +1,14 @@
from protocan.devboard_v1 import BoardFrame, command_setup, command_transmit, parse_frame_line
def test_parse_can_and_rs485_lines():
can = parse_frame_line("[ 12.345] EXT 0x073700A2 DLC=2 DATA=34 12 |4.|")
rs = parse_frame_line("[ 12.346] RS485 STD 0x123 RTR DLC=4")
assert can and can.can_id == 0x073700A2 and can.data == b"\x34\x12"
assert rs and rs.source == "RS485" and rs.rtr and rs.data == b""
def test_commands_are_firmware_compatible_and_lf_terminated():
frame = BoardFrame(0.0, True, 0x073700A2, b"\x34\x12")
assert command_transmit(frame) == b"T,E,73700A2,2,3412\n"
assert command_setup() == (b"S500\n", b"M0\n", b"B512000\n", b"Q3\n")