feat(vesc): integrate native calibration diagnostics and configuration archives
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""Owner-assigned drive slots, independent of USB addresses and motor commands."""
|
||||
import json
|
||||
|
||||
LAYOUTS = {"1x1": ("left.1", "right.1"), "2x2": ("left.1", "left.2", "right.1", "right.2")}
|
||||
|
||||
def slot_label(layout, slot):
|
||||
side = "Левый" if slot.startswith("left.") else "Правый"
|
||||
return side + ((" передний" if slot.endswith(".1") else " задний") if layout == "2x2" else "")
|
||||
|
||||
|
||||
class DriveProfile:
|
||||
def __init__(self, root, atomic):
|
||||
self.path, self.atomic = root / "drive-profile.json", atomic
|
||||
self.value = json.loads(self.path.read_text()) if self.path.exists() else {"layout": None, "revision": 0, "bindings": {}}
|
||||
|
||||
def update(self, action, params, device):
|
||||
current = self.value
|
||||
if params["revision"] != current["revision"]:
|
||||
raise ValueError("Профиль привода изменился. Обновите карточку.")
|
||||
bindings = dict(current["bindings"])
|
||||
layout = current["layout"]
|
||||
if action == "vesc.drive.layout":
|
||||
layout = params["layout"]
|
||||
if set(bindings) - set(LAYOUTS[layout]):
|
||||
raise ValueError("Сначала снимите назначения задних моторов.")
|
||||
elif action == "vesc.drive.assign":
|
||||
layout, slot = params["layout"], params["slot"]
|
||||
if set(bindings) - set(LAYOUTS[layout]):
|
||||
raise ValueError("Сначала снимите назначения задних моторов.")
|
||||
if slot and slot in bindings and bindings[slot]["device_id"] != device.id:
|
||||
raise ValueError("Это место уже занято. Сначала снимите прежнее назначение.")
|
||||
bindings = {key: value for key, value in bindings.items() if value["device_id"] != device.id}
|
||||
if slot:
|
||||
bindings[slot] = {"device_id": device.id, "uuid": device.identity["uuid"]}
|
||||
else:
|
||||
bindings.pop(params["slot"], None)
|
||||
value = {"layout": layout, "revision": current["revision"] + 1, "bindings": bindings}
|
||||
self.atomic(self.path, value)
|
||||
self.value = value
|
||||
return value
|
||||
|
||||
|
||||
def validate(action, params):
|
||||
keys = {"revision", "layout"} if action == "vesc.drive.layout" else ({"revision", "layout", "slot"} if action == "vesc.drive.assign" else {"revision", "slot"})
|
||||
if set(params) != keys or type(params["revision"]) is not int or params["revision"] < 0:
|
||||
raise ValueError("Invalid drive profile revision")
|
||||
if action == "vesc.drive.layout":
|
||||
if params["layout"] not in LAYOUTS:
|
||||
raise ValueError("Invalid drive layout")
|
||||
elif action == "vesc.drive.assign":
|
||||
if params["layout"] not in LAYOUTS or params["slot"] not in ("", *LAYOUTS[params["layout"]]):
|
||||
raise ValueError("Invalid drive layout or slot")
|
||||
elif params["slot"] not in LAYOUTS["2x2"]:
|
||||
raise ValueError("Invalid drive slot")
|
||||
Reference in New Issue
Block a user