Source code for jaeger.commands

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# @Author: José Sánchez-Gallego (gallegoj@uw.edu)
# @Date: 2018-08-27
# @Filename: __init__.py
# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause)

from __future__ import annotations

import enum

from typing import Dict, Type, Union


class TypesEnumMeta(enum.EnumMeta):
    """Metaclass to allow initialising an Enum from a string."""

    def __call__(cls: Type[enum.Enum], value: Union[str, int]):
        if isinstance(value, str):
            for flag in cls:
                if flag.name.lower() == value.lower():
                    return enum.EnumMeta.__call__(cls, flag.value)
            raise ValueError(f"Invalid {cls.__name__} value: {value}")

        return enum.EnumMeta.__call__(cls, value)


[docs] class CommandID(enum.IntEnum, metaclass=TypesEnumMeta): """IDs associated with commands.""" GET_ID = 1 GET_FIRMWARE_VERSION = 2 GET_STATUS = 3 SEND_NEW_TRAJECTORY = 10 SEND_TRAJECTORY_DATA = 11 TRAJECTORY_DATA_END = 12 SEND_TRAJECTORY_ABORT = 13 START_TRAJECTORY = 14 STOP_TRAJECTORY = 15 COLLISION_DETECTED = 18 GO_TO_DATUMS = 20 GO_TO_DATUM_ALPHA = 21 GO_TO_DATUM_BETA = 22 START_DATUM_CALIBRATION = 23 START_DATUM_CALIBRATION_ALPHA = 24 START_DATUM_CALIBRATION_BETA = 25 START_MOTOR_CALIBRATION = 26 START_MOTOR_CALIBRATION_ALPHA = 26 START_MOTOR_CALIBRATION_BETA = 27 GO_TO_ABSOLUTE_POSITION = 30 GO_TO_RELATIVE_POSITION = 31 GET_ACTUAL_POSITION = 32 SET_ACTUAL_POSITION = 33 GET_OFFSETS = 34 SET_OFFSETS = 35 SET_SPEED = 40 SET_CURRENT = 41 GET_HALL_CALIB_ERROR = 45 START_COGGING_CALIBRATION = 47 START_COGGING_CALIBRATION_ALPHA = 48 START_COGGING_CALIBRATION_BETA = 49 SAVE_INTERNAL_CALIBRATION = 53 GET_CURRENT = 56 GET_ALPHA_HALL_CALIB = 104 GET_BETA_HALL_CALIB = 105 SET_INCREASE_COLLISION_MARGIN = 111 SET_HOLDING_CURRENT = 112 GET_HOLDING_CURRENT = 113 HALL_ON = 116 HALL_OFF = 117 ALPHA_CLOSED_LOOP_COLLISION_DETECTION = 118 ALPHA_CLOSED_LOOP_WITHOUT_COLLISION_DETECTION = 119 ALPHA_OPEN_LOOP_COLLISION_DETECTION = 120 ALPHA_OPEN_LOOP_WITHOUT_COLLISION_DETECTION = 121 BETA_CLOSED_LOOP_COLLISION_DETECTION = 122 BETA_CLOSED_LOOP_WITHOUT_COLLISION_DETECTION = 123 BETA_OPEN_LOOP_COLLISION_DETECTION = 124 BETA_OPEN_LOOP_WITHOUT_COLLISION_DETECTION = 125 SWITCH_LED_ON = 126 SWITCH_LED_OFF = 127 SWITCH_ON_PRECISE_MOVE_ALPHA = 128 SWITCH_OFF_PRECISE_MOVE_ALPHA = 129 SWITCH_ON_PRECISE_MOVE_BETA = 130 SWITCH_OFF_PRECISE_MOVE_BETA = 131 GET_RAW_TEMPERATURE = 132 GET_NUMBER_TRAJECTORIES = 139 SET_NUMBER_TRAJECTORIES = 140 START_FIRMWARE_UPGRADE = 200 SEND_FIRMWARE_DATA = 201
[docs] def get_command_class(self) -> Type[Command]: """Returns the class associated with this command.""" if self in COMMAND_LIST: return COMMAND_LIST[self] raise ValueError("The command does not have an associated class.")
from .base import * from .base import Command from .bootloader import * from .calibration import * from .goto import * from .status import * from .trajectory import * def all_subclasses(cls): """Recursive subclasses.""" return set(cls.__subclasses__()).union( [s for c in cls.__subclasses__() for s in all_subclasses(c)] ) # Generate a dictionary of commands COMMAND_LIST: Dict[int, Type[Command]] = { cclass.command_id: cclass for cclass in all_subclasses(Command) if cclass.command_id in CommandID } # Dynamically generate command classes for those commands for which we # didn't write a class. These classes are identical to a generic Command # but with a custom name. for cid in list(CommandID): if cid not in COMMAND_LIST: CommandClass = type( cid.name.title().replace("_", ""), (Command,), {"command_id": cid, "broadcastable": False}, ) COMMAND_LIST[cid] = CommandClass