Files
NODEDC_MISSION_CORE/plugins/vesc/runtime/drive_profile.py
T

55 lines
2.9 KiB
Python

"""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")