Sync edgetx to Gitea
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
from enum import Enum
|
||||
from typing_extensions import List, Literal, Optional, Tuple, Union
|
||||
|
||||
from pydantic import BaseModel, model_validator
|
||||
from pydantic_core import from_json, PydanticCustomError
|
||||
|
||||
|
||||
class StrEnum(str, Enum):
|
||||
@staticmethod
|
||||
def _generate_next_value_(name, start, count, last_values):
|
||||
return name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
|
||||
ADCNameType = Literal["MAIN", "EXT", "SPI"]
|
||||
|
||||
|
||||
class ADC(BaseModel):
|
||||
name: ADCNameType
|
||||
adc: str
|
||||
sample_time: Optional[str] = None
|
||||
dma: Optional[str] = None
|
||||
dma_channel: Optional[str] = None
|
||||
dma_stream: Optional[str] = None
|
||||
dma_stream_irq: Optional[str] = None
|
||||
dma_stream_irq_handler: Optional[str] = None
|
||||
# SPI ADC fields
|
||||
gpio_pin_sck: Optional[str] = None
|
||||
gpio_pin_miso: Optional[str] = None
|
||||
gpio_pin_mosi: Optional[str] = None
|
||||
gpio_pin_cs: Optional[str] = None
|
||||
|
||||
|
||||
StickEnum = StrEnum(
|
||||
"StickEnum",
|
||||
(
|
||||
# 2 Gimbal radios
|
||||
"LH",
|
||||
"LV",
|
||||
"RV",
|
||||
"RH",
|
||||
# Surface radios
|
||||
"ST",
|
||||
"TH",
|
||||
),
|
||||
)
|
||||
|
||||
MAX_POTS = 8
|
||||
MAX_SLIDERS = 8
|
||||
MAX_EXT = 16
|
||||
MAX_RAW = 8
|
||||
|
||||
FlexInputEnum = StrEnum(
|
||||
"FlexInputEnum",
|
||||
(
|
||||
[f"P{i}" for i in range(1, MAX_POTS)]
|
||||
+ [f"SL{i}" for i in range(1, MAX_SLIDERS)]
|
||||
+ [f"EXT{i}" for i in range(1, MAX_EXT)]
|
||||
+ ["JSx", "JSy"]
|
||||
),
|
||||
)
|
||||
|
||||
SwitchInputEnum = StrEnum(
|
||||
"SwitchInputEnum",
|
||||
list([f"SW{chr(i)}" for i in range(ord("A"), ord("Z") + 1)]),
|
||||
)
|
||||
|
||||
RawInputEnum = StrEnum("RawInputEnum", list([f"RAW{i}" for i in range(1, MAX_RAW)]))
|
||||
|
||||
InputNameType = Union[StickEnum, FlexInputEnum, SwitchInputEnum, RawInputEnum]
|
||||
|
||||
InputType = StrEnum(
|
||||
"InputType",
|
||||
(
|
||||
"STICK",
|
||||
"FLEX",
|
||||
"SWITCH",
|
||||
"VBAT",
|
||||
"RTC_BAT",
|
||||
"RAW",
|
||||
"LUX",
|
||||
),
|
||||
)
|
||||
|
||||
FlexType = StrEnum(
|
||||
"FlexType",
|
||||
(
|
||||
"NONE",
|
||||
"POT",
|
||||
"POT_CENTER",
|
||||
"SLIDER",
|
||||
"MULTIPOS",
|
||||
"AXIS_X",
|
||||
"AXIS_Y",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class StickInput(BaseModel):
|
||||
name: StickEnum
|
||||
type: Literal["STICK"]
|
||||
adc: Optional[ADCNameType] = None
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
inverted: Optional[bool] = False
|
||||
pwm_channel: Optional[int] = None
|
||||
|
||||
|
||||
class FlexInput(BaseModel):
|
||||
name: FlexInputEnum
|
||||
type: Literal["FLEX"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
inverted: Optional[bool] = False
|
||||
default: Optional[FlexType] = None
|
||||
label: Optional[str] = None
|
||||
short_label: Optional[str] = None
|
||||
|
||||
|
||||
class SwitchInput(BaseModel):
|
||||
name: SwitchInputEnum
|
||||
type: Literal["SWITCH"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
inverted: Optional[bool] = False
|
||||
|
||||
|
||||
class RawInput(BaseModel):
|
||||
name: RawInputEnum
|
||||
type: Literal["RAW"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
|
||||
|
||||
class VBatInput(BaseModel):
|
||||
name: Literal["VBAT"]
|
||||
type: Literal["VBAT"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
|
||||
|
||||
class RTCBatInput(BaseModel):
|
||||
name: Literal["RTC_BAT"]
|
||||
type: Literal["RTC_BAT"]
|
||||
adc: Literal["MAIN", "EXT"]
|
||||
channel: str
|
||||
|
||||
|
||||
class LuxInput(BaseModel):
|
||||
name: Literal["LUX"]
|
||||
type: Literal["LUX"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
|
||||
|
||||
Input = Union[StickInput, FlexInput, SwitchInput, RawInput, VBatInput, RTCBatInput, LuxInput]
|
||||
|
||||
|
||||
class ADCInputs(BaseModel):
|
||||
adcs: List[ADC]
|
||||
inputs: List[Input]
|
||||
|
||||
|
||||
# MUST be the same order as 'EnumKeys'
|
||||
KeyEnum = StrEnum(
|
||||
"KeyEnum",
|
||||
(
|
||||
"KEY_MENU",
|
||||
"KEY_EXIT",
|
||||
"KEY_ENTER",
|
||||
"KEY_PAGEUP",
|
||||
"KEY_PAGEDN",
|
||||
"KEY_UP",
|
||||
"KEY_DOWN",
|
||||
"KEY_LEFT",
|
||||
"KEY_RIGHT",
|
||||
"KEY_PLUS",
|
||||
"KEY_MINUS",
|
||||
"KEY_MODEL",
|
||||
"KEY_TELE",
|
||||
"KEY_SYS",
|
||||
"KEY_SHIFT",
|
||||
"KEY_BIND",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class Key(BaseModel):
|
||||
name: str
|
||||
label: str
|
||||
key: KeyEnum
|
||||
active_low: Optional[bool] = False
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_hardware(self: "Key") -> "Key":
|
||||
if bool(self.gpio) != bool(self.pin):
|
||||
raise PydanticCustomError(
|
||||
"KeyHardwareError",
|
||||
"Key missing either 'gpio' or 'pin'",
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
SwitchHardwareTypeEnum = StrEnum(
|
||||
"SwitchTypeEnum",
|
||||
(
|
||||
"2POS",
|
||||
"3POS",
|
||||
"ADC",
|
||||
"FSWITCH",
|
||||
),
|
||||
)
|
||||
|
||||
SwitchTypeEnum = StrEnum(
|
||||
"SwitchTypeEnum",
|
||||
(
|
||||
"2POS",
|
||||
"3POS",
|
||||
"TOGGLE",
|
||||
"NONE",
|
||||
),
|
||||
)
|
||||
|
||||
SwitchDisplayType = Union[Tuple[int, int], Tuple]
|
||||
|
||||
|
||||
class Switch(BaseModel):
|
||||
name: str
|
||||
type: SwitchHardwareTypeEnum
|
||||
default: Optional[SwitchTypeEnum] = SwitchTypeEnum.NONE
|
||||
flags: Optional[int] = 0
|
||||
inverted: Optional[bool] = False
|
||||
is_cfs: Optional[bool] = False
|
||||
cfs_idx: Optional[int] = None
|
||||
adc_input: Optional[str] = None
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
gpio_high: Optional[str] = None
|
||||
pin_high: Optional[str] = None
|
||||
gpio_low: Optional[str] = None
|
||||
pin_low: Optional[str] = None
|
||||
display: Optional[SwitchDisplayType] = None
|
||||
|
||||
def _uses_single_gpio(self: "Switch") -> bool:
|
||||
return bool(self.pin)
|
||||
|
||||
def _uses_two_gpios(self: "Switch") -> bool:
|
||||
return bool(self.pin_high or self.pin_low)
|
||||
|
||||
def _uses_gpio(self: "Switch") -> bool:
|
||||
return bool(self.gpio_high or self.gpio_low or self.gpio)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_hardware(self: "Switch") -> "Switch":
|
||||
if bool(self.adc_input) == self._uses_gpio():
|
||||
if self.adc_input:
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"A switch is either using ADC or it's own GPIO pin(s)",
|
||||
)
|
||||
|
||||
if self._uses_gpio() and (self._uses_single_gpio() == self._uses_two_gpios()):
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"A switch based on GPIO pin(s) uses either a single or two GPIOs",
|
||||
)
|
||||
|
||||
if self._uses_single_gpio():
|
||||
if str(self.type) not in ["2POS", "FSWITCH"]:
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"Single GPIO switch type is either '2POS' or 'FSWITCH'",
|
||||
)
|
||||
# TODO: check 'default' as well?
|
||||
|
||||
if self._uses_two_gpios():
|
||||
if not self.pin_high or not self.pin_low:
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"Switch missing 'pin_high' or 'pin_low'",
|
||||
)
|
||||
if str(self.type) != "3POS":
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"Dual GPIO switch type is always '3POS",
|
||||
)
|
||||
# TODO: check 'default' as well?
|
||||
|
||||
return self
|
||||
|
||||
|
||||
class HardwareDefinition(BaseModel):
|
||||
adc_inputs: ADCInputs
|
||||
switches: List[Switch]
|
||||
keys: List[Key]
|
||||
|
||||
@staticmethod
|
||||
def from_json(data: Union[str, bytes, bytearray]) -> "HardwareDefinition":
|
||||
return HardwareDefinition.model_validate(from_json(data))
|
||||
Reference in New Issue
Block a user