From 16e43bed156a9832d39eafd604747c62917d2238 Mon Sep 17 00:00:00 2001 From: Mat Manna Date: Mon, 9 Feb 2026 22:09:39 -0500 Subject: [PATCH 01/10] :package: add vendored ltamp package --- backend/ltamp/README.md | 120 +++++++++++ backend/ltamp/ltamp/__init__.py | 7 + backend/ltamp/ltamp/hidDevice.py | 61 ++++++ backend/ltamp/ltamp/hidWrapper.py | 56 +++++ backend/ltamp/ltamp/ltAmpAsync.py | 166 +++++++++++++++ backend/ltamp/ltamp/ltAmpBase.py | 198 ++++++++++++++++++ backend/ltamp/ltamp/ltAmpSync.py | 143 +++++++++++++ .../ltamp/ltamp/protocol/ActiveDisplay_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/AudioStatus_pb2.py | 36 ++++ .../protocol/AuditionPresetStatus_pb2.py | 36 ++++ .../ltamp/protocol/AuditionPreset_pb2.py | 36 ++++ .../protocol/AuditionStateRequest_pb2.py | 36 ++++ .../ltamp/protocol/AuditionStateStatus_pb2.py | 36 ++++ .../ltamp/protocol/ClearPresetStatus_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/ClearPreset_pb2.py | 36 ++++ .../protocol/ConnectionStatusRequest_pb2.py | 36 ++++ .../ltamp/protocol/ConnectionStatus_pb2.py | 36 ++++ .../CurrentDisplayedPresetIndexStatus_pb2.py | 36 ++++ ...urrentLoadedPresetIndexBypassStatus_pb2.py | 36 ++++ .../CurrentLoadedPresetIndexStatus_pb2.py | 36 ++++ .../protocol/CurrentPresetRequest_pb2.py | 36 ++++ .../ltamp/protocol/CurrentPresetSet_pb2.py | 36 ++++ .../ltamp/protocol/CurrentPresetStatus_pb2.py | 36 ++++ .../protocol/DspUnitParameterStatus_pb2.py | 36 ++++ .../protocol/ExitAuditionPresetStatus_pb2.py | 36 ++++ .../ltamp/protocol/ExitAuditionPreset_pb2.py | 36 ++++ .../ltamp/protocol/FenderMessageLT_pb2.py | 104 +++++++++ .../protocol/FirmwareVersionRequest_pb2.py | 36 ++++ .../protocol/FirmwareVersionStatus_pb2.py | 36 ++++ .../protocol/FrameBufferMessageRequest_pb2.py | 36 ++++ .../ltamp/protocol/FrameBufferMessage_pb2.py | 36 ++++ backend/ltamp/ltamp/protocol/Heartbeat_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/IndexButton_pb2.py | 38 ++++ .../ltamp/ltamp/protocol/IndexEncoder_pb2.py | 36 ++++ backend/ltamp/ltamp/protocol/IndexPot_pb2.py | 36 ++++ .../protocol/LT4FootswitchModeRequest_pb2.py | 36 ++++ .../protocol/LT4FootswitchModeStatus_pb2.py | 38 ++++ .../ltamp/protocol/LineOutGainRequest_pb2.py | 36 ++++ .../ltamp/protocol/LineOutGainSet_pb2.py | 36 ++++ .../ltamp/protocol/LineOutGainStatus_pb2.py | 36 ++++ .../protocol/LoadPreset_TestSuite_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/LoadPreset_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/LoopbackTest_pb2.py | 36 ++++ .../ltamp/protocol/MemoryUsageRequest_pb2.py | 36 ++++ .../ltamp/protocol/MemoryUsageStatus_pb2.py | 36 ++++ .../ltamp/protocol/ModalStatusMessage_pb2.py | 40 ++++ .../protocol/NewPresetSavedStatus_pb2.py | 36 ++++ .../PresetJSONMessageRequest_LT_pb2.py | 36 ++++ .../ltamp/protocol/PresetJSONMessage_pb2.py | 36 ++++ .../ltamp/protocol/PresetSavedStatus_pb2.py | 36 ++++ .../ProcessorUtilizationRequest_pb2.py | 36 ++++ .../protocol/ProcessorUtilization_pb2.py | 36 ++++ .../ProductIdentificationRequest_pb2.py | 36 ++++ .../ProductIdentificationStatus_pb2.py | 36 ++++ .../ltamp/protocol/QASlotsRequest_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/QASlotsSet_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/QASlotsStatus_pb2.py | 36 ++++ .../ltamp/protocol/RenamePresetAt_pb2.py | 36 ++++ .../ltamp/protocol/ReplaceNodeStatus_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/ReplaceNode_pb2.py | 36 ++++ .../ltamp/protocol/RetrievePreset_pb2.py | 36 ++++ .../ltamp/protocol/SaveCurrentPresetTo_pb2.py | 36 ++++ .../ltamp/protocol/SaveCurrentPreset_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/SavePresetAs_pb2.py | 36 ++++ .../protocol/SetDspUnitParameterStatus_pb2.py | 36 ++++ .../ltamp/protocol/SetDspUnitParameter_pb2.py | 36 ++++ .../ltamp/protocol/ShiftPresetStatus_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/ShiftPreset_pb2.py | 36 ++++ .../ltamp/protocol/SwapPresetStatus_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/SwapPreset_pb2.py | 36 ++++ .../protocol/UnsupportedMessageStatus_pb2.py | 38 ++++ .../ltamp/protocol/UsbGainRequest_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/UsbGainSet_pb2.py | 36 ++++ .../ltamp/ltamp/protocol/UsbGainStatus_pb2.py | 36 ++++ backend/ltamp/ltamp/protocol/__init__.py | 163 ++++++++++++++ backend/ltamp/pyproject.toml | 38 ++++ backend/ltamp/tests/test_ltamp.py | 109 ++++++++++ 77 files changed, 3551 insertions(+) create mode 100644 backend/ltamp/README.md create mode 100644 backend/ltamp/ltamp/__init__.py create mode 100644 backend/ltamp/ltamp/hidDevice.py create mode 100644 backend/ltamp/ltamp/hidWrapper.py create mode 100644 backend/ltamp/ltamp/ltAmpAsync.py create mode 100644 backend/ltamp/ltamp/ltAmpBase.py create mode 100644 backend/ltamp/ltamp/ltAmpSync.py create mode 100644 backend/ltamp/ltamp/protocol/ActiveDisplay_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/AudioStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/AuditionPresetStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/AuditionPreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/AuditionStateRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/AuditionStateStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ClearPresetStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ClearPreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ConnectionStatusRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ConnectionStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/CurrentDisplayedPresetIndexStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/CurrentLoadedPresetIndexBypassStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/CurrentLoadedPresetIndexStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/CurrentPresetRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/CurrentPresetSet_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/CurrentPresetStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/DspUnitParameterStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ExitAuditionPresetStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ExitAuditionPreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/FenderMessageLT_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/FirmwareVersionRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/FirmwareVersionStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/FrameBufferMessageRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/FrameBufferMessage_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/Heartbeat_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/IndexButton_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/IndexEncoder_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/IndexPot_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LT4FootswitchModeRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LT4FootswitchModeStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LineOutGainRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LineOutGainSet_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LineOutGainStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LoadPreset_TestSuite_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LoadPreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/LoopbackTest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/MemoryUsageRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/MemoryUsageStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ModalStatusMessage_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/NewPresetSavedStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/PresetJSONMessageRequest_LT_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/PresetJSONMessage_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/PresetSavedStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ProcessorUtilizationRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ProcessorUtilization_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ProductIdentificationRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ProductIdentificationStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/QASlotsRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/QASlotsSet_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/QASlotsStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/RenamePresetAt_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ReplaceNodeStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ReplaceNode_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/RetrievePreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/SaveCurrentPresetTo_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/SaveCurrentPreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/SavePresetAs_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/SetDspUnitParameterStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/SetDspUnitParameter_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ShiftPresetStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/ShiftPreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/SwapPresetStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/SwapPreset_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/UnsupportedMessageStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/UsbGainRequest_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/UsbGainSet_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/UsbGainStatus_pb2.py create mode 100644 backend/ltamp/ltamp/protocol/__init__.py create mode 100644 backend/ltamp/pyproject.toml create mode 100644 backend/ltamp/tests/test_ltamp.py diff --git a/backend/ltamp/README.md b/backend/ltamp/README.md new file mode 100644 index 0000000..c86c0c6 --- /dev/null +++ b/backend/ltamp/README.md @@ -0,0 +1,120 @@ +# LtAmp.py + +[![PyPI Latest Release](https://img.shields.io/pypi/v/ltamp.svg)](https://pypi.org/project/ltamp/) +[![wakatime](https://wakatime.com/badge/user/7482ea9d-3085-4e9b-95ad-1ca78a14d948/project/08632cd5-4928-49fb-8d0d-2d8f2bebbdad.svg)](https://wakatime.com/badge/user/7482ea9d-3085-4e9b-95ad-1ca78a14d948/project/08632cd5-4928-49fb-8d0d-2d8f2bebbdad) +![MIT License](https://img.shields.io/github/license/bendertools/ltamp.py) + +🎸 A cross-platform Python module for interacting with LT amplifiers from a guitar company that rhymes with "bender" and names products after horses. + +> [!NOTE] +> At the moment, only LT25 amps are fully tested and have been tested for protocol support. + +## πŸ‘‹ Introduction + +I made this libray because I was disappointed by the lack of certain features in both my amp itself as well as the associated desktop app provided by its manufacturer. Failing to find a starting point (using modern technologies) I could build upon (.NET doesnt count), I wrote this little module based on the reverse-engineering work others initiated. + +### βš™οΈ Specifications + +This package requires Python 3.8+ to be installed on your system (due to demands of the protobuf 5 module). Additionally, the library only supports HID USB operations (no MIDI). + +## πŸš€ Quickstart + +``` +pip install ltamp +python +>>> from ltamp import LtAmp +>>> LtAmp().connect() +``` + +> [!IMPORTANT] +> On linux, hidapi relies on libusb: `sudo apt install libusb-1.0-0-dev libudev-dev pkg-config` + +## πŸ’Ύ Usage + +For full documentation of the LtAmp and LtAmpAsync classes, refer to the [wiki](/wiki). + +**Demonstration loop:** + +```python +import time +import ltamp + +amp = ltamp.LtAmp() +amp.connect() +amp.send_sync_begin() +amp.send_sync_end() +amp.set_preset(5) +amp.set_qa_slots([1,2]) +amp.request_firmware_version() +for i in range(5): + amp.send_heartbeat() + print(amp.request_qa_slots()) + time.sleep(1) +amp.disconnect() +``` + +> [!WARNING] +> On some linux distros, `sudo`-mode is required for running python files which interact with USB devices. + +## πŸ—ΊοΈ Roadmap + +Compatibility with LtAmp protocol: + +- [ ] Audio Status +- [x] Audition Preset (status, start, exit) +- [ ] Clear/rename/shift/swap/save (to/as) preset +- [x] Retrieve preset +- [x] Connection Status +- [x] Current Preset (request/load) +- [ ] DSP Unit Parameter +- [x] Firmware Version +- [x] Heartbeat +- [x] LT4 Footswitch Mode +- [ ] Loopback +- [x] Memory usage +- [x] Product Identification +- [x] Processor Utilization +- [x] QA Slots +- [x] Sync (Modal Status) +- [x] USB Gain + +Other TODOs: + +- [x] Publish to Pypi +- [x] Continuous Deployment +- [x] LtAmpAsync/Base Classes +- [x] Document classes in Wiki +- [ ] Unit Testing +- [x] Customize timeout +- [ ] Complete Protocol +- [x] Other LT Amps +- [ ] Multiple Connected Devices + +Fully-tested LT-series amps: + +- [x] LT25 +- [ ] LT40S +- [ ] LT50 +- [ ] LTX100? +- [ ] LTX50? +- [ ] R15-R100? + +## πŸ› οΈ Contributing + +> [!NOTE] +> If you need to contribute in a way which updates protocol classes, you can find the original .proto files in Brent Maxwell's [repository](https://github.com/brentmaxwell/LtAmp/). I unfortunately cannot include these files in this module due to copyleft licensing restrictions. + +LtAmp.py is licensed under the permissive MIT license, which means that you may fork, modify, adapt, and redistribute with few restrictions. If you wish to contribute your changes back to the base module, please open a [pull request](/pulls). To report bugs, request features, or discuss the project, open an [issue](/issues) or [discussion](/discussions). + +### πŸ§ͺ Testing + +To run unit tests, use the command: + +```bash +python -m unittest discover tests +``` + +## πŸ™Œ Acknowledgements + +- Brent Maxwell ([@brentmaxwell](https://github.com/brentmaxwell)) and his LtAmp .NET libray: his published reverse engineering docs, schemas, proto files, etc. were instrumental in the creation of this Python module. + - Additionally, some of the goals of his work greatly inspired those of this project. diff --git a/backend/ltamp/ltamp/__init__.py b/backend/ltamp/ltamp/__init__.py new file mode 100644 index 0000000..c6e0c3a --- /dev/null +++ b/backend/ltamp/ltamp/__init__.py @@ -0,0 +1,7 @@ +from .hidWrapper import HIDWrapper, HIDDevice +from .ltAmpSync import LtAmp +from .ltAmpAsync import LtAmpAsync + +__all__ = [ + 'LtAmp', 'LtAmpAsync', 'HIDWrapper', 'HIDDevice' +] diff --git a/backend/ltamp/ltamp/hidDevice.py b/backend/ltamp/ltamp/hidDevice.py new file mode 100644 index 0000000..bb6acc3 --- /dev/null +++ b/backend/ltamp/ltamp/hidDevice.py @@ -0,0 +1,61 @@ +class HIDDevice: + """unified HID device interface""" + + def __init__(self, device, backend, debug=False): + self.device = device + self.backend = backend + self.debug = debug + self.input_callback = None + + def write(self, data): + """write data to device""" + if self.backend == "hidapi": + # plain data but pad to 64 bytes + packet = bytearray(64) + for i in range(min(len(data), 64)): + packet[i] = data[i] + + result = self.device.write(packet) + elif self.backend == "pywinusb": + # needs 65 bytes: [report_id] + [64 bytes of data] + packet = bytearray(65) + packet[0] = 0x00 + for i in range(min(len(data), 64)): + packet[i + 1] = data[i] + + out_report = self.device.find_output_reports()[0] + out_report.set_raw_data(packet) + out_report.send() + + def read(self, length=64, timeout_ms=100): + """read data from device (hidapi only)""" + if self.backend == "hidapi": + try: + data = self.device.read(length, timeout_ms) + return bytes(data) if data else None + except Exception as e: + raise RuntimeError(f"Failed to read from device: {e}") + elif self.backend == "pywinusb": + return None + + def set_input_callback(self, callback): + """set callback for inputted data""" + self.input_callback = callback + if self.backend == "pywinusb": + self.device.set_raw_data_handler(self._pywinusb_callback) + + def _pywinusb_callback(self, data): + """internal callback adapter for pywinusb""" + if self.input_callback: + data_list = list(data) + if len(data_list) >= 4: + converted = data_list[0:] + self.input_callback(bytes(converted)) + + def close(self): + """close device""" + try: + self.device.close() + except: + pass + diff --git a/backend/ltamp/ltamp/hidWrapper.py b/backend/ltamp/ltamp/hidWrapper.py new file mode 100644 index 0000000..5c5299c --- /dev/null +++ b/backend/ltamp/ltamp/hidWrapper.py @@ -0,0 +1,56 @@ +import platform + +from .hidDevice import HIDDevice + +class HIDWrapper: + """unified HID interface that works across platforms""" + + def __init__(self, debug=False): + self.backend = None + self.hid_lib = None + self.debug = False + self._setup_hid_library() + + def _setup_hid_library(self): + """detect and setup the best available HID library""" + try: + import hid + self.hid_lib = hid + self.backend = "hidapi" + return + except ImportError: + pass + + if platform.system() == "Windows": + try: + from pywinusb import hid as pywinusb_hid + self.hid_lib = pywinusb_hid + self.backend = "pywinusb" + return + except ImportError: + pass + + raise ImportError("No HID library found. Please install hidapi or pywinusb") + + def enumerate(self, vendor_id=None, product_id=None): + """enumerate HID devices""" + if self.backend == "hidapi": + if vendor_id and product_id: + return self.hid_lib.enumerate(vendor_id, product_id) + else: + return self.hid_lib.enumerate() + elif self.backend == "pywinusb": + devices = self.hid_lib.find_all_hid_devices() + if vendor_id and product_id: + return [d for d in devices if d.vendor_id == vendor_id and d.product_id == product_id] + return devices + + def open_device(self, device_info): + """open and return an HID device""" + if self.backend == "hidapi": + device = self.hid_lib.device() + device.open_path(device_info['path']) + return HIDDevice(device, self.backend, debug=self.debug) + elif self.backend == "pywinusb": + device_info.open() + return HIDDevice(device_info, self.backend, debug=self.debug) diff --git a/backend/ltamp/ltamp/ltAmpAsync.py b/backend/ltamp/ltamp/ltAmpAsync.py new file mode 100644 index 0000000..980853f --- /dev/null +++ b/backend/ltamp/ltamp/ltAmpAsync.py @@ -0,0 +1,166 @@ +import os +import sys +import asyncio + +from .ltAmpBase import LtAmpBase + +# protobuf imports +protocol_path = os.path.join(os.path.dirname(__file__), 'protocol') +if protocol_path not in sys.path: + sys.path.insert(0, protocol_path) + +from .protocol import * + +class LtAmpAsync(LtAmpBase): + """ + async version of LtAmp controller using asyncio + + Methods: +- connect() connects to the amp (first matching device) +- disconnect() disconnect and clean up +- send_sync_begin() send SYNC_BEGIN (start handshake) +- send_sync_end() send SYNC_END (end handshake) +- send_heartbeat() periodic heartbeat (keep-alive) + request_connection_status() request connection status (status event) +- request_firmware_version() request firmware version from amp +- set_preset(idx) change preset slot +- request_current_preset() ask amp for current preset (status event) + retrieve_preset(idx) retrieve preset from amp (status event) +- set_qa_slots(idx[]) set QA slots (footswitch assignments) +- request_qa_slots() request QA slots from amp (status event) +- audition_preset(preset_json) audition a preset +- exit_audition() exit audition mode +- request_audition_state() get current audition state (status event) +- request_memory_usage() get memory usage +- request_processor_utilization() get processor utilization +- request_footswitch_mode() get current footswitch mode (lt4 only!) +- set_usb_gain(gain) set USB gain (0-100) +- request_usb_gain() get current USB gain setting + request_product_id() get product ID +- +- Data: +- device Current HID device connection +- hid_wrapper HID wrapper instance for backend operations + """ + + def __init__(self): + super().__init__() + self.loop = asyncio.get_event_loop() + self._cs_event = asyncio.Event() # connection status + self._fw_event = asyncio.Event() # firmware + self._cps_event = asyncio.Event() # current preset + self._ps_event = asyncio.Event() # preset + self._qa_event = asyncio.Event() # quick access + self._aud_event = asyncio.Event() # audition + self._mem_event = asyncio.Event() # memory + self._pu_event = asyncio.Event() # processor + self._ftsw_event = asyncio.Event() # footwitch + self._gain_event = asyncio.Event() # usb gain + + async def connect(self): + loop = asyncio.get_event_loop() + await loop.run_in_executor(None, super().connect) + + async def disconnect(self): + loop = asyncio.get_event_loop() + await loop.run_in_executor(None, super().disconnect) + + async def request_connection_status(self): + self._cs_event.clear() + request_connection_status(self.device) + try: + await asyncio.wait_for(self._cs_event.wait(), timeout=self.timeout) + return True + except asyncio.TimeoutError: + return False + + async def request_current_preset(self): + self._last_preset = None + self._cps_event.clear() + request_current_preset(self.device) + try: + await asyncio.wait_for(self._cps_event.wait(), timeout=self.timeout) + return self._last_preset + except asyncio.TimeoutError: + raise TimeoutError("No current preset response received within timeout window.") + + async def retrieve_preset(self, idx): + self._last_preset_json = None + self._ps_event.clear() + retrieve_preset(self.device, idx) + try: + await asyncio.wait_for(self._ps_event.wait(), timeout=self.timeout) + return self._last_preset_json + except asyncio.TimeoutError: + raise TimeoutError("No preset retrieval response received within timeout window.") + + async def request_firmware_version(self): + self._last_firmware_version = None + self._fw_event.clear() + from .protocol import request_firmware_version + request_firmware_version(self.device) + try: + await asyncio.wait_for(self._fw_event.wait(), timeout=self.timeout) + return self._last_firmware_version + except asyncio.TimeoutError: + raise TimeoutError("No firmware version response received within timeout window.") + + async def request_qa_slots(self): + self._last_qa_slots = None + self._qa_event.clear() + request_qa_slots(self.device) + try: + await asyncio.wait_for(self._qa_event.wait(), timeout=self.timeout) + return self._last_qa_slots + except asyncio.TimeoutError: + raise TimeoutError("No QA slots response received within timeout window.") + + async def request_audition_state(self): + self._last_audition_state = None + self._aud_event.clear() + request_audition_state(self.device) + try: + await asyncio.wait_for(self._aud_event.wait(), timeout=self.timeout) + return self._last_audition_state + except asyncio.TimeoutError: + raise TimeoutError("No audition state response received within timeout window.") + + async def request_memory_usage(self): + self._last_memory_state = None + self._mem_event.clear() + request_memory_usage(self.device) + try: + await asyncio.wait_for(self._mem_event.wait(), timeout=self.timeout) + return self._last_memory_state + except asyncio.TimeoutError: + raise TimeoutError("No memory state response received within timeout window.") + + async def request_processor_utilization(self): + self._last_processor_utilization = None + self._pu_event.clear() + request_processor_utilization(self.device) + try: + await asyncio.wait_for(self._pu_event.wait(), timeout=self.timeout) + return self._last_processor_utilization + except asyncio.TimeoutError: + raise TimeoutError("No processor utilization response received within timeout window.") + + async def request_usb_gain(self): + self._last_gain_state = None + self._gain_event.clear() + request_usb_gain(self.device) + try: + await asyncio.wait_for(self._gain_event.wait(), timeout=self.timeout) + return self._last_gain_state + except asyncio.TimeoutError: + raise TimeoutError("No usb gain state response received within timeout window.") + + async def request_product_id(self): + self._last_product_id = None + self._pid_event.clear() + request_product_id(self.device) + try: + await asyncio.wait_for(self._pid_event.wait(), timeout=self.timeout) + return self._last_product_id + except asyncio.TimeoutError: + raise TimeoutError("No product ID response received within timeout window.") diff --git a/backend/ltamp/ltamp/ltAmpBase.py b/backend/ltamp/ltamp/ltAmpBase.py new file mode 100644 index 0000000..f6fa69d --- /dev/null +++ b/backend/ltamp/ltamp/ltAmpBase.py @@ -0,0 +1,198 @@ +import time +import threading +import platform +import sys +import os + +from .hidWrapper import HIDWrapper, HIDDevice + +# protobuf imports +protocol_path = os.path.join(os.path.dirname(__file__), 'protocol') +if protocol_path not in sys.path: + sys.path.insert(0, protocol_path) + +from .protocol import * + +VENDOR_ID = 0x1ed8 +PRODUCT_ID = 0x0037 + +class LtAmpBase: + """ + base class for LT amplifier communication + """ + def __init__(self, debug=False, timeout=2.0): + self.debug = debug + self.timeout = timeout + self.hid_wrapper = HIDWrapper(self.debug) + self.device = None + self._msg_buffer = bytearray() + self._stop_event = threading.Event() + self._cs_event = threading.Event() # connection status + self._fw_event = threading.Event() # firmware + self._cps_event = threading.Event() # current preset + self._ps_event = threading.Event() # preset + self._qa_event = threading.Event() # quick access + self._aud_event = threading.Event() # audition + self._mem_event = threading.Event() # memory + self._pu_event = threading.Event() # processor + self._ftsw_event = threading.Event() # footswitch + self._gain_event = threading.Event() # usb gain + self._pid_event = threading.Event() # product ID + + def _set_event(self, event): + if hasattr(self, 'loop') and self.loop is not None: + self.loop.call_soon_threadsafe(event.set) + else: + event.set() + + def find_amp(self): + devices = self.hid_wrapper.enumerate(VENDOR_ID, PRODUCT_ID) + if devices: + return devices[0] + return None + + def connect(self): + amp_info = self.find_amp() + if not amp_info: + raise RuntimeError("LT amp not found") + self.device = self.hid_wrapper.open_device(amp_info) + self.device.set_input_callback(self._process_input_data) + if self.hid_wrapper.backend == "hidapi": + self._input_thread = threading.Thread(target=self._input_thread_proc, daemon=True) + self._input_thread.start() + return True + + def disconnect(self): + self._stop_event.set() + if self.device: + self.device.close() + + def _input_thread_proc(self): + while not self._stop_event.is_set(): + try: + data = self.device.read(64, 100) + if data and any(b != 0 for b in data): + self._process_input_data(data) + except Exception: + time.sleep(0.1) + + def _process_input_data(self, data): + try: + data_list = list(data) + if len(data_list) < 4: + return + if self.hid_wrapper.backend == "hidapi": + offset = 1 if data_list[0] == 0x00 else 0 + if len(data_list) < offset + 3: + return + tag = data_list[offset] + length = data_list[offset + 1] + value = data_list[offset + 2:offset + 2 + length] + else: # pywinusb + tag = data_list[2] + length = data_list[3] + value = data_list[4:4 + length] + if tag == 0x33: + self._msg_buffer = bytearray(value) + elif tag == 0x34: + self._msg_buffer += bytearray(value) + elif tag == 0x35: + self._msg_buffer += bytearray(value) + try: + msg = FenderMessageLT() + msg.ParseFromString(self._msg_buffer) + + if self.debug: + print("====== DEBUG =====\r\n", msg) + + if msg.HasField("connectionStatus"): + status = msg.connectionStatus.isConnected + self._set_event(self._cs_event) + elif msg.HasField("currentPresetStatus"): + preset_json = msg.currentPresetStatus.currentPresetData + preset_index = msg.currentPresetStatus.currentSlotIndex + self._last_preset = {"data": preset_json, "index": preset_index} + self._set_event(self._cps_event) + elif msg.HasField("presetJSONMessage"): + preset_json = msg.presetJSONMessage.data + preset_index = msg.presetJSONMessage.slotIndex + self._last_preset_json = {"data": preset_json, "index": preset_index} + self._set_event(self._ps_event) + elif msg.HasField("firmwareVersionStatus"): + version = msg.firmwareVersionStatus.version + self._last_firmware_version = version + self._set_event(self._fw_event) + elif msg.HasField("qASlotsStatus"): + slots = msg.qASlotsStatus + self._last_qa_slots = list(slots.slots) + self._set_event(self._qa_event) + elif msg.HasField("auditionStateStatus"): + state = msg.auditionStateStatus.isAuditioning + self._last_audition_state = state + self._set_event(self._aud_event) + elif msg.HasField("memoryUsageStatus"): + memory_state = msg.memoryUsageStatus + self._last_memory_state = {"stack": memory_state.stack, "heap": memory_state.heap} + self._set_event(self._mem_event) + elif msg.HasField("lt4FootswitchModeStatus"): + mode = msg.lt4FootswitchModeStatus.mode + self._last_ftsw_state = mode + self._set_event(self._ftsw_event) + elif msg.HasField("usbGainStatus"): + gain = msg.usbGainStatus.valueDB + self._last_gain_state = gain + self._set_event(self._gain_event) + elif msg.HasField("processorUtilization"): + utilization = msg.processorUtilization + self._last_processor_utilization = { + "percent": utilization.percent, + "minPercent": utilization.minPercent, + "maxPercent": utilization.maxPercent + } + self._set_event(self._pu_event) + elif msg.HasField("productIdentificationStatus"): + pid = msg.productIdentificationStatus.id + self._last_product_id = pid + self._set_event(self._pid_event) + except Exception: + pass + self._msg_buffer = bytearray() + except Exception as e: + import traceback + tb = traceback.format_exc() + raise RuntimeError(f"Error processing input data: {e}\n{tb}") + + def send_message(self, msg): + send_message(self.device, msg) + + def send_heartbeat(self): + send_heartbeat(self.device) + + def send_sync_begin(self): + send_sync_begin(self.device) + + def send_sync_end(self): + send_sync_end(self.device) + + def set_preset(self, preset_index: int): + if not isinstance(preset_index, int) or preset_index < 0: + raise ValueError("Preset index must be a non-negative integer.") + set_preset(self.device, preset_index) + + def set_qa_slots(self, slots: list): + if not isinstance(slots, list) or len(slots) != 2: + raise ValueError("QA slots must be a list of exactly 2 preset indices.") + set_qa_slots(self.device, slots) + + def audition_preset(self, preset_json: str): + if not isinstance(preset_json, str): + raise ValueError("Preset JSON must be a string.") + audition_preset(self.device, preset_json) + + def exit_audition(self): + exit_audition(self.device) + + def set_usb_gain(self, gain: float): + if not isinstance(gain, float) or not (-15.0 <= gain <= 15.0): + raise ValueError("USB gain must be a float between -15.0 \x01(\x0b\x32\x15.AuditionStateRequestH\x00\x12\x33\n\x13\x61uditionStateStatus\x18? \x01(\x0b\x32\x14.AuditionStateStatusH\x00\x12\x43\n\x1bproductIdentificationStatus\x18\x64 \x01(\x0b\x32\x1c.ProductIdentificationStatusH\x00\x12\x45\n\x1cproductIdentificationRequest\x18\x65 \x01(\x0b\x32\x1d.ProductIdentificationRequestH\x00\x12\x39\n\x16\x66irmwareVersionRequest\x18\x66 \x01(\x0b\x32\x17.FirmwareVersionRequestH\x00\x12\x37\n\x15\x66irmwareVersionStatus\x18g \x01(\x0b\x32\x16.FirmwareVersionStatusH\x00\x12\x35\n\x14\x63urrentPresetRequest\x18h \x01(\x0b\x32\x15.CurrentPresetRequestH\x00\x12)\n\x0eretrievePreset\x18i \x01(\x0b\x32\x0f.RetrievePresetH\x00\x12)\n\x0eusbGainRequest\x18j \x01(\x0b\x32\x0f.UsbGainRequestH\x00\x12\'\n\rusbGainStatus\x18k \x01(\x0b\x32\x0e.UsbGainStatusH\x00\x12)\n\x0eqASlotsRequest\x18l \x01(\x0b\x32\x0f.QASlotsRequestH\x00\x12\'\n\rqASlotsStatus\x18m \x01(\x0b\x32\x0e.QASlotsStatusH\x00\x12\x31\n\x12lineOutGainRequest\x18n \x01(\x0b\x32\x13.LineOutGainRequestH\x00\x12/\n\x11lineOutGainStatus\x18o \x01(\x0b\x32\x12.LineOutGainStatusH\x00\x12\x31\n\x12modalStatusMessage\x18q \x01(\x0b\x32\x13.ModalStatusMessageH\x00\x12!\n\nusbGainSet\x18r \x01(\x0b\x32\x0b.UsbGainSetH\x00\x12)\n\x0elineOutGainSet\x18s \x01(\x0b\x32\x0f.LineOutGainSetH\x00\x12!\n\nqASlotsSet\x18t \x01(\x0b\x32\x0b.QASlotsSetH\x00\x12>\n\x18unsupportedMessageStatus\x18\xc8\x01 \x01(\x0b\x32\x19.UnsupportedMessageStatusH\x00\x12 \n\theartbeat\x18\xc9\x01 \x01(\x0b\x32\n.HeartbeatH\x00\x12<\n\x17\x63onnectionStatusRequest\x18\xca\x01 \x01(\x0b\x32\x18.ConnectionStatusRequestH\x00\x12.\n\x10\x63onnectionStatus\x18\xcb\x01 \x01(\x0b\x32\x11.ConnectionStatusH\x00\x42\x06\n\x04type*B\n\x0cResponseType\x12\x0f\n\x0bUNSOLICITED\x10\x00\x12\x10\n\x0cNOT_LAST_ACK\x10\x01\x12\x0f\n\x0bIS_LAST_ACK\x10\x02') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'FenderMessageLT_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_RESPONSETYPE']._serialized_start=5185 + _globals['_RESPONSETYPE']._serialized_end=5251 + _globals['_FENDERMESSAGELT']._serialized_start=1736 + _globals['_FENDERMESSAGELT']._serialized_end=5183 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/FirmwareVersionRequest_pb2.py b/backend/ltamp/ltamp/protocol/FirmwareVersionRequest_pb2.py new file mode 100644 index 0000000..465267f --- /dev/null +++ b/backend/ltamp/ltamp/protocol/FirmwareVersionRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: FirmwareVersionRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'FirmwareVersionRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x46irmwareVersionRequest.proto\")\n\x16\x46irmwareVersionRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'FirmwareVersionRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_FIRMWAREVERSIONREQUEST']._serialized_start=32 + _globals['_FIRMWAREVERSIONREQUEST']._serialized_end=73 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/FirmwareVersionStatus_pb2.py b/backend/ltamp/ltamp/protocol/FirmwareVersionStatus_pb2.py new file mode 100644 index 0000000..bafcf1f --- /dev/null +++ b/backend/ltamp/ltamp/protocol/FirmwareVersionStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: FirmwareVersionStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'FirmwareVersionStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x46irmwareVersionStatus.proto\"(\n\x15\x46irmwareVersionStatus\x12\x0f\n\x07version\x18\x01 \x02(\t') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'FirmwareVersionStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_FIRMWAREVERSIONSTATUS']._serialized_start=31 + _globals['_FIRMWAREVERSIONSTATUS']._serialized_end=71 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/FrameBufferMessageRequest_pb2.py b/backend/ltamp/ltamp/protocol/FrameBufferMessageRequest_pb2.py new file mode 100644 index 0000000..ba4be61 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/FrameBufferMessageRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: FrameBufferMessageRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'FrameBufferMessageRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x46rameBufferMessageRequest.proto\",\n\x19\x46rameBufferMessageRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'FrameBufferMessageRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_FRAMEBUFFERMESSAGEREQUEST']._serialized_start=35 + _globals['_FRAMEBUFFERMESSAGEREQUEST']._serialized_end=79 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/FrameBufferMessage_pb2.py b/backend/ltamp/ltamp/protocol/FrameBufferMessage_pb2.py new file mode 100644 index 0000000..002b6ef --- /dev/null +++ b/backend/ltamp/ltamp/protocol/FrameBufferMessage_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: FrameBufferMessage.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'FrameBufferMessage.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x46rameBufferMessage.proto\"\"\n\x12\x46rameBufferMessage\x12\x0c\n\x04\x64\x61ta\x18\x01 \x02(\x0c') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'FrameBufferMessage_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_FRAMEBUFFERMESSAGE']._serialized_start=28 + _globals['_FRAMEBUFFERMESSAGE']._serialized_end=62 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/Heartbeat_pb2.py b/backend/ltamp/ltamp/protocol/Heartbeat_pb2.py new file mode 100644 index 0000000..1f9d97a --- /dev/null +++ b/backend/ltamp/ltamp/protocol/Heartbeat_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: Heartbeat.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'Heartbeat.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0fHeartbeat.proto\"\x1f\n\tHeartbeat\x12\x12\n\ndummyField\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'Heartbeat_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_HEARTBEAT']._serialized_start=19 + _globals['_HEARTBEAT']._serialized_end=50 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/IndexButton_pb2.py b/backend/ltamp/ltamp/protocol/IndexButton_pb2.py new file mode 100644 index 0000000..9e23fea --- /dev/null +++ b/backend/ltamp/ltamp/protocol/IndexButton_pb2.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: IndexButton.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'IndexButton.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11IndexButton.proto\"\xa0\x01\n\x0bIndexButton\x12\r\n\x05index\x18\x01 \x02(\x05\x12!\n\x05\x65vent\x18\x02 \x02(\x0e\x32\x12.IndexButton.Event\x12\x14\n\x0ctimestamp_ms\x18\x03 \x01(\r\"I\n\x05\x45vent\x12\x0f\n\x0b\x45VENT_ERROR\x10\x00\x12\x0f\n\x0b\x42UTTON_DOWN\x10\x01\x12\r\n\tBUTTON_UP\x10\x02\x12\x0f\n\x0b\x42UTTON_HELD\x10\x03') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'IndexButton_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_INDEXBUTTON']._serialized_start=22 + _globals['_INDEXBUTTON']._serialized_end=182 + _globals['_INDEXBUTTON_EVENT']._serialized_start=109 + _globals['_INDEXBUTTON_EVENT']._serialized_end=182 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/IndexEncoder_pb2.py b/backend/ltamp/ltamp/protocol/IndexEncoder_pb2.py new file mode 100644 index 0000000..263e51b --- /dev/null +++ b/backend/ltamp/ltamp/protocol/IndexEncoder_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: IndexEncoder.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'IndexEncoder.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12IndexEncoder.proto\",\n\x0cIndexEncoder\x12\r\n\x05index\x18\x01 \x02(\x05\x12\r\n\x05ticks\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'IndexEncoder_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_INDEXENCODER']._serialized_start=22 + _globals['_INDEXENCODER']._serialized_end=66 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/IndexPot_pb2.py b/backend/ltamp/ltamp/protocol/IndexPot_pb2.py new file mode 100644 index 0000000..37f8e2f --- /dev/null +++ b/backend/ltamp/ltamp/protocol/IndexPot_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: IndexPot.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'IndexPot.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eIndexPot.proto\"+\n\x08IndexPot\x12\r\n\x05index\x18\x01 \x02(\x05\x12\x10\n\x08position\x18\x02 \x02(\x02') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'IndexPot_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_INDEXPOT']._serialized_start=18 + _globals['_INDEXPOT']._serialized_end=61 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LT4FootswitchModeRequest_pb2.py b/backend/ltamp/ltamp/protocol/LT4FootswitchModeRequest_pb2.py new file mode 100644 index 0000000..2aafb99 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LT4FootswitchModeRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LT4FootswitchModeRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LT4FootswitchModeRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1eLT4FootswitchModeRequest.proto\"+\n\x18LT4FootswitchModeRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LT4FootswitchModeRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LT4FOOTSWITCHMODEREQUEST']._serialized_start=34 + _globals['_LT4FOOTSWITCHMODEREQUEST']._serialized_end=77 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LT4FootswitchModeStatus_pb2.py b/backend/ltamp/ltamp/protocol/LT4FootswitchModeStatus_pb2.py new file mode 100644 index 0000000..22cd0a1 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LT4FootswitchModeStatus_pb2.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LT4FootswitchModeStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LT4FootswitchModeStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dLT4FootswitchModeStatus.proto\"P\n\x17LT4FootswitchModeStatus\x12\x35\n\x0b\x63urrentMode\x18\x01 \x02(\x0e\x32\r.LT4FtswModes:\x11LT4_FTSW_MODE_OFF*m\n\x0cLT4FtswModes\x12\x15\n\x11LT4_FTSW_MODE_OFF\x10\x00\x12\x17\n\x13LT4_FTSW_MODE_BANK1\x10\x01\x12\x17\n\x13LT4_FTSW_MODE_BANK2\x10\x02\x12\x14\n\x10LT4_FTSW_MODE_FX\x10\x03') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LT4FootswitchModeStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LT4FTSWMODES']._serialized_start=115 + _globals['_LT4FTSWMODES']._serialized_end=224 + _globals['_LT4FOOTSWITCHMODESTATUS']._serialized_start=33 + _globals['_LT4FOOTSWITCHMODESTATUS']._serialized_end=113 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LineOutGainRequest_pb2.py b/backend/ltamp/ltamp/protocol/LineOutGainRequest_pb2.py new file mode 100644 index 0000000..18d7eca --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LineOutGainRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LineOutGainRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LineOutGainRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18LineOutGainRequest.proto\"%\n\x12LineOutGainRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LineOutGainRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LINEOUTGAINREQUEST']._serialized_start=28 + _globals['_LINEOUTGAINREQUEST']._serialized_end=65 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LineOutGainSet_pb2.py b/backend/ltamp/ltamp/protocol/LineOutGainSet_pb2.py new file mode 100644 index 0000000..252c68b --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LineOutGainSet_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LineOutGainSet.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LineOutGainSet.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14LineOutGainSet.proto\"!\n\x0eLineOutGainSet\x12\x0f\n\x07valueDB\x18\x01 \x02(\x02') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LineOutGainSet_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LINEOUTGAINSET']._serialized_start=24 + _globals['_LINEOUTGAINSET']._serialized_end=57 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LineOutGainStatus_pb2.py b/backend/ltamp/ltamp/protocol/LineOutGainStatus_pb2.py new file mode 100644 index 0000000..3a7dde9 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LineOutGainStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LineOutGainStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LineOutGainStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17LineOutGainStatus.proto\"$\n\x11LineOutGainStatus\x12\x0f\n\x07valueDB\x18\x01 \x02(\x02') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LineOutGainStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LINEOUTGAINSTATUS']._serialized_start=27 + _globals['_LINEOUTGAINSTATUS']._serialized_end=63 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LoadPreset_TestSuite_pb2.py b/backend/ltamp/ltamp/protocol/LoadPreset_TestSuite_pb2.py new file mode 100644 index 0000000..8195239 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LoadPreset_TestSuite_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LoadPreset_TestSuite.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LoadPreset_TestSuite.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aLoadPreset_TestSuite.proto\"+\n\x14LoadPreset_TestSuite\x12\x13\n\x0bpresetIndex\x18\x01 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LoadPreset_TestSuite_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LOADPRESET_TESTSUITE']._serialized_start=30 + _globals['_LOADPRESET_TESTSUITE']._serialized_end=73 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LoadPreset_pb2.py b/backend/ltamp/ltamp/protocol/LoadPreset_pb2.py new file mode 100644 index 0000000..fa833e8 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LoadPreset_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LoadPreset.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LoadPreset.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10LoadPreset.proto\"!\n\nLoadPreset\x12\x13\n\x0bpresetIndex\x18\x01 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LoadPreset_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LOADPRESET']._serialized_start=20 + _globals['_LOADPRESET']._serialized_end=53 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/LoopbackTest_pb2.py b/backend/ltamp/ltamp/protocol/LoopbackTest_pb2.py new file mode 100644 index 0000000..a73a768 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/LoopbackTest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: LoopbackTest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'LoopbackTest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12LoopbackTest.proto\"\x1c\n\x0cLoopbackTest\x12\x0c\n\x04\x64\x61ta\x18\x01 \x02(\t') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'LoopbackTest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_LOOPBACKTEST']._serialized_start=22 + _globals['_LOOPBACKTEST']._serialized_end=50 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/MemoryUsageRequest_pb2.py b/backend/ltamp/ltamp/protocol/MemoryUsageRequest_pb2.py new file mode 100644 index 0000000..8fafa5c --- /dev/null +++ b/backend/ltamp/ltamp/protocol/MemoryUsageRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: MemoryUsageRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'MemoryUsageRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18MemoryUsageRequest.proto\"%\n\x12MemoryUsageRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'MemoryUsageRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_MEMORYUSAGEREQUEST']._serialized_start=28 + _globals['_MEMORYUSAGEREQUEST']._serialized_end=65 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/MemoryUsageStatus_pb2.py b/backend/ltamp/ltamp/protocol/MemoryUsageStatus_pb2.py new file mode 100644 index 0000000..3dadc53 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/MemoryUsageStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: MemoryUsageStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'MemoryUsageStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17MemoryUsageStatus.proto\"0\n\x11MemoryUsageStatus\x12\r\n\x05stack\x18\x01 \x02(\x05\x12\x0c\n\x04heap\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'MemoryUsageStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_MEMORYUSAGESTATUS']._serialized_start=27 + _globals['_MEMORYUSAGESTATUS']._serialized_end=75 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ModalStatusMessage_pb2.py b/backend/ltamp/ltamp/protocol/ModalStatusMessage_pb2.py new file mode 100644 index 0000000..edcdae8 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ModalStatusMessage_pb2.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ModalStatusMessage.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ModalStatusMessage.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18ModalStatusMessage.proto\"P\n\x12ModalStatusMessage\x12\x1e\n\x07\x63ontext\x18\x01 \x02(\x0e\x32\r.ModalContext\x12\x1a\n\x05state\x18\x02 \x02(\x0e\x32\x0b.ModalState*\xf3\x01\n\x0cModalContext\x12\x0e\n\nSYNC_BEGIN\x10\x00\x12\x0c\n\x08SYNC_END\x10\x01\x12\x10\n\x0c\x42\x41\x43KUP_BEGIN\x10\x02\x12\x0e\n\nBACKUP_END\x10\x03\x12\x11\n\rRESTORE_BEGIN\x10\x04\x12\x0f\n\x0bRESTORE_END\x10\x05\x12\x10\n\x0cTUNER_ENABLE\x10\x06\x12\x11\n\rTUNER_DISABLE\x10\x07\x12\x19\n\x15\x46\x41\x43TORY_RESTORE_BEGIN\x10\x08\x12\x17\n\x13\x46\x41\x43TORY_RESTORE_END\x10\t\x12\x13\n\x0fTONE_BUSY_BEGIN\x10\n\x12\x11\n\rTONE_BUSY_END\x10\x0b*\x1e\n\nModalState\x12\x06\n\x02OK\x10\x00\x12\x08\n\x04\x46\x41IL\x10\x01') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ModalStatusMessage_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_MODALCONTEXT']._serialized_start=111 + _globals['_MODALCONTEXT']._serialized_end=354 + _globals['_MODALSTATE']._serialized_start=356 + _globals['_MODALSTATE']._serialized_end=386 + _globals['_MODALSTATUSMESSAGE']._serialized_start=28 + _globals['_MODALSTATUSMESSAGE']._serialized_end=108 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/NewPresetSavedStatus_pb2.py b/backend/ltamp/ltamp/protocol/NewPresetSavedStatus_pb2.py new file mode 100644 index 0000000..41db4a1 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/NewPresetSavedStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: NewPresetSavedStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'NewPresetSavedStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aNewPresetSavedStatus.proto\">\n\x14NewPresetSavedStatus\x12\x12\n\npresetData\x18\x01 \x02(\t\x12\x12\n\npresetSlot\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'NewPresetSavedStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_NEWPRESETSAVEDSTATUS']._serialized_start=30 + _globals['_NEWPRESETSAVEDSTATUS']._serialized_end=92 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/PresetJSONMessageRequest_LT_pb2.py b/backend/ltamp/ltamp/protocol/PresetJSONMessageRequest_LT_pb2.py new file mode 100644 index 0000000..0b8bd3a --- /dev/null +++ b/backend/ltamp/ltamp/protocol/PresetJSONMessageRequest_LT_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: PresetJSONMessageRequest_LT.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'PresetJSONMessageRequest_LT.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!PresetJSONMessageRequest_LT.proto\".\n\x1bPresetJSONMessageRequest_LT\x12\x0f\n\x07request\x18\x01 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'PresetJSONMessageRequest_LT_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_PRESETJSONMESSAGEREQUEST_LT']._serialized_start=37 + _globals['_PRESETJSONMESSAGEREQUEST_LT']._serialized_end=83 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/PresetJSONMessage_pb2.py b/backend/ltamp/ltamp/protocol/PresetJSONMessage_pb2.py new file mode 100644 index 0000000..2b106ff --- /dev/null +++ b/backend/ltamp/ltamp/protocol/PresetJSONMessage_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: PresetJSONMessage.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'PresetJSONMessage.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17PresetJSONMessage.proto\"4\n\x11PresetJSONMessage\x12\x0c\n\x04\x64\x61ta\x18\x01 \x02(\t\x12\x11\n\tslotIndex\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'PresetJSONMessage_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_PRESETJSONMESSAGE']._serialized_start=27 + _globals['_PRESETJSONMESSAGE']._serialized_end=79 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/PresetSavedStatus_pb2.py b/backend/ltamp/ltamp/protocol/PresetSavedStatus_pb2.py new file mode 100644 index 0000000..429edcb --- /dev/null +++ b/backend/ltamp/ltamp/protocol/PresetSavedStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: PresetSavedStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'PresetSavedStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17PresetSavedStatus.proto\"/\n\x11PresetSavedStatus\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04slot\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'PresetSavedStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_PRESETSAVEDSTATUS']._serialized_start=27 + _globals['_PRESETSAVEDSTATUS']._serialized_end=74 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ProcessorUtilizationRequest_pb2.py b/backend/ltamp/ltamp/protocol/ProcessorUtilizationRequest_pb2.py new file mode 100644 index 0000000..d415914 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ProcessorUtilizationRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ProcessorUtilizationRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ProcessorUtilizationRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!ProcessorUtilizationRequest.proto\".\n\x1bProcessorUtilizationRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ProcessorUtilizationRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_PROCESSORUTILIZATIONREQUEST']._serialized_start=37 + _globals['_PROCESSORUTILIZATIONREQUEST']._serialized_end=83 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ProcessorUtilization_pb2.py b/backend/ltamp/ltamp/protocol/ProcessorUtilization_pb2.py new file mode 100644 index 0000000..a08af02 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ProcessorUtilization_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ProcessorUtilization.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ProcessorUtilization.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aProcessorUtilization.proto\"O\n\x14ProcessorUtilization\x12\x0f\n\x07percent\x18\x01 \x02(\x02\x12\x12\n\nminPercent\x18\x02 \x02(\x02\x12\x12\n\nmaxPercent\x18\x03 \x02(\x02') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ProcessorUtilization_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_PROCESSORUTILIZATION']._serialized_start=30 + _globals['_PROCESSORUTILIZATION']._serialized_end=109 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ProductIdentificationRequest_pb2.py b/backend/ltamp/ltamp/protocol/ProductIdentificationRequest_pb2.py new file mode 100644 index 0000000..9227e4b --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ProductIdentificationRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ProductIdentificationRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ProductIdentificationRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"ProductIdentificationRequest.proto\"/\n\x1cProductIdentificationRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ProductIdentificationRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_PRODUCTIDENTIFICATIONREQUEST']._serialized_start=38 + _globals['_PRODUCTIDENTIFICATIONREQUEST']._serialized_end=85 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ProductIdentificationStatus_pb2.py b/backend/ltamp/ltamp/protocol/ProductIdentificationStatus_pb2.py new file mode 100644 index 0000000..cc4ff67 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ProductIdentificationStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ProductIdentificationStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ProductIdentificationStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!ProductIdentificationStatus.proto\")\n\x1bProductIdentificationStatus\x12\n\n\x02id\x18\x01 \x02(\t') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ProductIdentificationStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_PRODUCTIDENTIFICATIONSTATUS']._serialized_start=37 + _globals['_PRODUCTIDENTIFICATIONSTATUS']._serialized_end=78 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/QASlotsRequest_pb2.py b/backend/ltamp/ltamp/protocol/QASlotsRequest_pb2.py new file mode 100644 index 0000000..9e3367f --- /dev/null +++ b/backend/ltamp/ltamp/protocol/QASlotsRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: QASlotsRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'QASlotsRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14QASlotsRequest.proto\"!\n\x0eQASlotsRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'QASlotsRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_QASLOTSREQUEST']._serialized_start=24 + _globals['_QASLOTSREQUEST']._serialized_end=57 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/QASlotsSet_pb2.py b/backend/ltamp/ltamp/protocol/QASlotsSet_pb2.py new file mode 100644 index 0000000..1e88d34 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/QASlotsSet_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: QASlotsSet.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'QASlotsSet.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10QASlotsSet.proto\"\x1b\n\nQASlotsSet\x12\r\n\x05slots\x18\x01 \x03(\r') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'QASlotsSet_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_QASLOTSSET']._serialized_start=20 + _globals['_QASLOTSSET']._serialized_end=47 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/QASlotsStatus_pb2.py b/backend/ltamp/ltamp/protocol/QASlotsStatus_pb2.py new file mode 100644 index 0000000..fb89f82 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/QASlotsStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: QASlotsStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'QASlotsStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13QASlotsStatus.proto\"\x1e\n\rQASlotsStatus\x12\r\n\x05slots\x18\x01 \x03(\r') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'QASlotsStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_QASLOTSSTATUS']._serialized_start=23 + _globals['_QASLOTSSTATUS']._serialized_end=53 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/RenamePresetAt_pb2.py b/backend/ltamp/ltamp/protocol/RenamePresetAt_pb2.py new file mode 100644 index 0000000..6e83e56 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/RenamePresetAt_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: RenamePresetAt.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'RenamePresetAt.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14RenamePresetAt.proto\"8\n\x0eRenamePresetAt\x12\x12\n\npresetName\x18\x01 \x02(\t\x12\x12\n\npresetSlot\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'RenamePresetAt_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_RENAMEPRESETAT']._serialized_start=24 + _globals['_RENAMEPRESETAT']._serialized_end=80 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ReplaceNodeStatus_pb2.py b/backend/ltamp/ltamp/protocol/ReplaceNodeStatus_pb2.py new file mode 100644 index 0000000..9cb4f68 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ReplaceNodeStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ReplaceNodeStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ReplaceNodeStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17ReplaceNodeStatus.proto\"E\n\x11ReplaceNodeStatus\x12\x16\n\x0enodeIdReplaced\x18\x01 \x02(\t\x12\x18\n\x10\x66\x65nderIdReplaced\x18\x02 \x02(\t') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ReplaceNodeStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_REPLACENODESTATUS']._serialized_start=27 + _globals['_REPLACENODESTATUS']._serialized_end=96 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ReplaceNode_pb2.py b/backend/ltamp/ltamp/protocol/ReplaceNode_pb2.py new file mode 100644 index 0000000..71942a1 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ReplaceNode_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ReplaceNode.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ReplaceNode.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11ReplaceNode.proto\"E\n\x0bReplaceNode\x12\x17\n\x0fnodeIdToReplace\x18\x01 \x02(\t\x12\x1d\n\x15\x66\x65nderIdToReplaceWith\x18\x02 \x02(\t') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ReplaceNode_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_REPLACENODE']._serialized_start=21 + _globals['_REPLACENODE']._serialized_end=90 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/RetrievePreset_pb2.py b/backend/ltamp/ltamp/protocol/RetrievePreset_pb2.py new file mode 100644 index 0000000..2606d07 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/RetrievePreset_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: RetrievePreset.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'RetrievePreset.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14RetrievePreset.proto\"\x1e\n\x0eRetrievePreset\x12\x0c\n\x04slot\x18\x01 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'RetrievePreset_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_RETRIEVEPRESET']._serialized_start=24 + _globals['_RETRIEVEPRESET']._serialized_end=54 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/SaveCurrentPresetTo_pb2.py b/backend/ltamp/ltamp/protocol/SaveCurrentPresetTo_pb2.py new file mode 100644 index 0000000..14c2e80 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/SaveCurrentPresetTo_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: SaveCurrentPresetTo.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'SaveCurrentPresetTo.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19SaveCurrentPresetTo.proto\"=\n\x13SaveCurrentPresetTo\x12\x12\n\npresetName\x18\x01 \x02(\t\x12\x12\n\npresetSlot\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'SaveCurrentPresetTo_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SAVECURRENTPRESETTO']._serialized_start=29 + _globals['_SAVECURRENTPRESETTO']._serialized_end=90 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/SaveCurrentPreset_pb2.py b/backend/ltamp/ltamp/protocol/SaveCurrentPreset_pb2.py new file mode 100644 index 0000000..f70a8cc --- /dev/null +++ b/backend/ltamp/ltamp/protocol/SaveCurrentPreset_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: SaveCurrentPreset.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'SaveCurrentPreset.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17SaveCurrentPreset.proto\"!\n\x11SaveCurrentPreset\x12\x0c\n\x04save\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'SaveCurrentPreset_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SAVECURRENTPRESET']._serialized_start=27 + _globals['_SAVECURRENTPRESET']._serialized_end=60 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/SavePresetAs_pb2.py b/backend/ltamp/ltamp/protocol/SavePresetAs_pb2.py new file mode 100644 index 0000000..e3eb92f --- /dev/null +++ b/backend/ltamp/ltamp/protocol/SavePresetAs_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: SavePresetAs.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'SavePresetAs.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12SavePresetAs.proto\"L\n\x0cSavePresetAs\x12\x12\n\npresetData\x18\x01 \x02(\t\x12\x14\n\x0cisLoadPreset\x18\x02 \x02(\x08\x12\x12\n\npresetSlot\x18\x03 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'SavePresetAs_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SAVEPRESETAS']._serialized_start=22 + _globals['_SAVEPRESETAS']._serialized_end=98 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/SetDspUnitParameterStatus_pb2.py b/backend/ltamp/ltamp/protocol/SetDspUnitParameterStatus_pb2.py new file mode 100644 index 0000000..78fcc90 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/SetDspUnitParameterStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: SetDspUnitParameterStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'SetDspUnitParameterStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1fSetDspUnitParameterStatus.proto\"\xb1\x01\n\x19SetDspUnitParameterStatus\x12\x0e\n\x06nodeId\x18\x01 \x02(\t\x12\x13\n\x0bparameterId\x18\x02 \x02(\t\x12\x18\n\x0e\x66loatParameter\x18\x03 \x01(\x02H\x00\x12\x19\n\x0fstringParameter\x18\x04 \x01(\tH\x00\x12\x19\n\x0fsint32Parameter\x18\x05 \x01(\x11H\x00\x12\x17\n\rboolParameter\x18\x06 \x01(\x08H\x00\x42\x06\n\x04type') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'SetDspUnitParameterStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SETDSPUNITPARAMETERSTATUS']._serialized_start=36 + _globals['_SETDSPUNITPARAMETERSTATUS']._serialized_end=213 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/SetDspUnitParameter_pb2.py b/backend/ltamp/ltamp/protocol/SetDspUnitParameter_pb2.py new file mode 100644 index 0000000..1b37473 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/SetDspUnitParameter_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: SetDspUnitParameter.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'SetDspUnitParameter.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19SetDspUnitParameter.proto\"\xab\x01\n\x13SetDspUnitParameter\x12\x0e\n\x06nodeId\x18\x01 \x02(\t\x12\x13\n\x0bparameterId\x18\x02 \x02(\t\x12\x18\n\x0e\x66loatParameter\x18\x03 \x01(\x02H\x00\x12\x19\n\x0fstringParameter\x18\x04 \x01(\tH\x00\x12\x19\n\x0fsint32Parameter\x18\x05 \x01(\x11H\x00\x12\x17\n\rboolParameter\x18\x06 \x01(\x08H\x00\x42\x06\n\x04type') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'SetDspUnitParameter_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SETDSPUNITPARAMETER']._serialized_start=30 + _globals['_SETDSPUNITPARAMETER']._serialized_end=201 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ShiftPresetStatus_pb2.py b/backend/ltamp/ltamp/protocol/ShiftPresetStatus_pb2.py new file mode 100644 index 0000000..8e46df3 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ShiftPresetStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ShiftPresetStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ShiftPresetStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17ShiftPresetStatus.proto\"E\n\x11ShiftPresetStatus\x12\x18\n\x10indexToShiftFrom\x18\x01 \x02(\x05\x12\x16\n\x0eindexToShiftTo\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ShiftPresetStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SHIFTPRESETSTATUS']._serialized_start=27 + _globals['_SHIFTPRESETSTATUS']._serialized_end=96 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/ShiftPreset_pb2.py b/backend/ltamp/ltamp/protocol/ShiftPreset_pb2.py new file mode 100644 index 0000000..37dab2e --- /dev/null +++ b/backend/ltamp/ltamp/protocol/ShiftPreset_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: ShiftPreset.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'ShiftPreset.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11ShiftPreset.proto\"?\n\x0bShiftPreset\x12\x18\n\x10indexToShiftFrom\x18\x01 \x02(\x05\x12\x16\n\x0eindexToShiftTo\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'ShiftPreset_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SHIFTPRESET']._serialized_start=21 + _globals['_SHIFTPRESET']._serialized_end=84 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/SwapPresetStatus_pb2.py b/backend/ltamp/ltamp/protocol/SwapPresetStatus_pb2.py new file mode 100644 index 0000000..6576848 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/SwapPresetStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: SwapPresetStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'SwapPresetStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16SwapPresetStatus.proto\"2\n\x10SwapPresetStatus\x12\x0e\n\x06indexA\x18\x01 \x02(\x05\x12\x0e\n\x06indexB\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'SwapPresetStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SWAPPRESETSTATUS']._serialized_start=26 + _globals['_SWAPPRESETSTATUS']._serialized_end=76 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/SwapPreset_pb2.py b/backend/ltamp/ltamp/protocol/SwapPreset_pb2.py new file mode 100644 index 0000000..9e349ce --- /dev/null +++ b/backend/ltamp/ltamp/protocol/SwapPreset_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: SwapPreset.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'SwapPreset.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10SwapPreset.proto\",\n\nSwapPreset\x12\x0e\n\x06indexA\x18\x01 \x02(\x05\x12\x0e\n\x06indexB\x18\x02 \x02(\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'SwapPreset_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_SWAPPRESET']._serialized_start=20 + _globals['_SWAPPRESET']._serialized_end=64 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/UnsupportedMessageStatus_pb2.py b/backend/ltamp/ltamp/protocol/UnsupportedMessageStatus_pb2.py new file mode 100644 index 0000000..6c20119 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/UnsupportedMessageStatus_pb2.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: UnsupportedMessageStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'UnsupportedMessageStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1eUnsupportedMessageStatus.proto\"6\n\x18UnsupportedMessageStatus\x12\x1a\n\x06status\x18\x01 \x02(\x0e\x32\n.ErrorType*\x8a\x01\n\tErrorType\x12\x0f\n\x0bUNSUPPORTED\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x11\n\rINVALID_PARAM\x10\x02\x12\x13\n\x0fINVALID_NODE_ID\x10\x03\x12\x17\n\x13PARAM_OUT_OF_BOUNDS\x10\x04\x12\x1f\n\x1b\x46\x41\x43TORY_RESTORE_IN_PROGRESS\x10\x05') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'UnsupportedMessageStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_ERRORTYPE']._serialized_start=91 + _globals['_ERRORTYPE']._serialized_end=229 + _globals['_UNSUPPORTEDMESSAGESTATUS']._serialized_start=34 + _globals['_UNSUPPORTEDMESSAGESTATUS']._serialized_end=88 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/UsbGainRequest_pb2.py b/backend/ltamp/ltamp/protocol/UsbGainRequest_pb2.py new file mode 100644 index 0000000..8e37595 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/UsbGainRequest_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: UsbGainRequest.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'UsbGainRequest.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14UsbGainRequest.proto\"!\n\x0eUsbGainRequest\x12\x0f\n\x07request\x18\x01 \x02(\x08') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'UsbGainRequest_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_USBGAINREQUEST']._serialized_start=24 + _globals['_USBGAINREQUEST']._serialized_end=57 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/UsbGainSet_pb2.py b/backend/ltamp/ltamp/protocol/UsbGainSet_pb2.py new file mode 100644 index 0000000..8733949 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/UsbGainSet_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: UsbGainSet.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'UsbGainSet.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10UsbGainSet.proto\"\x1d\n\nUsbGainSet\x12\x0f\n\x07valueDB\x18\x01 \x02(\x02') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'UsbGainSet_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_USBGAINSET']._serialized_start=20 + _globals['_USBGAINSET']._serialized_end=49 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/UsbGainStatus_pb2.py b/backend/ltamp/ltamp/protocol/UsbGainStatus_pb2.py new file mode 100644 index 0000000..92498c9 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/UsbGainStatus_pb2.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: UsbGainStatus.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'UsbGainStatus.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13UsbGainStatus.proto\" \n\rUsbGainStatus\x12\x0f\n\x07valueDB\x18\x01 \x02(\x02') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'UsbGainStatus_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_USBGAINSTATUS']._serialized_start=23 + _globals['_USBGAINSTATUS']._serialized_end=55 +# @@protoc_insertion_point(module_scope) diff --git a/backend/ltamp/ltamp/protocol/__init__.py b/backend/ltamp/ltamp/protocol/__init__.py new file mode 100644 index 0000000..70f0750 --- /dev/null +++ b/backend/ltamp/ltamp/protocol/__init__.py @@ -0,0 +1,163 @@ +""" +protocol actions for LT amp USB control. + +covers QA, firmware, preset status, auditioning, +memory, footswitch status, USB gain. +""" + +from typing import List + +from .FenderMessageLT_pb2 import FenderMessageLT, ResponseType +from .Heartbeat_pb2 import Heartbeat +from .ModalStatusMessage_pb2 import ModalContext, ModalStatusMessage, ModalState +from .FirmwareVersionRequest_pb2 import FirmwareVersionRequest +from .LoadPreset_pb2 import LoadPreset +from .UsbGainSet_pb2 import UsbGainSet +from .QASlotsRequest_pb2 import QASlotsRequest +from .QASlotsSet_pb2 import QASlotsSet +from .CurrentPresetRequest_pb2 import CurrentPresetRequest +from .AuditionPreset_pb2 import AuditionPreset +from .LoadPreset_pb2 import LoadPreset +from .AuditionStateRequest_pb2 import AuditionStateRequest +from .ExitAuditionPreset_pb2 import ExitAuditionPreset +from .MemoryUsageRequest_pb2 import MemoryUsageRequest +from .ProcessorUtilizationRequest_pb2 import ProcessorUtilizationRequest +from .LT4FootswitchModeRequest_pb2 import LT4FootswitchModeRequest +from .UsbGainRequest_pb2 import UsbGainRequest +from .ConnectionStatusRequest_pb2 import ConnectionStatusRequest +from .LT4FootswitchModeRequest_pb2 import LT4FootswitchModeRequest +from .ProductIdentificationRequest_pb2 import ProductIdentificationRequest +from .RetrievePreset_pb2 import RetrievePreset + +def send_message(device, msg): + """ + send (potentially multi-packet) protobuf message + """ + payload = msg.SerializeToString() + max_chunk = 61 # max payload per packet + num_chunks = 1 + + if len(payload) <= max_chunk: + # single packet + tag = 0x35 + length = len(payload) + packet = bytearray([tag, length]) + payload + if len(packet) < 64: # pad to 64 + packet.extend([0x00] * (64 - len(packet))) + device.write(packet) + else: + # multiple packets + num_chunks = (len(payload) + max_chunk - 1) // max_chunk + for i in range(num_chunks): + start = i * max_chunk + end = min(len(payload), (i + 1) * max_chunk) + chunk = payload[start:end] + if i == 0: + tag = 0x33 # start + elif i == num_chunks - 1: + tag = 0x35 # end + else: + tag = 0x34 # middle + length = len(chunk) + packet = bytearray([tag, length]) + chunk + if len(packet) < 64: + packet.extend([0x00] * (64 - len(packet))) + device.write(packet) + + if device.debug: + print("====== DEBUG =====") + print(f"Sent {len(payload)} bytes in {num_chunks} packets") + +def _msg(**kwargs): + """construct a message with given fields""" + msg = FenderMessageLT() + msg.responseType = ResponseType.UNSOLICITED + for k, v in kwargs.items(): + field = getattr(msg, k) + if hasattr(field, 'CopyFrom'): # composite field + field.CopyFrom(v) + else: + setattr(msg, k, v) + return msg + +# --- qa --- + +def request_qa_slots(device): + """get current footswitch assignments""" + send_message(device, _msg(qASlotsRequest= QASlotsRequest(request=True))) + +def set_qa_slots(device, slots): + """set QA slots to list of preset indexes (length 2)""" + send_message(device, _msg(qASlotsSet=QASlotsSet(slots=slots))) + +# --- firmware --- + +def request_firmware_version(device): + send_message(device, _msg(firmwareVersionRequest=FirmwareVersionRequest(request=True))) + +# --- preset status --- + +def request_current_preset(device): + send_message(device, _msg(currentPresetRequest=CurrentPresetRequest(request=True))) + +def set_preset(device, preset_index): + send_message(device, _msg(loadPreset=LoadPreset(presetIndex=preset_index))) + +def retrieve_preset(device, preset_index): + send_message(device, _msg(retrievePreset=RetrievePreset(slot=preset_index))) + +# --- auditioning --- + +def audition_preset(device, preset_json): + """send a preset JSON string to be temporaily loaded""" + send_message(device, _msg(auditionPreset=AuditionPreset(presetData=preset_json))) + +def request_audition_state(device): + send_message(device, _msg(auditionStateRequest=AuditionStateRequest(request=True))) + +def exit_audition(device): + send_message(device, _msg(exitAuditionPreset=ExitAuditionPreset(exit=True))) + +# --- memory usage --- + +def request_memory_usage(device): + send_message(device, _msg(memoryUsageRequest=MemoryUsageRequest(request=True))) + +# --- processor utilization --- + +def request_processor_utilization(device): + send_message(device, _msg(processorUtilizationRequest=ProcessorUtilizationRequest(request=True))) + +# --- footswitch mode--- + +def request_footswitch_mode(device): + send_message(device, _msg(lt4FootswitchModeRequest=LT4FootswitchModeRequest(request=True))) + +# --- usb gain --- + +def request_usb_gain(device): + send_message(device, _msg(usbGainRequest=UsbGainRequest(request=True))) + +def set_usb_gain(device, value_db): + send_message(device, _msg(usbGainSet=UsbGainSet(valueDB=value_db))) + +# --- heartbeat --- + +def send_heartbeat(device): + send_message(device, _msg(heartbeat=Heartbeat(dummyField=True))) + +# --- sync --- + +def send_sync_begin(device): + send_message(device, _msg(modalStatusMessage=ModalStatusMessage(context=ModalContext.SYNC_BEGIN, state=ModalState.OK))) + +def send_sync_end(device): + send_message(device, _msg(modalStatusMessage=ModalStatusMessage(context=ModalContext.SYNC_END, state=ModalState.OK))) + +def request_connection_status(device): + send_message(device, _msg(connectionStatusRequest=ConnectionStatusRequest(request=True))) + +# --- product id --- + +def request_product_id(device): + send_message(device, _msg(productIdentificationRequest=ProductIdentificationRequest(request=True))) diff --git a/backend/ltamp/pyproject.toml b/backend/ltamp/pyproject.toml new file mode 100644 index 0000000..bf46d31 --- /dev/null +++ b/backend/ltamp/pyproject.toml @@ -0,0 +1,38 @@ +[project] +name = "ltamp" +version = "0.2.7" +description = "🎸 Cross-platform python interface for LT guitar/bass amplifiers" +readme = "README.md" +license = {text = "MIT"} +requires-python = ">=3.8" +dependencies = [ + "protobuf>=5.0.0", + "hidapi; sys_platform != 'win32'", + "pywinusb; sys_platform == 'win32'", +] + +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Operating System :: OS Independent", + "Development Status :: 3 - Alpha", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: System :: Hardware :: Universal Serial Bus (USB)", + "Topic :: Artistic Software", + "License :: OSI Approved :: MIT License" +] + +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["."] + +[project.urls] +Homepage = "https://github.com/bendertools/LtAmp.py" +Repository = "https://github.com/bendertools/LtAmp.py" diff --git a/backend/ltamp/tests/test_ltamp.py b/backend/ltamp/tests/test_ltamp.py new file mode 100644 index 0000000..0d96518 --- /dev/null +++ b/backend/ltamp/tests/test_ltamp.py @@ -0,0 +1,109 @@ +import unittest +import time +from ltamp import LtAmp +import threading + +class TestLtAmp(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.amp = LtAmp() + try: + cls.amp.connect() + cls.amp.send_sync_begin() + time.sleep(1) + cls.amp.send_heartbeat() + cls.amp.send_sync_end() + cls._heartbeat_running = True + def heartbeat(): + while cls._heartbeat_running: + cls.amp.send_heartbeat() + time.sleep(0.1) + cls._heartbeat_thread = threading.Thread(target=heartbeat, daemon=True) + cls._heartbeat_thread.start() + except Exception as e: + cls.amp = None + print(f"SKIPPING tests: Could not connect to amp: {e}") + + @classmethod + def tearDownClass(cls): + if getattr(cls, "amp", None): + cls._heartbeat_running = False + cls._heartbeat_thread.join(timeout=2) + cls.amp.disconnect() + + def setUp(self): + if self.amp is None: + self.skipTest("Amp not connected, skipping hardware integration tests.") + + def test_firmware_version(self): + version = self.amp.request_firmware_version() + self.assertIsInstance(version, str) + self.assertRegex(version, r"^\d+\.\d+\.\d+$") + + def test_product_id(self): + pid = self.amp.request_product_id() + self.assertIsInstance(pid, str) + + def test_qa_slots(self): + slots = self.amp.request_qa_slots() + self.assertIsInstance(slots, list) + self.assertEqual(len(slots), 2) + self.assertTrue(all(isinstance(x, int) for x in slots)) + + def test_set_and_get_preset(self): + orig_preset = self.amp.request_current_preset() + idx = orig_preset["index"] + self.amp.set_preset(idx) + time.sleep(1) + curr = self.amp.request_current_preset() + self.assertEqual(curr["index"], idx) + + def test_usb_gain(self): + orig_gain = self.amp.request_usb_gain() + self.amp.set_usb_gain(orig_gain) + time.sleep(0.5) + gain = self.amp.request_usb_gain() + self.assertEqual(gain, orig_gain) + + + def test_memory_usage(self): + mem = self.amp.request_memory_usage() + self.assertIsInstance(mem, dict) + self.assertIn("stack", mem) + self.assertIn("heap", mem) + self.assertIsInstance(mem["stack"], int) + self.assertIsInstance(mem["heap"], int) + + def test_processor_utilization(self): + util = self.amp.request_processor_utilization() + self.assertIsInstance(util, dict) + for key in ("percent", "minPercent", "maxPercent"): + self.assertIn(key, util) + self.assertIsInstance(util[key], float) + self.assertGreaterEqual(util[key], 0) + + def test_send_sync_begin_end(self): + # Just ensure both calls do not raise + try: + self.amp.send_sync_begin() + time.sleep(1) + self.amp.send_sync_end() + except Exception as e: + self.fail(f"send_sync_begin() or send_sync_end() raised an exception: {e}") + + def test_disconnect(self): + try: + self.amp.disconnect() + except Exception as e: + self.fail(f"disconnect() raised an exception: {e}") + # Reconnect for further tests (if needed) + try: + self.amp.connect() + self.amp.send_sync_begin() + time.sleep(1) + self.amp.send_sync_end() + except Exception as e: + self.skipTest(f"Could not reconnect to amp after disconnect: {e}") + +if __name__ == "__main__": + unittest.main() -- 2.51.2 From 0cad37cddd1feed2b79dc5e692cba3610bd6645a Mon Sep 17 00:00:00 2001 From: Mat Manna Date: Mon, 16 Feb 2026 20:30:29 -0500 Subject: [PATCH 02/10] :hammer: add nix system flake --- .gitignore | 2 + .gitmodules | 1 + README.md | 16 ++ backend/app.py | 17 +- backend/default.nix | 46 ++++ .../.github/workflows/python-publish.yml | 70 ++++++ backend/ltamp/.gitignore | 207 ++++++++++++++++++ backend/ltamp/LICENSE | 8 + flake.lock | 123 +++++++++++ flake.nix | 161 ++++++++++++++ frontend/default.nix | 23 ++ scripts/dhcpcd.conf | 3 - scripts/dnsmasq.conf | 3 - scripts/hostapd.conf | 14 -- scripts/setup.sh | 34 --- scripts/thetwist.service | 12 - 16 files changed, 670 insertions(+), 70 deletions(-) create mode 100644 .gitmodules create mode 100644 backend/default.nix create mode 100644 backend/ltamp/.github/workflows/python-publish.yml create mode 100644 backend/ltamp/.gitignore create mode 100644 backend/ltamp/LICENSE create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 frontend/default.nix delete mode 100644 scripts/dhcpcd.conf delete mode 100644 scripts/dnsmasq.conf delete mode 100644 scripts/hostapd.conf delete mode 100644 scripts/setup.sh delete mode 100644 scripts/thetwist.service diff --git a/.gitignore b/.gitignore index 2d47584..d087b54 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .wakatime-project +result/**/**.* +.env diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.gitmodules @@ -0,0 +1 @@ + diff --git a/README.md b/README.md index 1fddac7..12373e4 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,22 @@ To build new changes to the Svelte frontend, run. Unfortunately, due to no amp s ```bash cd frontend npm run build + +To build the SD installer file, please run the following: + +``` +nix build \ + --system aarch64-linux \ + --max-jobs 0 \ + --builders "ssh://eu.nixbuild.net aarch64-linux - 100 1 big-parallel,benchmark" \ + .#installerImages.rpi02 + +sudo dd if=/dev/zero of=/dev/sda bs=8192 + +zstd -dc result/sd-image/nixos-image-rpi02-uboot.img.zst | sudo dd of=/dev/sda bs=4M conv=fsync status=progress + +sudo umount /dev/sda*; sudo eject /dev/sda +``` ``` ## πŸ—ΊοΈ Roadmap diff --git a/backend/app.py b/backend/app.py index f8cc2f6..f9bf046 100644 --- a/backend/app.py +++ b/backend/app.py @@ -18,8 +18,10 @@ import asyncio app = FastAPI(title="Twist API") -DATABASE_URL = "sqlite:///twist.db" -engine = create_engine(DATABASE_URL, echo=False) +DATA_DIR = os.environ.get("DATA_DIR", "/var/lib/the-twist-api") + +DATABASE_URL = f"sqlite:///{DATA_DIR}/db.sqlite3" +engine = create_engine(DATABASE_URL, echo=False, connect_args={"check_same_thread": False},) # websocket stuff @@ -719,11 +721,18 @@ def skip_backward_playlist(): @app.get("/") def index(): - return FileResponse("../frontend/dist/index.html") + return FileResponse(STATIC_PATH + "/index.html") @app.get("/api/version") def get_version(): with open("VERSION") as f: return {"version": f.read().strip()} -app.mount("/", StaticFiles(directory="../frontend/dist", html=True), name="static") + +STATIC_PATH = os.environ["STATIC_PATH"] + +app.mount( + "/", + StaticFiles(directory=STATIC_PATH, html=True), + name="static", +) diff --git a/backend/default.nix b/backend/default.nix new file mode 100644 index 0000000..82e7d7f --- /dev/null +++ b/backend/default.nix @@ -0,0 +1,46 @@ +{ pkgs }: + +let + python = pkgs.python312; + + ltamp = python.pkgs.buildPythonPackage { + pname = "ltamp"; + version = "0.2.7"; + + src = ./ltamp; + + format = "pyproject"; + nativeBuildInputs = with python.pkgs; [ + setuptools + wheel + ]; + + propagatedBuildInputs = with python.pkgs; [ + hidapi + protobuf + ]; + }; + + pythonEnv = python.withPackages (ps: with ps; [ + hidapi + protobuf + fastapi + uvicorn + python-socketio + aiofiles + sqlmodel + ltamp + ]); +in +pkgs.writeShellApplication { + name = "twist-backend"; + runtimeInputs = [ pythonEnv ]; + text = '' + cd ${./.} + exec uvicorn app:app \ + --host 0.0.0.0 \ + --port 8000 + ''; +} + + diff --git a/backend/ltamp/.github/workflows/python-publish.yml b/backend/ltamp/.github/workflows/python-publish.yml new file mode 100644 index 0000000..e028c36 --- /dev/null +++ b/backend/ltamp/.github/workflows/python-publish.yml @@ -0,0 +1,70 @@ +# This workflow will upload a Python Package to PyPI when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: 🐍 Publish Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + release-build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Build release distributions + run: | + # NOTE: put your own distribution build steps here. + python -m pip install build + python -m build + + - name: Upload distributions + uses: actions/upload-artifact@v4 + with: + name: release-dists + path: dist/ + + pypi-publish: + runs-on: ubuntu-latest + needs: + - release-build + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + + # Dedicated environments with protections for publishing are strongly recommended. + # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules + environment: + name: pypi + # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: + url: https://pypi.org/p/ltamp + # + # ALTERNATIVE: if your GitHub Release name is the PyPI project version string + # ALTERNATIVE: exactly, uncomment the following line instead: + # url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }} + + steps: + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Publish release distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ diff --git a/backend/ltamp/.gitignore b/backend/ltamp/.gitignore new file mode 100644 index 0000000..12aeee2 --- /dev/null +++ b/backend/ltamp/.gitignore @@ -0,0 +1,207 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock +#poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +#pdm.lock +#pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +#pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Cursor +# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to +# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data +# refer to https://docs.cursor.com/context/ignore-files +.cursorignore +.cursorindexingignore + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ diff --git a/backend/ltamp/LICENSE b/backend/ltamp/LICENSE new file mode 100644 index 0000000..7eaebf0 --- /dev/null +++ b/backend/ltamp/LICENSE @@ -0,0 +1,8 @@ +Copyright (c) 2025 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3f52a5f --- /dev/null +++ b/flake.lock @@ -0,0 +1,123 @@ +{ + "nodes": { + "argononed": { + "flake": false, + "locked": { + "lastModified": 1729566243, + "narHash": "sha256-DPNI0Dpk5aym3Baf5UbEe5GENDrSmmXVdriRSWE+rgk=", + "owner": "nvmd", + "repo": "argononed", + "rev": "16dbee54d49b66d5654d228d1061246b440ef7cf", + "type": "github" + }, + "original": { + "owner": "nvmd", + "repo": "argononed", + "type": "github" + } + }, + "flake-compat": { + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "nixos-images": { + "inputs": { + "nixos-stable": [ + "nixos-raspberrypi", + "nixpkgs" + ], + "nixos-unstable": [ + "nixos-raspberrypi", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1747747741, + "narHash": "sha256-LUOH27unNWbGTvZFitHonraNx0JF/55h30r9WxqrznM=", + "owner": "nvmd", + "repo": "nixos-images", + "rev": "cbbd6db325775096680b65e2a32fb6187c09bbb4", + "type": "github" + }, + "original": { + "owner": "nvmd", + "ref": "sdimage-installer", + "repo": "nixos-images", + "type": "github" + } + }, + "nixos-raspberrypi": { + "inputs": { + "argononed": "argononed", + "flake-compat": "flake-compat", + "nixos-images": "nixos-images", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1769297295, + "narHash": "sha256-WNI4AzwrYPeKzI/maEE+pRm8y+l9+zELkmVzMzOrOfY=", + "owner": "nvmd", + "repo": "nixos-raspberrypi", + "rev": "251861d8e7e4806e185a8e41e09b3ad1e6e088e6", + "type": "github" + }, + "original": { + "owner": "nvmd", + "ref": "main", + "repo": "nixos-raspberrypi", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1769296100, + "narHash": "sha256-T5VGtbz2X+waw2P1dYvLa56osxj3cNZArfa5aRBVT+s=", + "owner": "nvmd", + "repo": "nixpkgs", + "rev": "87f37c7a374071ec0924b99b846c1a7cc44a8c6c", + "type": "github" + }, + "original": { + "owner": "nvmd", + "ref": "modules-with-keys-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1770197578, + "narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixos-raspberrypi": "nixos-raspberrypi", + "nixpkgs": "nixpkgs_2" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..e6f001d --- /dev/null +++ b/flake.nix @@ -0,0 +1,161 @@ +{ + description = "Nix system flake for The Twist, a wireless guitar amplifier augmentation platform."; + + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main"; + }; + + nixConfig = { + extra-substituters = [ "https://nixos-raspberrypi.cachix.org" ]; + extra-trusted-public-keys = [ "nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI=" ]; + }; + + outputs = { self, nixpkgs, nixos-raspberrypi }: { + nixpkgs.config.doCheck = false; + nixosConfigurations.rpi-app = nixos-raspberrypi.lib.nixosInstaller { + specialArgs = { nixos-raspberrypi = nixos-raspberrypi; }; + modules = [ + { + imports = with nixos-raspberrypi.nixosModules; [ + raspberry-pi-02.base + raspberry-pi-02.bluetooth + usb-gadget-ethernet + ]; + } + ({ pkgs, ... }: { + nixpkgs.overlays = [ + (final: prev: { + twist-frontend = final.callPackage ./frontend { }; + twist-backend = final.callPackage ./backend { }; + }) + ]; + + environment.systemPackages = with pkgs; [ + twist-backend + twist-frontend + ]; + + users.users.twistapi = { + isSystemUser = true; + group = "twistapi"; + }; + + users.groups.twistapi = { }; + + systemd.services.the-twist-api = { + description = "Twist backend"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + environment = { + STATIC_PATH = "${pkgs.twist-frontend}/static"; + }; + + serviceConfig = { + ExecStart = "${pkgs.twist-backend}/bin/twist-backend"; + Restart = "always"; + RestartSec = 2; + + User = "twistapi"; + Group = "twistapi"; + + NoNewPrivileges = true; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + StateDirectory = "the-twist-api"; + StateDirectoryMode = "0755"; + + Environment = "PYTHONUNBUFFERED=1"; + }; + environment = { + DATA_DIR = "/var/lib/the-twist-api"; + }; + }; + + + services.openssh = { + enable = true; + + settings = { + PasswordAuthentication = true; + PermitRootLogin = "yes"; + KbdInteractiveAuthentication = true; + }; + }; + + users.users.root = { + initialPassword = "bendernotfender"; + }; + + users.users.nixos = { + isNormalUser = true; + initialPassword = "bendernotfender"; + extraGroups = [ "wheel" "networkmanager" ]; + }; + + systemd.tmpfiles.rules = [ + "d /var/lib/the-twist-api 0755 the-twist-api the-twist-api -" + ]; + + security.sudo.wheelNeedsPassword = false; + + networking = { + hostName = "rpi02w"; + firewall.allowedTCPPorts = [ 8000 ]; + networkmanager = { + enable = true; + + ensureProfiles.profiles = { + "my-wifi" = { + connection = { + id = "my-wifi"; + interface-name = "wlan0"; + type = "wifi"; + }; + + wifi = { + mode = "infrastructure"; + ssid = "this_wifi_name_is_meta"; + }; + + wifi-security = { + key-mgmt = "wpa-psk"; + psk = "this_wifi_password_is_super_insecure_so_i_pray_this_isnt_your_password_otherwise_you_should_change_it"; + }; + + ipv4.method = "auto"; + ipv6.method = "auto"; + }; + "my-ap" = { + connection = { + id = "my-ap"; + interface-name = "wlan0"; + type = "wifi"; + autoconnect = true; + }; + wifi = { + mode = "ap"; + ssid = "MyRPI-AP"; + }; + wifi-security = { + key-mgmt = "wpa-psk"; + psk = "apPassword123"; + }; + ipv4.method = "shared"; + ipv6.method = "ignore"; + }; + }; + }; + }; + + + }) + ]; + }; + + installerImages.rpi02 = self.nixosConfigurations.rpi-app.config.system.build.sdImage; + }; +} diff --git a/frontend/default.nix b/frontend/default.nix new file mode 100644 index 0000000..e998e06 --- /dev/null +++ b/frontend/default.nix @@ -0,0 +1,23 @@ +{ pkgs, nodejs }: +let + src = ./.; +in +pkgs.buildNpmPackage { + pname = "twist-frontend"; + version = "0.1.0"; + inherit src; + + npmDeps = pkgs.fetchNpmDeps { + inherit src; + hash = "sha256-wNzBsjJOrECI3REYIfDSPdMvWxwIBXosjJVTicsRpWw="; + }; + + npmBuildScript = "build"; + + postInstall = '' + mkdir -p $out/static + cp -r dist/* $out/static/ + ''; + + passthru.staticPath = "${placeholder "out"}/static"; +} diff --git a/scripts/dhcpcd.conf b/scripts/dhcpcd.conf deleted file mode 100644 index 12eed0a..0000000 --- a/scripts/dhcpcd.conf +++ /dev/null @@ -1,3 +0,0 @@ -interface wlan0 - static ip_address=192.168.4.1/24 - nohook wpa_supplicant diff --git a/scripts/dnsmasq.conf b/scripts/dnsmasq.conf deleted file mode 100644 index c7b4660..0000000 --- a/scripts/dnsmasq.conf +++ /dev/null @@ -1,3 +0,0 @@ -interface=wlan0 -dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h -address=/#/192.168.4.1 diff --git a/scripts/hostapd.conf b/scripts/hostapd.conf deleted file mode 100644 index c1b56d3..0000000 --- a/scripts/hostapd.conf +++ /dev/null @@ -1,14 +0,0 @@ -interface=wlan0 -driver=nl80211 -ssid=the-twist -hw_mode=g -channel=7 -wmm_enabled=0 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -wpa=2 -wpa_passphrase=thetwist123 -wpa_key_mgmt=WPA-PSK -wpa_pairwise=TKIP -rsn_pairwise=CCMP diff --git a/scripts/setup.sh b/scripts/setup.sh deleted file mode 100644 index 9719434..0000000 --- a/scripts/setup.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# 1. Install dependencies -sudo apt update -sudo apt install -y hostapd dnsmasq python3-pip nodejs npm - -# 2. Setup AP configs (copy pre-made configs) -sudo cp scripts/hostapd.conf /etc/hostapd/hostapd.conf -sudo cp scripts/dnsmasq.conf /etc/dnsmasq.conf -sudo cp scripts/dhcpcd.conf /etc/dhcpcd.conf -sudo cp scripts/hostapd /etc/default/hostapd - -# 3. Enable services -sudo systemctl unmask hostapd -sudo systemctl enable hostapd -sudo systemctl enable dnsmasq - -# 4. Install Python backend requirements -cd backend -pip3 install -r requirements.txt - -# 5. Build frontend -cd ../frontend -npm install -npm run build -cp -r dist/* ../backend/static/ - -# 6. Install and enable the backend service -sudo cp ../scripts/thetwist.service /etc/systemd/system/ -sudo systemctl enable thetwist -sudo systemctl restart thetwist - -# 7. Reboot to finish -sudo reboot diff --git a/scripts/thetwist.service b/scripts/thetwist.service deleted file mode 100644 index 1842930..0000000 --- a/scripts/thetwist.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=The Twist FastAPI Server -After=network.target - -[Service] -ExecStart=/usr/bin/env uvicorn app:app --host 0.0.0.0 --port 80 -WorkingDirectory=/home/pi/the-twist-pi/backend -Restart=always -User=pi - -[Install] -WantedBy=multi-user.target -- 2.51.2 From 35e59870c21361e53aea335c72e032666e1695fb Mon Sep 17 00:00:00 2001 From: Mat Manna Date: Mon, 16 Feb 2026 20:43:05 -0500 Subject: [PATCH 03/10] :memo: add lil note/warning to readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 12373e4..91733be 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # The Twist +> [!WARNING] +> nixos tooling is wip and doesnt really work rn. please check back later + > [!IMPORTANT] > This repository is still in the prototype stage with many of The Twist's components, resources, and documentation being WIP. **Nevertheless, leaving a star (⭐) helps the project!** -- 2.51.2 From cedfe59bbaa36833ac856396d0211b9224f9a8f4 Mon Sep 17 00:00:00 2001 From: Mat Manna Date: Tue, 17 Feb 2026 20:51:26 -0500 Subject: [PATCH 04/10] fix: remove .gitmodules (why does it still exist --- .gitmodules | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 8b13789..0000000 --- a/.gitmodules +++ /dev/null @@ -1 +0,0 @@ - -- 2.51.2 From 93c995c2caab9b155bc0f5cd2903490937cd6f72 Mon Sep 17 00:00:00 2001 From: Mat Manna <91392083+matmanna@users.noreply.github.com> Date: Wed, 18 Feb 2026 09:27:04 -0500 Subject: [PATCH 05/10] fix: vendored workflows are unnecessary --- .../.github/workflows/python-publish.yml | 70 ------------------- 1 file changed, 70 deletions(-) delete mode 100644 backend/ltamp/.github/workflows/python-publish.yml diff --git a/backend/ltamp/.github/workflows/python-publish.yml b/backend/ltamp/.github/workflows/python-publish.yml deleted file mode 100644 index e028c36..0000000 --- a/backend/ltamp/.github/workflows/python-publish.yml +++ /dev/null @@ -1,70 +0,0 @@ -# This workflow will upload a Python Package to PyPI when a release is created -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -name: 🐍 Publish Python Package - -on: - release: - types: [published] - -permissions: - contents: read - -jobs: - release-build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - - name: Build release distributions - run: | - # NOTE: put your own distribution build steps here. - python -m pip install build - python -m build - - - name: Upload distributions - uses: actions/upload-artifact@v4 - with: - name: release-dists - path: dist/ - - pypi-publish: - runs-on: ubuntu-latest - needs: - - release-build - permissions: - # IMPORTANT: this permission is mandatory for trusted publishing - id-token: write - - # Dedicated environments with protections for publishing are strongly recommended. - # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules - environment: - name: pypi - # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: - url: https://pypi.org/p/ltamp - # - # ALTERNATIVE: if your GitHub Release name is the PyPI project version string - # ALTERNATIVE: exactly, uncomment the following line instead: - # url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }} - - steps: - - name: Retrieve release distributions - uses: actions/download-artifact@v4 - with: - name: release-dists - path: dist/ - - - name: Publish release distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - packages-dir: dist/ -- 2.51.2 From 671caf40b47bb8ddb9c689ae8a01d7d197e99a45 Mon Sep 17 00:00:00 2001 From: Mat Manna <91392083+matmanna@users.noreply.github.com> Date: Wed, 18 Feb 2026 09:49:12 -0500 Subject: [PATCH 06/10] chore: update LICENSE gplv3 -> agplv3 --- LICENSE | 149 ++++++++++++++++++++++++++------------------------------ 1 file changed, 68 insertions(+), 81 deletions(-) diff --git a/LICENSE b/LICENSE index f288702..0ad25db 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies @@ -7,17 +7,15 @@ Preamble - The GNU General Public License is a free, copyleft license for -software and other kinds of works. + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to +our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. +software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you @@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. The precise terms and conditions for copying, distribution and modification follow. @@ -72,7 +60,7 @@ modification follow. 0. Definitions. - "This License" refers to version 3 of the GNU General Public License. + "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. @@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU Affero General Public License. + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single +under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General +Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published +GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's +versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. @@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Affero General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see +For more information on this, and how to apply and follow the GNU AGPL, see . - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. -- 2.51.2 From 7897dd4a629044d8d03795b8601e01d16ba82934 Mon Sep 17 00:00:00 2001 From: Mat Manna <91392083+matmanna@users.noreply.github.com> Date: Wed, 18 Feb 2026 09:52:34 -0500 Subject: [PATCH 07/10] chore: clean up .gitignore --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d087b54..10ccff6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ +# dev .wakatime-project -result/**/**.* +.vscode + +# nix build output +result/ +*.img + +# secrets stuff .env -- 2.51.2 From 1c5d355dcb55250773175e7ba5f9faad870d215a Mon Sep 17 00:00:00 2001 From: Mat Manna <91392083+matmanna@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:49:37 -0500 Subject: [PATCH 08/10] docs: quickstart --- README.md | 130 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 91733be..9625a81 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,81 @@ -# The Twist +# The Twist πŸ”€ -> [!WARNING] -> nixos tooling is wip and doesnt really work rn. please check back later +![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/benderhq/the-twist/ci-workflow) -> [!IMPORTANT] -> This repository is still in the prototype stage with many of The Twist's components, resources, and documentation being WIP. **Nevertheless, leaving a star (⭐) helps the project!** +https://github.com/user-attachments/assets/ab2fa6d3-ed6a-48c6-a2fd-b2e2458a9679 -πŸŒ€ The Bender Twist is a [free](https://en.wikipedia.org/wiki/Free_software), portable platform which augments the functional capabilities of LT-series amps made by a certain guitar brand that rhymes with "bender" and names products after horses. -## πŸ“Œ This Repository +> [!IMPORTANT] +> The Twist, whose components are housed by this repository, is still in alpha/prototype stages. Expect frequent breaking changes (but also enthusiastic support) until the version number reaches 1.0.0 + + + +The Bender Twist is a free, portable platform which augments the functionality of the LT-series amps made by a guitar company that rhymes with "bender". + + +## Quick Start + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Required Materials
    +
  • 1x MicroSD Card (>8GB)
  • +
  • 1x Raspberry Pi Zero 2w
  • +
  • 1x MicroUSB -> MicroUSB Data Cable
  • +
    +
  • 1x USB -> MicroUSB Power Cable
  • +
  • 1x External MicroSD Card Reader (and/or 1x SD Card Adapter)
  • +
  • Completely Optional: 1x MiniHDMI -> HDMI Cable
  • +
InstructionsSetup Diagram
  1. Go to Releases and download a .img file which matches your target device (Raspberry Pi Zero 2w)
Fallback image description
  1. Use a tool such as the Raspberry Pi Imager, Rufus, or `zstd` to flash the image file onto your microSD card.
  1. Unmount, eject, and unplug microSD before inserting it into target device.
  1. Supply power to target device.
+ +### Usage + +- Connect to local WAP (wireless access point) + - Default AP credentials: + - SSID: the-twist + - Password: bendernotfender + - Access Network Management Captive Portal + - Toggle/Configure Wifi or AP modes/credentials + - Automatically reconfigures control panel as default portal + - Redirect to mobile-friendly Control Panel Interface with: + - Amp connection manager with: + - Soon: Support for all models + - Amp stat viewing (memory, CPU usage) with: + - Soon: Dynamic graphs + - Amp preset remote control + - Footswitch playlist management + - Light/dark mode color themes + +## The Layout This repository contains the key functionality behind the twist, which is designed to be combined with other add-ons that may be developed in the future (think rechargeable battery support, etc.) The two main parts within this codebase are the **backend server**–controlling access point, API, and Amp connectivity functionalities–and the **frontend control panel**, which provides a user-friendly and easily accessible interface for using and interacting with your Twist device. An overview of both of these parts can be found in the respository's [Wiki Documentation](/wiki). -## ✨ Current features: - -- πŸ”Œ Device connection configuration - - πŸ“Š Viewing stats (memory, CPu usage) -- πŸ“‘ Device preset remote control -- πŸ•ΉοΈ Preset (footswitch) playlist management -- πŸ“± Mobile friendly UI -- πŸŒ— Light/dark control panel themes - -## πŸ“Ί Demo Video - -https://github.com/user-attachments/assets/ab2fa6d3-ed6a-48c6-a2fd-b2e2458a9679 - -## πŸ–ΌοΈ Overview - -In the alpha version, replace the Raspberry Pi with a Windows machine and AP with LAN WiFi. - - - - - Fallback image description - - -## πŸš€ Getting Started - -> [!NOTE] -> Everything in this repository is designed and tested to be run on Windows (at the moment). This doesn't mean it won't work on Linux platforms or devices, just that they haven't been fully tested - - - - -1. Install The Twist on your computer (Windows or Pi) - - b. Alternatively: DIY install in terminal - ```bash - git clone https://github.com/bendertools/twist-pi.git - cd twist-pi/frontend - npm ci && npm run build - cd ../backend - pip install -r requirements.txt - uvicorn app:app --port 8000 --host 0.0.0.0 - ``` -2. Connect to the WiFi network "the-twist" and you're set! - -## πŸ’» Developing +## Developing Hints To start the backend manually, run: @@ -91,6 +107,12 @@ sudo umount /dev/sda*; sudo eject /dev/sda ``` ``` -## πŸ—ΊοΈ Roadmap +Default SSH Credentials + +- Hostname: twist.local +- Password: bendernotfender + +## Roadmap Planned features, known bugs, and the overall project roadmap are coorinated using a combination of GitHub's Issues and Projects. The project [tab](https://github.com/bendertools/projects) is where more broad, long-term, and important work is tracked, while day-to-day development progress is reserved for Issues and Pull Requests. + -- 2.51.2 From 8440978011738c2e03e38c85a8661178ee1e8a97 Mon Sep 17 00:00:00 2001 From: Mat Manna <91392083+matmanna@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:53:46 -0500 Subject: [PATCH 09/10] docs: move readme trailer and fix table formatting --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9625a81..35b0671 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,14 @@ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/benderhq/the-twist/ci-workflow) -https://github.com/user-attachments/assets/ab2fa6d3-ed6a-48c6-a2fd-b2e2458a9679 - - > [!IMPORTANT] > The Twist, whose components are housed by this repository, is still in alpha/prototype stages. Expect frequent breaking changes (but also enthusiastic support) until the version number reaches 1.0.0 - - The Bender Twist is a free, portable platform which augments the functionality of the LT-series amps made by a guitar company that rhymes with "bender". +# Trailer + +https://github.com/user-attachments/assets/ab2fa6d3-ed6a-48c6-a2fd-b2e2458a9679 ## Quick Start @@ -27,7 +25,7 @@ The Bender Twist is a free, portable platform which augments the functionality o
  • 1x USB -> MicroUSB Power Cable
  • -
  • 1x External MicroSD Card Reader (and/or 1x SD Card Adapter)
  • +
  • 1x MicroSD Card Reader (and/or 1x SD Card Adapter)
  • Completely Optional: 1x MiniHDMI -> HDMI Cable
@@ -116,3 +114,4 @@ Default SSH Credentials Planned features, known bugs, and the overall project roadmap are coorinated using a combination of GitHub's Issues and Projects. The project [tab](https://github.com/bendertools/projects) is where more broad, long-term, and important work is tracked, while day-to-day development progress is reserved for Issues and Pull Requests. + -- 2.51.2 From 2b202dc351fa0447a383eb067c76d0e1eee5121e Mon Sep 17 00:00:00 2001 From: Mat Manna <91392083+matmanna@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:35:45 -0500 Subject: [PATCH 10/10] docs: refactor readme for readability Updated README.md to improve formatting and content clarity. --- README.md | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 35b0671..3c63ac8 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ https://github.com/user-attachments/assets/ab2fa6d3-ed6a-48c6-a2fd-b2e2458a9679
  • 1x USB -> MicroUSB Power Cable
  • 1x MicroSD Card Reader (and/or 1x SD Card Adapter)
  • -
  • Completely Optional: 1x MiniHDMI -> HDMI Cable
  • +
  • Optional: 1x MiniHDMI -> HDMI Cable
@@ -69,11 +69,32 @@ https://github.com/user-attachments/assets/ab2fa6d3-ed6a-48c6-a2fd-b2e2458a9679 ## The Layout -This repository contains the key functionality behind the twist, which is designed to be combined with other add-ons that may be developed in the future (think rechargeable battery support, etc.) +This repository contains almost everything related to The Twist, as well asthe various add-ons that may be developed in the future. -The two main parts within this codebase are the **backend server**–controlling access point, API, and Amp connectivity functionalities–and the **frontend control panel**, which provides a user-friendly and easily accessible interface for using and interacting with your Twist device. An overview of both of these parts can be found in the respository's [Wiki Documentation](/wiki). - -## Developing Hints +```bash +~/the-twist +β”œβ”€β”€ .github # automated builds & CI +β”œβ”€β”€ 3d # 3d-print files for thetwist's case options (soon) +β”œβ”€β”€ addons # battery support, speaker, screens (soon) +β”œβ”€β”€ backend # api server controlling amp connectivity +β”‚ β”œβ”€β”€ ltamp # vendored ltamp.py package +β”‚ β”œβ”€β”€ app.py # fastapi entry point +β”‚ └── default.nix +β”œβ”€β”€ docs # documentation markdown +β”œβ”€β”€ frontend # svelte control panel interface +β”‚ β”œβ”€β”€ public # assets +β”‚ β”œβ”€β”€ src +β”‚ β”‚ β”œβ”€β”€ components # reusable ui parts +β”‚ β”‚ β”œβ”€β”€ lib # utils and lil things +β”‚ β”‚ β”œβ”€β”€ pages # SPA routes +β”‚ β”‚ └── stores # event/state management +β”‚ └── default.nix +β”œβ”€β”€ portal # wifi/WAP configuration server +β”œβ”€β”€ site # marketing website +β”œβ”€β”€ flake.nix +└── flake.lock +``` +## Development To start the backend manually, run: @@ -115,3 +136,4 @@ Default SSH Credentials Planned features, known bugs, and the overall project roadmap are coorinated using a combination of GitHub's Issues and Projects. The project [tab](https://github.com/bendertools/projects) is where more broad, long-term, and important work is tracked, while day-to-day development progress is reserved for Issues and Pull Requests. + -- 2.51.2