From f1a7bcd8bc52fed90ec51b77afb4a0c526e21418 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 9 Oct 2026 16:41:47 +0300 Subject: [PATCH 01/12] Support shared serial ports and optional verification in TMS flashing --- python/protocan/tms_firmware.py | 3 ++ python/set_devices/qt_ports/tms_bootloader.py | 46 +++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/python/protocan/tms_firmware.py b/python/protocan/tms_firmware.py index 2531ca9..081d896 100644 --- a/python/protocan/tms_firmware.py +++ b/python/protocan/tms_firmware.py @@ -73,6 +73,7 @@ class TmsTarget: kind: str = "tms" board: int = 0 load_only: bool = False + verify: bool = True def validate(self, size: int) -> None: if not 0 <= self.controller <= 255: @@ -116,6 +117,8 @@ def programming_steps(data: bytes, target: TmsTarget): raise ValueError(f"Проверка EEPROM не пройдена: код {error}, обработано {words} слов") return yield tflash(t.controller, t.ram, t.flash, len(data)), 6, 180000, "CMD_TFLASH: запись Flash", 85 + if not t.verify: + return for offset in range(0, len(data), 256): block = data[offset:offset + 256] count = (len(block) + 1) & ~1 diff --git a/python/set_devices/qt_ports/tms_bootloader.py b/python/set_devices/qt_ports/tms_bootloader.py index 510dffe..d338f1a 100644 --- a/python/set_devices/qt_ports/tms_bootloader.py +++ b/python/set_devices/qt_ports/tms_bootloader.py @@ -11,12 +11,15 @@ from protocan import tms_firmware as wire class TmsBootloader(QObject): progress = Signal(int, str) finished = Signal(bool, str) + request_sent = Signal(bytes) def __init__(self, parent=None): super().__init__(parent) self._serial = QSerialPort(self) self._serial.readyRead.connect(self._read) self._serial.errorOccurred.connect(self._error) + self._owned_serial = self._serial + self._owns_serial = True self._timeout = QTimer(self) self._timeout.setSingleShot(True) self._timeout.timeout.connect(lambda: self._finish(False, f"Тайм-аут {self._stage}")) @@ -31,6 +34,7 @@ class TmsBootloader(QObject): self._active = False self._waiting = False self._rx = bytearray() + self.readback = bytearray() self._stage = "" def start(self, image, port: str, baud: int, target: wire.TmsTarget): @@ -45,6 +49,8 @@ class TmsBootloader(QObject): return self._image, self._target = image, target self._active = True + self._serial = self._owned_serial + self._owns_serial = True self._serial.setPortName(port) self._serial.setBaudRate(baud) self._serial.setDataBits(QSerialPort.DataBits.Data8) @@ -54,8 +60,29 @@ class TmsBootloader(QObject): if not self._serial.open(QSerialPort.OpenModeFlag.ReadWrite): self._finish(False, self._serial.errorString()) return + self._begin() + + def start_connected(self, image, serial, target: wire.TmsTarget): + """Use an existing port; its owner must forward RX and handle errors.""" + if self._active: + return + try: + target.validate(len(image.data)) + if not serial.isOpen() or serial.baudRate() <= 0: + raise ValueError("Подключите COM-порт в настройках 2812") + except ValueError as error: + self.finished.emit(False, str(error)) + return + self._image, self._target = image, target + self._serial = serial + self._owns_serial = False + self._active = True + self._begin() + + def _begin(self): + self.readback.clear() self._response = None - self._steps = wire.programming_steps(image.data, target) + self._steps = wire.programming_steps(self._image.data, self._target) self._advance() def _advance(self): @@ -66,6 +93,7 @@ class TmsBootloader(QObject): except StopIteration: self._finish(True, "Образ загружен в RAM TMS" if self._target.load_only else "Запись Spartan-6 подтверждена платой" if self._target.kind == "spartan6" + else "Прошивка записана; проверка отключена" if not self._target.verify else "Прошивка завершена, записанные данные проверены") return except (ValueError, RuntimeError) as error: @@ -79,11 +107,15 @@ class TmsBootloader(QObject): if self._serial.write(request) != len(request): self._finish(False, "Ошибка передачи " + self._stage) return + self.request_sent.emit(request) if self._active: - self._timeout.start(timeout + int(len(request) * 10000 / self._serial.baudRate())) + self._timeout.start(timeout + int((len(request) + self._size) * 10000 / self._serial.baudRate())) def _read(self): - chunk = bytes(self._serial.readAll()) + self.receive(bytes(self._serial.readAll())) + + def receive(self, chunk): + """Forward fragments from a shared port without reading it twice.""" if not self._waiting: return self._rx.extend(chunk) @@ -116,6 +148,10 @@ class TmsBootloader(QObject): self._timeout.stop() self._settle.stop() self._waiting = False + if self._command == wire.CMD_UPLOAD and self._target.kind == "tms": + data = wire.decode_upload_reply(reply, self._target.controller, self._size - 8) + remaining = len(self._image.data) - len(self.readback) + self.readback.extend(data[:remaining]) self._response = reply self._delay.start() @@ -133,8 +169,10 @@ class TmsBootloader(QObject): self._active = self._waiting = False for timer in (self._timeout, self._settle, self._delay): timer.stop() - if self._serial.isOpen(): + if self._owns_serial and self._serial.isOpen(): self._serial.close() + if not success: + self.readback.clear() if success: self.progress.emit(100, message) self.finished.emit(success, message) From 3c0f6fd9e6275f375732e7f4b2c1adb42a838942 Mon Sep 17 00:00:00 2001 From: Andrey Kruchinkin Date: Sun, 11 Oct 2026 03:24:44 +0300 Subject: [PATCH 02/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D1=83?= =?UTF-8?q?=20F28335=20=D0=BF=D0=BE=20ProtoCAN=20=D0=B8=20=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D0=B2=D0=B8=D1=81=D0=BD=D1=8B=D0=B5=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D0=B4=D1=8B=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/protocan-boot/CMakeLists.txt | 29 +- c/protocan-boot/README.md | 14 +- c/protocan-boot/docs/BOOTLOADER.md | 20 +- c/protocan-boot/include/pcan_boot.h | 82 ++++-- c/protocan-boot/ports/tms320f28335/README.md | 156 ++++++++++ .../ports/tms320f28335/f28335_boot_hw.c | 181 ++++++++++++ .../ports/tms320f28335/f28335_boot_platform.h | 17 ++ .../ports/tms320f28335/f28335_boot_store.c | 254 ++++++++++++++++ .../ports/tms320f28335/f28335_boot_store.h | 55 ++++ .../ports/tms320f28335/f28335_can_boot.c | 276 ++++++++++++++++++ .../ports/tms320f28335/f28335_can_boot.h | 28 ++ c/protocan-boot/src/pcan_boot.c | 223 ++++++++++---- .../tests/f28335_stubs/DSP2833x_Device.h | 13 + c/protocan-boot/tests/f28335_stubs/spise2p.h | 7 + c/protocan-boot/tests/run_tests.py | 27 ++ .../tests/test_f28335_boot_store.c | 118 ++++++++ c/protocan-boot/tests/test_f28335_can_boot.c | 94 ++++++ c/protocan-boot/tests/test_pcan_boot.c | 35 ++- doc/setcan/DEVICE_REGISTRY.md | 1 + doc/setcan/Протокол CAN и ОАП.md | 4 +- doc/setcan/Протокол CAN и ОАП.xlsx | Bin 103216 -> 87602 bytes python/protocan/can_boot.py | 95 ++++++ python/tests/test_can_boot_services.py | 70 +++++ 23 files changed, 1702 insertions(+), 97 deletions(-) create mode 100644 c/protocan-boot/ports/tms320f28335/README.md create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_platform.h create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_store.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_store.h create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_can_boot.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_can_boot.h create mode 100644 c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h create mode 100644 c/protocan-boot/tests/f28335_stubs/spise2p.h create mode 100644 c/protocan-boot/tests/run_tests.py create mode 100644 c/protocan-boot/tests/test_f28335_boot_store.c create mode 100644 c/protocan-boot/tests/test_f28335_can_boot.c create mode 100644 python/tests/test_can_boot_services.py diff --git a/c/protocan-boot/CMakeLists.txt b/c/protocan-boot/CMakeLists.txt index 47d6c8e..2548300 100644 --- a/c/protocan-boot/CMakeLists.txt +++ b/c/protocan-boot/CMakeLists.txt @@ -1,6 +1,6 @@ -# Сборка библиотеки protocan_boot. Состав исходников и публичные include-пути задают -# подключение к проекту потребителя. Файл также собирает и регистрирует хостовые проверки; -# запускать их следует через CTest из каталога сборки. +# РЎР±РѕСЂРєР° библиотеки protocan_boot. Состав РёСЃС…РѕРґРЅРёРєРѕРІ Рё публичные include-пути задают +# подключение Рє проекту потребителя. Файл также собирает Рё регистрирует хостовые проверки; +# запускать РёС… следует через CTest РёР· каталога СЃР±РѕСЂРєРё. cmake_minimum_required(VERSION 3.13) project(protocan_boot C) @@ -17,10 +17,31 @@ else() target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic) endif() -option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN boot" ON) +option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN boot" ON) if(PCAN_BOOT_BUILD_TESTS) enable_testing() add_executable(test_pcan_boot tests/test_pcan_boot.c) target_link_libraries(test_pcan_boot PRIVATE protocan_boot) add_test(NAME pcan_boot COMMAND test_pcan_boot) endif() + +if(PCAN_BOOT_BUILD_TESTS) + add_executable(test_f28335_can_boot tests/test_f28335_can_boot.c src/pcan_boot.c ports/tms320f28335/f28335_boot_store.c) + target_compile_definitions(test_f28335_can_boot PRIVATE PCAN_BOOT_WIDE_BYTES) + target_include_directories(test_f28335_can_boot PRIVATE tests/f28335_stubs) + add_test(NAME f28335_can_boot COMMAND test_f28335_can_boot) +endif() + +if(PCAN_BOOT_BUILD_TESTS) + add_executable(test_f28335_application tests/test_f28335_can_boot.c src/pcan_boot.c ports/tms320f28335/f28335_boot_store.c) + target_compile_definitions(test_f28335_application PRIVATE PCAN_BOOT_WIDE_BYTES F28335_BOOT_LOADER=0) + target_include_directories(test_f28335_application PRIVATE tests/f28335_stubs) + add_test(NAME f28335_application COMMAND test_f28335_application) + foreach(width native wide) + add_executable(test_f28335_store_${width} tests/test_f28335_boot_store.c ports/tms320f28335/f28335_boot_store.c) + if(width STREQUAL "wide") + target_compile_definitions(test_f28335_store_${width} PRIVATE PCAN_BOOT_WIDE_BYTES) + endif() + add_test(NAME f28335_store_${width} COMMAND test_f28335_store_${width}) + endforeach() +endif() diff --git a/c/protocan-boot/README.md b/c/protocan-boot/README.md index 174756f..b1bb5c7 100644 --- a/c/protocan-boot/README.md +++ b/c/protocan-boot/README.md @@ -97,7 +97,8 @@ typedef struct { } pcan_boot_port_t; ``` -Обязательны `send`, `erase_slot`, `write_slot` и `set_pending_slot`. +Обязательны `send`, `erase_slot`, `write_slot`; в A/B также `set_pending_slot`. +В single-slot этот callback необязателен и может завершать активацию образа. `authorize` проверяет политику до стирания (тип, версия, anti-rollback). `verify_image` выполняет платформенную проверку подписанного контейнера после CRC32. Если callbacks отсутствуют, соответствующие дополнительные проверки @@ -175,5 +176,12 @@ ctest --test-dir build --output-on-failure - включить watchdog и rollback при неподтверждённом запуске; - согласовать фильтры CAN для `MsgType=0x9..0xD`. -Проект пока не подключён ни к одной конкретной плате; это самостоятельный -шаблон для интеграции в будущие загрузчики приборов SET. +Ядро поддерживает платформенные порты; особенности интеграции перечислены ниже. + +## F28335 / большая EEPROM + +[Порт M95M02](ports/tms320f28335/README.md) подключён в `tms_periph/periph_167`. +Использует отдельный Flash-загрузчик и два слота EEPROM по 130560 байт. +Реализованы readback/CRC, проверка SCI8, журнал метаданных, пробный запуск, +CONFIRM/откат, PING/discovery и сервисный паспорт. Первичная установка Flash- +загрузчика и выбор Flash boot описаны в README порта. diff --git a/c/protocan-boot/docs/BOOTLOADER.md b/c/protocan-boot/docs/BOOTLOADER.md index f4ccf78..b180cdb 100644 --- a/c/protocan-boot/docs/BOOTLOADER.md +++ b/c/protocan-boot/docs/BOOTLOADER.md @@ -63,6 +63,10 @@ BlockIndex = 0x0000…0xFFFF | `0x09` | `REBOOT` | 0 | отсутствует | активная сессия | | `0x0A` | `ABORT` | 0 | отсутствует | активная сессия | | `0x0B` | `QUERY_PROGRESS` | 0 | отсутствует | активная сессия | +| `0x0C` | `PING` | 0 | отсутствует | любое | +| `0x0D` | `CAPABILITIES` | 0 | отсутствует | любое, при поддержке порта | +| `0x0E` | `DEVICE_NAME` | 1 | номер страницы имени | любое, при поддержке порта | +| `0x0F` | `MEMORY_INFO` | 1 | номер страницы памяти | любое, при поддержке порта | ### `BEGIN_IMAGE` @@ -81,7 +85,8 @@ DATA[4..7] FirmwareVersion, uint32 little-endian ``` До `ERASE` прибор обязан получить обе части метаданных и проверить размер, -тип изделия, аппаратную ревизию, версию и политику anti-rollback. +тип изделия и аппаратную ревизию. Проверка версии/anti-rollback выполняется +только при наличии соответствующей политики платформы (callback authorize). ## `BOOT_STATUS` @@ -181,3 +186,16 @@ Boot metadata должна атомарно хранить: 5. ПМ выполняет `ERASE` и передаёт `BOOT_DATA_A` либо `BOOT_DATA_B`. 6. ПМ выполняет `VERIFY`, затем `COMMIT` и `REBOOT`. 7. Новое приложение после самопроверки выполняет `CONFIRM`. + +## F28335 M95M02 + +Реализованы отдельный Flash-загрузчик, A/B по 130560 байт, журнал, пробный запуск +и откат. Подробная раскладка памяти, сервисных ответов и первичная установка: +[README порта](../ports/tms320f28335/README.md). + +Общий discovery: Route=0, DeviceType=7, DeviceID=15, MsgType=D, Body=0, DLC=0. +Он только запрашивает IDENTIFY; операции изменения всегда адресные. +ENTER_BOOT может отложить ACK до готовности отдельного загрузчика после reset. +CONFIRM с ненулевой session может обрабатываться приложением без ENTER_BOOT. +`pcan_boot_poll` обслуживает задержку discovery и тайм-аут сессии, если он задан +портом. Старым портам с timeout=0 периодический вызов нужен только для discovery. diff --git a/c/protocan-boot/include/pcan_boot.h b/c/protocan-boot/include/pcan_boot.h index 7118b51..cf9f7a9 100644 --- a/c/protocan-boot/include/pcan_boot.h +++ b/c/protocan-boot/include/pcan_boot.h @@ -11,6 +11,13 @@ #include #include +/* C28x has 16-bit addressable chars; wire octets use the low eight bits. */ +#if defined(__TMS320C28XX__) || defined(PCAN_BOOT_WIDE_BYTES) +typedef unsigned int pcan_boot_byte_t; +#else +typedef uint8_t pcan_boot_byte_t; +#endif + #ifdef __cplusplus extern "C" { #endif @@ -41,7 +48,11 @@ typedef enum { PCAN_BOOT_CMD_CONFIRM = 0x08U, PCAN_BOOT_CMD_REBOOT = 0x09U, PCAN_BOOT_CMD_ABORT = 0x0AU, - PCAN_BOOT_CMD_QUERY_PROGRESS = 0x0BU + PCAN_BOOT_CMD_QUERY_PROGRESS = 0x0BU, + PCAN_BOOT_CMD_PING = 0x0CU, + PCAN_BOOT_CMD_CAPABILITIES = 0x0DU, + PCAN_BOOT_CMD_DEVICE_NAME = 0x0EU, + PCAN_BOOT_CMD_MEMORY_INFO = 0x0FU } pcan_boot_command_t; typedef enum { @@ -66,7 +77,8 @@ typedef enum { PCAN_BOOT_STATE_READY_TO_ERASE, PCAN_BOOT_STATE_RECEIVING, PCAN_BOOT_STATE_VERIFIED, - PCAN_BOOT_STATE_FAILED + PCAN_BOOT_STATE_FAILED, + PCAN_BOOT_STATE_COMMITTED } pcan_boot_state_t; typedef struct { @@ -74,36 +86,47 @@ typedef struct { uint32_t image_crc32; uint32_t firmware_version; uint16_t product_type; - uint8_t hardware_revision_min; - uint8_t hardware_revision_max; + pcan_boot_byte_t hardware_revision_min; + pcan_boot_byte_t hardware_revision_max; } pcan_boot_manifest_t; typedef struct { - uint8_t device_type; - uint8_t device_id; + pcan_boot_byte_t device_type; + pcan_boot_byte_t device_id; uint16_t product_type; - uint8_t hardware_revision; + pcan_boot_byte_t hardware_revision; uint32_t firmware_version; - uint8_t active_slot; + pcan_boot_byte_t active_slot; /** 1 for an in-place/single-slot target, 2 for A/B. Zero keeps legacy A/B. */ - uint8_t slot_count; + pcan_boot_byte_t slot_count; /** Writable image capacity. Zero uses PCAN_BOOT_SLOT_SIZE. */ uint32_t max_image_size; - uint8_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */ + pcan_boot_byte_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */ + uint32_t session_timeout_ms; /**< 0 disables timeout for legacy ports. */ } pcan_boot_config_t; typedef struct { - bool (*send)(void *user, uint32_t can_id, const uint8_t *data, uint8_t dlc); - bool (*erase_slot)(void *user, uint8_t slot); - bool (*write_slot)(void *user, uint8_t slot, uint32_t offset, - const uint8_t *data, uint8_t length); + bool (*send)(void *user, uint32_t can_id, const pcan_boot_byte_t *data, pcan_boot_byte_t dlc); + bool (*erase_slot)(void *user, pcan_boot_byte_t slot); + bool (*write_slot)(void *user, pcan_boot_byte_t slot, uint32_t offset, + const pcan_boot_byte_t *data, pcan_boot_byte_t length); bool (*authorize)(void *user, const pcan_boot_manifest_t *manifest); - bool (*verify_image)(void *user, uint8_t slot, + bool (*verify_image)(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest); - bool (*set_pending_slot)(void *user, uint8_t slot, + /** A/B metadata, or optional single-slot activation after verification. */ + bool (*set_pending_slot)(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest); bool (*confirm_running_slot)(void *user); void (*reboot)(void *user); + /** ENTER: 0 ready, 1 deferred ACK after reset, 2 denied. NULL = legacy ready. */ + unsigned int (*enter_boot)(void *user, pcan_boot_byte_t session); + bool (*can_reboot)(void *user); + /** Eight-octet service response, addressed by command + page. */ + bool (*service_info)(void *user, pcan_boot_byte_t command, + pcan_boot_byte_t page, pcan_boot_byte_t *out); + /** Optional precise result, replacing legacy boolean verify_image. */ + pcan_boot_status_t (*verify_status)(void *user, pcan_boot_byte_t slot, + const pcan_boot_manifest_t *manifest); } pcan_boot_port_t; typedef struct { @@ -115,11 +138,13 @@ typedef struct { uint32_t running_crc32; uint32_t bytes_received; uint16_t next_block; - uint8_t session_id; - uint8_t target_slot; - uint8_t last_status; + pcan_boot_byte_t session_id; + pcan_boot_byte_t target_slot; + pcan_boot_byte_t last_status; bool have_image; bool have_compat; + uint32_t now_ms, last_activity_ms, discovery_at; + bool discovery_pending; } pcan_boot_t; /** Инициализирует экземпляр. Все обязательные callbacks должны быть заданы. */ @@ -134,16 +159,19 @@ void pcan_boot_abort(pcan_boot_t *boot); * Возвращает true, если кадр принадлежал загрузочному сервису этого прибора. */ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, - const uint8_t *data, uint8_t dlc); + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc); + +/** Call regularly with a wrapping monotonic millisecond clock. */ +void pcan_boot_poll(pcan_boot_t *boot, uint32_t now_ms); /** Переносимые операции с 29-битным ProtoCAN ID. */ -uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route, - uint8_t device_type, uint8_t device_id, - uint8_t msg_type, uint16_t msg_body); -uint8_t pcan_boot_id_route(uint32_t can_id); -uint8_t pcan_boot_id_device_type(uint32_t can_id); -uint8_t pcan_boot_id_device_id(uint32_t can_id); -uint8_t pcan_boot_id_msg_type(uint32_t can_id); +uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route, + pcan_boot_byte_t device_type, pcan_boot_byte_t device_id, + pcan_boot_byte_t msg_type, uint16_t msg_body); +pcan_boot_byte_t pcan_boot_id_route(uint32_t can_id); +pcan_boot_byte_t pcan_boot_id_device_type(uint32_t can_id); +pcan_boot_byte_t pcan_boot_id_device_id(uint32_t can_id); +pcan_boot_byte_t pcan_boot_id_msg_type(uint32_t can_id); uint16_t pcan_boot_id_msg_body(uint32_t can_id); #ifdef __cplusplus diff --git a/c/protocan-boot/ports/tms320f28335/README.md b/c/protocan-boot/ports/tms320f28335/README.md new file mode 100644 index 0000000..3d45984 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/README.md @@ -0,0 +1,156 @@ +# F28335 + M95M02: CAN, отдельный загрузчик и A/B + +Реализация состоит из Flash-загрузчика `periph_167/Bootloader`, переносимого +`f28335_boot_store.c`, аппаратного `f28335_boot_hw.c` и адаптера +`f28335_can_boot.c`. Приложение подключает их через `Source/Internal/can_boot.c`. +В сборке `EEPROM_M95M02=0` CAN Boot отключён. Для установленной M95M02 — значение 1. + +## Адрес и формат + +Device Type **3**, Device ID **7**, имя **F28335-M95M02**, Product **0x2833**, HW **1**. +В приложении FW берётся из `firmware_version.h`, формат `major<<24 | minor<<16 | patch`; +для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа +из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT. +CAN **250000 бит/с**, Extended ID, окно **16 блоков по 8 октетов**. +ENTER_BOOT для session=1: `0x13790102`, STATUS: `0x1B7C0102`. + +Образ — SCI8 BIN (`AA 08`), чётная длина от 24 до **130560 байт** включительно. +Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное +слово, затем младшее; каждое слово little endian. В C28x `char` 16-битный, +поэтому `pcan_boot_byte_t` хранит октет в младших 8 битах. + +## Разметка EEPROM, байтовые адреса + +| Область | Начало | Конец включительно | Размер | +|---|---:|---:|---:| +| Журнал 0 | 0x00000 | 0x000FF | 256 | +| Журнал 1 | 0x00100 | 0x001FF | 256 | +| Slot A | 0x00200 | 0x1FFFF | 130560 | +| Slot B | 0x20000 | 0x3FDFF | 130560 | +| Резерв | 0x3FE00 | 0x3FEFB | 252 | +| Параметры | 0x3FEFC | 0x3FFFD | 258 | +| Последнее слово | 0x3FFFE | 0x3FFFF | 2 | + +В каждой странице журнала первые 64 октета содержат magic `FAB2`, версию 1, +sequence, active/pending/attempted, два manifest, CRC32 первых 56 октетов и +commit marker в октетах 60..63. Сначала обнуляется marker запасной страницы, +затем записывается тело с проверкой чтением, последним — marker. Предыдущая +страница остаётся действующей до полной публикации новой. Выбор sequence +учитывает переполнение u32. После ошибки публикации журнал перечитывается; +ошибка чтения блокирует последующие записи. + +## Сценарий обновления и отката + +1. Приложение принимает ENTER_BOOT, останавливает управление нагрузкой, выставляет 4 мА и выдерживает + секундный STOP, затем сохраняет session в NOINIT RAM 0x50..0x57. Watchdog выполняет reset. + ACK ENTER_BOOT отправляет уже Flash-загрузчик; приложение ничего не стирает. +2. BEGIN_IMAGE/BEGIN_COMPAT проверяют размер, Product, HW и сессию. Неактивный + слот выбирается автоматически; при первом образе это A. ERASE инвалидирует + только его manifest. Полного стирания EEPROM не требуется. +3. Последовательные DATA_A/B записываются с немедленным readback. VERIFY + проверяет потоковый CRC32, CRC32 EEPROM и полную таблицу SCI8. + Разрешена загрузка только в CPU word RAM `[0x8000,0xE000)`: максимум 64 секции, + без пересечений, усечений и хвостовых данных; entry должен попасть в секцию. + Запись в Flash, периферию, стек, RAM загрузчика и handoff запрещена. +4. COMMIT повторно проверяет образ и публикует pending в журнале. Подтверждённый + слот сохраняется. Повтор COMMIT безопасен. REBOOT выполняется после физического + CAN ACK ответа. Потеря ACK/тайм-аут передачи отменяет запрос reset. +5. Перед первым запуском кандидата загрузчик сохраняет attempted=1, затем + проверяет и копирует SCI8 в RAM. Следующий reset без CONFIRM сбрасывает pending + и запускает прежний active. Если прежнего образа нет — остаётся CAN recovery. +6. Новое приложение включает watchdog в начале запуска. До подтверждения + прерывания не кормят watchdog вместо основного цикла. После READY, 100 проходов + main и 5 секунд выполняется автоматический CONFIRM. Неудача сохранения + подтверждения через 10 секунд прекращает кормление watchdog, вызывая откат. + Адресная команда CONFIRM с ненулевой session также разрешена после READY. + CONFIRM в загрузчике и до первого запуска кандидата отклоняется. + +PING, IDENTIFY и паспорт доступны без ENTER_BOOT. QUERY_PROGRESS/ABORT привязаны +к сессии. Сессия в RAM истекает через 30 секунд без подходящих команд/данных. +После reset передачу начинают заново; параметры и подтверждённый образ остаются. +ABORT после COMMIT не отменяет опубликованный pending. Для его пробного запуска +можно открыть новую сессию и отправить REBOOT. Pending запрещено перезаписывать. +Повторы ENTER_BOOT, метаданных, ERASE до первого блока, VERIFY и COMMIT учитывают +потерю ответа. Broadcast никогда не разрешает запись. + +## Сервисные команды + +Запрос: MsgType=9, Body=`session<<8 | command`. IDENTIFY/PING/паспорт не требуют сессии. +Ответ паспорта: MsgType=D, Body=`page<<8 | command`, DLC=8. + +| Код | Имя | DLC запроса | Ответ | +|---:|---|---:|---| +| 01 | IDENTIFY | 0 | Product:u16, HW:u8, protocol:u8, FW:u32; Body=1 | +| 0C | PING | 0 | protocol, state, active, target, session, slot_count, last_status, 0 | +| 0D | CAPABILITIES | 0 | flags:u32, slot_capacity:u32 | +| 0E | DEVICE_NAME | 1 (page) | 8 ASCII-октетов имени; последний фрагмент с NUL | +| 0F | MEMORY_INFO | 1 (page) | Страницы ниже | + +MEMORY_INFO 0: EEPROM bytes:u32, page bytes:u16, mode:u8 (0 app/1 boot), running:u8. +Страница 1: адреса A:u32, B:u32. Страница 2: active, pending, attempted, storage_healthy, +session_timeout_ms:u32. Страница 3: parameters_offset:u32, parameters_bytes:u32. +Слот FF означает отсутствие образа/запущенного приложения. +CAPABILITIES bits 0..11: ping, discovery, identify, name, memory, A/B, confirm, +rollback, separate loader, session timeout, readback, SCI8 validation. +Приложение, запущенное старым SPI ROM без handoff загрузчика, сообщает только +базовые сервисы (0x1F) и отклоняет ENTER_BOOT. + +Обнаружение: MsgType=D, Body=0, DLC=0, Route=0. Адресный запрос или общий +DeviceType=7/DeviceID=15. Ответ IDENTIFY приходит с адреса прибора через +`2*(1+16*DeviceType+DeviceID)` мс. При нескольких одинаковых адресах конфликт +остаётся: каждому физическому устройству нужен уникальный адрес. +Python API: `protocan.can_boot.CanBootServices` — запросы и разбор паспорта; +`CanBootTransfer` — загрузка. Кнопка «Пинг» доступна в режиме ProtoCAN Boot +окна прошивки SETGUI. Для ENTER/VERIFY/COMMIT клиент ждёт до 15 секунд. + +## Аппаратная интеграция + +MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery. +MBOX0..2 сохраняют legacy/UMP, MBOX5 остаётся heartbeat. ISR помещает сообщения +в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди. +При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново. +SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес, +разбиение по страницам 256 байт и восстановление конфигурации SPI приложения. +Он работает только при остановленном Timer2. Обычный Seeprom_write приложения +ограничен областью параметров; старый RS EXTEND 0x44 запрещён для A/B. + +Загрузчик исполняется из внутренней Flash A 0x338000..0x33FF7F, entry 0x33FFF6. +Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует +0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации, +0xE000..0xFFFF для .ebss после перехода в C runtime. Linker резервирует +NOINIT handoff в обоих проектах. CAN не содержит операций записи внутренней Flash. + +## Первичная установка + +1. Собрать приложение с EEPROM_M95M02=1 и обновлённым F28335.cmd; получить SCI8 BIN. + Старые BIN/OUT автоматически не заменены. Приложение должно содержать интеграцию + READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом. +2. Собрать отдельный загрузчик TI C2000 COFF compiler: + `Bootloader/build.ps1 -CompilerRoot <путь-к-ti-cgt-c2000>`. + Результат — `Bootloader/build/F28335_CAN_AB.out` и MAP. +3. Один раз установить этот OUT через JTAG и выбрать аппаратный Flash boot + согласно схеме платы. Не загружать поверх него старый application OUT с + секцией codestart во Flash. +4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery. + Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и + проверить MEMORY_INFO page 2: pending=FF, active=A. Затем проверить обновление в B. + +Старая SPI-ROM разметка с AA08 по адресу 0 несовместима с новым журналом. +Первое обновление заменяет её; параметры по прежнему адресу сохраняются. +Загрузчик не выполняет скрытую миграцию и не меняет boot pins программно. + +## Проверки и границы проверенного + +`python c/protocan-boot/tests/run_tests.py` (переменная CC — clang/gcc) проверяет +ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом +из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти. +Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B. +Проверка синтаксиса использует настоящие DSP2833x headers. Сборка TI/CCS, +раскладка итогового MAP и физические CAN/SPI/reset на плате ещё не подтверждены. + +CRC32 защищает от повреждения, криптографической подписи и anti-rollback по +версии в этом порту нет. Удалённый CONFIRM подтверждает готовность приложения, +но не заменяет проверку датчиков/силовой части на стенде. + +Аппаратный формат SPI boot описан в [TI Boot ROM Reference Guide](https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/2742.Boot-ROM.pdf). +В A/B-схеме ROM выбирает Flash, а разбор EEPROM выполняет этот загрузчик. diff --git a/c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c b/c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c new file mode 100644 index 0000000..e3f7aa1 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c @@ -0,0 +1,181 @@ +/* Shared by the application and the separate Flash bootloader. */ +/* Аппаратный слой: общая RAM между reset, watchdog и SPI EEPROM. + * Один исходник компилируется и в приложение, и в отдельный Flash-загрузчик. + * В отличие от store.c этот файл требует настоящих регистров F28335. */ +#include "DSP2833x_Device.h" +#include "f28335_boot_platform.h" +#include "f28335_can_boot.h" + +/* Must be NOINIT in BOTH linkers, outside ROM scratch and application payload. */ +#pragma DATA_SECTION(boot_handoff,".boot_shared") +/* 8 слов NOINIT по адресу 0x50, одинаково зарезервированных обоими linker-файлами. + * [0..1] magic; [2] запрошенная session; [3] запущенный слот; [4..6] служебные + * поля; [7] XOR-контроль. Это кратковременная передача контекста через watchdog + * reset, а не замена энергонезависимого журнала EEPROM. */ +static volatile unsigned int boot_handoff[8]; +/* Проверяем magic и XOR прежде, чем трактовать RAM как запрос входа в boot. + * После включения питания содержимое NOINIT может быть произвольным. */ +static unsigned int handoff_valid(void) +{ + unsigned int i,sum=0; + for(i=0;i<8;++i) sum^=boot_handoff[i]; + return boot_handoff[0]==0xB283 && boot_handoff[1]==0x4D7C && sum==0xA95B; +} +/* Сначала снимаем признак действительности, затем заполняем поля и контроль. + * Первый magic записываем последним; volatile сохраняет обращения к общей RAM. + * request=0 означает обычный запуск, ненулевая session — явный ENTER_BOOT. */ +static void handoff_set(unsigned int request,unsigned int running) +{ + unsigned int i,sum=0; + boot_handoff[0]=0; boot_handoff[1]=0x4D7C; + boot_handoff[2]=request; boot_handoff[3]=running; + boot_handoff[4]=0xF335; boot_handoff[5]=0x0CCA; boot_handoff[6]=1; + sum=0xB283; + for(i=1;i<7;++i) sum^=boot_handoff[i]; + boot_handoff[7]=sum^0xA95B; + boot_handoff[0]=0xB283; /* publish last */ +} +/* Приложение узнаёт свой слот из handoff, а не предполагает, что оно active: + * во время пробного запуска выполняется pending, active ещё указывает на старый образ. */ +unsigned int F28335Boot_RunningSlot(void) +{ return handoff_valid()?boot_handoff[3]:F28335_AB_NONE; } +unsigned int F28335Boot_RequestedSession(void) +{ return handoff_valid() && boot_handoff[2]<256?boot_handoff[2]:0; } +/* Одновременно публикуем выбранный слот и потребляем запрос ENTER_BOOT: + * он не должен повторяться при следующем обычном reset. */ +void F28335Boot_SetRunning(unsigned int slot) { handoff_set(0,slot); } +/* Timer1 должен давать 1 мс на InterruptCount и в приложении, и в загрузчике. + * Тайм-ауты используют разность unsigned-счётчиков для переноса через wrap. */ +uint32_t F28335Boot_Now(void) { return CpuTimer1.InterruptCount; } +/* Вызвать сразу после InitSysCtrl, который штатно отключает watchdog. + * Сбрасываем разрешение кормления из ISR до полной инициализации CAN-сервиса. + * Для приложения, запущенного нашим загрузчиком, включаем watchdog с делителем. */ +void F28335Boot_StartupWatchdog(void) +{ + F28335CanBoot_EarlyInit(); + if(F28335Boot_RunningSlot()<2) { + EALLOW; SysCtrlRegs.WDKEY=0x55; SysCtrlRegs.WDKEY=0xAA; + SysCtrlRegs.WDCR=0x002F; EDIS; + } +} +/* Платформенный Quiesce останавливает управление выходами перед reset. + * Session сохраняется до включения watchdog; ненулевую session загрузчик + * использует для отложенного ACK ENTER_BOOT. В бесконечном цикле watchdog + * намеренно не обслуживается — выход из функции должен произойти через reset. */ +void F28335Boot_Reset(unsigned int session) +{ + F28335Boot_Quiesce(); + DINT; + handoff_set(session,F28335_AB_NONE); + EALLOW; SysCtrlRegs.WDCR=0x0028; EDIS; + for(;;) { } +} + +/* Main context only. Legacy Timer2 EEPROM driver must be idle/stopped. Save + * its SPI configuration: it changes the character width during transactions. */ +typedef struct { unsigned int ccr,ctl,brr,tx,rx,ct,pri; } boot_spi_saved; +static void spi_cs(unsigned int high) +{ if(high) GpioDataRegs.GPASET.bit.GPIO19=1; else GpioDataRegs.GPACLEAR.bit.GPIO19=1; } +/* Доступ разрешён только из main при остановленном Timer2 старого SPI-драйвера. + * Это проверка занятости в однопоточном приложении, не универсальный mutex. + * Сохраняем режим SPI, поскольку штатный драйвер меняет разрядность передачи. + * CS сначала поднимаем, затем переключаем SPI на 8-битные транзакции. */ +static bool spi_take(boot_spi_saved *s) +{ + volatile unsigned int discard; + if(!CpuTimer2Regs.TCR.bit.TSS) return false; + s->ccr=SpiaRegs.SPICCR.all; s->ctl=SpiaRegs.SPICTL.all; s->brr=SpiaRegs.SPIBRR; + s->tx=SpiaRegs.SPIFFTX.all; s->rx=SpiaRegs.SPIFFRX.all; + s->ct=SpiaRegs.SPIFFCT.all; s->pri=SpiaRegs.SPIPRI.all; + EALLOW; + GpioCtrlRegs.GPAMUX2.bit.GPIO16=1; GpioCtrlRegs.GPAMUX2.bit.GPIO17=1; + GpioCtrlRegs.GPAMUX2.bit.GPIO18=1; GpioCtrlRegs.GPAMUX2.bit.GPIO19=0; + GpioDataRegs.GPASET.bit.GPIO19=1; GpioCtrlRegs.GPADIR.bit.GPIO19=1; + GpioCtrlRegs.GPAQSEL2.bit.GPIO17=3; + EDIS; + SpiaRegs.SPICCR.all=7; SpiaRegs.SPICTL.all=0x0E; /* master, phase=1, IRQ off */ + SpiaRegs.SPIBRR=CLKMULT*6+1; + SpiaRegs.SPIFFTX.all=0x8000; SpiaRegs.SPIFFRX.all=0; SpiaRegs.SPIFFCT.all=0; + SpiaRegs.SPIPRI.all=0x10; SpiaRegs.SPICCR.all=0x87; +/* Снимаем оставшийся RX/INT_FLAG от прежней операции, чтобы первый обмен + * не принял старое содержимое RXBUF за ответ EEPROM. */ + discard=SpiaRegs.SPIRXBUF; (void)discard; + return true; +} +/* Выход и при успехе, и при ошибке: CS не должен остаться активным. + * Настройки возвращаются при удержании SPI в reset; исходный SPISWRESET + * восстанавливается последним, после остальных регистров. */ +static void spi_release(const boot_spi_saved *s) +{ + volatile unsigned int discard; + spi_cs(1); discard=SpiaRegs.SPIRXBUF; (void)discard; + SpiaRegs.SPICCR.all=s->ccr&0x7FU; SpiaRegs.SPICTL.all=s->ctl; + SpiaRegs.SPIBRR=s->brr; SpiaRegs.SPIFFTX.all=s->tx; SpiaRegs.SPIFFRX.all=s->rx; + SpiaRegs.SPIFFCT.all=s->ct; SpiaRegs.SPIPRI.all=s->pri; SpiaRegs.SPICCR.all=s->ccr; +} +/* У F28335 8-битный символ для передачи выравнивается в старшие биты TXBUF. + * Полученный октет читается из младших битов RXBUF. Счётчик budget ограничивает + * ожидание даже при неработающем Timer1; это число итераций, а не миллисекунды. */ +static bool spi_octet(unsigned int tx,unsigned int *rx) +{ + uint32_t budget=100000UL; + SpiaRegs.SPITXBUF=(tx&255U)<<8; + while(!SpiaRegs.SPISTS.bit.INT_FLAG) if(--budget==0) return false; + *rx=SpiaRegs.SPIRXBUF&255U; return true; +} +/* Команда EEPROM и 24-битный байтовый адрес, старший октет адреса первым. + * CS удерживается вызывающей функцией на всю команду и полезные данные. */ +static bool spi_prefix(unsigned int command,uint32_t address) +{ + unsigned int discard; + return spi_octet(command,&discard) && spi_octet((unsigned int)(address>>16),&discard) && + spi_octet((unsigned int)(address>>8),&discard) && spi_octet((unsigned int)address,&discard); +} +/* RDSR (05h): WIP в бите 0 означает незавершённую внутреннюю запись EEPROM. + * Ожидание ограничено и 50 мс, и числом опросов на случай остановки tick. + * После каждого чтения статуса CS снимается, в том числе при ошибке SPI. */ +static bool spi_ready(void) +{ + unsigned int status,discard; uint32_t started=F28335Boot_Now(),budget=20000UL; + do { + spi_cs(0); + if(!spi_octet(5,&discard) || !spi_octet(255,&status)) { spi_cs(1); return false; } + spi_cs(1); + if(!(status&1U)) return true; + } while(--budget && (uint32_t)(F28335Boot_Now()-started)<50UL); + return false; +} +/* Читать разрешено всю физическую EEPROM, включая параметры. Проверка + * через вычитание защищает от переполнения адреса. spi_release обязателен + * после успешного захвата SPI независимо от результата последующего обмена. */ +bool F28335Boot_Read(void *u,uint32_t address,pcan_boot_byte_t *p,unsigned int n) +{ + boot_spi_saved saved; unsigned int i,value; bool ok; (void)u; + if(address>0x40000UL || n>0x40000UL-address || !spi_take(&saved)) return false; + ok=spi_ready(); + spi_cs(0); if(ok) ok=spi_prefix(3,address); + for(i=0;ok && i0x3FE00UL || n>0x3FE00UL-address || !spi_take(&saved)) return false; + ok=spi_ready(); + while(ok && n) { +/* Нельзя пересекать страницу одной командой WRITE: EEPROM может завернуть + * адрес внутри страницы. Для каждого фрагмента заново выдаём WREN (06h), + * WRITE (02h) и ждём снятия WIP. Сравнение readback выполняет верхний слой. */ + chunk=256U-(unsigned int)(address&255U); if(chunk>n) chunk=n; + spi_cs(0); ok=spi_octet(6,&discard); spi_cs(1); /* WREN */ + spi_cs(0); if(ok) ok=spi_prefix(2,address); + for(i=0;ok && i + +/* Формат журнала фиксирован: u32 little endian. Нельзя сохранять C-структуру + * через memcpy: выравнивание и sizeof на C28x отличаются от обычного ПК. */ +static uint32_t bs_get32(const pcan_boot_byte_t *p) +{ return (uint32_t)p[0] | ((uint32_t)p[1]<<8) | ((uint32_t)p[2]<<16) | ((uint32_t)p[3]<<24); } +static void bs_put32(pcan_boot_byte_t *p, uint32_t v) +{ unsigned int i; for(i=0;i<4;++i) p[i]=(pcan_boot_byte_t)((v>>(8*i))&255U); } +/* Потоковый CRC32: первый вызов получает crc=0, следующие — предыдущий результат. + * Внутренняя инверсия позволяет считать один CRC по нескольким порциям EEPROM. + * Маска 255 исключает старшие биты 16-битного представления октета на C28x. + * Это проверка повреждения данных, а не криптографическая подпись. */ +uint32_t f28335_boot_crc(uint32_t crc, const pcan_boot_byte_t *p, unsigned int n) +{ unsigned int i,b; crc=~crc; for(i=0;i>1)^((crc&1U)?0xEDB88320UL:0); } return ~crc; } +static uint32_t bs_base(unsigned int slot) { return slot?F28335_AB_SLOT_B:F28335_AB_SLOT_A; } +/* Принимаем запись только при совпадении magic, версии, marker и CRC. + * Дополнительно проверяем смысл номеров слотов: pending не может быть active. + * Наличие правильного marker без правильного CRC не разрешает запуск. */ +static bool bs_record_valid(const pcan_boot_byte_t *p) +{ + return bs_get32(p)==0x32424146UL && bs_get32(p+4)==1 && + bs_get32(p+60)==0x51AFC03DUL && bs_get32(p+56)==f28335_boot_crc(0,p,56) && + (p[12]<2 || p[12]==F28335_AB_NONE) && + (p[13]<2 || p[13]==F28335_AB_NONE) && p[14]<=1 && + (p[13]==F28335_AB_NONE || p[13]!=p[12]); +} +/* Карта записи, смещения в октетах: + * 0..3 magic FAB2; 4..7 версия; 8..11 sequence; 12 active; 13 pending; + * 14 attempted; 15 резерв; 16..35 manifest A; 36..55 manifest B; + * 56..59 CRC первых 56 октетов; 60..63 marker завершённой публикации. + * Manifest: size, CRC, FW (по u32), Product (u16), HW min/max, 4 октета резерва. */ +static void bs_decode(f28335_boot_store_t *s, const pcan_boot_byte_t *p) +{ + unsigned int i; s->sequence=bs_get32(p+8); s->active=p[12]; + s->pending=p[13]; s->attempted=p[14]; + for(i=0;i<2;++i) { + const pcan_boot_byte_t *q=p+16+i*20; + s->image[i].image_size=bs_get32(q); s->image[i].image_crc32=bs_get32(q+4); + s->image[i].firmware_version=bs_get32(q+8); + s->image[i].product_type=(uint16_t)(q[12]|(q[13]<<8)); + s->image[i].hardware_revision_min=q[14]; s->image[i].hardware_revision_max=q[15]; + } +} +/* Читаем обе копии журнала. Нераспознанная разметка допускает CAN recovery + * с active=NONE; ошибка чтения запрещает запись, поскольку реальный active неизвестен. + * Эта функция не преобразует старый SCI8 по адресу 0 в новую A/B-разметку. */ +bool f28335_boot_open(f28335_boot_store_t *s, const f28335_boot_io_t *io) +{ + pcan_boot_byte_t a[64],b[64]; bool va,vb; + if(!s || !io || !io->read || !io->write) return false; + memset(s,0,sizeof(*s)); s->io=*io; s->active=s->pending=F28335_AB_NONE; + if(!io->read(io->user,0,a,64) || !io->read(io->user,256,b,64)) { s->io_fault=true; return false; } + va=bs_record_valid(a); vb=bs_record_valid(b); + if(!va && !vb) return true; +/* Сравнение sequence по модулю 2^32: разность менее половины диапазона + * считается более новой записью. При равенстве выбирается страница 1. + * Соседние публикации отличаются на единицу, в том числе после переполнения. */ + s->page=vb && (!va || (uint32_t)(bs_get32(b+8)-bs_get32(a+8))<0x80000000UL)?1:0; + bs_decode(s,s->page?b:a); s->valid=true; return true; +} +/* Публикация выполняется в другую страницу, текущую действующую не трогаем. + * Порядок принципиален: обнулить marker -> проверить -> записать тело -> + * проверить тело -> записать marker последним -> проверить всю запись. + * При обрыве питания загрузчик выбирает прежнюю либо полностью новую запись. + * Каждый memcmp учитывает sizeof элемента, поскольку элемент здесь — октет + * протокола, но на C28x занимает адресуемое 16-битное слово. */ +static bool bs_save(f28335_boot_store_t *s) +{ + pcan_boot_byte_t p[64],check[64],invalid[4]={0,0,0,0}; unsigned int i; + unsigned int page=s->valid?(s->page^1U):0; + uint32_t addr=(uint32_t)page*256; + memset(p,0,sizeof(p)); bs_put32(p,0x32424146UL); bs_put32(p+4,1); + bs_put32(p+8,s->sequence+1); p[12]=s->active; p[13]=s->pending; p[14]=s->attempted; + for(i=0;i<2;++i) { + pcan_boot_byte_t *q=p+16+i*20; + bs_put32(q,s->image[i].image_size); bs_put32(q+4,s->image[i].image_crc32); + bs_put32(q+8,s->image[i].firmware_version); + q[12]=s->image[i].product_type&255U; q[13]=(s->image[i].product_type>>8)&255U; + q[14]=s->image[i].hardware_revision_min; q[15]=s->image[i].hardware_revision_max; + } + bs_put32(p+56,f28335_boot_crc(0,p,56)); bs_put32(p+60,0x51AFC03DUL); + /* The old page is never erased. A torn write cannot publish a partial record. */ + if(!s->io.write(s->io.user,addr+60,invalid,4) || + !s->io.read(s->io.user,addr+60,check,4) || memcmp(check,invalid,sizeof(invalid)) || + !s->io.write(s->io.user,addr,p,60) || + !s->io.read(s->io.user,addr,check,60) || memcmp(p,check,60*sizeof(*p)) || + !s->io.write(s->io.user,addr+60,p+60,4) || + !s->io.read(s->io.user,addr,check,64) || memcmp(p,check,sizeof(p))) return false; + s->page=page; s->sequence++; s->valid=true; return true; +} +/* Изменения сначала готовятся в копии состояния next. Рабочее состояние + * заменяем только после публикации. Если запись/контрольное чтение сорвались, + * перечитываем журнал: marker мог успеть записаться до ошибки readback. + * После неудачи чтения io_fault блокирует дальнейшие изменения хранилища. */ +static bool bs_publish(f28335_boot_store_t *s, f28335_boot_store_t *next) +{ + if(bs_save(next)) { *s=*next; return true; } + /* A failed final read may still have committed: reload before any more writes. */ + { f28335_boot_io_t io=s->io; if(!f28335_boot_open(s,&io)) { + s->valid=false; s->io_fault=true; return false; } } + return false; +} +/* Логический ERASE: обнуляем manifest неактивного слота в журнале. + * Саму EEPROM стирать целиком не требуется — каждый байт будет перезаписан. + * Active защищён всегда; наличие pending запрещает начало новой записи, + * пока кандидат не подтверждён либо не снят при следующем выборе загрузки. */ +bool f28335_boot_prepare(f28335_boot_store_t *s, unsigned int slot) +{ + f28335_boot_store_t next=*s; + if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE) return false; + memset(&next.image[slot],0,sizeof(next.image[slot])); + return bs_publish(s,&next); +} +/* Записываем не более одного CAN-блока и немедленно сравниваем прочитанное. + * Проверка n <= capacity-off выполняется после off <= capacity: это исключает + * переполнение суммы off+n и выход из слота в соседний слот или параметры. */ +bool f28335_boot_write(f28335_boot_store_t *s, unsigned int slot, uint32_t off, + const pcan_boot_byte_t *p, unsigned int n) +{ + pcan_boot_byte_t check[8]; + if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE || !n || n>8 || + off>F28335_AB_SLOT_BYTES || n>F28335_AB_SLOT_BYTES-off) return false; + return s->io.write(s->io.user,bs_base(slot)+off,p,n) && + s->io.read(s->io.user,bs_base(slot)+off,check,n) && !memcmp(check,p,n*sizeof(*p)); +} +/* Слово SCI8 занимает два октета файла, младший октет идёт первым. + * Смещение увеличиваем только после успешного чтения; усечённый файл отклоняем. */ +static bool bs_u16(f28335_boot_store_t *s,uint32_t base,uint32_t size,uint32_t *off,uint16_t *v) +{ + pcan_boot_byte_t p[2]; if(*off>size || size-*off<2 || + !s->io.read(s->io.user,base+*off,p,2)) return false; + *v=(uint16_t)(p[0]|(p[1]<<8)); *off+=2; return true; +} +/* Особенность таблицы TI: адрес u32 передаётся старшим словом вперёд, + * при этом внутри каждого слова остаётся little endian. Не заменять на get32. */ +static bool bs_addr(f28335_boot_store_t *s,uint32_t base,uint32_t size,uint32_t *off,uint32_t *v) +{ + uint16_t hi,lo; if(!bs_u16(s,base,size,off,&hi) || !bs_u16(s,base,size,off,&lo)) return false; + *v=((uint32_t)hi<<16)|lo; return true; +} +/* The complete table is validated before any application RAM is written. + * Loader RAM is E000..FFFF and M0/M1. Flash, peripherals and XINTF are forbidden. */ +/* writer=NULL: только разбираем и проверяем таблицу, RAM приложения не меняем. + * writer задан: повторно проверяем таблицу и переносим слова в разрешённую RAM. + * Массивы starts/ends ограничены MAX_SECTIONS; они нужны для обнаружения + * пересекающихся секций, в том числе секций с разным порядком адресов. */ +static bool bs_table(f28335_boot_store_t *s,unsigned int slot,uint32_t size, + f28335_boot_ram_writer writer,void *user,uint32_t *entry) +{ + uint32_t starts[F28335_AB_MAX_SECTIONS],ends[F28335_AB_MAX_SECTIONS]; + uint32_t off=0,addr,end,base=bs_base(slot); unsigned int sections=0,i; + uint16_t count,word; bool entry_loaded=false; + if(!bs_u16(s,base,size,&off,&word) || word!=0x08AA) return false; +/* После ключа AA 08 пропускаем 16 резервных октетов; далее расположен entry. + * Нулевой count завершает таблицу строго на конце файла, без хвостовых данных. */ + off=18; if(!bs_addr(s,base,size,&off,entry)) return false; + for(;;) { + if(!bs_u16(s,base,size,&off,&count)) return false; + if(!count) return off==size && entry_loaded; + if(sections==F28335_AB_MAX_SECTIONS || !bs_addr(s,base,size,&off,&addr)) return false; + end=addr+count; +/* Разрешён только полуинтервал RAM [0x8000,0xE000) в словах CPU. + * Верхняя граница защищает RAM работающего загрузчика; нижняя — стек, + * handoff и регистры. Проверка размера payload использует уже октеты файла. */ + if(addr<0x8000UL || end>0xE000UL || end<=addr || + off>size || (uint32_t)count*2>size-off) return false; + for(i=0;istarts[i]) return false; + starts[sections]=addr; ends[sections++]=end; + if(*entry>=addr && *entry1 || m->image_size<24 || m->image_size>F28335_AB_SLOT_BYTES || + (m->image_size&1) || m->product_type!=0x2833 || + m->hardware_revision_min>1 || m->hardware_revision_max<1) return false; + for(off=0;offimage_size;off+=n) { + n=(m->image_size-off<32)?(unsigned int)(m->image_size-off):32; + if(!s->io.read(s->io.user,bs_base(slot)+off,p,n)) return false; + crc=f28335_boot_crc(crc,p,n); + } + if(crc!=m->image_crc32 || !bs_table(s,slot,m->image_size,0,0,&local_entry)) return false; + if(entry) *entry=local_entry; + return true; +} +/* COMMIT публикует проверенный образ как pending, не меняя active. + * Повторная проверка EEPROM непосредственно перед публикацией не позволяет + * назначить кандидатом образ, испорченный после предыдущего VERIFY. */ +bool f28335_boot_commit(f28335_boot_store_t *s,unsigned int slot,const pcan_boot_manifest_t *m) +{ + f28335_boot_store_t next=*s; + if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE || + !f28335_boot_verify(s,slot,m,0)) return false; + next.image[slot]=*m; next.pending=slot; next.attempted=0; + return bs_publish(s,&next); +} +/* Подтверждать можно только действительно выбранный для пробного запуска слот. + * Требование attempted исключает подтверждение ещё ни разу не запускавшегося + * кандидата. Повтор CONFIRM уже активного слота возвращает успех без записи. */ +bool f28335_boot_confirm(f28335_boot_store_t *s,unsigned int running_slot) +{ + f28335_boot_store_t next=*s; + if(s->io_fault || running_slot>1) return false; + if(s->pending==F28335_AB_NONE) return s->valid && s->active==running_slot; + if(s->pending!=running_slot || !s->attempted) return false; + next.active=running_slot; next.pending=F28335_AB_NONE; next.attempted=0; + return bs_publish(s,&next); +} +/* Выбор выполняется при старте загрузчика. attempted сохраняется ДО перехода + * в приложение: после зависания, watchdog reset или потери питания следующий + * старт уже знает о незавершённой пробе и возвращает прежний active. + * Успех функции с slot=NONE означает recovery, а не разрешение перехода в RAM. */ +bool f28335_boot_select(f28335_boot_store_t *s,unsigned int *slot) +{ + f28335_boot_store_t next=*s; *slot=F28335_AB_NONE; + if(s->io_fault) return false; + if(s->pending!=F28335_AB_NONE) { + if(!s->attempted && f28335_boot_verify(s,s->pending,&s->image[s->pending],0)) { + next.attempted=1; + if(!bs_publish(s,&next)) return false; + *slot=s->pending; return true; + } +/* Кандидат уже запускался без подтверждения либо не прошёл проверку. + * Снимаем pending отдельной публикацией; подтверждённый active остаётся прежним. */ + next.pending=F28335_AB_NONE; next.attempted=0; + if(!bs_publish(s,&next)) return false; + } + if(s->active<2 && f28335_boot_verify(s,s->active,&s->image[s->active],0)) *slot=s->active; + return true; +} +/* Сначала полная проверка CRC и всех адресов без записи, затем перенос слов. + * Платформа вызывает entry только при true; частичная загрузка при ошибке I/O + * не даёт разрешения на запуск приложения. */ +bool f28335_boot_load(f28335_boot_store_t *s,unsigned int slot, + f28335_boot_ram_writer writer,void *user,uint32_t *entry) +{ + return slot<2 && writer && entry && f28335_boot_verify(s,slot,&s->image[slot],entry) && + bs_table(s,slot,s->image[slot].image_size,writer,user,entry); +} diff --git a/c/protocan-boot/ports/tms320f28335/f28335_boot_store.h b/c/protocan-boot/ports/tms320f28335/f28335_boot_store.h new file mode 100644 index 0000000..f5065a9 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_boot_store.h @@ -0,0 +1,55 @@ +#ifndef F28335_BOOT_STORE_H +#define F28335_BOOT_STORE_H +#include "../../include/pcan_boot.h" + +/* All EEPROM offsets/lengths below are OCTETS, CPU destinations are WORDS. */ +/* Физическая EEPROM 256 КиБ: две страницы журнала по 256 октетов, + * два слота по 130560 октетов. С 0x3FE00 начинается резерв, с 0x3FEFC — + * прежняя область параметров. Константы ниже не являются CPU word-адресами. */ +#define F28335_AB_SLOT_BYTES 0x1FE00UL +#define F28335_AB_SLOT_A 0x00200UL +#define F28335_AB_SLOT_B 0x20000UL +#define F28335_AB_PARAMS 0x3FEFCUL +#define F28335_AB_NONE 0xFFU +#define F28335_AB_RECORD 64U +#define F28335_AB_MAX_SECTIONS 64U + +/* Контракт I/O: address и n измеряются в октетах, независимо от sizeof(char). + * true означает, что выполнена вся операция; короткий обмен должен вернуть false. + * Callbacks вызываются синхронно из main, а user передаётся им без изменений. */ +typedef struct { + bool (*read)(void *, uint32_t, pcan_boot_byte_t *, unsigned int); + bool (*write)(void *, uint32_t, const pcan_boot_byte_t *, unsigned int); + void *user; +} f28335_boot_io_t; +typedef struct { + f28335_boot_io_t io; +/* sequence — номер последней публикации; page — выбранная копия журнала. + * active — подтверждённый слот; pending — кандидат; attempted — уже была проба. + * valid показывает наличие распознанной записи, io_fault запрещает изменения + * после ошибки чтения. Отсутствующий слот обозначается NONE, а не нулём. */ + uint32_t sequence; + unsigned int page, active, pending, attempted; + bool valid, io_fault; + pcan_boot_manifest_t image[2]; +} f28335_boot_store_t; + +uint32_t f28335_boot_crc(uint32_t crc, const pcan_boot_byte_t *p, unsigned int n); +bool f28335_boot_open(f28335_boot_store_t *s, const f28335_boot_io_t *io); +/* Blank/unrecognised EEPROM opens successfully with active=NONE. I/O errors fail. */ +bool f28335_boot_prepare(f28335_boot_store_t *s, unsigned int slot); +bool f28335_boot_write(f28335_boot_store_t *s, unsigned int slot, uint32_t offset, + const pcan_boot_byte_t *data, unsigned int n); +bool f28335_boot_verify(f28335_boot_store_t *s, unsigned int slot, + const pcan_boot_manifest_t *m, uint32_t *entry); +bool f28335_boot_commit(f28335_boot_store_t *s, unsigned int slot, + const pcan_boot_manifest_t *m); +bool f28335_boot_confirm(f28335_boot_store_t *s, unsigned int running_slot); +/* Records a trial BEFORE returning it; a second unconfirmed boot rolls back. */ +bool f28335_boot_select(f28335_boot_store_t *s, unsigned int *slot); +/* Запись одного проверенного слова приложения по CPU word-адресу. + * Должна вернуть false при невозможности записи; после отказа запуск запрещён. */ +typedef bool (*f28335_boot_ram_writer)(void *, uint32_t, uint16_t); +bool f28335_boot_load(f28335_boot_store_t *s, unsigned int slot, + f28335_boot_ram_writer write_word, void *user, uint32_t *entry); +#endif diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c new file mode 100644 index 0000000..5cbd7a4 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c @@ -0,0 +1,276 @@ +/* Separate Flash recovery loader and application service adapter. */ +#include "DSP2833x_Device.h" +#include "f28335_can_boot.h" +#if EEPROM_M95M02 +#include "f28335_boot_platform.h" +#include +/* boot хранит текущую CAN-сессию в RAM, store — прочитанное состояние журнала. + * Сброс сессии не удаляет active/pending из EEPROM. */ +static pcan_boot_t boot; +static f28335_boot_store_t store; +/* Кольцевая очередь: ISR производит кадры, main потребляет. Из 32 элементов + * используется 31, чтобы head==tail однозначно означало пустую очередь. + * Долгие операции SPI запрещены внутри обработчика CAN. */ +static volatile unsigned int head,tail,overflow; +static struct { uint32_t id; unsigned int dlc; pcan_boot_byte_t data[8]; } queue[32]; +/* reset_requested только планирует reset; Service ждёт завершения TX. + * ready сообщает об окончании старта приложения, confirmed — о сохранённом + * подтверждении слота. healthy отражает результат открытия журнала при Init. */ +static unsigned int reset_requested,reset_session,ready,healthy,confirmed; +static uint32_t sent_at,ready_at; +static unsigned int main_passes; +static int tx_busy,tx_canceling; +/* Один исходящий mailbox исключает перезапись ещё передаваемого ответа. + * MDL содержит первые четыре октета, MDH — следующие четыре, младшим вперёд. + * Запрос CANTRS ещё не означает успешную доставку: CANTA проверяется в Service. + * Аппаратный CAN ACK не является отдельным прикладным подтверждением от ПК. */ +static bool transmit(void *u, uint32_t id, const pcan_boot_byte_t *d, pcan_boot_byte_t n) +{ + unsigned int i; unsigned long lo=0, hi=0; (void)u; + if (tx_busy) return false; + for(i=0;i1) return false; + if(!f28335_boot_confirm(&store,running)) return false; + boot.config.active_slot=running; confirmed=1; return true; +} +static bool can_reboot(void *u) { (void)u; return healthy; } +static void reboot(void *u) { (void)u; reset_session=0; reset_requested=1; } +/* Контракт enter_boot: 0 — загрузчик готов и ядро может отправить ACK; + * 1 — переход отложен, ACK придёт после reset; 2 — вход запрещён. + * Приложение требует handoff нашего загрузчика и подтверждённый текущий слот, + * чтобы не начать обновление из старого SPI-ROM старта или незавершённой пробы. */ +static unsigned int enter(void *u,pcan_boot_byte_t session) +{ + (void)u; + if(!healthy) return 2; + if(F28335_BOOT_LOADER) return 0; + /* No destructive fallback on boards still starting through the SPI ROM. */ + if(F28335Boot_RunningSlot()>1 || !confirmed) return 2; + reset_session=session; reset_requested=1; return 1; +} +static void info32(pcan_boot_byte_t *p,uint32_t v) +{ unsigned int i; for(i=0;i<4;++i) p[i]=(pcan_boot_byte_t)((v>>(i*8))&255U); } +/* Паспорт помещается в classic CAN по страницам из восьми октетов. + * NAME возвращает фрагменты строки с завершающим NUL; неизвестная страница + * отклоняется. MEMORY: 0 — ёмкость/страница/режим/running, 1 — базы A/B, + * 2 — active/pending/attempted/healthy/тайм-аут, 3 — область параметров. */ +static bool info(void *u,pcan_boot_byte_t command,pcan_boot_byte_t page,pcan_boot_byte_t *out) +{ + static const char name[]=F28335_CAN_BOOT_DEVICE_NAME; + unsigned int i,index; (void)u; + if(command==PCAN_BOOT_CMD_CAPABILITIES && page==0) { + /* bits: ping, discovery, identity, name, memory, A/B, confirm, rollback, + * separate loader, session timeout, readback, SCI8 validation. */ + info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2)?0xFFFUL:0x1FUL); + info32(out+4,F28335_AB_SLOT_BYTES); return true; + } + if(command==PCAN_BOOT_CMD_DEVICE_NAME) { + if((unsigned int)page*8U>=sizeof(name)) return false; + for(i=0;i<8;++i) { index=(unsigned int)page*8U+i; + out[i]=indexMSGCTRL.bit.RTR) { ECanaRegs.CANRMP.all=mask; return; } + id=box->MSGID.all&0x1FFFFFFFUL; + type=pcan_boot_id_msg_type(id); + if(!(box->MSGID.all&0x80000000UL) || pcan_boot_id_route(id)!=0 || + (type!=9 && type!=10 && type!=11 && type!=13) || + !((pcan_boot_id_device_type(id)==F28335_CAN_BOOT_DEVICE_TYPE && + pcan_boot_id_device_id(id)==F28335_CAN_BOOT_DEVICE_ID) || + (type==13 && pcan_boot_id_device_type(id)==7 && pcan_boot_id_device_id(id)==15 && + pcan_boot_id_msg_body(id)==0))) { ECanaRegs.CANRMP.all=mask; return; } + if(next==tail) overflow=1; + else { + queue[head].id=box->MSGID.all&0x1FFFFFFFUL; + queue[head].dlc=box->MSGCTRL.bit.DLC; + lo=box->MDL.all; hi=box->MDH.all; + for(i=0;i<4;++i) { queue[head].data[i]=(lo>>(8U*i))&255U; + queue[head].data[i+4]=(hi>>(8U*i))&255U; } + head=next; + } + ECanaRegs.CANRMP.all=mask; +} + +void F28335CanBoot_RxISR(void) +{ + receive_box(&ECanaMboxes.MBOX3,8UL); + receive_box(&ECanaMboxes.MBOX6,64UL); +} +/* Вызывать после инициализации параметров, датчиков и прикладного режима. + * От этого момента отсчитывается интервал наблюдения перед авто-CONFIRM. */ +void F28335CanBoot_Ready(void) +{ ready=1; ready_at=F28335Boot_Now(); } +/* Используется таймерными ISR приложения. Во время пробы кормление watchdog + * должно доказывать выполнение main: работа одного ISR не доказывает готовность. + * Старый старт без handoff сохраняет прежнюю политику watchdog. */ +unsigned int F28335CanBoot_WatchdogAllowed(void) +{ return F28335Boot_RunningSlot()>1 || confirmed; } +/* Неблокирующий диспетчер относительно ожидания CAN: вызывать в каждом проходе main. + * Сами callbacks проверки/записи EEPROM синхронные. Порядок здесь важен: + * проба приложения -> завершение TX -> reset -> poll -> ошибки RX -> один кадр. */ +void F28335CanBoot_Service(void) +{ + uint32_t now=F28335Boot_Now(); + if(!F28335_BOOT_LOADER && ready && !confirmed && healthy && F28335Boot_RunningSlot()<2) { + /* A trial must keep executing main, not merely a timer ISR. */ +/* После 100 проходов main и 5 секунд пробуем сохранить CONFIRM. + * Если до 10 секунд сохранение не удалось, main перестаёт кормить watchdog, + * что позволяет следующему старту откатиться к подтверждённому образу. */ + if((uint32_t)(now-ready_at)<10000UL) ServiceDog(); + if(main_passes<100) ++main_passes; + if(main_passes==100 && (uint32_t)(now-ready_at)>=5000UL) (void)confirm(0); + } + if(tx_busy) { +/* После CANTRR ждём завершения отмены или запоздавшего ACK, прежде чем + * повторно использовать mailbox. reset_requested к этому моменту уже снят, + * поэтому позднее подтверждение не должно перезапустить устройство. */ + if(tx_canceling) { + if(!((ECanaRegs.CANAA.all|ECanaRegs.CANTA.all)&16UL)) return; + ECanaRegs.CANAA.all=16UL; ECanaRegs.CANTA.all=16UL; + tx_busy=tx_canceling=0; + } else if((uint32_t)(now-sent_at)>250UL) { + /* Cancel reset immediately, even if a late CAN ACK races CANTRR. */ + reset_requested=0; pcan_boot_abort(&boot); tail=head; + tx_canceling=1; ECanaRegs.CANTRR.all=16UL; return; + } else if(ECanaRegs.CANTA.all&16UL) { + ECanaRegs.CANTA.all=16UL; tx_busy=0; + } else return; + } + if(reset_requested) { F28335Boot_Reset(reset_session); return; } + pcan_boot_poll(&boot,now); + if(tx_busy) return; +/* После потери кадра нельзя молча продолжать запись: сбрасываем RAM-сессию + * и накопленную очередь. Подтверждённый образ и опубликованный pending сохраняются. */ + if(overflow || (ECanaRegs.CANRML.all&72UL)) { + overflow=0; ECanaRegs.CANRML.all=72UL; + pcan_boot_abort(&boot); tail=head; return; + } + if(tail!=head) { + pcan_boot_process(&boot,queue[tail].id,queue[tail].data,queue[tail].dlc); + tail=(tail+1U)&31U; + } +} +/* Используем session из NOINIT только для нового ENTER_BOOT после reset. + * Это отправка отложенного ACK готовности, а не восстановление принятых блоков + * или CRC незавершённой передачи: данные сессии через reset не сохраняются. */ +void F28335CanBoot_Resume(unsigned int session) +{ + if(F28335_BOOT_LOADER && session && session<256) + (void)pcan_boot_process(&boot,pcan_boot_make_id(1,0, + F28335_CAN_BOOT_DEVICE_TYPE,F28335_CAN_BOOT_DEVICE_ID,9,(session<<8)|2),0,0); +} +#else +void F28335CanBoot_EarlyInit(void) {} +void F28335CanBoot_Init(void) {} +void F28335CanBoot_RxISR(void) {} +void F28335CanBoot_Service(void) {} +void F28335CanBoot_Ready(void) {} +unsigned int F28335CanBoot_WatchdogAllowed(void) { return 1; } +void F28335CanBoot_Resume(unsigned int session) { (void)session; } +#endif diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h new file mode 100644 index 0000000..17b44db --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h @@ -0,0 +1,28 @@ +#ifndef F28335_CAN_BOOT_H +#define F28335_CAN_BOOT_H +#include "../../include/pcan_boot.h" +/* Приложение задаёт версию из firmware_version.h до подключения этого заголовка. + * Формат поля FW: major[31:24], minor[23:16], patch[15:0]. Ноль — запасное + * значение при отсутствии версии сборки, а не прошитая здесь версия устройства. */ +#ifndef F28335_CAN_BOOT_FIRMWARE_VERSION +#define F28335_CAN_BOOT_FIRMWARE_VERSION 0UL /* Board supplies the build identity. */ +#endif +/* Адрес ProtoCAN состоит из Device Type (3 бита) и Device ID (4 бита). + * ProductType — отдельный код совместимости прошивки; это не CAN ID и не RS-адрес. */ +#define F28335_CAN_BOOT_DEVICE_TYPE 3U +#define F28335_CAN_BOOT_DEVICE_ID 7U +#define F28335_CAN_BOOT_PRODUCT 0x2833U +#define F28335_CAN_BOOT_DEVICE_NAME "F28335-M95M02" +/* Порядок интеграции приложения: + * StartupWatchdog/EarlyInit сразу после InitSysCtrl; Init после настройки + * таймера и EEPROM; Ready после старта прикладных подсистем; Service в main. + * RxISR вызывается из CAN ISR, WatchdogAllowed проверяется перед кормлением + * watchdog таймерным ISR. Resume применяется только отдельным загрузчиком. */ +void F28335CanBoot_Init(void); +void F28335CanBoot_EarlyInit(void); +void F28335CanBoot_RxISR(void); +void F28335CanBoot_Service(void); +void F28335CanBoot_Ready(void); +void F28335CanBoot_Resume(unsigned int session); +unsigned int F28335CanBoot_WatchdogAllowed(void); +#endif diff --git a/c/protocan-boot/src/pcan_boot.c b/c/protocan-boot/src/pcan_boot.c index 7b92239..2748d03 100644 --- a/c/protocan-boot/src/pcan_boot.c +++ b/c/protocan-boot/src/pcan_boot.c @@ -1,21 +1,16 @@ -/* - * Автомат адресной загрузки прошивки по ProtoCAN с сессией, контрольной суммой и A/B-слотами. - * Приём блоков, проверка образа и активация разделены на этапы; операции Flash и метаданные - * слотов предоставляет платформа. - */ - -#include "pcan_boot.h" +/* ProtoCAN update state machine; platform owns storage and reset. */ +#include "../include/pcan_boot.h" #include #define PCAN_BOOT_ID_MASK 0x1FFFFFFFUL -static uint16_t get_u16(const uint8_t *p) +static uint16_t get_u16(const pcan_boot_byte_t *p) { return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } -static uint32_t get_u32(const uint8_t *p) +static uint32_t get_u32(const pcan_boot_byte_t *p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8) @@ -23,26 +18,26 @@ static uint32_t get_u32(const uint8_t *p) | ((uint32_t)p[3] << 24); } -static void put_u16(uint8_t *p, uint16_t value) +static void put_u16(pcan_boot_byte_t *p, uint16_t value) { - p[0] = (uint8_t)value; - p[1] = (uint8_t)(value >> 8); + p[0] = (pcan_boot_byte_t)(value & 0xFFU); + p[1] = (pcan_boot_byte_t)((value >> 8) & 0xFFU); } -static void put_u32(uint8_t *p, uint32_t value) +static void put_u32(pcan_boot_byte_t *p, uint32_t value) { - p[0] = (uint8_t)value; - p[1] = (uint8_t)(value >> 8); - p[2] = (uint8_t)(value >> 16); - p[3] = (uint8_t)(value >> 24); + p[0] = (pcan_boot_byte_t)(value & 0xFFU); + p[1] = (pcan_boot_byte_t)((value >> 8) & 0xFFU); + p[2] = (pcan_boot_byte_t)((value >> 16) & 0xFFU); + p[3] = (pcan_boot_byte_t)(value >> 24); } -static uint32_t crc32_update(uint32_t crc, const uint8_t *data, size_t length) +static uint32_t crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length) { size_t i; crc = ~crc; for (i = 0U; i < length; ++i) { - uint8_t bit; + pcan_boot_byte_t bit; crc ^= data[i]; for (bit = 0U; bit < 8U; ++bit) { crc = (crc >> 1) ^ ((crc & 1U) != 0U ? 0xEDB88320UL : 0U); @@ -51,9 +46,9 @@ static uint32_t crc32_update(uint32_t crc, const uint8_t *data, size_t length) return ~crc; } -uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route, - uint8_t device_type, uint8_t device_id, - uint8_t msg_type, uint16_t msg_body) +uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route, + pcan_boot_byte_t device_type, pcan_boot_byte_t device_id, + pcan_boot_byte_t msg_type, uint16_t msg_body) { return ((((uint32_t)priority & 1U) << 28) | (((uint32_t)route & 1U) << 27) @@ -63,14 +58,14 @@ uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route, | msg_body) & PCAN_BOOT_ID_MASK; } -uint8_t pcan_boot_id_route(uint32_t can_id) { return (uint8_t)((can_id >> 27) & 1U); } -uint8_t pcan_boot_id_device_type(uint32_t can_id) { return (uint8_t)((can_id >> 24) & 7U); } -uint8_t pcan_boot_id_device_id(uint32_t can_id) { return (uint8_t)((can_id >> 20) & 15U); } -uint8_t pcan_boot_id_msg_type(uint32_t can_id) { return (uint8_t)((can_id >> 16) & 15U); } +pcan_boot_byte_t pcan_boot_id_route(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 27) & 1U); } +pcan_boot_byte_t pcan_boot_id_device_type(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 24) & 7U); } +pcan_boot_byte_t pcan_boot_id_device_id(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 20) & 15U); } +pcan_boot_byte_t pcan_boot_id_msg_type(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 16) & 15U); } uint16_t pcan_boot_id_msg_body(uint32_t can_id) { return (uint16_t)can_id; } -static bool send_frame(pcan_boot_t *boot, uint8_t msg_type, uint16_t body, - const uint8_t *data, uint8_t dlc) +static bool send_frame(pcan_boot_t *boot, pcan_boot_byte_t msg_type, uint16_t body, + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { uint32_t id = pcan_boot_make_id(1U, PCAN_BOOT_ROUTE_FROM_DEVICE, boot->config.device_type, @@ -79,9 +74,12 @@ static bool send_frame(pcan_boot_t *boot, uint8_t msg_type, uint16_t body, return boot->port.send(boot->port_user, id, data, dlc); } -static bool send_status(pcan_boot_t *boot, uint8_t command, uint8_t status) +/* STATUS всегда содержит состояние передачи: status, target_slot, next_block, CRC32. + * CRC здесь относится к уже принятому потоку, а не заменяет проверку EEPROM. + * Номер следующего блока помогает клиенту продолжить обмен после потери ACK. */ +static bool send_status(pcan_boot_t *boot, pcan_boot_byte_t command, pcan_boot_byte_t status) { - uint8_t data[8]; + pcan_boot_byte_t data[8]; uint16_t body = (uint16_t)(((uint16_t)boot->session_id << 8) | command); data[0] = status; data[1] = boot->target_slot; @@ -91,9 +89,11 @@ static bool send_status(pcan_boot_t *boot, uint8_t command, uint8_t status) return send_frame(boot, PCAN_BOOT_MSG_STATUS, body, data, 8U); } +/* IDENTIFY имеет отдельный тип сообщения DISCOVERY и Body=1. Он доступен + * без открытия сессии, поэтому обнаружение устройства не должно запускать обновление. */ static bool send_identity(pcan_boot_t *boot) { - uint8_t data[8]; + pcan_boot_byte_t data[8]; put_u16(&data[0], boot->config.product_type); data[2] = boot->config.hardware_revision; data[3] = PCAN_BOOT_VERSION; @@ -101,6 +101,9 @@ static bool send_identity(pcan_boot_t *boot) return send_frame(boot, PCAN_BOOT_MSG_DISCOVERY, 1U, data, 8U); } +/* Отменяется только состояние протокола в RAM: manifest, счётчики и session. + * Функция не стирает EEPROM и не снимает ранее опубликованный pending. + * Ответственность за постоянное состояние слотов остаётся у платформы. */ void pcan_boot_abort(pcan_boot_t *boot) { if (boot == NULL) { @@ -118,19 +121,24 @@ void pcan_boot_abort(pcan_boot_t *boot) boot->have_compat = false; } +/* Конфигурация копируется в экземпляр; указатели callbacks остаются привязаны + * к port_user. Значения slot_count=0 и max_image_size=0 сохраняют исторические + * настройки по умолчанию. Для пустого A/B-хранилища допустим active_slot=NONE. */ bool pcan_boot_init(pcan_boot_t *boot, const pcan_boot_config_t *config, const pcan_boot_port_t *port, void *port_user) { - uint8_t slot_count; + pcan_boot_byte_t slot_count; if ((boot == NULL) || (config == NULL) || (port == NULL) || (config->device_type > 7U) || (config->device_id > 15U) - || (config->active_slot > 1U) + || ((config->active_slot > 1U) && (config->active_slot != PCAN_BOOT_SLOT_NONE)) || (port->send == NULL) || (port->erase_slot == NULL) || (port->write_slot == NULL)) { return false; } slot_count = config->slot_count == 0U ? 2U : config->slot_count; - if ((slot_count > 2U) || (config->active_slot >= slot_count) + if ((slot_count > 2U) || ((config->active_slot >= slot_count) && + (config->active_slot != PCAN_BOOT_SLOT_NONE || slot_count != 2U)) + || config->max_image_size > PCAN_BOOT_SLOT_SIZE || ((slot_count == 2U) && (port->set_pending_slot == NULL))) { return false; } @@ -149,7 +157,10 @@ bool pcan_boot_init(pcan_boot_t *boot, const pcan_boot_config_t *config, return true; } -static bool metadata_complete(pcan_boot_t *boot, uint8_t command) +/* BEGIN_IMAGE и BEGIN_COMPAT приходят отдельными кадрами. До получения обоих + * не разрешаем ERASE. Проверяем размер, Product, HW и необязательную политику + * authorize. В A/B выбираем противоположный active слот; для первого образа — A. */ +static bool metadata_complete(pcan_boot_t *boot, pcan_boot_byte_t command) { if (!boot->have_image || !boot->have_compat) { boot->state = PCAN_BOOT_STATE_METADATA; @@ -160,8 +171,11 @@ static bool metadata_complete(pcan_boot_t *boot, uint8_t command) boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_SIZE); } - if ((boot->manifest.product_type != boot->config.product_type) - || (boot->config.hardware_revision < boot->manifest.hardware_revision_min) + if (boot->manifest.product_type != boot->config.product_type) { + boot->state = PCAN_BOOT_STATE_FAILED; + return send_status(boot, command, PCAN_BOOT_STATUS_WRONG_DEVICE); + } + if ((boot->config.hardware_revision < boot->manifest.hardware_revision_min) || (boot->config.hardware_revision > boot->manifest.hardware_revision_max)) { boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_WRONG_HARDWARE); @@ -171,19 +185,51 @@ static bool metadata_complete(pcan_boot_t *boot, uint8_t command) boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_SIGNATURE_ERROR); } - boot->target_slot = boot->config.slot_count == 1U + boot->target_slot = boot->config.active_slot == PCAN_BOOT_SLOT_NONE ? 0U : + boot->config.slot_count == 1U ? boot->config.active_slot - : (uint8_t)(boot->config.active_slot ^ 1U); + : (pcan_boot_byte_t)(boot->config.active_slot ^ 1U); boot->state = PCAN_BOOT_STATE_READY_TO_ERASE; return send_status(boot, command, PCAN_BOOT_STATUS_OK); } +/* Body состоит из session в старшем октете и command в младшем. + * Сначала проверяем DLC, чтобы обработчики не читали отсутствующие данные. + * Идентификация и паспорт не открывают сессию; CONFIRM обрабатывается отдельно, + * поскольку приложение не должно входить в загрузчик ради подтверждения себя. + * Остальные команды изменяют RAM-автомат только в допустимой сессии/состоянии. */ static bool process_control(pcan_boot_t *boot, uint16_t body, - const uint8_t *data, uint8_t dlc) + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { - uint8_t session = (uint8_t)(body >> 8); - uint8_t command = (uint8_t)body; + pcan_boot_byte_t session = (pcan_boot_byte_t)(body >> 8); + pcan_boot_byte_t command = (pcan_boot_byte_t)(body & 0xFFU); + if (dlc != ((command == PCAN_BOOT_CMD_BEGIN_IMAGE || command == PCAN_BOOT_CMD_BEGIN_COMPAT) ? 8U : + (command == PCAN_BOOT_CMD_DEVICE_NAME || command == PCAN_BOOT_CMD_MEMORY_INFO) ? 1U : 0U)) { + return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_SIZE); + } + if (command == PCAN_BOOT_CMD_PING) { + pcan_boot_byte_t reply[8] = {0}; + reply[0] = PCAN_BOOT_VERSION; reply[1] = boot->state; + reply[2] = boot->config.active_slot; reply[3] = boot->target_slot; + reply[4] = boot->session_id; reply[5] = boot->config.slot_count; + reply[6] = boot->last_status; + return send_frame(boot, PCAN_BOOT_MSG_DISCOVERY, command, reply, 8); + } + if (command >= PCAN_BOOT_CMD_CAPABILITIES && command <= PCAN_BOOT_CMD_MEMORY_INFO) { + pcan_boot_byte_t reply[8] = {0}; + pcan_boot_byte_t page = dlc ? data[0] : 0; + if (!boot->port.service_info || !boot->port.service_info(boot->port_user,command,page,reply)) + return send_status(boot,command,PCAN_BOOT_STATUS_INVALID_COMMAND); + return send_frame(boot,PCAN_BOOT_MSG_DISCOVERY,(uint16_t)((page<<8)|command),reply,8); + } + if (command == PCAN_BOOT_CMD_CONFIRM) { + pcan_boot_byte_t saved=boot->session_id; bool sent; + boot->session_id=session; + sent=send_status(boot,command,session && boot->port.confirm_running_slot && + boot->port.confirm_running_slot(boot->port_user) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_INVALID_STATE); + boot->session_id=saved; return sent; + } if (command == PCAN_BOOT_CMD_IDENTIFY) { return send_identity(boot); } @@ -191,8 +237,18 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, if (session == 0U) { return send_status(boot, command, PCAN_BOOT_STATUS_SESSION_ERROR); } + if (boot->state != PCAN_BOOT_STATE_IDLE && boot->session_id != session) + return send_status(boot,command,PCAN_BOOT_STATUS_BUSY); + if (boot->port.enter_boot) { + unsigned int result=boot->port.enter_boot(boot->port_user,session); + if(result==1) return true; + if(result!=0) return send_status(boot,command,PCAN_BOOT_STATUS_INVALID_STATE); + } + if (boot->session_id==session && boot->state!=PCAN_BOOT_STATE_IDLE) + return send_status(boot,command,PCAN_BOOT_STATUS_OK); pcan_boot_abort(boot); boot->session_id = session; + boot->last_activity_ms=boot->now_ms; boot->state = PCAN_BOOT_STATE_METADATA; return send_status(boot, command, PCAN_BOOT_STATUS_OK); } @@ -200,8 +256,11 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_SESSION_ERROR); } + boot->last_activity_ms=boot->now_ms; switch (command) { case PCAN_BOOT_CMD_BEGIN_IMAGE: + if(boot->state==PCAN_BOOT_STATE_READY_TO_ERASE && boot->manifest.image_size==get_u32(data) && + boot->manifest.image_crc32==get_u32(data+4)) return send_status(boot,command,PCAN_BOOT_STATUS_OK); if ((dlc != 8U) || (boot->state != PCAN_BOOT_STATE_METADATA)) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } @@ -211,6 +270,9 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return metadata_complete(boot, command); case PCAN_BOOT_CMD_BEGIN_COMPAT: + if(boot->state==PCAN_BOOT_STATE_READY_TO_ERASE && boot->manifest.product_type==get_u16(data) && + boot->manifest.hardware_revision_min==data[2] && boot->manifest.hardware_revision_max==data[3] && + boot->manifest.firmware_version==get_u32(data+4)) return send_status(boot,command,PCAN_BOOT_STATUS_OK); if ((dlc != 8U) || (boot->state != PCAN_BOOT_STATE_METADATA)) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } @@ -222,6 +284,8 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return metadata_complete(boot, command); case PCAN_BOOT_CMD_ERASE: + if(boot->state==PCAN_BOOT_STATE_RECEIVING && boot->bytes_received==0) + return send_status(boot,command,PCAN_BOOT_STATUS_OK); if (boot->state != PCAN_BOOT_STATE_READY_TO_ERASE) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } @@ -236,6 +300,8 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_VERIFY: + if(boot->state==PCAN_BOOT_STATE_VERIFIED || boot->state==PCAN_BOOT_STATE_COMMITTED) + return send_status(boot,command,PCAN_BOOT_STATUS_OK); if ((boot->state != PCAN_BOOT_STATE_RECEIVING) || (boot->bytes_received != boot->manifest.image_size)) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); @@ -244,7 +310,13 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_CRC_ERROR); } - if ((boot->port.verify_image != NULL) + if (boot->port.verify_status) { + pcan_boot_status_t status=boot->port.verify_status(boot->port_user,boot->target_slot,&boot->manifest); + if(status!=PCAN_BOOT_STATUS_OK) { + boot->state=PCAN_BOOT_STATE_FAILED; return send_status(boot,command,status); + } + } + if (!boot->port.verify_status && (boot->port.verify_image != NULL) && !boot->port.verify_image(boot->port_user, boot->target_slot, &boot->manifest)) { boot->state = PCAN_BOOT_STATE_FAILED; @@ -254,21 +326,16 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_COMMIT: + if(boot->state==PCAN_BOOT_STATE_COMMITTED) return send_status(boot,command,PCAN_BOOT_STATUS_OK); if (boot->state != PCAN_BOOT_STATE_VERIFIED) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } - if ((boot->config.slot_count == 2U) + if ((boot->port.set_pending_slot != NULL) && !boot->port.set_pending_slot(boot->port_user, boot->target_slot, &boot->manifest)) { return send_status(boot, command, PCAN_BOOT_STATUS_FLASH_ERROR); } - return send_status(boot, command, PCAN_BOOT_STATUS_OK); - - case PCAN_BOOT_CMD_CONFIRM: - if ((boot->port.confirm_running_slot == NULL) - || !boot->port.confirm_running_slot(boot->port_user)) { - return send_status(boot, command, PCAN_BOOT_STATUS_FLASH_ERROR); - } + boot->state=PCAN_BOOT_STATE_COMMITTED; return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_QUERY_PROGRESS: @@ -280,7 +347,9 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_REBOOT: - (void)send_status(boot, command, PCAN_BOOT_STATUS_OK); + if(!boot->port.reboot || (boot->port.can_reboot && !boot->port.can_reboot(boot->port_user))) + return send_status(boot,command,PCAN_BOOT_STATUS_INVALID_STATE); + if(!send_status(boot,command,PCAN_BOOT_STATUS_OK)) return false; if (boot->port.reboot != NULL) { boot->port.reboot(boot->port_user); } @@ -291,11 +360,16 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, } } -static bool process_data(pcan_boot_t *boot, uint8_t msg_type, uint16_t block, - const uint8_t *data, uint8_t dlc) +/* DATA не содержит session в Body: все 16 бит заняты номером блока. Поэтому + * кадры данных принимаются только в состоянии RECEIVING и для выбранного A/B. + * При неверном номере ничего не записываем и возвращаем ожидаемый next_block. + * Последний кадр дополняется клиентом до 8 октетов, но запись и CRC учитывают + * только оставшиеся октеты image_size. ACK выдаётся на границе окна или в конце. */ +static bool process_data(pcan_boot_t *boot, pcan_boot_byte_t msg_type, uint16_t block, + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { - uint8_t expected_type; - uint8_t write_length; + pcan_boot_byte_t expected_type; + pcan_boot_byte_t write_length; uint32_t remaining; if (boot->state != PCAN_BOOT_STATE_RECEIVING) { @@ -309,8 +383,9 @@ static bool process_data(pcan_boot_t *boot, uint8_t msg_type, uint16_t block, if ((block != boot->next_block) || (dlc != PCAN_BOOT_BLOCK_SIZE)) { return send_status(boot, 0U, PCAN_BOOT_STATUS_SEQUENCE_ERROR); } + boot->last_activity_ms=boot->now_ms; remaining = boot->manifest.image_size - boot->bytes_received; - write_length = remaining < PCAN_BOOT_BLOCK_SIZE ? (uint8_t)remaining + write_length = remaining < PCAN_BOOT_BLOCK_SIZE ? (pcan_boot_byte_t)remaining : PCAN_BOOT_BLOCK_SIZE; if ((write_length == 0U) || !boot->port.write_slot(boot->port_user, boot->target_slot, @@ -329,10 +404,14 @@ static bool process_data(pcan_boot_t *boot, uint8_t msg_type, uint16_t block, return true; } +/* Общая точка входа для одного кадра после аппаратной фильтрации. + * Проверки адреса повторяются программно, чтобы широкая маска CAN не разрешила + * обновление чужого устройства. Broadcast допускается только для DISCOVERY + * с Body=0/DLC=0; ответ откладывается до poll для разведения устройств по времени. */ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, - const uint8_t *data, uint8_t dlc) + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { - uint8_t msg_type; + pcan_boot_byte_t msg_type; if ((boot == NULL) || (dlc > 8U) || ((dlc != 0U) && (data == NULL))) { return false; } @@ -340,6 +419,17 @@ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, if ((msg_type < PCAN_BOOT_MSG_CONTROL) || (msg_type > PCAN_BOOT_MSG_DISCOVERY)) { return false; } + if(msg_type==PCAN_BOOT_MSG_DISCOVERY && pcan_boot_id_route(can_id)==0 && + pcan_boot_id_msg_body(can_id)==0 && dlc==0 && + ((pcan_boot_id_device_type(can_id)==7 && pcan_boot_id_device_id(can_id)==15) || + (pcan_boot_id_device_type(can_id)==boot->config.device_type && + pcan_boot_id_device_id(can_id)==boot->config.device_id))) { + if(!boot->discovery_pending) { + boot->discovery_at=boot->now_ms+2U*(1U+16U*boot->config.device_type+boot->config.device_id); + boot->discovery_pending=true; + } + return true; + } if ((pcan_boot_id_route(can_id) != PCAN_BOOT_ROUTE_FROM_PM) || (pcan_boot_id_device_type(can_id) != boot->config.device_type) || (pcan_boot_id_device_id(can_id) != boot->config.device_id)) { @@ -353,3 +443,18 @@ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, } return false; } + +/* Обслуживание времени не требует входящего кадра. Регулярно вызывать из main + * с монотонным счётчиком миллисекунд: иначе не истечёт сессия и не выйдет discovery. + * При занятом TX discovery остаётся pending до успешного send_identity. + * Вычитание unsigned учитывает переход счётчика через 0xFFFFFFFF. */ +void pcan_boot_poll(pcan_boot_t *boot,uint32_t now_ms) +{ + if(!boot) return; + boot->now_ms=now_ms; + if(boot->config.session_timeout_ms && boot->state!=PCAN_BOOT_STATE_IDLE && + (uint32_t)(now_ms-boot->last_activity_ms)>=boot->config.session_timeout_ms) + pcan_boot_abort(boot); + if(boot->discovery_pending && (uint32_t)(now_ms-boot->discovery_at)<0x80000000UL && send_identity(boot)) + boot->discovery_pending=false; +} diff --git a/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h b/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h new file mode 100644 index 0000000..00842d5 --- /dev/null +++ b/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h @@ -0,0 +1,13 @@ +#ifndef TEST_DSP_H +#define TEST_DSP_H +#include +#define EALLOW +#define EDIS +struct test_reg { uint32_t all; struct { unsigned DLC, RTR; } bit; }; +struct MBOX { struct test_reg MSGID, MSGCTRL, MDL, MDH; }; +static struct { struct MBOX MBOX3, MBOX4, MBOX6; } ECanaMboxes; +static struct { struct test_reg CANME,CANMD,CANRMP,CANRML,CANMIM,CANTA,CANAA,CANTRS,CANTRR; } ECanaRegs; +static struct { struct test_reg LAM3,LAM6; } ECanaLAMRegs; +static struct { unsigned long InterruptCount; } CpuTimer1; +static struct { unsigned WDCR; } SysCtrlRegs; +#endif diff --git a/c/protocan-boot/tests/f28335_stubs/spise2p.h b/c/protocan-boot/tests/f28335_stubs/spise2p.h new file mode 100644 index 0000000..acb88b5 --- /dev/null +++ b/c/protocan-boot/tests/f28335_stubs/spise2p.h @@ -0,0 +1,7 @@ +#include +#ifndef EEPROM_M95M02 +#define EEPROM_M95M02 1 +#endif +#define BALSAM167_EEPROM_FIRMWARE_BYTES 261884UL +void Seeprom_write(unsigned long word, unsigned int *data, unsigned long bytes); +void Seeprom_read(unsigned long word, unsigned int *data, unsigned long bytes); diff --git a/c/protocan-boot/tests/run_tests.py b/c/protocan-boot/tests/run_tests.py new file mode 100644 index 0000000..5180dea --- /dev/null +++ b/c/protocan-boot/tests/run_tests.py @@ -0,0 +1,27 @@ +"""Host regression suite. CC may point to clang/gcc; this does not replace a TI build.""" +import os +from pathlib import Path +import shutil +import subprocess +import tempfile + +root = Path(__file__).resolve().parents[1] +cc = os.environ.get('CC') or shutil.which('clang') or shutil.which('gcc') +if not cc: + raise SystemExit('Set CC to a C99 host compiler') +store = 'ports/tms320f28335/f28335_boot_store.c' +cases = [ + ('core', [], ['src/pcan_boot.c', 'tests/test_pcan_boot.c']), + ('store_native', [], [store, 'tests/test_f28335_boot_store.c']), + ('store_wide', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'tests/test_f28335_boot_store.c']), + ('loader', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), + ('application', ['-DPCAN_BOOT_WIDE_BYTES', '-DF28335_BOOT_LOADER=0'], + [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), +] +with tempfile.TemporaryDirectory(prefix='f28335-ab-') as tmp: + for name, defines, sources in cases: + exe = Path(tmp) / (name + '.exe') + subprocess.run([cc, '-std=c99', '-Wall', '-Wextra', '-Werror', '-Iinclude', + '-Itests/f28335_stubs', *defines, *sources, '-o', str(exe)], cwd=root, check=True) + sample = os.environ.get('F28335_SAMPLE_IMAGE') if name == 'store_wide' else None + subprocess.run([str(exe), *([sample] if sample else [])], check=True, timeout=30) diff --git a/c/protocan-boot/tests/test_f28335_boot_store.c b/c/protocan-boot/tests/test_f28335_boot_store.c new file mode 100644 index 0000000..7c0fe34 --- /dev/null +++ b/c/protocan-boot/tests/test_f28335_boot_store.c @@ -0,0 +1,118 @@ +#define _CRT_SECURE_NO_WARNINGS +#include "../ports/tms320f28335/f28335_boot_store.h" +#include +#include +#include +static unsigned char eeprom[0x40000],backup[0x40000]; +static long budget=-1; +static int read_fail; +static unsigned written_words; +static bool read_mem(void *u,uint32_t addr,pcan_boot_byte_t *p,unsigned int n) +{ unsigned i; (void)u; assert(addr+n<=sizeof(eeprom)); if(read_fail) return false; + for(i=0;i0) --budget; eeprom[addr+i]=(unsigned char)p[i]; } + return true; } +static f28335_boot_io_t io={read_mem,write_mem,0}; +static pcan_boot_byte_t image[40]; +static pcan_boot_manifest_t manifest; +static void make_image(void) +{ + memset(image,0,sizeof(image)); image[0]=0xAA; image[1]=8; + image[20]=0; image[21]=0x80; /* entry=8000, high-word first */ + image[22]=5; image[26]=0; image[27]=0x80; + image[28]=0x34; image[29]=0x12; + memset(&manifest,0,sizeof(manifest)); manifest.product_type=0x2833; + manifest.hardware_revision_min=manifest.hardware_revision_max=1; + manifest.image_size=40; manifest.image_crc32=f28335_boot_crc(0,image,40); + manifest.firmware_version=0x01010002; +} +static void image_to(f28335_boot_store_t *s,unsigned slot) +{ unsigned i; assert(f28335_boot_prepare(s,slot)); + for(i=0;i<40;i+=8) assert(f28335_boot_write(s,slot,i,image+i,8)); } +static bool ram(void *u,uint32_t address,uint16_t word) +{ (void)u; assert(address==0x8000+written_words); if(!written_words) assert(word==0x1234); + ++written_words; return true; } +static void reopen(f28335_boot_store_t *s) { assert(f28335_boot_open(s,&io)); } +int main(int argc,char **argv) +{ + f28335_boot_store_t s; unsigned slot; uint32_t entry; long cut; + memset(eeprom,0xA5,sizeof(eeprom)); make_image(); reopen(&s); + assert(s.active==255 && !s.valid); assert(f28335_boot_select(&s,&slot) && slot==255); + image_to(&s,0); assert(f28335_boot_verify(&s,0,&manifest,&entry) && entry==0x8000); + assert(f28335_boot_commit(&s,0,&manifest)); + assert(!f28335_boot_confirm(&s,0)); /* Cannot confirm an image not yet started. */ + reopen(&s); assert(f28335_boot_select(&s,&slot) && slot==0 && s.attempted); + assert(f28335_boot_load(&s,slot,ram,0,&entry) && written_words==5); + assert(!f28335_boot_confirm(&s,1)); assert(f28335_boot_confirm(&s,0)); + assert(f28335_boot_confirm(&s,0)); /* idempotent */ + assert(!f28335_boot_prepare(&s,0)); + assert(!f28335_boot_write(&s,0,0,image,8)); + assert(!f28335_boot_write(&s,1,F28335_AB_SLOT_BYTES,image,8)); + image_to(&s,1); memcpy(backup,eeprom,sizeof(eeprom)); + /* Every torn write position in journal publication keeps confirmed A. */ + for(cut=0;cut<=68;++cut) { + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut; + (void)f28335_boot_commit(&s,1,&manifest); budget=-1; reopen(&s); + assert(s.active==0); assert(f28335_boot_verify(&s,0,&s.image[0],0)); + assert(s.pending==255 || s.pending==1); + } + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); assert(f28335_boot_commit(&s,1,&manifest)); + memcpy(backup,eeprom,sizeof(eeprom)); + /* Torn trial bookkeeping must never select an unrecorded trial. */ + for(cut=0;cut<=68;++cut) { + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut; + if(f28335_boot_select(&s,&slot)) { assert(slot==1); assert(s.attempted); } + budget=-1; reopen(&s); assert(s.active==0); + } + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); + assert(f28335_boot_select(&s,&slot) && slot==1); + reopen(&s); assert(f28335_boot_select(&s,&slot) && slot==0 && s.pending==255); + image_to(&s,1); assert(f28335_boot_commit(&s,1,&manifest)); + assert(f28335_boot_select(&s,&slot) && slot==1); + memcpy(backup,eeprom,sizeof(eeprom)); + for(cut=0;cut<=68;++cut) { + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut; + (void)f28335_boot_confirm(&s,1); budget=-1; reopen(&s); + assert(s.active==0 || s.active==1); + assert(f28335_boot_select(&s,&slot) && (slot==0 || slot==1)); + } + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); assert(f28335_boot_confirm(&s,1)); + /* CRC correct but malicious SCI8 destination and entry are rejected. */ + image_to(&s,0); image[26]=0; image[27]=0xE0; + manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); + image[27]=0x80; image[21]=0x90; manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); + make_image(); image[22]=1; image[30]=1; image[35]=0x80; + manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); /* overlapping sections */ + make_image(); image_to(&s,0); manifest.image_size=38; + manifest.image_crc32=f28335_boot_crc(0,image,38); + assert(!f28335_boot_verify(&s,0,&manifest,0)); /* missing terminator */ + make_image(); image[22]=4; manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); /* trailing octets */ + make_image(); image_to(&s,0); eeprom[F28335_AB_SLOT_A+29]^=1; + assert(!f28335_boot_verify(&s,0,&manifest,0)); + /* Failed EEPROM reads fail closed, including subsequent writes. */ + read_fail=1; assert(!f28335_boot_open(&s,&io)); + assert(!f28335_boot_prepare(&s,0)); assert(!f28335_boot_write(&s,0,0,image,8)); read_fail=0; + for(entry=0x3FE00;entry<0x40000;++entry) assert(eeprom[entry]==0xA5); + if(argc>1) { + FILE *file=fopen(argv[1],"rb"); uint32_t offset,crc=0; + pcan_boot_byte_t bytes[32]; unsigned n; + assert(file); make_image(); + manifest.image_size=(uint32_t)fread(eeprom+F28335_AB_SLOT_A,1,F28335_AB_SLOT_BYTES,file); + assert(!ferror(file) && fgetc(file)==EOF); fclose(file); reopen(&s); + for(offset=0;offset +#include +#include +void ServiceDog(void); +#include "../ports/tms320f28335/f28335_can_boot.c" +static unsigned char memory[0x40000]; +static unsigned int running=255,resets,reset_arg,dog_feeds; +static int fail_write; +void ServiceDog(void) { ++dog_feeds; } +bool F28335Boot_Read(void *u,uint32_t a,pcan_boot_byte_t *p,unsigned int n) +{ unsigned i; (void)u; assert(a+n<=sizeof(memory)); for(i=0;i>(i*8))&255; } +int main(void) +{ + pcan_boot_byte_t image[40]={0xAA,8},meta[8],compat[8]={0x33,0x28,1,1,2,0,1,1}; + unsigned i,slot; pcan_boot_manifest_t m; + memset(memory,0xA5,sizeof(memory)); image[21]=0x80; image[22]=5; image[27]=0x80; + F28335CanBoot_Init(); assert(boot.config.max_image_size==130560 && boot.config.slot_count==2); + if(!F28335_BOOT_LOADER) { + /* SPI-ROM application without Flash-loader handoff cannot erase anything. */ + command(2,0,0); assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE && !reset_requested); + memset(&m,0,sizeof(m));m.image_size=40;m.image_crc32=f28335_boot_crc(0,image,40); + m.product_type=0x2833;m.hardware_revision_min=m.hardware_revision_max=1; + assert(f28335_boot_prepare(&store,0)); + for(i=0;i<40;i+=8)assert(f28335_boot_write(&store,0,i,image+i,8)); + assert(f28335_boot_commit(&store,0,&m)); assert(f28335_boot_select(&store,&slot)); + running=0; F28335CanBoot_Init(); + assert(!F28335CanBoot_WatchdogAllowed()); + command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE); + F28335CanBoot_Ready(); + for(i=0;i<100;++i) F28335CanBoot_Service(); + assert(!confirmed && store.pending==0); + CpuTimer1.InterruptCount=5000; F28335CanBoot_Service(); + assert(confirmed && store.active==0 && dog_feeds); + command(2,0,0); assert(reset_requested && reset_session==1 && boot.state==PCAN_BOOT_STATE_IDLE); + F28335CanBoot_Service();assert(resets==1 && reset_arg==1); + command(1,0,0);assert(ECanaMboxes.MBOX4.MDH.all==0x12345678UL); + } else { + command(2,0,0); put32(meta,40);put32(meta+4,f28335_boot_crc(0,image,40)); + command(3,meta,8);command(4,compat,8);assert(boot.target_slot==0); + command(5,0,0); + for(i=0;i<5;++i) { tx_busy=0; assert(pcan_boot_process(&boot, + pcan_boot_make_id(1,0,3,7,10,i),image+i*8,8)); } + command(6,0,0);assert(boot.state==PCAN_BOOT_STATE_VERIFIED); + command(7,0,0);assert(store.pending==0 && boot.state==PCAN_BOOT_STATE_COMMITTED); + command(7,0,0);assert(boot.last_status==0); + command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE); + command(9,0,0);assert(reset_requested);tx_busy=0; + F28335CanBoot_Service();assert(resets==1 && reset_arg==0); + command(10,0,0);command(2,0,0);command(3,meta,8);command(4,compat,8); + command(5,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_FLASH_ERROR); /* Pending is protected. */ + } + command(12,0,0); assert((ECanaMboxes.MBOX4.MSGID.all&65535)==12); + command(13,0,0); assert(ECanaMboxes.MBOX4.MDH.all==130560); + meta[0]=0;command(14,meta,1); assert(ECanaMboxes.MBOX4.MDL.all==0x33383246UL); /* F283 */ + meta[0]=3;command(15,meta,1);assert(ECanaMboxes.MBOX4.MDL.all==0x3FEFCUL); + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,6,9,0x102),0,0)); + tx_busy=0; + assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),0,0)); + assert(boot.discovery_pending); pcan_boot_poll(&boot,boot.discovery_at); + assert(!boot.discovery_pending && (ECanaMboxes.MBOX4.MSGID.all&65535)==1); + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x102),0,0)); + head=tail=0; ECanaRegs.CANRMP.all=8; + ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|pcan_boot_make_id(1,0,3,7,9,12); + ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0; + F28335CanBoot_RxISR(); assert(head==1 && tail==0); + tx_busy=0; F28335CanBoot_Service(); assert(tail==1); + ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=1; F28335CanBoot_RxISR(); assert(head==1); + ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=0; + overflow=1;tx_busy=0;F28335CanBoot_Service();assert(boot.state==PCAN_BOOT_STATE_IDLE); + /* An ACK arriving after cancellation must never execute a queued reset. */ + tx_busy=1;tx_canceling=0;reset_requested=1;sent_at=0; + CpuTimer1.InterruptCount=300;ECanaRegs.CANTA.all=0;ECanaRegs.CANAA.all=0; + F28335CanBoot_Service();assert(!reset_requested && tx_canceling); + ECanaRegs.CANTA.all=16; F28335CanBoot_Service();assert(!tx_busy && resets==1); + for(i=0x3FE00;i<0x40000;++i)assert(memory[i]==0xA5); + puts(F28335_BOOT_LOADER?"F28335 loader CAN services: OK":"F28335 application handoff/confirmation: OK"); + return 0; +} diff --git a/c/protocan-boot/tests/test_pcan_boot.c b/c/protocan-boot/tests/test_pcan_boot.c index d871412..259dcb9 100644 --- a/c/protocan-boot/tests/test_pcan_boot.c +++ b/c/protocan-boot/tests/test_pcan_boot.c @@ -264,7 +264,7 @@ static void test_rejects_wrong_session_and_compatibility(void) data[3] = 3U; put_u32(&data[4], 1U); assert(command(&boot, 7U, PCAN_BOOT_CMD_BEGIN_COMPAT, data, 8U)); - assert(fake.last_data[0] == PCAN_BOOT_STATUS_WRONG_HARDWARE); + assert(fake.last_data[0] == PCAN_BOOT_STATUS_WRONG_DEVICE); assert(boot.state == PCAN_BOOT_STATE_FAILED); } @@ -306,8 +306,41 @@ static void test_single_slot_update(void) assert(memcmp(fake.flash[0], image, sizeof(image)) == 0); } +static void test_services_timeout_and_retries(void) +{ + pcan_boot_t boot; fake_t fake; + uint8_t image[8]={0},compat[8]={0}; unsigned count; + setup(&boot,&fake); boot.config.session_timeout_ms=30000; + pcan_boot_poll(&boot,0xFFFFFF00UL); + assert(command(&boot,7,PCAN_BOOT_CMD_ENTER_BOOT,NULL,0)); + assert(command(&boot,8,PCAN_BOOT_CMD_ENTER_BOOT,NULL,0)); + assert(boot.session_id==7 && fake.last_data[0]==PCAN_BOOT_STATUS_BUSY); + assert(command(&boot,7,PCAN_BOOT_CMD_ERASE,image,1)); + assert(fake.last_data[0]==PCAN_BOOT_STATUS_INVALID_SIZE); + pcan_boot_poll(&boot,29743); assert(boot.state!=PCAN_BOOT_STATE_IDLE); + pcan_boot_poll(&boot,29744); assert(boot.state==PCAN_BOOT_STATE_IDLE); + assert(command(&boot,0,PCAN_BOOT_CMD_PING,NULL,0)); + assert(pcan_boot_id_msg_body(fake.last_id)==12); + count=fake.sends; + assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),NULL,0)); + assert(fake.sends==count); pcan_boot_poll(&boot,boot.discovery_at); + assert(fake.sends==count+1 && pcan_boot_id_msg_body(fake.last_id)==1); + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x702),NULL,0)); + begin_update(&boot,image,8); + put_u16(compat,boot.manifest.product_type); + compat[2]=boot.manifest.hardware_revision_min; compat[3]=boot.manifest.hardware_revision_max; + put_u32(compat+4,boot.manifest.firmware_version); + assert(command(&boot,7,4,compat,8)); assert(fake.last_data[0]==0); + assert(command(&boot,7,5,NULL,0)); count=fake.erases; + assert(command(&boot,7,5,NULL,0)); assert(fake.erases==count && fake.last_data[0]==0); + assert(pcan_boot_process(&boot,request_id(PCAN_BOOT_MSG_DATA_B,0),image,8)); + assert(command(&boot,7,6,NULL,0)); assert(command(&boot,7,6,NULL,0)); assert(fake.last_data[0]==0); + assert(command(&boot,7,7,NULL,0)); assert(command(&boot,7,7,NULL,0)); assert(fake.last_data[0]==0); +} + int main(void) { + test_services_timeout_and_retries(); test_id_layout(); test_crc32_reference(); test_complete_update(); diff --git a/doc/setcan/DEVICE_REGISTRY.md b/doc/setcan/DEVICE_REGISTRY.md index f25a2cd..62df0ec 100644 --- a/doc/setcan/DEVICE_REGISTRY.md +++ b/doc/setcan/DEVICE_REGISTRY.md @@ -7,6 +7,7 @@ Device Name — отображаемое имя адреса, а не допол | DeviceType | DeviceID | Device Name | Назначение | |---|---|---|---| | `0x0` | существующие | Верхний уровень | Существующие адреса исходной таблицы | +| `0x3` | `0x7` | **F28335-M95M02** | Загрузка прошивки по ProtoCAN в EEPROM M95M02 платы TMS320F28335; ProductType `0x2833` | | `0x6` | `0xE` | **Altera Logic** | Онлайн-анализатор 16 цифровых каналов | | `0x7` | `0xD` | configurator | Существующий конфигуратор | | `0x7` | `0xF` | KONOR / SETTINGS | Существующий профиль SETCAN и привязка датчиков | diff --git a/doc/setcan/Протокол CAN и ОАП.md b/doc/setcan/Протокол CAN и ОАП.md index da42337..171ec3b 100644 --- a/doc/setcan/Протокол CAN и ОАП.md +++ b/doc/setcan/Протокол CAN и ОАП.md @@ -597,11 +597,11 @@ CRC32 обнаруживает случайное повреждение, но   64 битовых адресса - +     0x3 -0x0 - 0xF устройств +0x0 - 0xF устройств
0x7: F28335-M95M02
ProductType: 0x2833 0x3. Установка времени     diff --git a/doc/setcan/Протокол CAN и ОАП.xlsx b/doc/setcan/Протокол CAN и ОАП.xlsx index 7ddba5f08aabed041d3dd2b145e341a7c40310b6..0ce7a429c13acf0d072a187c2202ab926d75cee2 100644 GIT binary patch literal 87602 zcma&NWmwf+us)1}AgzQT5+WhpogyOADIFpu-Q6v%bazN2-AGG!m(rV*W&<1kzl{>l zIp@8u_X7y5nKiTSi8V88D=h{KhXn%z^APwVhUsOs(!(79r6a)$vh7eCx-Tjqk(mq_;2XN+mgtji|)RPOtT%B zk3ljjB>p&T#rrOep<3>sIwr13!5>4D3Bje0#eRrpi`I5dcJI45wqOJ`Q>7;QBoN%2 zbhdS1bm4RS;XU%iN}+Ylj8jB{kcRm+6D7(S2`=8H39a z;w7SspKud|*9Op4iroLC)0sw_ugr-#w;>zw?#$V26i4(_^5?tBkqtNPKs5jhl=R4;^+O_vvb)>*bcQiY55c`^A9S`!0tROpZ#W&GOh8eE)*3O)DV zNj&^>1~VI7rI4Kz^t`piZJY124rGxkU6h9b})T^jSaJ4G$4B^BjfN zkqNduD88hw<4^p(QO}$s1;L4FZt26$eO6EJov6IVI4 zOH+M%KtAT-&mMVL@bLQqtJUl6H>fmH!w>eg(Nz-c!z4O$<|D={qz&LNH1$erA6tar2E;>;5Q-ONj?g@h03_qmU4o=|l7owWrYZ z4DClp_=4$xw4$dFGr-D_wYDM1!wrTBp#Lwl32T~YY=Emt0MMfUh4wC}1>sGm!>=Cs z?!2pOG2AKG8t{J9mLqB)ME71^)XCqQZ9}Bay57i^owT|f8)wcPvtRlVCyb%J&*3vh z+qf@7VqZBXm`f`f!K<2PPIhr3dxSyQDs3!NXq5NbY+j5|WEDxFRmMdqb;vhoC_EZ| zs#G)WaQ=;VaK$<0kW;|Dgi#`~TUFqL1JcvdX)XjGDc>ob9xa2n9=)i=tywU1;R3WM z&ji}N)5KnP^LVHF2{!%qSy@DhP<@T^ZbiC5LdaCHEQlX2n$e1{ud=Go@(qeNmZ^dO zWv6`}x9n80N9*@&85g1U141s$nNN9srq5(5U+nZg^AW(J72YoMd)*8gvTfcw|E#Nv zBjT?!MnKvufFTz_d~ zwaOprnoSvY@eN!Ylk?o`W>vl08y5(TPw8oq#)hK7^G|H1GCi{IlOKg9>xyLQzb13U zkmGq;8tg2assF;lK-@?M0&?6U`z*8maSA2=F!va~Mz%8G&HLJIesKIkSASsOf>-j{ zP8->7V*qmFk2ar6k8vrt;Oye_4ApJ!3piR2e-OFMQ1A#Vpz^+7ai)4-i}QPN^4^EmiXYbeI7yf+Z=jE z-e4rGg>M?p{YD*6Ozm0 zzT{+0^v{;=o*;ioTg|rF+MkZ^!uy!mHE;4k+s^D{8m6BCPR>#B# zVwgI>qMGWfcM832Gs1Ez8;D*Jr3A^$y^?dy%QV2%-K%9A*qk0cY}lDD_eiSu3!=H2nRWF)G4FrATp|CypZkM z8hRz8>gZo#O%u9_Bg!$RRVEN#A=bqh)z)1;*=kjR=*VYjcXnWhK`4u+6_!HTX{6s3&z+{!MW-Iw8S;zfYu`T_QTIP4!-Gl*U4Nf2#@1K#oHYig)Z~Hny;1Nb9P4ER*yID!j3@nXX^ISJJSx!1xmbi}B+XB~wS%>t@ zIJPp`ABpVGfgV-FJ&Po2xrzr3)#xOHm-DDOPgvO21oUB3Q<@MTGe1yF@m*6*@M}RD z8Ca1T(ueQ2Cf&i8478|Y-rN$lVEDL-!Oca~M8@a!{3V+^mH^j~EgD3S#)>6c54L6L zhiBjx`v45O6Zs?b;nc5RJ&u&iiSBV@#d}o!9MIE2kcUBFAV_1)c9)jD#9b4}M?5ZN z7`)HBVU50o^msfL*$WA+u^O3l5O$Kgsr1eCG_U2CO+Od-R*qhu$YvWkIdiYz{RQK! zv{Y8h(w*cy+mfB+l$yC7B1wso$lp=4d;5O4yc_m&a-ut{Ca$ju2AwC7ng%t&ouTmu zpEJKCdDJ^w^X{DQzF9dS%hb%UO;dlKm#h7vxw-r3yon3HZv5bfbHMJwR+E*T$4&yB zi2WXtZ`~dr*uj>>ch>l$dIQoKgQc5bXqND26YD1b)`MVVec(Q*%| zXJ~+xA*bH5g0^u`BGQ^?irg&DYf+zA8$`TSJPJ+I9XzE4Y?XW=XK%4VLvGd>4~vKF zo$VsZ8_5x@()$IE^;n92^2f9WuqbAI#6FjGqB5`Td~1Frf+_)PF{49s`Z;>*E0uT= zFO@~Byc5HsA7UTYGruoVG^Uu8rfDUES|u~-KWAo)vAvq*D>S0M1yy}#nzY1YClFXq z-R40zFy%X!p9-IPX4<7IAG8&mXwW0EC*4yr91&iz_|1iAR{pudpx{r47{!O)qIZKc zYi{!2BYx)b1P$+edqF;u7u=1{gk2$$K3P62n`i5;GV0BNWr4Q5gPYRF<4yK6<^qpg zAq=97CP&WpeVZU-`I~Kg=TUDyKhtkfiXopg zyf6wxlbJJ4*E$-$Vgd6{bXX2| z!u^Nk(*5tdQYJ7t;RFelMr1QcpIcuNDUrvdH|WV8pkdjqu__geB<*2jK+@6nRdJ(+ zC}=70A$V*Y4yd~**uk`R98)x*`jjj$Qp8jBggq0NH(zIdmH6Oa%7R1H0Y*Z=Ka>m$ zQ9uweV~e9!&)2T#4R0dqq{02!i_s|ioBesFL<<4(ivE$%^EU0C${Z)5C^(rws^H%# z6koO2!=E~m-HTd|bWLz0cP&8sb$EUx#;EQH`qKV$%ylwT?C~d-cFp|d`+Wn&_fx+b zX&XICp(2~`d6CujLfZ6Ri$f0n=C8{89qZqoFH67Sfvm24l1CG6#`S!r?Cu|b=FUas ziAkdrVW^qqs1*KyOxbwsXUT^wMzX$=Fl~A73ENhK{0MiRXTcKKMuFi@C+!8_L#Un$ zqHrGO%_rgs61^%>GtW3F$+?)M_*MP6hc6?H3eR#k^-Mhi>)6qP;M?c!ew6vBx8FyQ z?Q>v1&U)A{NTmN%R7)B>WjdttY)}^WtIP6M*VT3?(R#NmL|XqaPAS5j8U2w(QdhfG zVc-{es`A6o^{?WG23VBE^hh9ccQW31glyQYkY`j~9ouq#lD#YVpE_LDC^z+v_8)V} z1iepB8c{K)Pg{F|CF3-VN0bhBFPd-P&d6qzYHj!fGlT^b#xE^V_&bT?US#?a4Sc=+ zDAm26{6vs)%!1~hl>uSf1H|8lNxF0q%SGx)Sa=N&EnMAv15XktE2oHd+rI=1VgAHp z{v}=l*|j{aF(cwRaX{g45?^KLg_TKs45ywhCJszx(#iPvlq1A-BA*XrqU1SFlks^(ru9 zg4-|6MICx%W%sj%3C+sKpC5aP zIVXpjnwOBRW3$Wi(|NN-H;7a!^G5mxnW_0Hc_L!+S}%Eg^j2gpvEICXxcsZq&L+`E zRnNDo%rDN*9bY9Z3|O(R&25=JcGMz$Q+p_{mgMs(y96F9`&d_UFHc(%lhu2QO4EUP%O5 zr=NUT34?-D`IJBbH7sS|^oAki2^*%(02)eBG>t|nwfWtdAJsmWYIOk--VF`Ih@dn? zO3C1x7nw$W3O{VB^P^x50ZZi23&iuTP2qCxGsDEMk55YTopR*-ri_bBu`tO9J;#f~ zupjP`Pc+%#Np|ckzkJxYMjO%;?)!|GEu#O(y7FLt@82vhT0XFrEp=nJ`!5)Ed5DbvzrbMp zzrlcz&eHj6F>Jkst6Xq?^;Mp~c>g)JD&)-np%*HhTGbU8Dh2faz>w}nf^)#!{Kbvh z=(n}XehmgSV?F?eq11oD5dPm_giL%@Q5cOD4Mq8+C;q(@Z>Wz>0Kf37hL&Fi0g8zy zC+8lx6H(W*_Ptt63|ALk#yPr?vVBUD(a6q7%uJPtJsp3N|Af=g#JFV*cg|#EJpX^e z;PpXlS@{J6V~+C>2KRq?#;s4}*QO|45LHdAgOAlj|jF8iwtN zhq7{%8zrm$Iy&RE=WeryQ@2{mj`aH=i^0gXB{2r^N>Hwey$g1b^~~#q`ip$ z;$--kXlZ=s60(Zkcz#jwvjg4ja{E~7@?!qtXqex1c=Tf5FYD0tZSr#-PYXc+yU<&(_R)QH=doCU0#G<9vS?0 zb3R?ZSk7*|JUDZ60kb!pt*`DhIzYxXT_Gp4jpvYI&81=f&Dx!Gw`IHKy{*eWDQXBf zl>hudWV+w%a}l5G$*$DS1(Wms7DHpuPQ%4MQKR^!o7?H1{`s`ai}ih{-@s0X^L&>? zMf~TW+3wXGO&lvowC2v``N=3ck?Z;P{N+V0@A8X@p#C^uGijoVi{|G=hIOF147=yE(peb{yn)2IIJ1Zp^!# z?KNsb&WGtW^)Ak5-CV(!m*69njjhbNC!=mHyTfMu?1cR6N&JF^~Z`zgoH9u=6|8hX`o|%rnYkLMi=A54KU=U~G?)YM)W*Vg!*YaTuQv&_@ zmOz8EWaCA~F6F^V!oVW%{Rm0*yxSypghhXXxxi)!PXe!0WRJ~&XXFyHn61q33hr-o zIo@qS-{w)Rr`qaK+!J(+mU8-HW}RyFyLJrNAwF(y;kQ(Buvd+H-%#K=T-#7Osr$o4j- z@u|O}o<5D3Q1Z`=#t^$=(W(CS#&*~#aN6PP!q7i@|6@j8Un$4zxkw4)f@S;Kat#e}j_3~+ND&CZ6%75&Qn7Cr{ z!oZ~71y}Bnv_(fU(Yh;tuq?Latf-@L_CNgj7GlDJks+&qA{Ev7^*QWAStew0v@yD$ zNytpCo}1OszvR&Qnl5iLcs?g9{h?zopSa?APKHC8!|hl12R~(xC6Y>eO~DaO+UY*9 zT&3dL(2p&$(O(BckaC|j(hyklM3eUVyXHHk_B8{IVDGiHyXc5~Zb+&sCD$ujq@MfX zzYRI5s$YokaxFao!C-^ba`=2r$v`lylnlt?zInPi-Pj`QL&Wsr2;an4MX{NzsU;A; zNq8uKU{a%%aw&W#n~dh*!S%|AYdrU>DcL#+xsh48pVBjOm@=4^)ER29p<_3GG9HbeVe|hw+4%J#vL<29S^V;+z%w#BhtGFfQL zmWBwGVj2GBG#q~)8`dr(H(z$*KxjcLo) zfop=R^QRvuCm+In&HsP|xY+%kd;33{o6wXc=r+(wB&+kC0`r|}^M^~@7sxl@`tAcb z{lI5Hr@`O+!pgs#lJ1`mR*aIYq0W;u3@eZ4j{T7cbE{1*U3D((H?GxO!tez_is`UC z(Qw0Dz76vP-{J|rSxHl}YPOG=$co$5tqU6P@L7K88v z&Gu)_a*1SSzLUm7{BUt+LPH`;@J=0i}X z;e1iAH5d2q?BdRG8~y!ee1Y1?6x>zwt0c>n&gg#hgP!}CAE1)5Ms%0ij6^F1=B#NO z%A%gA(@*5*B=^Ss(7O>r`CZvT@wjLhsb)o3Bvb^w5EjRIY@}ab;#cV{iaqYng545- zeA+T9GzuJyqr)x8Ngj;*@#$t4ubjf_;kX|LTSAfLm35l*9JIqG$Q|y3_w_tFJ5BX# z2%t!d>-Hu_aVCz9gNx>RQJ#v6e)j^?oeWqGy3cg$^JjG+|TFxU2(Zcr2LjZ5$8?YX2z{) zOTra>*df8e&P2R;p}L)|$mF|B4!s5GoxR*(|8B)Zn{h`Xz)nR24DxJC;*}(F@I5F% ze7kdgAXH+=iS4v`K+lX4IV_u%{DAR;z%^{1A~f$bD2dX^9io>H5AqDYKVR{DzzCuF zd=L5lwSmMx3har3aeJ+MX-ofaf|Aj2#V)QmS4XSv{L*br>`H3IHdBNjC`ym6{q93p zeNvkIoXB`rt?_oH5VMyRjGhM~140ihvQ>#txEVQq`eZiy<@PA+wg$G1YsaKQ z8c*7Lw`3yWI{;a1p;O_;fcg6o9K)gVc;48iq}v#9ISt61g(FZ$PUg0=B4)0-5pQ0+ z$lm|#f(xn9q0&m1*&g*;FX#fj;~rOCWTRu_nHdOPtp+yQw8;mF5E=tnjgA`48w}^` zv)iUIscHzw0KI`146NZW^BnPhvps*AAWy0&0F=!L5prY9V$XnPeFR1=iy&cmIy~XxlCr(xx(I% zC`RCtd2Z_ci6=LCk55-AtkC|V{`-&JbYip3`t|%;G{b7?X*!7E^aDfHn{zSDn*6l! zfqf@9hvz)1Y{%PTnOdQKn)pg3r3w)67kLD3>)yuQkU{bBnLtqfS&asVXW0R_XW1(d z%C+s$Y}ex45(xp+t8r9S`kvF`0AI7~dk@wvuSFG;+BjUiFG$yoEU~8U#-Zp2u8qHm zEi7Ug%w8VSY&N&U$Z>#=@AwFf7ZD-X67Wc+uv{K99NN(|XOKb!y>!G)RwbkC+V|~~ zE$ECkWd+}7<-B%brLZ`jo$57;^OafAy$7Oqq?0+!Sq%>Ev1`^6P$;K9zco_cp_(<+ z5(uIS-%M|mYBJ=-A@J3#SGBY8xsP?7r}9PY%Gav%M~~L03hHZK2S2<9U@W6v$<0hN1ZWXQg%&5>VjhXt)Ao<|`wWylA!v`&ivpff~N(Jib@_C2P*rJ>O zQWQ=TR?5+Jt6}^qt7_|O)l2={pW8{2S(fc6i#jO-7o5B#mBqmZFzSn@{X#Fx?F-81 zDFY)3Yv1*&XCTnO1|tH2V&pi$Jsx>Y*HDNfshkf1zNBYv+>Dh|SH^kKB*SQqL`_vv zc`bun{fyv1Bh~uGLyauE(oVQ$MaJu*GmU1(51R#c3N*8wy_)f_p)l@r2tKcMOy9?o zo9iA@wsTTGeJxRQv|(T-eRyLgTF#=cIQKigiAX+(J?9frU)(->|B@9n)hlECi{d)D zG)K+I#~%j*4mQ>`d0L=J;s_gl?;6;OC5?$XKkFbp!=<*bg%+0*wyBTn54nRIJiKmV zUe(f_XGfX<@ID8Nj4N$ti&YzIwb+Y=f!um;1q!wp+Lu*Gkv7XPD}9J{FyO>h&ulmJ z>)DDmZb^20d)0>+6ATCnlA`?Qi{n{;S% z43}GG&(4{QYav*{UduRYoxw`{sm&pmzK1nbKmE29Eea06{AFNVICS@yQ5l~kx0gg# zx?bw;*m3D0P(z{8ML&ylN}6U_LT})UcHB^u1P{MU-+h-%R!i=~%SZuc-<5>d?c6~c z2J+_k5wgDNk*k6}Lf##r>r0xg+{%e$ZW&W^A8n4174&!XZETCVZqSj+m%QMu3m;Xs z%qy)_N`!chPM#?z66B*@hu#EcUbq|jj*d;#%=#v+f_~!%oBu5ZYkqCXI%)>ANh_(} z_{;jpRZ<_ASKgi-gjIg;X(HK9(GKlfUuFR7y#>iFJq7;r+^1m*0$Lc&GEjRjdg#PE8)x7erEu4Pan- zhNQg2#Zpj7;YvVEz$sZRtKFH|FP|dau4F%`P#|VhV)T4H@c01Et67v?-jCUTKki6v zc{~0jVU*m0-|84jl9_hz-!@}->0C($3FDQkOm>YEeaa?y$E7-EM%Z|AeR!{k*B&~0 z3TPDw=Pt&!3tg1a?f-IdZc0R@hipzxtN64>%)m=O6dnp>dql%`rsb0x6F^tH`;vtPLrn-g|8&)~xri)^NN{DaAvwW4|{~?fD{8o zK1-YpM>xmMOky6-my-Z1XRajfsF(y2a%=53?5~8O=cMMk3A%+<3uM>2+%&eO4S?|?H zp+l@c+n=|SWczV0;FA7ZR=Ko)o~}rmoG?u2Tv3EupDov^?ccek#lT4({_ntJ{DePO zv56^G%MdU$cO9fU5;`!#`&%-sg18X=dPun&&leKv`!apHglhan93|Oa!`i`}U$tzx ze6#;;G6ifBhD}U(W!jIOr$XP+BibZy-Fdp>RPZd}lbU?#YMoL8WB=62Q389!Jz~K| zmSc~F8AO$9r#5UnIZsu!+CKD7?iwsIvqZI9TL1KoVly#?i~{a2wnwhQ=JJbTgV7@f z$Bjkp)FJDjKPO7smhurqQqraj+mQRv=rG)|gA-$Iz;f!U>46x5?Av5{351D^#G?W* zK!{z4M8~ee;fJmro3g8>fduvQJSluhkBpM)AzpoXhpsjpkZ$bJnTe&5c4|qJ&8imm zu=lW^5Rn9~OlMTD2{m0nb=JU{l|p#pU)McWng*V0*p45Vr z-Ec(2kI-%n%{y?2uZiiOS7Lpj^GNS9>2~GF^Cgq6(Dp3nR+H*Z0A+j)FP*cy+SxH2 zt-!ymwv|(|YQLyjG#$%Hj^SxBxo%M#evHG)*6|t zOF3P11(HtBcd?~(xg4nklaOvzwJ|_-$So1eyMj?JHYBO*OZNR+6xCG(lX5qQ;RdOeG&F^+r!cOer^|w)! zr#=;Xu0ENW7=J$N+&14kn-p?cAy3RW$?g8{f-{U(=$LkVZ6z$l7XI=-j8EBXkmT6d zV@tq*@oRlt>uKM=6Hh|94v?wL(cSh+4Pg@2@UH+`U8wCQD(=vG%w%}oUINEuqh2Du zxB8%xvio3TElkf+1UNM3??v0~1mVEo$p<~NPq?S5C#QQlFkkTQ57!E;j!so`8Hc?` z+Rq%`jxN~8-eE2CFi99&AstW4EkD7R9B1QSC z@8PW(GkzquWc-+rxW`0yYdbR33w-hiS*A!|gznusn-u1Nmh2B}Id^=xS2x*6#E;)k z#G^X?{u1`BKBA)MoZ?6{vsfvHM7N?c+maVao2Df0Q^nt!S;g?2Qxd~?mNcd0$t`Kc zck2YwiCU3Yx-V}l<3tt856pzYA zD_2$b<7nHLAq3 z&cwsI)y2lxngcs?MQYqs7bL1nd83cLGkoAqTDeA4;cVAXWS8uXHUCJboKUH3=z^vS zXw-9P9^4{G8&IwhSvZ?J6q$QVUObkjv>^l#Q>f=q{14*r!db(iNW=d@Oa>Y&Af5e2 z`XAx~jjyJ&R71g3{~?}Oe*h3apZ)gymN<_#pkOXb=Kll?w%0UD<&L|70hKYK(955{J<0Psqt(EE8?D{how)N zH=m0~{7OVBwWAiK9EYZTq-h^zOD$_3!5CVc6*fX-<`Hj@LZWOd^isvDKn7S){282x zdtNmMv1-*|7hu@}2_MU6tJ&CxL7OJ1Q*JwbS1D#{e?9yIc$re`TSVpu2hX%(^_coc zdZONxObMoo-x;#VgFxgc*i{iIQqWEJqhI5OKa}J7bpRDO?j2i;D5y&>REr7Sw~pRB z7E>!gA8DptTg$K(L4@ths#%&*d~y>`NUN5i;*p++H>Kq29CVfYp-9y!u<9@Vd;Mxv z_F*Y`GuE_1C7@FQdC!;xE>!|0L1GGpF-|*nGihWICDnW))qIWun0$AoA5k!pzAgSr zD%PNh?x=Ik9h;Eld6}*Ae{_&6R{Gm*d{Dsp&t{#P(Y&i~~7cPdTC_YEX%?|^$7inRm(irVi-=h)Do!m^TNPbL0TinuH z+~bDxAvr%uGGAO(1R&x;r>P~0*l7$iVZqh3i(vBBbsf!ZEpd{leF(&gLnM=$@E04K z5X}Y+=FVGG!NY=?Elz9_A)4z-(3de-sjnYBp+&@fS=!~x6gq?rHa}Nam=0W}H=^`0TB; z>k%TP#DT(aRaOTX&{?{^QS=K(KaSxJ8@Gx?81F}xO2Fk_c@Y{BD1LpBwX@)G^1}iO z?!`F8j{_~*#;VUt$snnY7s5#4_tNBbuIu=&r;AoqJW{MjVzh*meY z|GHARJ2;~Dwrw6m!%JSwXexbglW`AwG~&a}CC6>x95Sq*syQn5xDLu)GqHzkN>A{B zrQSO7ENe@YaC3qY-8O?q>H5G7Sq{Z*$E%Fz-#|d65nn;=P^{g-Gx2rr!*zGi60_3u zM6*8zL6xoEdJ3|!YHcw53-oH@-NzEx2!wy<#U19ESePc-|Bxq96!Nr?M7Ij#rjjVn z8i$LAA2^7MV?!;}sR|)rRuk?r2hRStxzUdMt-?}IKEdLiH9k^iU{2O-+6}ofwPL;6gzw(rjLThnRQmUBDy(WP_|kOJ+Yd^9JKfWh%q_YiBSV7VBvGbtuM7 zK)Drh?FvE4QwCa?)(I?Ya$=yJpH<;z~GG?9kPqvk~8J=_yI8 zl=Mism0AwUT>PVK&sD-a}#T108LYgLKy={)EKFk?0x%2mn=nyoO#^ zyau>ezOpSOOVPrVH|~+5j-% zXo;tD1)4Djtmm`WbF~|VU=@knMukS{i6^%&5$iw0)~!r1YFK61OI)8SrFiUs>uP<< zW!RQX!)g<^h*P$X{Pt`{j#_nklLt%^@$f4{Sxv*>xUa1`2oxIOe_fs-Yd3DWlE2MJ zAzp)kgi$!4mGs7Bc>c;P^(e-8uZFu>Oz_nFTk*Nyehk6#zoQ>U=_kkDVgncn`b68y zQwOrgz)0dTGt{aNKK@Uuepr6z5qXWTmN+bRVAeQoQAtF~JR(t7){R)CJPCRN1g~*= z9?OhB@2(HZp!fT$kHmn*P>LpUg6E4{w|yY=B!iA_PgT(Chu7Mq(Y0|0T6b z{uWPKM&i5wbsIgJHLhmn$xmR6Yw+ql{W2c3fs5DpTNfV0Z2)%d^dccczqads5_|m~ z!t%@$?l_G$X2di^3!x~NY+puH7Me!W=L3%bm)&YG;MQY}t8n%AB_YGR8xqlIm8|tq z`rWf@s1l5Rx4IR8G8z5Q<1~O-&~R319DduLF(-kT_#w+O#U0e*(oa&Z;+4&%0NQH{ zNlTO5H7w|lSJwDYnL)AI6pPa7jb{e<%Q`4(aWB8xpY*vIl<8_l=gSyaNu%~T#H&g5tQxNC4oj4o@&p{gOVrcy zAC$ksZbSHo?r+5Pd(n$ifKd^nuSG+RT0R#4%czl@gY1sNfJs%%Jc}T?8c1<~IzV40 zK@aq0xWg%(C4U(@@S;n|0jIHS?vN<5=>tMl@QYa>fke@QL-?Tgw-?=JUMO5eV+TV( zqynxyUuHn47jK|?cDPMR5`L`~MLrORRRy4OTOJa@rr2Ap06?2!@0#=UpE=2_?wYd) z{6EZj@bZ6|a|$r0#uUrM>7+;SCd^Gsp=9I;GFKfoavFR7W`_p}|0b^@8A;Hi;=2qS z487mh!pqYaSqeqoekdSQUFuN1gSm!wnBPy&KWc#A|X$eliARUho}-0V9vb|8i=~jZPDX z+RV#h82M^=9k0P9iD#W}L0JLK_Ai}h4yOF_L6Ha+HPau3hx2}7aK6kJ8K$m{f=^Tg z04uIGo3aM-Vuhw7dGB12om6%1T~sn#OtMVeDrSP`2jq8TbN?L2w<@}i(&T?{cFp3 zHLDC8Wg|?|FCUf~41Z`WF(^JRWykt>r(6M&k{VYXC^Nn`mZI>^&MftPz<-XJMojki zG`PFn20lIN+`&*UnRtZ2f3{f#?!|%!d@?gP)dn!McT8M7P+l8@O{P%3vo~vfACR3@ zF`d&MDPL#ptLv!)R64K|1AgNHJv>k$J-L^p1I)5nVD0MrcFVSV10ocGh*L=@Rmlwn zWon}G${azZNuCtv92w}%$#=I5LPNEj$M1-Z*d%wkA7$8K-&2B>pzp%cX*b%)VWqcP zDV#Dvqh> zZf3JSWr^{iY)o4cf69+{s7UD=k`WwNdgG31`wi?QQu_=es^&F1-pJJ7nDRHV#qME| zM^)#cRd2kZoLtSeHKn@UdUPSTOby+2oJrfO@dqw^HzuB;8oh{Bsw zXR)ZW@8p8aZ6P!Xg8v_?C~ZuE%pD;!hPl=(^8e+n++5PC+g4FZ&a$5ciPmk8FlyMP z*{fe0lp%AsMmPJ>zD;HH>%}M&e~@Uy_JMVSX+9&E0%_tJTKQmPl1#+fPBLripa|gk z2g7k$&o@WYbLS0W!}VdbL@}MaC9^|bjt{I+ed!z;gh=N@d#k@ML*I7ln=d})o1KE` zHbd#GF7a|p>AD~IW3LBafa@&0_2Pb~XFP^&=TTMZXzBMStw-eN3 zwPF07zsBcj6aM^A!X5|AUs)7O1Lo$*c|H|}*ug%v=BQ=Dc_N`$?WQ}{hF8=BIZB}r zziC{=m18W4cOAkVXm(}gGSdsvoOQ23NGZ1bDC1XZ^j0g+8t7-1!CkEBi&;2r?AIL{ zyiZ4#qB6!nX=KGY;W^OFbniv-7KQvC!1NKkrO6snVft=QBbOp4QA10xt z!xL=5w87tsEH|BF48pUf8K)$<(>f70bGOTQhs0w>EZn#emV(r8f<=ng9bD0#w%4*+ zBH*{8dW*F2h1Qh(Wk+s(TWL%3idf}q^BrQJttV{@^7K!V(WZliQa*kivNbdREaaYY z4|w~FDJh#xQ%P7K{n%JG>px_BHTj8-aLMzBPJU*=|9kQS5_`BPmF${nH*y)fXMCS| z8A9Yz4lbBc+dt|z;W-uFX)A1FG@0wyJeiKjbaQu=X~YzQ07Z?EmiiXEO(P#ROSNZB zbLy`sYWruQ*fd9^AqM`Qh}~G5cH#FPJOD5Pnto5K)L&mHs&J69ip(jL5@xxwGLg`1 z9-JjUO^eY2%uivgXikZRul-;=`gK#ftmM2`+nl$g7#98p(ot=b2U7rm6fn|gDwj4F z#p<#0x8ad1o^Tid1j(s4gtQzy#is9jr*<-i~ z9HoC7;LX-_LF&D!J6q&BmVWz(`Q6%(932NPHQf$26wJ%UM=ysbdT$~j-V7N>jDxSnejxH6!bJNXdu{cys z)B^_rWqw<-i98$c2lN;o?rizqsuM%u7<1ii?;XHG-yua^pv^;05%i^5P^h#0+KIJ9 z!-E40qDd!}mf==e#uMcl;g`MMo7`vcB9VlC;^-e4@{tC*yWDvakY<`5t` zlYcT}m=TXPWUYNYD&{;8M95`WAKJrjZFNq>HHl@Ca66{hs|HgW*rM_@^ z`B`iOPrydD)Qd%p@x8De8{N^*+?rc!yDR>02JO#73kgzOxMnypqEH^_asz|BjR8~5 z*s0;yVeSjiNh?;i^T(^{;X+o0u9P?BQK}g*J+u;vAuT_l)S@W+%kD!d=~N){AYndX z9XiERd64ktDgR3p>>m+2P`#1m@E26V?{hS!j|c;l-~E+6AW)3ty8leFHR+gvp_kXUY)a0+HSLc|y>YZoBc`=m7g@Lj><% z_5Pb+|JI_yD9jwc4O93o9^mlfNEXM-uyw}_R?(fcE;B{a=m`W3PrhuM#ti*??ZF$W}1aR(X$TvKD-ym18w-uepEn|DdSwStw zqEnG^(2Fh(D65dAaC#&*l1L%*ck&!b$;G59d$zKg;KBkpUY^U@@}^`&>0f2LpvqFZ z`kgzMgp#)ojpWX|?$%ePNUQ<9}m6Mo1;17cmcyf6@$!J*s zg-VR2!C#6ey?lV$ZGRYv!?P4nj=RGXDWsqkI?{9|WgN>{n5dk5ONY03oC@o?^*3Wu z)b}kBl>gK=I4Z;IGb8%L1!YCGL-9(aK!LKptaDp*pphKR<&4Hfw+Zm%hBH}4+)}w(#u}?oK*g05m1TdY3$Wb>gPAKa$BK}`pN(am zKZTo55~J@d>ryOq;3_yG&q=LPxl>#%o`RV{&)E5m4;_KhFW5=a$Z;_)8`eTQvWe=^ z&A>6zY21t-v)%%m&wepUjJ?6)jCXNR`p0ciVn4(Abzaxq=}i@&+eN2_O0XAXM+Aet`ok%Z(;-2yfZNK`a{&`=aNnAW0V56is(3t(m#PmOnFZ zh8eXcq?_+t+SO+2ellLJeVx(@w>7X*EwOrsjJGK_ysxLj^`+<4JQcjMYX5Y@lR zf6ceGP~c-D3jx(tA{zSTywN>81WeB$pl=#kLCXKewIa-Vfji6ubC~a`oRC*QN)smp z60G#g%{L>GDeXAq_`3bQWAH|G*X(LoVyOyY{|7F;9=xuYn{$%)#?Ust`du9&ctNo5 zC|P@^#$-kIam+d>h82tP=5*qCjH<5uEmi~_=Tzs8z$Zl@b$e>U`_`?-q>NARi^lxx zRAN}PD$Y;+R=Gl~mOn%~aAC4JuF6o{>2)0n)6ufgO?u79oq2&q0WzX2L9`tLF7e&d zy|IYMzHXo-PJ8!CC0PUTlA_69)Y=^vvRmT2aEE45H?S`nZQiZ$gmdfSP>%W2bYZeo zNB3KdaJMw;8-%n!1h&VavGXd<@FdRQ0b@HE8Efi)W4qL-WuL>r&9SB7#N>20-e?E& zd#s9lvjmk$&yx;sKLzv+4`*%_*X@taF3@*SQy3GDux_uVQ#^!P@^9mN)txPNS{3bg z(AEJT^-+5rEfzgsnq7}V)^s}r%(eKPVa+pIW$8IX6dAj8& z5^WS&$pG#sjFzv3do}sc+EY06Epf|D%xe|Y=C+7TM$Qvl{`H?S?n7%|3sOd9mH>vE z*CnV9AT*ltZNm;}ZNb!=(iNB@)p9j$kHpMlpF0-r{W^8fwaeAkDM|gQbCWNM$J7%) z*ctZh(7Ezv^H#ZPOeU`5{xqiea#N*J0B3wTkr=n<_vy+|{PbIrhuuzW5yv;BHr7~8 z9_FUxd%2FDVd9=a?oip78^>%mv>W|#G$L=SXcK#eBb_*U0CMHZ;v9>~M_*>S?ll!^ z^WcxNyJo%v%`^4i=Gg^{?53WD_Zi*J^+3&~bj#}509==BL~SZ%J^Ij?V&jgQwu-2m z(h{S1W!mngsWAH2NBl6LrB8R&#SiF0yLdZj7cc&# zM(ui7RuTS<5UDs+HB{)SX53-m^L!h>{$OpCD?LP<*|hTfB+sE(XaU2TH@&8M9c?Swgx2r=qMMYrIBI1y z|C-CFtLE|bkwINvz3F>xqZU>$vQ@0BcjjKrfmB+?RLx{db4g3yhs)T#&$uZZeKS=F z%1ShYI`hf2xcXN?M|MkU`;ivksL+SbiJA047Tk3r793~XT<4yAKy+VC#i9l7=2yvy znQ>NFWrFgp(es{1mKIi8j(mZZshJLRoHD)MiFI2;{F1oyxygVV*$|dcP2m$(9I800 zR!3%TBFhf7#bd(g=>u>^;OPc+dXD_1POG|i{G9AKdQ-Ir?SVO?ia2lg4f2X^^M|$@ zjy+j6mx~gs(F@55o=sX=!Fjy4W+Rt^S2&HLtQtYwq%oLz&@L4rj)9 zrNy@>gwi)TA~8TCp`2QC_p&&_b-}xK2cKH~b-^zHh@iwMJxtS=i*!$8X@`nE+QD_w zk=nY-J#7etC1`sv2utSPfS84_K&pAHsn3zuBN*3)Q!`R}=o@!MEi9Sf%rkvx1;O~b zJI0Y5i^v(#$BEB~+9z@U9TpAeWScI*c=*+wmcI8A*C|+c zbMsQK%#oZNJ&N&gI4uL;Gr6%6zr?wfKD34nNk)<55xFA#qm4TZ7IKxAGvrD6+=@?PC$9BciU!%r>S6#eIY&>$WH?+r6W=4asj?9; z?&IyDOKU=>pMh@eiJ%Ugn+02M*#|h$zNPH_44vZvuL7*Bie3|<_!2sWo9Rw*3L*^; zv>R&L62_gVrs6)Zx<3&LsN1+1MWWf5!_wg<9HI0r(R^lPh}39~>djg@s)q2u+=Z|q zGpnO~|8RC{;0KZ`#aYUR>+oG^me|OxiqBA+T4*7Kp{JKl6gtn#b|%M?^_g`O<$7jkiY*9=hNML=ow zC5Pd`7iUep+%eANcyi8&0Zkm+qOZ<%G8MF&X^vCYm)ejM$ZV7$?Q$}=0MjZ;eGXlm z+MrM8TO3P3bUkjrw)w#*Q=%Et%-z!`gH%jZK1+hNw8OT;Y87Qi6?K4?bH$G3`GHCwit{XZ@%~dcAM7aIanK;jx<0h& zO9(891uYx`=FUcQ+TX&ThRPiSe<+~gZ9Y$uRnXplC#W*XGWwcol{-_D)7IITMC)x_ zvJ&B88Xy^CMU8e(n*;^uT~5u2mEFP}K>AA+Q#FEe`GlLPi?e+`*Ji`PjaxZ4m@Kb) zr>W}=3LtYjNzyxcjkOo5Xpn>W;2uX?1ALETpaG`vJ+(v;_m0_+14dG7@M4g{aPt`~ zRAE3zVcQQaoS-=C!Ptrhm<*IK0rxlZ?aqp_MA`T6FfDWpb?Tn~^APLmAVBW>e6J~DY-nY-6^O6wM`S>T4 z#}F#xgdKp1`Rgs=^r2%NH{CH3%B7ipmcKxN;6(eIuOmYxHPCS>YKGUhA`oA2QRlhz z!ck`cVhL%y!g~(YgDw>>;-1zI#v?Iqpt$mdKD3OfujeIL0p>d}KGe`#RBuvZZy_^7 zK*N~7%>!O>HCl-~cw~Z(A)%t28M<{z5zlHPsN`n>4o-eq0llc9UaF#Hgk}pZW;?W$ zoaQ6~wfv7DFhzU_Qg_-ZxrC+QHBRUj$Gg(L?O)(A^XBV<<3}bb30wZsSpqd^CpiV? zh*+!Gsv!E+olKrZU&1@d4>nZiNzUIu`^f7NY}J{B;6-V(hxu}FY$wqP%$VZkzV6UD zwk=Tq82OfRYRm`(6&%v04_!z`*c+8l?8sJi#E@y!hbVBXgy{>;>C=aF#B3^2tH7Jw z$bMZhn@i+nyMJv>neQAOkrT!92eLezhKf{Qk zGD)sKWuFD9Y`9-z&FKuLJaA{oAs-;V-bs3qt{&tllZNAx^*xPX6dmou7QcViZP8{! zh2Q<(ZrJy_&1A5cdNDn2NhN1J{3XwaD!(OD3x^q|j`C_%uvc*SPRRM%)md%UxI*i+w0*`$L_Xi4wJXd@Saap#=LkL$R zeQ_1e?2{ADxz)9{BBY%AZ;v9Lf7Z+rC?JEE6&))3d$pGOkXF_UroHmAyMF6HzGn_w`R1_ESLATyavtBsGn}2dz zg(H=kiDykd&vXYe!B7x}mOtS-`TC59e5zjQc9*8uLlTDv`w59hm19JwzTPa$xlw*b z$>!Ld!%Rx;v%j>KVuIgIJrJ``)zrj7IZhN&t?;+M{ACnV(qc+i8oX)NEaoy;?3EwV zuoMwzy;3;hTVEZfwkARk7pls_{HIqh0^$XgDfhMDt{=r%w^^dS6p?zV`I@_ zn(H@b{Fx4jfUt70zDN>e&$VgmM=SMX!IOzGufG1DDe-?HsxNclgLMxu-qJg>uBlO9 z?sD2vIt?8X6B$$U?)JV3w)qAb;#Ju6A4~dWHC(f-o*JnX&(&>?6=B)wZOIk4YB?*< z1$*kR&R4k*&gbqS_?B4adZyyLNFUEetX>3$>`7(JRzZmzalN{;sk}=ct3P&C8_j&s zX`)wTm~Afmk^DpWQMl?_P3Shk-d^%L=r+Mnm`K~|m8jB-C(O|s3X<3sf6Xi_P?E7nahERa^!IlJ_$QlCol5bu18xVH&1qeO;uyoW9Y6aOy!aTNc!lz& z0sgC#W(?(vabdog$u$0fa#rEg4|ChxnvZ(VUBa=fo^X+{AbF=^v ztbNOc(Jt`gn15YbZSzR@9rS?=3aR6v4i*lMLx`YOCbbSa@IVi&q| zJU#orL0^>VzeaPYH#^8R@1tC7{Rv;YpC>toDIs$`U*VFJDAmziAun4lt}pq(qP+|E z7Y-Fkf7HeLjDIr1)#V5>)&Z2bW2KnG*TqDSE|qlQv6mHAKfZr##QoKTGMA;28kp_~5Rkax6+^|VDAa@N7FwOR`0mv# z@pMXc(^B=d^1M+N^r%43SiU_azkDe$Mjy5P=yf#oZjAaI zO@Gv8q1Rf~IrF5N#5q!i<8)W$}We6ls~e6)}_r&-3Gt(Z7?c4vVXMl$;6*Z zUng1%hM%t?FPHR-V9y?9@g4k2j2Rqu4XE3k4Po09^7oHVSF8WSgh~qdwQqvRoVBAyMn|+ zGdy3MIV=^C);>ZBbH{dT-)!HRwK3HuP3ED$}q^H(PSDs0e+Bd=Z8xOjDV)mHWR=eNNE-Y-cz?dFyqkFw+;LsyaKw@Co&Op;0 zfe~rVHBwJ9o~n2MIqjBj)YjRL`s;PJ^@docLvC;LYnR@zT-NmOY>=#GWZ9|1dnmG> z^BdAtZ0HWQ`cvcQ#(W!oG}JpKBs51*4qckfyw+(jxn_j&)ZVuYt+JNCF9Axl?iuSJ zTku+X+cBl@_V;8y!X@Qpzx4F!t9D65lEFG50$tA!)ayUd+-W2_Vj@`ne>(^YmdX*BW_72TOS|V zlq}y4hN@(Gp<2G-S`~2p?5`vCguR&A+p}(~!j-#Jzzbrdf#;FRa^bglGWaJ^H3u^Y z;)RI4L9yUSMsG2ScwAOF*J@_E!g*j#rVmjqzWjZn4>2sg*@)p`SZ>>uDr-77*v^b* zJ!L_W@~0UMcsRgXxckno4``XPx~nV~iukDT{m4y96`%libef zrpQa&p3amFzm=^^ZAdlR2xTDT1<5xm=7t&k2FIHAy_z05_sKD%rP3|TCOpNcO|7r_ z$5?1f@4kIjaj<-iPXI%VMB>I2xBscE@nFMEgf!+yd!M;|MhnJZ>SoRDokzURu6e!( zdXZc&^c!TDf7)xk2PqP3GAfLv17$*fSM9sNd}bdIp|`~g z#snwt<~idv4#8Q=lxsBzSn2){DbecJ-s^#$3|^zVep`om#|FPl={Ow>d8z_kveUJ? ziLYvri+U^92_h?kc3oMNE*rX~FKm)!{UCF7_(33~t`_gYt1{ui1{z%9i`HrtE z(dR8>87tAQnS@H8V-x&+pEyX`qHXSdmil5}$5+$|SxmR^p6h`%>oY3k^f5(0Zx&;B z9x2hTDTEy)k7zd@5*}C-y<%Rp2@oC70sMnZe(Vjs@E>~Nua<wv1v54eOw?osn= z`68TFiX0JfFE?!G+(Oi~DtMXJB3JK^jH#CE$NiZAl0!g80M;-g9(gYtzMc+lyI~r0 zy*KMUX9k5`29H+!b21%Ws{fezh#FymVqW#}*DLP|;YU z=x8W%C43GdBhZKOw6t=%@rZiVI$f&;ZYzq8wo<>gG|1`q3WIx}uq8IYk^{c?oUVes`fxQcXH3tlQFAuM z;bL@)ro6x3;mg~`>1Uv_wcRGLS;tr@BsCuTa5-7*arwTq>A$wV7$>(Xl#+Kdp6Yh* z6Y#2eod_J2sqT4}C$6bQEoE>3e0X-j?@rMz#`6AYhkN&p-#-g+{jyKM^QRc?dtvzH>zg+%-Y^_yj%u5ZEJh03Bw8R4PKsO zcVTJ_&oSm9pta7TpBpleAL9kTBtZ<3F%@$4Uxcq-4|Jo-)z5T%J;zD#=oBBDf|mm= zayfwHFS&)xfoKOxkumI&%I6(B787xaj#Kp&& z6uNMv584$f8MrZt$c^m61Uh#Mi`)qG%7Qcd-_T7RdW{8b6o3g}wW{Om3bbnmp)w^N z3B)YqcKNL{RJ+-8*Cja!3P_e072iQx4xwEK2Ou#EwUTQM!P8jt=?yzF#?9c|{vr&t z)TPSF1LvIJs(#%e;c-6gDF+y9Ifek~MjnB>8b!q+T=?`Sz^CKq=kbZ7Aducd{o2$Z zC(ngXWyt`a44=;96Gy=}a`Kp>;t97velC1cfa15Nj}t#jK=SWYOgr%pDmnud|Kw6J z3aFT2IIrTSj<0LbuB(cQNz||82Duz=6;sg%G@cI5ORkX1`66t7J?Z207;e?#XYHN|}7qb1{cu!{thFj?)|1T^-XR|2- z#`rF~JMV8`?;l7@U=r~6q+6g2m%np?za`(y*9%1Q|H*3WJ;`a5#Vq4E5)B-Aip!Bm z*pZ&GA!k5y6X^KLi+1HHDhADs)F6lEjttb?mfdYz9nYNGk-=Y7?1$`lBZvMXTvUqe z09E*8u?i=$ir&iwDflB*cVC7YAz;U$1%`u0D8^;Di?KB5y}_%W1DxP+Q@S3Aq{=NQ zSyu5gHJ6r&lx4L>pMge`1KY!uUBd6VA$EZ10By}Y0+Arqpl%Ju>Oq+zPDenrQ(`i0 zHdjBPqdyY%fEGJ+*RSJ^CK|(2!Z;Kn2B2z^H%y6T%41RRvS=4HOo>sc&lb8;iJxD` z5burQtJ{=7lcNdL|0P!DDfq^{)mYeyhSF+4W=wx?4V&UH1sLnESfqSAH>!}4?XLhPGkdw)-PS+fn%h6j_NMaCXH>uFOMJiQ z+Ph5?G-2mP|IPpt(pw$?&iTR;*A-O1WaXQXO1miRsj}GV&edU0D_&RFx{QCdIc8wC zE|!#oZH(wNHhy-so8@p~T1Y;o#`+oHoiT~wDP|tJqav!wL36yr@zIRsADc1Q+4VN5 zbtSuml;!r3o>qDZs%(B!hF-?>;k~|x2O33gFp3?PrEtg(-3H_VE&i)MS1gm(P3Gk( zZWH*@*|3a$c^T;4=hX4`r@r_!E<4*8-f7J9EP#*ga3b5M`>gx^J2mSW70c*o7lD6!1J%aj`Y2tguRd{OG7INotSLAcVXyl z#K_CL(9pZ}i?zocZwG`Zd?NIx(|-C`#`|H9Byu<{&w>Y}^J=w0d#cyj6tR|hk{o7VI4 z_uDbV<`j74DLwogTGOr^?23?1zOSbZ50|fHz>iPp#GZBmo|47TB{5(-5v@v>4KE$q z*A|J68w2mloW4JW7X&YU7PLvJ*&ha*jK>5tU`ECnSx94AjdK*Js(lnAe=zw#r)4w7 z3nxncI2-F-19RO6aUI+T)+2MZK2}qmF%kUqk3ig?@P6cC8V^>U62HgLn#gMeG3AAs zY67Nfdm*N_+W^xm8CIP{*eo7V&z)p zZCcB*NpKRfN#z}E(^}Z3wb05J+x@9QRIqpL{G9jtE*4t&>c4}>LZ#R5^BjG*Jf?eD z{q=N}cZurnmmZv)V`=ZA{UXvp9ESC78=+;ogN1aB0uc+AzK6K?l;j%h7SW_m&yhd#cl z;fyo)wMy`w`6r#O2WnB}1VLNSTx<)snzcY%$i6W@&MZT_E-N~E2e}oDGv5Y;`Ig3+ zXbCXRTn&e_vRjz%dLU16N-I^fI!~~fd07xy?KAfSdVu+;`pQKe#4a;Y}2+}YS=~FQj-*WN!rfwerinOzN-#3Q^b7( zu6oCejaRH)dFlR4W}TTgI@+kqAuiJofp@GCjk*C-4zN>Ws*d!X(_6iN-DAvG*E$ODwsg?=*L>y{X zMcpWIsj;^-mT!5wjHlw+#d4=tt=8b#SzBb9Q-T?4#SOnZmfN<8{8rtkzAe&qd5NLs zl5&nbMm9FEa;vLX%~M9Q?^u3V)q7(3l5!~mI#?`FPP#Q}B3PA_c^~5VZ|Iy_!R4yo z<~h=NZitG6@UPmrWQ5{2h84$%dDVdI5}|5)OHKKWAzVfvT0FvGBb;3Q5S9tTBI%WV zMBzwRe6gY2f)Q)H9i7j2nZib7RIZw*jASD$KeT>5f&UHmaAw@ZFk7SVHw%15rN7g8 z_DpCMqSY{vzvb%5 z<#KwQTvHG$H~;owE!#AD(5BOX0UE!*hinFoG#5 zSUEHZf6`+3u?*6D_`{uO%+nIirdklkU+D;@!@0byeW$BI=+P#D6xX-9>U?YvF02A5LQaB6mW9Ai|C*`yNa0yinZ>Tubq*sqC(+?+JP8xC<(ch zC`(AhLha;slDTRJFoG#*MByS(JLeZ`hj_~wuAMPW_MrQJX$Hvl1#|nBpGU!pE%2ij zBW`kub?5k4!ohj~?^v!;a{)&_E~lKX?O_v$wvelUrWgHCI3bKOZEe-$&du45Sl<=QVt{Dp~>ioVmQe#D{&wpT@yQ z)lajLMq#r64A|>J1Xnas`I5y%LV{MTw=K3E=bLfiY07?SB^JVBjXmW%iC?Y5w|sEh zHu06o1R)(I`EB9=(ymwFrtYGBgzm5@sfUrMHpLWTBZLXq=BI*DO~;Lu9nN}mJw;m@ zD?6QCsC6d-0P!dN5Qx`q^6JkslbJ{&jGk7?krZc0aRS|X?WGkZm^BIE20|%m6Qc3B zOex#!W)GtAybK5V5OsxQJTBb@Mygg(+$Vp*(oa;6M9DV)xYCzzhQ$3q2cjYv<{M_8 zN?pdK^5^;?vdnQ3TRv&=u-Lp4JzG8*^9X;7nlqme_iO90uKOH$yRXD&>WVpyV${-= z6_)A8>iW5VEOCvRNn&~K35}dJYNp$P!Tk*rHfD*lc5i{pi_EZlpuT|H65OCla`Im> z!CdvNYEwemij|w?+owsp$4_Obwz-hAQ?O$Gtl1yQX`a!F7GJloQ9GF!uy=xa{#%uH zV%pvXP{kLx@Edk%#7%5;Y2B@>x-lVO#f0IVS>m#p;uRAncNVfcViL7{sP;ox+*jPK z15BZGH6i@KsB=SbmYM;c55{}vBQg$Msj)d{{sc6w6ZZoikB7L&XL>ELkU+%gRL%ars-Haj@;wo{lzUyj-x_pm&%~4Lwvpx%r0#ShtkSMC@u%Kv> z7Pu!SS`=Jc9D7g@?iFoL?iJo*4yE7EfzH#qk}T*~sFgrt`V|KA7sRd*n5T(&?Y+Sv z(5GC*lqcMbR(w^$8Gqtmsf0_}O-@ISxC5p4ByFm34j3bk);dd?TdRbN%o`?qlZkJ2 zsu|vrj;}u@V?q)P$9I{N)N}IPGiB$Mw)jRzX0@7-Aoqmhwd`qz7Hq6Ntw-89t!4$( z1_}6~+%>ZR-w=BCw25VUmqwmfA#i`EV&kJsX>=qm6=MA)4_4Wp#tg>?XJyAq^UoV* zhG%y=0Wrq*j*r#GFJx_!b}rA&##-9bOe_}S6-f;?%gV@(RlksNVDjT7oLPGI3^6~* zH5_ATzZ@R85Oso+Kbrv`hQvA`P%u54M|!w8H~W&Mz4#Iz7qwJ~&s}NV1&yn)_ToL# z!wDR_fX3M2MzaVXnSG`_k!EQN!g~HLjL2}1(Jl9T3Z^^24~V)`qfD0>-fV8cXDU4J z=n-UaVg3Z=6exFmRE=^1q!bq;k?eSXNnZ;KmWsP?&F}eU#uj`g5zU*uAy_aWx!PD% z71t=I=P$d@uh{UGCiXa}TtMN~A8O?9O$x#(P6>*rx5Ib7D{p%p#Qv`Q!N2Wz_o{^g zXiow^n!f&g4G#$7y|(4u7)?*`lgyaM{JD4E@&kZ#1HX0f{h$m?_SUe5=fyu#jW=T1 z#E2dj=VEcy=Y;Tgi1jNa3-;GQsW(BglT9O#R+64@-skUQ)D(U*D0_s z58-?TPl|X*x+pj4y%zx4V`$#VLfh8@TTyvV38YN92#_>|m5AMl0DSvs;$t(117H$E z<5+Aa@JJ_u;Z_Vp7C7ZYY0+AEq4wnPOJTO!)5bM&r=Y3Wv?w18c3FiNK%TY=*MhX5 z*vW0c!CIY?DcB5+#Aei*2mpd)J5XDuNZDXK0u_iqS0Lz|*QEuZ(+(Qe5f~X{PzX>O zs$*0hfHS-t>0qOBcBPMyeZh&q-@&Br+={z)>;x&Z+Z2@6k=J8Dq5I~LLf=`CLfzV2 z3f(t{6#8BR6cV$B6nZ<%G(079PlQXME!L1i?_?l_JRybnb0LM+S#v974=IGph7<~K z%{Lo9oRhzMu}C?dG`84a8u6k1Q1B7Np7iWNVt%S?_>uDqMZqyFswOHu|L})6uk6+} z;YXLOVTCiTq^eu1vZ*UsViirKt{_61& zjt3AQOi3rW{GEc61#TL<;{ZB?roEh@MJ?7|4rD+gR|YhhMW~OQ_0lYeszHEXdrr^p zBj!iAhU1~0AQIz*^F>-*=_)MolAsr?JYg!Hd-$ObEL)_Ur}ooq8J)E0cLsw z$=?y%UJL)0+o%3I!nGT3=m{iuL}|QX)g?jG&o%qV!pfV!M`ZeeA85;4g}CM?jHDy4 ziMHAC<2Nr1e2X*)@ZX~TcW5s78RJ^tLU8yh+=?vRtbGB_n@V8^NMMOe9>y{d*J8J- zw0~~X%*?m8j)AV=xB*sQG?hjcj?SqCr8p-RU2q|>-E40mgV;`Ttt>Rk1GZ+*oy+yL zxW*DJf_<`)a>UTFbp<@yZlv6@xi(yEhsm3=bbyhZ z;*6LpY>O1oY||rDnL;7PG7o2RZDDi(j8qpGDckw0BDXh?*s92?zRzd9xER$PT4GfF zYSY-YvW8a}%Q)QAtN(LG1oXT{|ICO0Yc!k+nHD#g9dcEs_w%jztCV6@%HD=$(8CDO z0{<=|E$mmlA}-!5ACX8!4^(`!-M{&n3J!#*e5?1p+P&58~}?PK+^@&YM*4uo?bMc zZPsQMG3%-i4d5mbcWZ7KTF{C49mO>_mMn9@z-&weOc3~aS$%Ywf8axuKgQ`wg3`6e z?Mv7-H+rONm#inY;=@x$PyMs3cdLf4cF99cOi}QV zv_@Nc9$TYur~8jOY`4NY-O*I&QCZe%h0|Rtn?pRIQS@FUK}bPK{`FRW5eP0XG5VQt zFkH$E10Ye70%@g)LVP?Pc+BB|N0%MiGVqwwfraI#rW6d0b=7b-2)li<6GVKZ7Cn<} zvx`Hloge=T^NFYf*h7%|xYSD3f@cB3;9u0;sW7Q2OF2xp)I2ctvbrB1Ft5#m+uazG=eQk4s9u@pPj6^>T}y&Mh* z$@PySKL$G=FpygS1EfV);WMHr9K&Wi3B*UOz$v!ycn{*Eao|EpnURXRQ(QPPycZep zeQcfetorNe;_qWiwF%Vm98}VW)#>ir{#x~3WVw)nhWu+);7RzYZtFFBEckyy^Xhnd z{iYz)-8cHKHke<*U~!rU>X=2$t7B{-AziCwKgF&Y11YuC!+|>C3+k9e1k{WfTFesj zCqdD1(YU+F=ypAxuW)f`=YSeA7%C*qEmRgOJlmEDDqID6KvCdyMD?GRu_Ck9AI3r7 zvoNi2=%JYbFiOmy1c(AgCjG^dl4-{}fBU-|ND&k{BXdR(8imPAH=Rv294zSV%XWF zBrv%RxI$YctTRxG8IF0J1(t5k#!q66Ug^38rm|60eXoS6@G9T~iw|4C(}Vv~b$Ftj z7f7j5o?V-j-KF)=><{=6dKMiCt(0I*+J?aA*IYniXc%~z}0oy+ywqPZ^<9i{l&>JA`#=MuwvCE9 zb|NCT(rngrmXTL6WTQRH^RwEmmOSlyWkavWHC%8%WAtvWD#^Nt-5&j+vh!pf=ZTrk z?^f&xsa_d7JE3~^-tP{TQRT-6j&;@7-CDl8`t6`Pf10bs(euKb$DAUXBJcZtn_BTq z_TISqZ|bXw2d}kurga~d7ua)Fi_>6m@(;o8>cr5l8&n=O$-;j>^F91x)+BLNnycK= z^ZXn>PMGtSK_RVC!XF31#ilZq#+V&NVpHBDlqa|UcpO7NbYn|o=mvYvJ1VU9td_?| zAobC+D?sX+>044ZDlWZ-kYF?Ro5FDUD+6DPXLA=7n~agqSZ3c&E|KK|GJAcK=YTAd#q50MLFg^_@Ul&MN!^S9XJWCmM3_vo4bWQ$@J@v3s8m*gs+ zvZB#grh7VNkcdum#i*R8&b#kTHZiRb$#~N8u%5l`=gyxsFHOBA6UK{|#qQJOyz;_d zX;Uj&p6QaJ-{v*!t@371h57v_14Vr#tmPSGb$&Bn3a zrF?_2gwO`VKb@juP)tyfOi|7UvVu(M-_*ia7by-QM3sz|iH+o7?Te(YQP&G&AD){d;5J~{2 z;io!;Gl*g;9H)g6>cx)T9KPL!8!tx3W*}jY%<|ik`rX7bSi&^!fYo_fqUueeIdcZ$ zm0~=F+@j=|HvGEoNyl5rX*e=FD5eV2dro}*&FK;6@e-O2Hribp$~iQ;7u%pQKpcoa z)H`rHKEAei+H$W3ERim={v-Leuz+TtL~ zbg6}ypC%TFXDBEd^u4|zr7>}eIH5LY$%^xp4~ehE`pEZ;xg}0>l05gp=THTd&yY$Z z9LzQ`uYvJ~RXZ>x!7cWd$?_XBV28}D+OIN}^27w|ee1_4U7ps^e-W{=*3IZ`4+I$T7jhmbAC$6UOn+UjUh4cM|!rrL<*HjPO3wB?7s z0q|d2IqCEJD=8cDbc@JKkUmLoa+SvF17i744&9Kb!5_J6 zk$5J)Bq*yc+-U_Lp!f=O~(Ug)THoI)xK;Z)9%GUp0sF6#79?KikIMckxDz1vG5ziroO zV^4R0XrAJVW*3MivmK76i_(}XlXi-DJQ>XlEqxN$@?^&**x2%AS56c0p_wkP4Q_Vw zRm>M28N5#IKZRc?Je4sVP7gbbEv-j(RWF|h4Ub;M94RF(&0K(H(W9_tb&+aC#DG|2 z*SmUwF*ia(1Ip3|{WPAF+nWvmesu;eV;i7;HT>lD_{9O<&{FE@Aw_v3rKQpopCX;g zR0>_gh4OVMOB9+b&AQ0siBv_UTkWeCx|CFrt9Z%z(+e;gblX{_DLP1YAU0a8Wa`QQ z2}E%i`0Th3nmJYSq_*M77$-BzcR+ra8r1W73*&#Nhx$mzHlrf84)uff(5cWxh?VLh z>o9g3b#rCd;D^@KBr>PITcgBFoSmDa$+81Dm)>O%q$oO3v8PL2#Rs|If=&*aNR_Jf zqCi@u0gVP(67I^?1|IS8XiFdE8Uwg|*^j250e0hVN>iXEZv06*MOT(|SAJmPA(?@; zOjhRdRf)3{=2u_oDdi}N0~EVn!D`DbF3+x$d?n?9LeWzdxpWsF{D4VL3W8rRvNmD; zTt2$Z6xNYD@Qx+X1+sI}b!ApI-@zCH+9p6-@r@Y-1tX;#9q~>3I3=h35zuOvM(^;4 z8@tQs?b*QuBo$j!>Pj6-=V|~sG!pfuObqk*e4x}dsm04M8xt1s-vf1rzFSjVZEoc} z#KuRUEfLCGO^Ki==Mfgs_nP*kBfHM3YuuoXIo*6bw3NMr(etRqIFu7}^Y__xSY$F` zpV3i(V)J=VPejgOi&#J>?xsYfnavCvb5$f?x}-=#+=`9hb0>rcR4iGK;Ol z=-JU~oV=jlwI-}sM!-W8NWWa>Wc}$E5=Nx1v~0=9{5T`wg{lmrgH|q~$5oWe7(FXm zjPER@_HHT|GkmqqwRuH*tEjDC1NnoXl2~6AFu%0&PjjMr;fld=lFw zbzVq&Xf&`TSjNae8_sKYo6yUOgG9NecN_P`fDr@gN`Q(wG)ia<9yT*r8Zgc?&th(4mcP;xZ#WZ12beJQ zxh4#(b8A!(G}M-O&6Y6L<~rDMzVwiIHr9s@I#SwVN3w_>%_-ZlTcaDAFFLDL;(h7s zGT7K;de06_nhs~$Qn&-Ci2qTmPM}pu^SHsC`Hm%C5NTk5*r@JT1`@x)4Pv4RTNm)dQNwN~Xx48ksN0zj?QN zY5GVor@S85Hr$sj*i^H2Cxx@?EMiMbiTlA^3D>4rv7G(os;dS{CaoY){!M5#V_)ig)#u_2&p~N+tYK!by4H{w* zsiT)HYS*PfR1ugAAMqVXk~&VG+Bwm^d|#7!qTQ6D#@y7^cdT)&th4BvjgGPfUHSC3 zT&>HsTN2wc`ciXq!({Guxv;E+bZcWQV<>lK2I2)|+L?JHm45fNxA4=-kCr->3x+BL zU6GArxi*d}%@7At?G1A(Q9owK8}9EKWnY*?Xin^S;y-D_Pb~#bXgfg=F__V0on%Ry z$aa~HXv|%^@PQa?FQ-)vQ6WjIrZEq$Ss)9QG2YDq0U0_r{*U@7CXis~R%TwdeY$CK z-Y1{h(m)_r&iSQvT0}IFcq?bEPx+vS+66hc8?Nf_>4*2b?|E#MupC&#{`yTSHGX*A z)YtZQe`5`K79%yDue@_&&)KhoTI&sX!aU#ZyQ4HtJUj#F>JH`f`+~h6h~W% zetV%N4;)A;M5E$xLH3gtfCIV?)w*n@)1H#p_?d z&1+6*jwd@=UBm1DEH)e67JTq05XX4)Pg-5_U>S=M0-snN1-S>Jk8MELCRhdvolzAy z_jPsHW(Q3u^1|+E8u&A>|E82gd*LB2r3PT7`daGrB)PytsYe+aHy7H-m4JgWx zuA(t!Xfice=!PFuG?JMZi3_+xW-^OD9VkRF1Uv_o@f{Nkm0bJpY`yaF zUbZ9kn+dRUnU&{xG(ZVf=H>CH`B+W>GA1B9qw1^k)ysB$!?X7=*&P0*%1nu#9rl3U zTkb&qtIrs?-!q{6ui`7wgz{ggRaq#TB$~Aec74$`U?38gg(KZ|Dj6JRUaI}VjP@A- zzOeI{T}P;W({8nxVIY>eVuUPCENxs^Uf+lHd=qzCtMB}AaQ{P*b9S&p<`C_%vrW5y zIQ^RW_O=xH#mpx(+mH*X*C_How~0WpgcCo~ueH>cE0m5|m{+Z(-|t$^$fKZ0+9*r* z%5Nmp2DDr8exU!s6-gU%JN4Sg+YCvO8K34+YzV<{y@KSQo}$m*^Y1Ut1gLf^7$x4nMe4{0SQnX>}?+ZrK7I=>L`pYC5PKl z6v$B##!5=q1cT(<6Uf@(04FOxv*AarYv5Ey7OKqPailskXLXQTG^HDD^?W7HAcEm` z9y99*!ytkOI2b_>Oo~4DO?NxSp@mRpK1QA%97<$|Kzq7;fjj)L12a23iHkLGe! z7uktXh)}v6l2!ZQG?egNAmPy)36y|#DoFVIT(0UOw==k1Mcw~tES;;&1Kd8) z(U(N@XNteIMH7dyA;WtgQUi9n^MtiuT+ah{*|xXz39IP$1U44#EPjH13N#BkN2 z2Z}=fd$OA;y+nv}Im-%(BP`}sDJa97@#8s3?HEbBHi5@h0bBv}K#kD31BiM0p02f? z;CE(Zu~CE0lcV>Qy8A#3%WoczJ{6*EDau?)MJPmhPznVldsoc2CX*}>KS3^R&%u$X zi^yO#aM!YJYFpd+ky4?&VZIMJRqY&)Dg;pn*^2HSVub5MRoY;n83%&~F>U9h9t!CaWqx3x>30>OyxR*I+{ixj#)-j| z=u8w|q7b2`QH}4aW`OF$0<{eChBe;jNNy%b%ws6=C@XxNd(?taw9R-uTjF{h?6w`|Cq|O?%);RExs$Lk;Jl7GZmoQmA%~a*G?-eQfc!vdtD-IJ*!bgv7;3 z_L5zCSs-#m5V^E=28f){W2<1U$T3kP65NqvJbgc_wVn+k$2~I;^}fFQHFE4Xg;Xw$ z%3&|brJ>O*O$f*eBbY+1rJym3a|O>Ei3?cFCpz#H6KJMVNuS;B&ICAhi3_KgyWOdh zi{WE-0=iv4X170N`ki@wi7U^+f-C%M_^5n^w4kNxo57;wD1|^V7ZwykPHSd@*33O+ zbs=gC5w#fu{V=L~s8>?~EYLR+*Z`^kst0lTtINv!S5PosKMFuW^4WV8Zct#-@GpPu z&FU{v9$cwD>h1g)D9R00k{56)T-C=+!e7h6$CQ>00#yIiTfu&L-nJZXQAJMszN+WO zs$0zscfmBnx9i7`?GJg)i-~FY=TS)T*{xZ4gBs*tM8FC>_ftFgBJ^Do7 zb14Jy5#+Ln6~`ZdTQt&u0whPqOxM(?N#c|NVkofAK*98Z&I zDX$8cRpXr;^_y87Q33gEtA{Q;qIS)xd}3c?CY)7QHyJzd@=u}c%M0Vyk-0{*e4?Ln z_fk_V@m~9p%HzfvM~besO`nb?u%rh~VoPU6m#I@Y&HA^`mu#ygHs>!4^^4lI(Db_0 zDQb{fu?_A*LtQ;ua}qpk=9}3CxUd?RM9mEmQZ~$QYMoaJe5PYR68{YL3%_l9Z2LavKCT;pWET9n0-s^(%mlR*&8^Z-8P1GCiWoe`GXo zmXX^VHCOqU&Gy-(Evj37luyLZ^|f{iOmBZC?|GQ+lQ`F$&h|$;e>@&jXju0ou(|8f zXN~yhECcm-w1j;bs-AOcKj&sN<|y9Z%csYE(*~Ihj9HgCcKOWI+$^npPGfd-Zov1U z#zmjm>9)CUo5+i^@v{Vm@3hU_z}zG|zy~pr^i!kn@!WL4xP~NtE-%S=FTZ@GPb4?mpH=yIOCojY}!P?9vDWl7fi9`Wkh6ZdiRc-4W) zQ|uGu#LLKZa#c96E!$n%;ssbgY1ad7v!^xS@dR{P? z7tB<&Wg5Ze?>_FJB>A-oor#Z0X+=xW`j0gdL*3Kcg)=8zH?h5Cvtp$q9Apb@2wo1+ zLavTVqR9FtCnX{Cu^0!BWbyn$|4ghUX;z}vDJ^@~7XG>uL}#UjtK-|{X{pW(*>W;X zVe3b?7t}EK-$)S03Kqoik8lo0TbN^I=2b6erSdVEhKG}}1zORChWKD-;ByOFOX^AR zV1Qh=q2u-gUBW|SwOS-$Dn-Rhzd$ls+z#*m0=s2%)`kz#@HCFIDmVOTEa>W3gqMaH zPVQ*Hle=EFs-G{@mmI=uxsba-?fx#%>;q?qD_r9}#rRCDjdM4V1B_+(X2io`SYMEinTgisxHJu!5gT*3j9|bUM)`^h(>axsnGr&35_^ zPHaDy=66x~;xo{!q?#m?R}UtADyshcC^;aDmB((w#F+I4w8ZeH_TS4`4H}+~Z^-WC z;1gXtL}bR8@pHq@W7^5;2w$rJM>QXZDo0xt{q`VGI}axK98a+JPS9NO5`$8&S)pGz zoVLX9lD^zK^4k)pnQ3;HoXnVbAg=n|qhw;V`ULgx%hBBdFT(8DafGv4@35l0{Wk zFL6Q7GDmv~uXXZd<&NJ-ef(VG@<-MEm#%!=yrgRs{&SF*&;!Ls5mQ-d}}L|g)#uIKWa z�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 diff --git a/python/protocan/can_boot.py b/python/protocan/can_boot.py index 8b80446..46e5a4b 100644 --- a/python/protocan/can_boot.py +++ b/python/protocan/can_boot.py @@ -37,6 +37,8 @@ class CanBootTransfer: def __init__(self, image, target: CanBootTarget): if not 0 < len(image.data) <= 512 * 1024: raise ValueError("ProtoCAN Boot: размер образа 1…512 КиБ") + if target.product_type == 0x2833 and len(image.data) > 0x1FE00: + raise ValueError("F28335 M95M02 A/B: образ не должен превышать 130560 байт") if not 0 <= image.version <= 0xFFFFFFFF: raise ValueError("Версия образа вне диапазона u32") self.image, self.target = image, target @@ -46,6 +48,10 @@ class CanBootTransfer: self.finished = False self._window_end = 0 + @property + def response_timeout_ms(self): + return 15000 if self.stage in ("enter", "verify", "commit") else 1500 + @property def percent(self): return min(100, self.next_block * 8 * 100 // len(self.image.data)) @@ -128,4 +134,93 @@ class CanBootTransfer: self.stage = "reboot" return self._control(9), "Перезапуск прибора" self.stage, self.finished = "finished", True + if self.target.product_type == 0x2833: + return [], "Образ принят; после перезапуска приложение подтвердит пробный запуск" return [], "Прошивка ProtoCAN Boot завершена" + + +class CanBootServices: + """Read-only passport queries and explicit session service commands. + + Replies use message D, body=(page<<8)|command. IDENTIFY/discovery reply body=1. + All multibyte values are little endian; version is major:8/minor:8/patch:16. + """ + def __init__(self, target: CanBootTarget): + self.target = target + + def request(self, command: int, page: int = 0): + if command not in (1, 8, 11, 12, 13, 14, 15): + raise ValueError("Unsupported service command") + if not 0 <= page <= 255 or (page and command not in (14, 15)): + raise ValueError("Invalid service page") + t = self.target + payload = bytes([page]) if command in (14, 15) else b"" + return build_frame(ProtoCanId.build(1, 0, t.device_type, t.device, 9, + t.session_id << 8 | command), payload, to_can=True) + + @staticmethod + def discover(): + return build_frame(ProtoCanId.build(1, 0, 7, 15, 13, 0), b"", to_can=True) + + def decode(self, frame, *, discovery=False): + p = ProtoCanId.parse(frame.can_id) + if (frame.to_can or not frame.ide or frame.rtr or frame.is_error or p.pm != 1 + or p.msg_type not in (12, 13) or len(frame.data) != 8): + return None + if discovery: + if p.msg_type != 13 or p.body != 1: + return None + elif (p.device_type, p.device) != (self.target.device_type, self.target.device): + return None + if p.msg_type == 12: + if p.body >> 8 != self.target.session_id: + return None + status, slot, next_block, crc32 = struct.unpack("> 8 + d = frame.data + result = {"kind": "passport", "device_type": p.device_type, "device": p.device, "command": command, "page": page} + if command == 1 and page == 0: + product, hardware, protocol, version = struct.unpack("> 24, (version >> 16) & 255, version & 65535)) + elif command == 12 and page == 0: + result.update(protocol_version=d[0], state=d[1], active_slot=d[2], target_slot=d[3], + session_id=d[4], slot_count=d[5], last_status=d[6]) + elif command == 13 and page == 0: + flags, capacity = struct.unpack(" Date: Sun, 11 Oct 2026 21:23:21 +0300 Subject: [PATCH 03/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA?= =?UTF-8?q?=D1=83=20GAS=20167=20=D0=B8=20=D0=A3=D0=9C=D0=9F,=20=D1=83?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D1=88=D0=B8=D1=82=D1=8C=20=D0=BE=D0=B1=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BF=D0=BE=20CAN=20=D0=B8=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=D0=B4=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=BE=D0=BC=D1=83=20=D0=BF=D0=BE=D1=80=D1=82=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../protocan/GAS_ADDRESS_ALLOCATION_167.md | 97 ++ doc/setcan/protocan/GAS_MODBUS_MAP_167.md | 288 +++++ doc/setcan/protocan/PROTOCOL.md | 75 ++ python/protocan/balsam.py | 2 +- python/protocan/gas_167.py | 51 + python/protocan/gas_167_registers.json | 1030 +++++++++++++++++ python/protocan/protocan.py | 42 +- python/pyproject.toml | 2 +- python/pysetterminal/rawprotocol.py | 19 +- python/pysetterminal/serialbus.py | 60 +- python/set_devices/balsam_can.py | 4 +- python/set_devices/bus_demo.py | 52 +- python/set_devices/can485_board.py | 11 +- python/set_devices/can_bridge.py | 22 +- python/set_devices/can_monitor.py | 23 +- python/set_devices/qt_ports/can_monitor.py | 6 + python/set_devices/ump_can.py | 50 + 17 files changed, 1797 insertions(+), 37 deletions(-) create mode 100644 doc/setcan/protocan/GAS_ADDRESS_ALLOCATION_167.md create mode 100644 doc/setcan/protocan/GAS_MODBUS_MAP_167.md create mode 100644 python/protocan/gas_167.py create mode 100644 python/protocan/gas_167_registers.json create mode 100644 python/set_devices/ump_can.py diff --git a/doc/setcan/protocan/GAS_ADDRESS_ALLOCATION_167.md b/doc/setcan/protocan/GAS_ADDRESS_ALLOCATION_167.md new file mode 100644 index 0000000..9d38746 --- /dev/null +++ b/doc/setcan/protocan/GAS_ADDRESS_ALLOCATION_167.md @@ -0,0 +1,97 @@ +# Сквозная нумерация GAS: распределение адресов + +Дата: **9 октября 2026 года**. + +УКСС выделен диапазон **0…11999**: общий блок 0 и блоки узлов 1…11, по **1000 ID** каждый. Соответствие технологических слов Modbus текущему профилю 167/v1 и новым ID УМП приведено в [GAS_MODBUS_MAP.md](GAS_MODBUS_MAP_167.md). Новая нумерация назначена в документации; в прошивке пока действует профиль 167/v1. + +## Диапазоны проектов + +В новой схеме числа без префикса `0x` — **десятичные**. Каждому номеру узла соответствует блок 1000 адресов с базой `номер × 1000`. + +| Проект / семейство | Первый ID | Последний ID включительно | Число адресов | Статус | +|---|---:|---:|---:|---| +| УКСС | 0 | 11999 | 12000 | Выделено: 12 блоков по 1000 ID | +| Остальные проекты | 12000 | 65535 | 53536 | Свободно для последующего распределения | + +Границы УКСС в hex: `0x0000…0x2EDF`; свободная область начинается с `0x2EE0`. + +Резерв диапазона не означает, что каждый адрес уже реализован. Адреса обозначают логические 16-битные слова; память для незадействованных ID не выделяется. Параметр шириной 32 бита занимает два последовательных слова. Служебные слова также должны входить в выделенный диапазон проекта. + +## Узлы УКСС + +Номера узлов: **1…11**; **5 и 6 — УМП**. Назначения 1…9 подтверждены в `package.h` (проект tms_periph/periph_167); служебные адреса 10/11 определены в `cntrl_adr.c` (проект tms_periph/periph_167). + +| Номер | Назначение в текущем коде | Обозначение | +|---:|---|---| +| 1 | Трансформаторный узел 1 | `adr_TRN1` | +| 2 | Трансформаторный узел 2 | `adr_TRN2` | +| 3 | Силовой узел 1 | `adr_POW1` | +| 4 | Силовой узел 2 | `adr_POW2` | +| 5 | УМП 1, LOAD | `adr_LOA1` | +| 6 | УМП 2, LOAD | `adr_LOA2` | +| 7 | Узел ENG1 | `adr_ENG1` | +| 8 | Пульт | `adr_PULT` | +| 9 | Шкаф | `adr_SHKF` | +| 10 | Универсальный адрес / адрес общей посылки | `CNTRL_ADDR_UNIVERSAL`, `ADDR_FOR_ALL` | +| 11 | Адрес терминала | `ADDR_TERMINAL` | + +Номер узла, тип платы `Desk` и ID параметра GAS — отдельные величины. Например, УМП 1 имеет `Mode = 5`, а тип обеих плат УМП равен `dsk_LOAD = 6`. Блок номера 10 зарезервирован для роли общего адреса; существующий номер 10 не идентифицирует отдельную физическую плату. + +## Назначенные блоки УКСС + +Границы включительные. Все блоки содержат по 1000 слов, пересечений нет. + +| Область | Первый ID, dec | Последний ID, dec | База, hex | +|---|---:|---:|---| +| Блок 0: общий резерв УКСС | 0 | 999 | `0x0000` | +| Трансформаторный узел 1, номер 1 | 1000 | 1999 | `0x03E8` | +| Трансформаторный узел 2, номер 2 | 2000 | 2999 | `0x07D0` | +| Силовой узел 1, номер 3 | 3000 | 3999 | `0x0BB8` | +| Силовой узел 2, номер 4 | 4000 | 4999 | `0x0FA0` | +| УМП 1, номер 5 | 5000 | 5999 | `0x1388` | +| УМП 2, номер 6 | 6000 | 6999 | `0x1770` | +| Узел ENG1, номер 7 | 7000 | 7999 | `0x1B58` | +| Пульт, номер 8 | 8000 | 8999 | `0x1F40` | +| Шкаф, номер 9 | 9000 | 9999 | `0x2328` | +| Резерв роли общего адреса, номер 10 | 10000 | 10999 | `0x2710` | +| Терминал, номер 11 | 11000 | 11999 | `0x2AF8` | + +Правило адресации: + +```text +GAS_ID = номер_узла × 1000 + смещение +номер_узла = 0…11 +смещение = 0…999 +``` + +## Технологические слова УМП + +Для штатного технологического Modbus-адреса `n = 0…127` в новой карте назначено смещение `n`: + +```text +УМП 1, номер 5: GAS_ID = 5000 + n → 5000…5127 +УМП 2, номер 6: GAS_ID = 6000 + n → 6000…6127 +``` + +| Параметр | Штатный Modbus, hex | УМП 1: новый GAS, dec | УМП 2: новый GAS, dec | +|---|---|---:|---:| +| Первое технологическое слово | `0x0000` | 5000 | 6000 | +| `DAC_go` | `0x0050` | 5080 | 6080 | +| `DAC_stop` | `0x0051` | 5081 | 6081 | +| `LOAD_CAN_TIMEOUT` | `0x0052` | 5082 | 6082 | +| `LOAD_STATUS` | `0x007C` | 5124 | 6124 | +| `LOAD_ATTEMPTS` | `0x007D` | 5125 | 6125 | +| `LastMode` | `0x007E` | 5126 | 6126 | +| `Commands` | `0x007F` | 5127 | 6127 | + +Смещения **128…999** в каждом блоке остаются резервом для расширений. Служебные параметры и новые данные в этих смещениях пока не назначены. Полная таблица всех 128 технологических слов: [GAS_MODBUS_MAP.md](GAS_MODBUS_MAP_167.md). + +## Связь с текущей прошивкой + +В существующей реализации база технологических GAS-регистров равна **`0x5000` = 20480**, а дескриптор находится на **`0x5F00` = 24320**. Это локальное окно профиля 167/v1, выбранное независимо от новой схемы сквозной нумерации. + +Текущее `0x5000` не означает `5 × 1000`: последнее вычисление даёт **5000 десятичных = `0x1388`**. Для адресации УМП 1 и УМП 2 по номеру узла потребуются разные базы, определяемые по `Mode`. + +Штатные адреса Modbus, служебные окна регистратора, паспорта, защиты и EEPROM уже имеют собственные значения. При переносе сквозной карты нужно определить соответствие GAS ↔ адрес протокола: глобальный ID может отличаться от прежнего Modbus-адреса. Это позволяет отдельно согласовать новую нумерацию и совместимость существующих клиентов. + +Диапазон УКСС и размеры блоков назначены. Перенос этих ID в обработчики прошивки и размещение служебных параметров в резерве — отдельные изменения реализации. diff --git a/doc/setcan/protocan/GAS_MODBUS_MAP_167.md b/doc/setcan/protocan/GAS_MODBUS_MAP_167.md new file mode 100644 index 0000000..13bba27 --- /dev/null +++ b/doc/setcan/protocan/GAS_MODBUS_MAP_167.md @@ -0,0 +1,288 @@ + +# GAS ↔ Modbus: карта регистров Бальзам 167 + +## Использование в SETGUI + +В `Терминал → TMS28335 → periph_28335 → rs232_periph_28335 → Работа с GAS` +доступны словарь 128 технологических слов, поиск, чтение диапазона и запись FC06. +Порт и адрес контроллера используются из общих настроек RS232/485. +Кнопка «Проверить профиль» читает восемь слов с `0x5F00`; запись разрешается +только после подтверждения GAS 167/v1, M95M02 и возможностей RTU/FC06. +Проверка сбрасывается при смене соединения/адреса, ошибке и отмене обмена. +Все 128 слов читаются двумя запросами: смещение 0, количество 124, затем +кнопкой «Прочитать 0x507C…0x507F». Таблица показывает raw и HEX без +неподтверждённых преобразований единиц. + +Машинный словарь: `python/protocan/gas_167_registers.json` проекта templates. +В общей вкладке Modbus имена и пары новых ID УМП 1/2 подставляются для FC03 +по штатным адресам и действующему окну GAS; сохранённые пользовательские +имена имеют приоритет. Обмен этой вкладки GAS реализован через RS232/485. + +Ниже сохранена карта из проекта `tms_periph/periph_167`, коммит `378e06a`. +Ссылки на исходники относятся к дереву того проекта. + +Профиль: **GAS 167/v1**. Соответствие проверено по исходникам проекта на **9 октября 2026 года**. + +УКСС выделен сквозной диапазон **0…11999** с блоком **1000 ID** на номер узла: [GAS_ADDRESS_ALLOCATION.md](GAS_ADDRESS_ALLOCATION_167.md). В полной таблице приведены текущие адреса прошивки 167/v1 и новые назначенные ID УМП 1/2. Новая нумерация пока не перенесена в прошивку. + +GAS предоставляет доступ к тем же значениям `modbus[]`, что и штатные адреса Modbus. В Modbus RTU можно обращаться как по прежнему адресу `0x0000…0x007F`, так и по GAS-адресу `0x5000…0x507F`. Это два адреса одного слова RAM; отдельной копии параметров нет. + +**GAS доступен только при `EEPROM_M95M02=1`.** В текущем `eeprom_config.h` (проект tms_periph/periph_167) по умолчанию задано `0` — сборка для AT25256B, в которой GAS-окна отсутствуют. Фактическая сборка может переопределять этот параметр. + +## Правило соответствия + +```text +Для штатного адреса n = 0…127: + GAS-адрес = 0x5000 + n + Штатный Modbus = GAS-адрес - 0x5000 + Источник значения = modbus[n] + +Пример: modbus[0x52] → штатный адрес 0x0052 (82) + → GAS-адрес 0x5052 (20562) + +Новая сквозная карта (десятичные ID): + УМП 1, номер 5: GAS_ID = 5000 + n + УМП 2, номер 6: GAS_ID = 6000 + n + modbus[0x52] → УМП 1: 5082; УМП 2: 6082 +``` + +Столбцы Modbus и GAS 167/v1 содержат **нулевые адреса из поля запроса**, без прибавления единицы и без префикса `4xxxx`. Столбцы «Новый ID УМП 1/2» содержат назначенные ID новой сквозной карты; текущая прошивка ещё не обслуживает их как новые GAS-адреса. Каждый адрес обозначает одно **16-битное слово raw**. Знаковость, единицы и масштаб зависят от параметра и типа платы `Desk`; GAS передаёт исходное слово. + +| Область | Штатный Modbus | GAS / адрес обращения через Modbus RTU | Слова | Доступ | +|---|---|---|---:|---| +| Технологические регистры | `0x0000…0x007F` | `0x5000…0x507F` | 128 | RW с исключениями LOAD | +| Информация GAS-профиля | Нет штатного аналога | `0x5F00…0x5F07` | 8 | RO | + +`RW` в документе означает, что обработчик разрешает FC06. Измерения и статусы могут затем обновляться прошивкой; разрешение записи само по себе не делает такой регистр уставкой. `RO` означает, что обработчик отклоняет запись. + +## Полное соответствие 128 технологических регистров + +Имена взяты из `package.h` (проект tms_periph/periph_167), `measure.c` (проект tms_periph/periph_167), `ADC.c` (проект tms_periph/periph_167) и `DAC.c` (проект tms_periph/periph_167). Индексы `sens_*` начинаются с нуля. Конкретное назначение каналов зависит от платы; таблица не назначает всем платам одинаковые физические каналы. + +Перекрывающиеся имена относятся к одному слову и используются в разных режимах. Например, `0x0052` входит в общий диапазон `sens_lo_edge[]`, а на LOAD служит `LOAD_CAN_TIMEOUT`. + +| Modbus, hex | Modbus, dec | GAS 167/v1, hex | GAS 167/v1, dec | Новый ID УМП 1, dec | Новый ID УМП 2, dec | Имя / источник | Доступ | +|---|---:|---|---:|---:|---:|---|---| +| `0x0000` | 0 | `0x5000` | 20480 | 5000 | 6000 | `sens_error[0]`; `InputRep0/1/2` — биты A/B/C | RW | +| `0x0001` | 1 | `0x5001` | 20481 | 5001 | 6001 | `sens_error[1]` | RW | +| `0x0002` | 2 | `0x5002` | 20482 | 5002 | 6002 | `sens_error[2]` | RW | +| `0x0003` | 3 | `0x5003` | 20483 | 5003 | 6003 | `sens_error[3]` | RW | +| `0x0004` | 4 | `0x5004` | 20484 | 5004 | 6004 | `sens_error[4]` | RW | +| `0x0005` | 5 | `0x5005` | 20485 | 5005 | 6005 | `sens_error[5]` | RW | +| `0x0006` | 6 | `0x5006` | 20486 | 5006 | 6006 | `sens_error[6]` | RW | +| `0x0007` | 7 | `0x5007` | 20487 | 5007 | 6007 | `sens_error[7]` | RW | +| `0x0008` | 8 | `0x5008` | 20488 | 5008 | 6008 | `sens_error[8]` | RW | +| `0x0009` | 9 | `0x5009` | 20489 | 5009 | 6009 | `sens_error[9]` | RW | +| `0x000A` | 10 | `0x500A` | 20490 | 5010 | 6010 | `sens_error[10]` | RW | +| `0x000B` | 11 | `0x500B` | 20491 | 5011 | 6011 | `sens_error[11]` | RW | +| `0x000C` | 12 | `0x500C` | 20492 | 5012 | 6012 | `sens_error[12]` | RW | +| `0x000D` | 13 | `0x500D` | 20493 | 5013 | 6013 | `sens_error[13]` | RW | +| `0x000E` | 14 | `0x500E` | 20494 | 5014 | 6014 | `sens_error[14]` | RW | +| `0x000F` | 15 | `0x500F` | 20495 | 5015 | 6015 | `sens_error[15]` | RW | +| `0x0010` | 16 | `0x5010` | 20496 | 5016 | 6016 | `sens_error[16]`; `Inputs` | RW | +| `0x0011` | 17 | `0x5011` | 20497 | 5017 | 6017 | `sens_error[17]` | RW | +| `0x0012` | 18 | `0x5012` | 20498 | 5018 | 6018 | `sens_error[18]` | RW | +| `0x0013` | 19 | `0x5013` | 20499 | 5019 | 6019 | `sens_error[19]` | RW | +| `0x0014` | 20 | `0x5014` | 20500 | 5020 | 6020 | `sens_error[20]` | RW | +| `0x0015` | 21 | `0x5015` | 20501 | 5021 | 6021 | `sens_error[21]` | RW | +| `0x0016` | 22 | `0x5016` | 20502 | 5022 | 6022 | `sens_error[22]`; `Buttons` | RW | +| `0x0017` | 23 | `0x5017` | 20503 | 5023 | 6023 | `sens_error[23]`; `Jumpers` | RW | +| `0x0018` | 24 | `0x5018` | 20504 | 5024 | 6024 | `sens_data[0]` | RW | +| `0x0019` | 25 | `0x5019` | 20505 | 5025 | 6025 | `sens_data[1]` | RW | +| `0x001A` | 26 | `0x501A` | 20506 | 5026 | 6026 | `sens_data[2]` | RW | +| `0x001B` | 27 | `0x501B` | 20507 | 5027 | 6027 | `sens_data[3]` | RW | +| `0x001C` | 28 | `0x501C` | 20508 | 5028 | 6028 | `sens_data[4]`; LOAD: расчётный выход 4–20 мА, raw ×10 | RW | +| `0x001D` | 29 | `0x501D` | 20509 | 5029 | 6029 | `sens_data[5]`; LOAD: измеренный вход 4–20 мА, raw ×10 | RW | +| `0x001E` | 30 | `0x501E` | 20510 | 5030 | 6030 | `sens_data[6]` | RW | +| `0x001F` | 31 | `0x501F` | 20511 | 5031 | 6031 | `sens_data[7]` | RW | +| `0x0020` | 32 | `0x5020` | 20512 | 5032 | 6032 | `sens_data[8]` | RW | +| `0x0021` | 33 | `0x5021` | 20513 | 5033 | 6033 | `sens_data[9]` | RW | +| `0x0022` | 34 | `0x5022` | 20514 | 5034 | 6034 | `sens_data[10]` | RW | +| `0x0023` | 35 | `0x5023` | 20515 | 5035 | 6035 | `sens_data[11]` | RW | +| `0x0024` | 36 | `0x5024` | 20516 | 5036 | 6036 | `sens_data[12]` | RW | +| `0x0025` | 37 | `0x5025` | 20517 | 5037 | 6037 | `sens_data[13]` | RW | +| `0x0026` | 38 | `0x5026` | 20518 | 5038 | 6038 | `sens_data[14]` | RW | +| `0x0027` | 39 | `0x5027` | 20519 | 5039 | 6039 | `sens_data[15]` | RW | +| `0x0028` | 40 | `0x5028` | 20520 | 5040 | 6040 | `sens_data[16]` | RW | +| `0x0029` | 41 | `0x5029` | 20521 | 5041 | 6041 | `sens_data[17]` | RW | +| `0x002A` | 42 | `0x502A` | 20522 | 5042 | 6042 | `sens_data[18]` | RW | +| `0x002B` | 43 | `0x502B` | 20523 | 5043 | 6043 | `sens_data[19]` | RW | +| `0x002C` | 44 | `0x502C` | 20524 | 5044 | 6044 | `sens_data[20]` | RW | +| `0x002D` | 45 | `0x502D` | 20525 | 5045 | 6045 | `sens_data[21]` | RW | +| `0x002E` | 46 | `0x502E` | 20526 | 5046 | 6046 | `sens_data[22]` | RW | +| `0x002F` | 47 | `0x502F` | 20527 | 5047 | 6047 | `sens_data[23]` | RW | +| `0x0030` | 48 | `0x5030` | 20528 | 5048 | 6048 | `sens_hi_edge[0]` | RW | +| `0x0031` | 49 | `0x5031` | 20529 | 5049 | 6049 | `sens_hi_edge[1]` | RW | +| `0x0032` | 50 | `0x5032` | 20530 | 5050 | 6050 | `sens_hi_edge[2]` | RW | +| `0x0033` | 51 | `0x5033` | 20531 | 5051 | 6051 | `sens_hi_edge[3]` | RW | +| `0x0034` | 52 | `0x5034` | 20532 | 5052 | 6052 | `sens_hi_edge[4]` | RW | +| `0x0035` | 53 | `0x5035` | 20533 | 5053 | 6053 | `sens_hi_edge[5]` | RW | +| `0x0036` | 54 | `0x5036` | 20534 | 5054 | 6054 | `sens_hi_edge[6]` | RW | +| `0x0037` | 55 | `0x5037` | 20535 | 5055 | 6055 | `sens_hi_edge[7]` | RW | +| `0x0038` | 56 | `0x5038` | 20536 | 5056 | 6056 | `sens_hi_edge[8]` | RW | +| `0x0039` | 57 | `0x5039` | 20537 | 5057 | 6057 | `sens_hi_edge[9]` | RW | +| `0x003A` | 58 | `0x503A` | 20538 | 5058 | 6058 | `sens_hi_edge[10]` | RW | +| `0x003B` | 59 | `0x503B` | 20539 | 5059 | 6059 | `sens_hi_edge[11]` | RW | +| `0x003C` | 60 | `0x503C` | 20540 | 5060 | 6060 | `sens_hi_edge[12]` | RW | +| `0x003D` | 61 | `0x503D` | 20541 | 5061 | 6061 | `sens_hi_edge[13]` | RW | +| `0x003E` | 62 | `0x503E` | 20542 | 5062 | 6062 | `sens_hi_edge[14]` | RW | +| `0x003F` | 63 | `0x503F` | 20543 | 5063 | 6063 | `sens_hi_edge[15]` | RW | +| `0x0040` | 64 | `0x5040` | 20544 | 5064 | 6064 | `sens_hi_edge[16]` | RW | +| `0x0041` | 65 | `0x5041` | 20545 | 5065 | 6065 | `sens_hi_edge[17]` | RW | +| `0x0042` | 66 | `0x5042` | 20546 | 5066 | 6066 | `sens_hi_edge[18]` | RW | +| `0x0043` | 67 | `0x5043` | 20547 | 5067 | 6067 | `sens_hi_edge[19]` | RW | +| `0x0044` | 68 | `0x5044` | 20548 | 5068 | 6068 | `sens_hi_edge[20]` | RW | +| `0x0045` | 69 | `0x5045` | 20549 | 5069 | 6069 | `sens_hi_edge[21]` | RW | +| `0x0046` | 70 | `0x5046` | 20550 | 5070 | 6070 | `sens_hi_edge[22]` | RW | +| `0x0047` | 71 | `0x5047` | 20551 | 5071 | 6071 | `sens_hi_edge[23]` | RW | +| `0x0048` | 72 | `0x5048` | 20552 | 5072 | 6072 | `sens_lo_edge[0]` | RW | +| `0x0049` | 73 | `0x5049` | 20553 | 5073 | 6073 | `sens_lo_edge[1]` | RW | +| `0x004A` | 74 | `0x504A` | 20554 | 5074 | 6074 | `sens_lo_edge[2]` | RW | +| `0x004B` | 75 | `0x504B` | 20555 | 5075 | 6075 | `sens_lo_edge[3]` | RW | +| `0x004C` | 76 | `0x504C` | 20556 | 5076 | 6076 | `sens_lo_edge[4]` | RW | +| `0x004D` | 77 | `0x504D` | 20557 | 5077 | 6077 | `sens_lo_edge[5]` | RW | +| `0x004E` | 78 | `0x504E` | 20558 | 5078 | 6078 | `sens_lo_edge[6]` | RW | +| `0x004F` | 79 | `0x504F` | 20559 | 5079 | 6079 | `sens_lo_edge[7]` | RW | +| `0x0050` | 80 | `0x5050` | 20560 | 5080 | 6080 | `sens_lo_edge[8]`; LOAD: `DAC_go` — параметр начала рампы | RW | +| `0x0051` | 81 | `0x5051` | 20561 | 5081 | 6081 | `sens_lo_edge[9]`; LOAD: `DAC_stop` — параметр конца рампы | RW | +| `0x0052` | 82 | `0x5052` | 20562 | 5082 | 6082 | `sens_lo_edge[10]`; LOAD: `LOAD_CAN_TIMEOUT`, мс | RW; LOAD: 1…60000 | +| `0x0053` | 83 | `0x5053` | 20563 | 5083 | 6083 | `sens_lo_edge[11]` | RW | +| `0x0054` | 84 | `0x5054` | 20564 | 5084 | 6084 | `sens_lo_edge[12]` | RW | +| `0x0055` | 85 | `0x5055` | 20565 | 5085 | 6085 | `sens_lo_edge[13]` | RW | +| `0x0056` | 86 | `0x5056` | 20566 | 5086 | 6086 | `sens_lo_edge[14]` | RW | +| `0x0057` | 87 | `0x5057` | 20567 | 5087 | 6087 | `sens_lo_edge[15]` | RW | +| `0x0058` | 88 | `0x5058` | 20568 | 5088 | 6088 | `sens_lo_edge[16]` | RW | +| `0x0059` | 89 | `0x5059` | 20569 | 5089 | 6089 | `sens_lo_edge[17]` | RW | +| `0x005A` | 90 | `0x505A` | 20570 | 5090 | 6090 | `sens_lo_edge[18]` | RW | +| `0x005B` | 91 | `0x505B` | 20571 | 5091 | 6091 | `sens_lo_edge[19]` | RW | +| `0x005C` | 92 | `0x505C` | 20572 | 5092 | 6092 | `sens_lo_edge[20]` | RW | +| `0x005D` | 93 | `0x505D` | 20573 | 5093 | 6093 | `sens_lo_edge[21]` | RW | +| `0x005E` | 94 | `0x505E` | 20574 | 5094 | 6094 | `sens_lo_edge[22]` | RW | +| `0x005F` | 95 | `0x505F` | 20575 | 5095 | 6095 | `sens_lo_edge[23]` | RW | +| `0x0060` | 96 | `0x5060` | 20576 | 5096 | 6096 | `Cancount[m_FAST]` — пауза быстрых посылок CAN | RW | +| `0x0061` | 97 | `0x5061` | 20577 | 5097 | 6097 | `Cancount[m_SLOW]` — пауза медленных посылок CAN | RW | +| `0x0062` | 98 | `0x5062` | 20578 | 5098 | 6098 | `Brightness` / `Bright[0]` — яркость | RW | +| `0x0063` | 99 | `0x5063` | 20579 | 5099 | 6099 | `Owncount` / `Bright[1]`; LOAD: исходное значение АЦП | RW | +| `0x0064` | 100 | `0x5064` | 20580 | 5100 | 6100 | `Bright[2]`; `Current_count`: исходное значение канала 0 | RW | +| `0x0065` | 101 | `0x5065` | 20581 | 5101 | 6101 | `Bright[3]`; `Current_count`: исходное значение канала 1 | RW | +| `0x0066` | 102 | `0x5066` | 20582 | 5102 | 6102 | `Bright[4]`; `Current_count`: исходное значение канала 2 | RW | +| `0x0067` | 103 | `0x5067` | 20583 | 5103 | 6103 | `Bright[5]`; `Current_count`: исходное значение канала 3 | RW | +| `0x0068` | 104 | `0x5068` | 20584 | 5104 | 6104 | `lev_count[]`, запись из `Current_count`; назначение по режиму | RW | +| `0x0069` | 105 | `0x5069` | 20585 | 5105 | 6105 | `lev_count[]`, запись из `Current_count`; назначение по режиму | RW | +| `0x006A` | 106 | `0x506A` | 20586 | 5106 | 6106 | `lev_count[]`, запись из `Current_count`; назначение по режиму | RW | +| `0x006B` | 107 | `0x506B` | 20587 | 5107 | 6107 | `lev_count[]`, запись из `Current_count`; назначение по режиму | RW | +| `0x006C` | 108 | `0x506C` | 20588 | 5108 | 6108 | `lev_count[]`, запись из `Current_count`; назначение по режиму | RW | +| `0x006D` | 109 | `0x506D` | 20589 | 5109 | 6109 | `lev_count[]`, запись из `Current_count`; назначение по режиму | RW | +| `0x006E` | 110 | `0x506E` | 20590 | 5110 | 6110 | `DAC_20` — калибровка входа 20 мА | RW | +| `0x006F` | 111 | `0x506F` | 20591 | 5111 | 6111 | `DAC_04` — калибровка входа 4 мА | RW | +| `0x0070` | 112 | `0x5070` | 20592 | 5112 | 6112 | `Zero_lev[0]` — нулевой уровень канала тока 0 | RW | +| `0x0071` | 113 | `0x5071` | 20593 | 5113 | 6113 | `Zero_lev[1]` — нулевой уровень канала тока 1 | RW | +| `0x0072` | 114 | `0x5072` | 20594 | 5114 | 6114 | `Zero_lev[2]` — нулевой уровень канала тока 2 | RW | +| `0x0073` | 115 | `0x5073` | 20595 | 5115 | 6115 | `Zero_lev[3]` — нулевой уровень канала тока 3 | RW | +| `0x0074` | 116 | `0x5074` | 20596 | 5116 | 6116 | `Caliber[0]`: `K380_1` / `KPOW_1` | RW | +| `0x0075` | 117 | `0x5075` | 20597 | 5117 | 6117 | `Caliber[1]`: `K380_2` / `KPOW_2` | RW | +| `0x0076` | 118 | `0x5076` | 20598 | 5118 | 6118 | `Caliber[2]`: `KPOW_3` | RW | +| `0x0077` | 119 | `0x5077` | 20599 | 5119 | 6119 | `Caliber[3]`: `KPOW_4` | RW | +| `0x0078` | 120 | `0x5078` | 20600 | 5120 | 6120 | `Caliber[4]` / `TCaliber[0]`; LOAD: `DAC_max()` | RW | +| `0x0079` | 121 | `0x5079` | 20601 | 5121 | 6121 | `Caliber[5]` / `TCaliber[1]`; LOAD: `DAC_min()` | RW | +| `0x007A` | 122 | `0x507A` | 20602 | 5122 | 6122 | `Caliber[6]` / `TCaliber[2]`; LOAD: `DAC_cal()` | RW | +| `0x007B` | 123 | `0x507B` | 20603 | 5123 | 6123 | `Caliber[7]` / `TCaliber[3]`; LOAD: текущий 12-битный код ЦАП | RW | +| `0x007C` | 124 | `0x507C` | 20604 | 5124 | 6124 | `NormaU` = `Caliber[8]`; LOAD: `LOAD_STATUS` | RO для LOAD; иначе RW | +| `0x007D` | 125 | `0x507D` | 20605 | 5125 | 6125 | `DeltaU` = `Caliber[9]`; LOAD: `LOAD_ATTEMPTS` | RO для LOAD; иначе RW | +| `0x007E` | 126 | `0x507E` | 20606 | 5126 | 6126 | `LastMode` | RW | +| `0x007F` | 127 | `0x507F` | 20607 | 5127 | 6127 | `Commands` — битовая маска команд | RW | + +Слово `modbus[128]` в массиве используется для CRC сохраняемых параметров и **не входит** в эту карту. `0x5080` не является допустимым GAS-адресом. + +## Информация GAS-профиля + +Эти слова читаются через FC03 непосредственно по адресам `0x5F00…0x5F07`. Для них нет соответствующих штатных регистров `0x0000…0x007F`. + +| GAS = адрес Modbus, hex | Адрес, dec | Значение | Назначение | +|---|---:|---|---| +| `0x5F00` | 24320 | `0x4741` | Сигнатура `GA` | +| `0x5F01` | 24321 | `0x5331` | Сигнатура `S1` | +| `0x5F02` | 24322 | `1` | Версия контракта GAS | +| `0x5F03` | 24323 | `167` | Профиль устройства | +| `0x5F04` | 24324 | `0x5000` | База технологических GAS-регистров | +| `0x5F05` | 24325 | `128` | Число технологических регистров | +| `0x5F06` | 24326 | `0x0007` | Возможности: бит 0 — RTU, бит 1 — служебный CAN, бит 2 — FC06 | +| `0x5F07` | 24327 | `1` | Аппаратный вариант EEPROM M95M02 | + +Все восемь слов — **RO**. В сборке AT25256B GAS-адреса, включая этот блок, отклоняются с кодом недопустимого адреса. + +## Маски команд и состояния LOAD + +Регистр `Commands`: штатный Modbus **`0x007F`**, GAS **`0x507F`**. Операция FC06 записывает всё слово; обработчик вызывает `ump_log_rs()`. Смысл и выполнение команд определяет прошивка. + +| Бит | Маска | Имя в исходниках | +|---:|---|---| +| 0 | `0x0001` | `cTestLamp` | +| 1 | `0x0002` | `cDefParam` | +| 2 | `0x0004` | `cSaveParam` | +| 3 | `0x0008` | `cLoadParam` | +| 4 | `0x0010` | `cTermoCal` | +| 5 | `0x0020` | `cKoefCalc` | +| 6 | `0x0040` | `cUMPreset` | +| 7 | `0x0080` | `cUMPstart` | +| 8 | `0x0100` | `cInitDac` | +| 9 | `0x0200` | `cCalibrDac` | +| 10 | `0x0400` | `cSecretBt` | +| 11 | `0x0800` | `cLiteFire` | +| 12 | `0x1000` | `cRawMeat` | +| 13 | `0x2000` | Имя команды в package.h не задано | +| 14 | `0x4000` | Имя команды в package.h не задано | +| 15 | `0x8000` | `cReset` | + +Для `Desk == dsk_LOAD` регистр `LOAD_STATUS` (`0x007C` / `0x507C`) формируется в `DAC.c` (проект tms_periph/periph_167): + +| Бит | Маска | Смысл | +|---:|---|---| +| 0 | `0x0001` | Состояние `LOAD_FAULT`: ошибка после пяти попыток пуска | +| 1 | `0x0002` | Нет свежего напряжения ЗПТ | +| 2 | `0x0004` | Состояние `LOAD_RELOAD`: сброс перед повторным пуском | +| 3 | `0x0008` | Состояние `LOAD_RUN`: работа рампы | +| 4 | `0x0010` | Имитация потери ЗПТ: приём напряжения из CAN игнорируется | +| 5 | `0x0020` | Имитация 0 В для защиты; реальные значения CAN в логгере сохраняются | + +`LOAD_ATTEMPTS` (`0x007D` / `0x507D`) содержит число попыток пуска. Оба слова доступны только для чтения на LOAD. + +## Запросы и ограничения + +| Операция | Штатные адреса `0x0000…0x007F` | GAS-адреса | +|---|---|---| +| FC03 | 1…125 слов в пределах 128 регистров | 1…124 слова; весь блок внутри одного GAS-региона | +| FC06 | Одно 16-битное слово | Одно 16-битное слово; ответ сохраняет GAS-адрес | +| FC04 / FC16 | Не используются этими обработчиками для данной карты | GAS-provider поддерживает функции 3 и 6 | +| LOAD: запись `LOAD_STATUS`, `LOAD_ATTEMPTS` | Код 2 | Код 2 | +| LOAD: запись `LOAD_CAN_TIMEOUT` вне 1…60000 мс | Код 3 | Код 3 | + +GAS-provider возвращает код 1 для неподдерживаемой функции, код 2 для недопустимого адреса, пересечения границы или записи RO-блока; код 3 — для количества слов 0 или >124 и недопустимого LOAD-timeout. В RTU запросы к этой карте маршрутизируются обработчиками FC03/FC06. + +В RTU данные одного слова передаются старшим байтом вперёд. Формат ответа GAS-расширения отличается от исторического ответа низких адресов: у GAS нет дополнительных хвостовых нулей. + +Примеры ниже задают функцию, адрес и количество/значение; это параметры запроса, без адреса устройства и CRC: + +| Действие | Штатный Modbus | Через GAS | +|---|---|---| +| Прочитать информацию профиля | Нет аналога | `FC03(0x5F00, 8)` | +| Прочитать слово 0 | `FC03(0x0000, 1)` | `FC03(0x5000, 1)` | +| Прочитать все 128 слов | `FC03(0x0000, 125)` + `FC03(0x007D, 3)` | `FC03(0x5000, 124)` + `FC03(0x507C, 4)` | +| Прочитать timeout LOAD | `FC03(0x0052, 1)` | `FC03(0x5052, 1)` | +| Задать timeout LOAD = 1000 мс | `FC06(0x0052, 1000)` | `FC06(0x5052, 1000)` | +| Прочитать статус и попытки LOAD | `FC03(0x007C, 2)` | `FC03(0x507C, 2)` | + +Два запроса на чтение всей карты дают два отдельных снимка. FC06 меняет RAM; сохранение параметров в EEPROM выполняется штатным механизмом прошивки. + +Эти же GAS-адреса доступны через **служебный CAN УМП** с маркером `0x1F00`, token и функцией 3/6. CAN-чтение принимает чётное количество **2…124 слова**; каждый фрагмент ответа содержит два слова. Формат запроса приведён в `GAS_167_M95M02.md` проекта tms_periph/periph_167. + +Другие расширения Modbus — регистратор `0x1000…0x117B`, паспорт `0x1200…0x120B`, защита `0x1300…0x1307` и EEPROM `0x8000…0xFFFF` — имеют собственные обработчики. Формула `GAS = 0x5000 + Modbus` применяется только к штатным **128 технологическим словам**. + +## Источники + +- `gas167.h` (проект tms_periph/periph_167) — базы, размеры, версия и лимит GAS. +- `gas167.c` (проект tms_periph/periph_167) — прямое соответствие `modbus[]`, информация профиля и ограничения записи. +- `package.h` (проект tms_periph/periph_167) — группы регистров, имена и маски команд. +- `message.c` (проект tms_periph/periph_167) — FC03/FC06, инициализация и сохранение параметров. +- `measure.c` (проект tms_periph/periph_167), `ADC.c` (проект tms_periph/periph_167), `DAC.c` (проект tms_periph/periph_167) — значения измерений и особенности LOAD. +- `GAS_167_M95M02.md` проекта tms_periph/periph_167 — включение GAS, форматы транспорта и проверки реализации. diff --git a/doc/setcan/protocan/PROTOCOL.md b/doc/setcan/protocan/PROTOCOL.md index aea4627..a770cf6 100644 --- a/doc/setcan/protocan/PROTOCOL.md +++ b/doc/setcan/protocan/PROTOCOL.md @@ -112,3 +112,78 @@ CAN ID = 0x13590702 Этот пример соответствует `ENTER_BOOT`, `SessionID=7`. Машинные варианты находятся в [examples/test-vectors.json](examples/test-vectors.json). + +## GAS: сквозная карта УКСС и профиль 167/v1 + +УКСС назначены десятичные ID **0…11999**, блоки по 1000 слов: +`GAS_ID = номер_узла × 1000 + смещение`. Блок 0 — общий резерв; +узлы 1…11 и все границы описаны в +[GAS_ADDRESS_ALLOCATION_167.md](GAS_ADDRESS_ALLOCATION_167.md). +Диапазон 12000…65535 свободен для последующего распределения. + +УМП 1 (узел 5) назначены ID 5000…5127, УМП 2 (узел 6) — +6000…6127. Смещения 128…999 зарезервированы. Полный словарь 128 слов, +ограничения LOAD, биты Commands/LOAD_STATUS и соответствие Modbus приведены в +[GAS_MODBUS_MAP_167.md](GAS_MODBUS_MAP_167.md). + +Новые ID пока назначены только в документации. Действующий профиль 167/v1 +использует Modbus 0x0000…0x007F и окно GAS 0x5000…0x507F; +например, LOAD_CAN_TIMEOUT: Modbus 0x0052, GAS 0x5052, +новые ID 5082/6082. Десятичный ID 5000 не равен hex-адресу 0x5000. +Служебный CAN УМП с маркером 0x1F00 — отдельный транспорт; +его пакет нельзя интерпретировать как обычный payload ProtoCAN GAS. + +Словарь и lookup находятся в `python/protocan/gas_167.py` и +`gas_167_registers.json` проекта templates. Парсер обычных кадров GAS +показывает назначенные имена, узел, старые адреса и статус для запросов +и каждого слова ответа; неизвестные и резервные адреса сохраняются raw. +Общая сводка `Decoded.summary` содержит имя каждого назначенного параметра, +УМП 1/2, десятичный ID, hex-адрес и значение в dec/hex. Поэтому имена видны +непосредственно в колонке «Расшифровка» всех клиентов общего декодера: +онлайн-монитор, трассировка, фильтр кадров, ручной разбор и DevBoard_V1. +Полный текст длинной строки доступен во всплывающей подсказке. +Тип сообщения отображается как `GAS (General Address Space)`. +Обычные демо-потоки шины и DevBoard также включают назначенные адреса УМП. +Низкие Modbus-адреса и старое окно не определяют профиль прибора автоматически. +DATA обычного ProtoCAN GAS — до четырёх u16 little-endian; Modbus RTU +передаёт каждое слово старшим байтом вперёд. GUI использует этот же словарь +через совместимый импорт, без собственной реализации карты. + +### Демо УМП в SETGUI + +Общий список «Протокол» позволяет выбрать `ProtoCAN / GAS`, +`УМП / Balsam 167 (legacy CAN)`, карту `GAS 167/v1` отдельно для УМП 1/2 +или `УМП / ProtoCAN GAS — новые ID 5000/6000`. +Выбор перерисовывает уже полученные кадры. Для старой карты номер УМП +выбирается оператором и обозначается «выбран вручную»; низкие адреса +0…127 и окно 0x5000…0x507F сами по себе номер узла не кодируют. +Этот режим накладывает словарь на слова ProtoCAN GAS/Modbus Holding; +он не является декодером служебных CAN-пакетов с маркером 0x1F00. +Профиль Balsam принимает только собственный формат и показывает +несоответствие для чужих кадров. В сводке Commands показаны активные +биты с названиями команд; это не подтверждение их выполнения. + +В режиме «Авто» legacy-ID Balsam проверяются первыми. Для корректного +ProtoCAN GAS с целыми словами все адреса кадра сверяются с назначенными +диапазонами УМП. Если все они принадлежат одному узлу, поля Device Name +и Msg Type показывают УМП 1/2; основание выбора записывается в подробности +«Автоопределение». Это распознавание назначенной карты, а не подтверждение +её поддержки прошивкой. Для старых/неизвестных адресов, смешанных диапазонов +и некорректного payload автоматический выбор УМП не выполняется; +сводка сообщает «профиль/узел не определены». Номер Device в ProtoCAN сам +по себе не считается номером УМП. «Демо УМП» запускается с режимом «Авто». + +Открыть `CAN → Шина CAN / мост → Настройки → Демо УМП`. +Генератор `python/set_devices/bus_demo.py:UmpDemoSource` моделирует два +узла с демонстрационными адресами `Device Type=3`, `Device=5/6`. +Он передаёт PULSE раз в секунду и четыре GAS-слова каждого узла каждые +250 мс: ID 5000…5127 и 6000…6127, полный обход за 8 секунд. +Это имитация назначенной карты, а не эмуляция текущего транспорта 167/v1. + +Кадры проходят обычное кадрирование AA 55, CRC и общий парсер ProtoCAN. +Их можно смотреть в онлайн-мониторе, трассировке и адресном пространстве; +в буфере сессии и его CSV источник обозначен `DEMO УМП`. +Значения синтетические, в формате raw u16. LOAD_STATUS показывает RUN +(бит 3), LOAD_ATTEMPTS — 0, LOAD_CAN_TIMEOUT — 1000 мс. +Кнопка «Стоп демо УМП» останавливает поток. Для запуска нужно отключить +COM-порт и CAN-снифер; генератор работает локально без передачи в оборудование. diff --git a/python/protocan/balsam.py b/python/protocan/balsam.py index 8b7fef8..0ce27ab 100644 --- a/python/protocan/balsam.py +++ b/python/protocan/balsam.py @@ -62,7 +62,7 @@ class BalsamFrame: "%s=0x%04X (%d)" % (item.name or "R%04X" % item.address, item.value, item.signed_value) + (" — " + self.command_description(item.value) - if not self.from_device and item.address == 0x7F else "") + if item.address == 0x7F else "") for item in self.registers ) or "нет отмеченных регистров" return "BALZAM · %s · %s · %s" % (self.route, direction, values) diff --git a/python/protocan/gas_167.py b/python/protocan/gas_167.py new file mode 100644 index 0000000..1f44341 --- /dev/null +++ b/python/protocan/gas_167.py @@ -0,0 +1,51 @@ +"""GAS 167/v1 dictionary and assigned UKSS IDs; values remain raw u16.""" +import json +from pathlib import Path + +REGISTERS = tuple(json.loads(Path(__file__).with_name('gas_167_registers.json').read_text(encoding='utf-8'))['registers']) +BY_ADDRESS = {entry['address']: entry for entry in REGISTERS} +BY_ASSIGNED_ID = {entry[key]: (node, entry) for node, key in ((5, 'ump1_id'), (6, 'ump2_id')) for entry in REGISTERS} + +COMMAND_NAMES = ( + 'cTestLamp — проверка ламп', 'cDefParam — параметры по умолчанию', + 'cSaveParam — сохранение параметров', 'cLoadParam — загрузка параметров', + 'cTermoCal — термокалибровка', 'cKoefCalc — расчёт коэффициентов', + 'cUMPreset — останов заряда', 'cUMPstart — пуск заряда', + 'cInitDac — инициализация ЦАП', 'cCalibrDac — калибровка ЦАП', + 'cSecretBt', 'cLiteFire', 'cRawMeat', 'бит 13 (не назначен)', + 'бит 14 (не назначен)', 'cReset — сброс', +) + + +def describe_word(offset, value): + """Describe active bits using the selected LOAD register map.""" + if offset == 127: + return ', '.join(name for bit, name in enumerate(COMMAND_NAMES) + if value & (1 << bit)) or 'нет активных команд' + if offset == 124: + names = ('LOAD_FAULT — ошибка пуска', 'нет свежего напряжения ЗПТ', + 'LOAD_RELOAD — сброс перед пуском', 'LOAD_RUN — работа рампы', + 'имитация потери ЗПТ', 'имитация 0 В') + return ', '.join(names[bit] if bit < len(names) else 'бит %d' % bit + for bit in range(16) if value & (1 << bit)) or 'нет активных флагов LOAD' + return '' + + +def metadata(address): + """Metadata for the explicitly selected legacy Modbus profile.""" + index = address if 0 <= address < 128 else address - 0x5000 + if not 0 <= index < 128: + return {} + entry = REGISTERS[index] + return {'name': entry['description'], 'gas_id': f"{entry['ump1_id']} / {entry['ump2_id']}"} + + +def assigned_metadata(address): + """Only assigned global IDs; reserved offsets have no parameter name.""" + match = BY_ASSIGNED_ID.get(address) + if match is None: + return {} + node, entry = match + return {'node': node, 'name': entry['description'], 'access': entry['access'], + 'modbus': entry['modbus'], 'legacy_address': entry['address'], + 'status': 'назначен; прошивка 167/v1 ещё не обслуживает'} diff --git a/python/protocan/gas_167_registers.json b/python/protocan/gas_167_registers.json new file mode 100644 index 0000000..d0b03be --- /dev/null +++ b/python/protocan/gas_167_registers.json @@ -0,0 +1,1030 @@ +{ + "profile": "167/v1", + "source_commit": "378e06a", + "registers": [ + { + "modbus": 0, + "address": 20480, + "ump1_id": 5000, + "ump2_id": 6000, + "description": "sens_error[0]; InputRep0/1/2 — биты A/B/C", + "access": "RW" + }, + { + "modbus": 1, + "address": 20481, + "ump1_id": 5001, + "ump2_id": 6001, + "description": "sens_error[1]", + "access": "RW" + }, + { + "modbus": 2, + "address": 20482, + "ump1_id": 5002, + "ump2_id": 6002, + "description": "sens_error[2]", + "access": "RW" + }, + { + "modbus": 3, + "address": 20483, + "ump1_id": 5003, + "ump2_id": 6003, + "description": "sens_error[3]", + "access": "RW" + }, + { + "modbus": 4, + "address": 20484, + "ump1_id": 5004, + "ump2_id": 6004, + "description": "sens_error[4]", + "access": "RW" + }, + { + "modbus": 5, + "address": 20485, + "ump1_id": 5005, + "ump2_id": 6005, + "description": "sens_error[5]", + "access": "RW" + }, + { + "modbus": 6, + "address": 20486, + "ump1_id": 5006, + "ump2_id": 6006, + "description": "sens_error[6]", + "access": "RW" + }, + { + "modbus": 7, + "address": 20487, + "ump1_id": 5007, + "ump2_id": 6007, + "description": "sens_error[7]", + "access": "RW" + }, + { + "modbus": 8, + "address": 20488, + "ump1_id": 5008, + "ump2_id": 6008, + "description": "sens_error[8]", + "access": "RW" + }, + { + "modbus": 9, + "address": 20489, + "ump1_id": 5009, + "ump2_id": 6009, + "description": "sens_error[9]", + "access": "RW" + }, + { + "modbus": 10, + "address": 20490, + "ump1_id": 5010, + "ump2_id": 6010, + "description": "sens_error[10]", + "access": "RW" + }, + { + "modbus": 11, + "address": 20491, + "ump1_id": 5011, + "ump2_id": 6011, + "description": "sens_error[11]", + "access": "RW" + }, + { + "modbus": 12, + "address": 20492, + "ump1_id": 5012, + "ump2_id": 6012, + "description": "sens_error[12]", + "access": "RW" + }, + { + "modbus": 13, + "address": 20493, + "ump1_id": 5013, + "ump2_id": 6013, + "description": "sens_error[13]", + "access": "RW" + }, + { + "modbus": 14, + "address": 20494, + "ump1_id": 5014, + "ump2_id": 6014, + "description": "sens_error[14]", + "access": "RW" + }, + { + "modbus": 15, + "address": 20495, + "ump1_id": 5015, + "ump2_id": 6015, + "description": "sens_error[15]", + "access": "RW" + }, + { + "modbus": 16, + "address": 20496, + "ump1_id": 5016, + "ump2_id": 6016, + "description": "sens_error[16]; Inputs", + "access": "RW" + }, + { + "modbus": 17, + "address": 20497, + "ump1_id": 5017, + "ump2_id": 6017, + "description": "sens_error[17]", + "access": "RW" + }, + { + "modbus": 18, + "address": 20498, + "ump1_id": 5018, + "ump2_id": 6018, + "description": "sens_error[18]", + "access": "RW" + }, + { + "modbus": 19, + "address": 20499, + "ump1_id": 5019, + "ump2_id": 6019, + "description": "sens_error[19]", + "access": "RW" + }, + { + "modbus": 20, + "address": 20500, + "ump1_id": 5020, + "ump2_id": 6020, + "description": "sens_error[20]", + "access": "RW" + }, + { + "modbus": 21, + "address": 20501, + "ump1_id": 5021, + "ump2_id": 6021, + "description": "sens_error[21]", + "access": "RW" + }, + { + "modbus": 22, + "address": 20502, + "ump1_id": 5022, + "ump2_id": 6022, + "description": "sens_error[22]; Buttons", + "access": "RW" + }, + { + "modbus": 23, + "address": 20503, + "ump1_id": 5023, + "ump2_id": 6023, + "description": "sens_error[23]; Jumpers", + "access": "RW" + }, + { + "modbus": 24, + "address": 20504, + "ump1_id": 5024, + "ump2_id": 6024, + "description": "sens_data[0]", + "access": "RW" + }, + { + "modbus": 25, + "address": 20505, + "ump1_id": 5025, + "ump2_id": 6025, + "description": "sens_data[1]", + "access": "RW" + }, + { + "modbus": 26, + "address": 20506, + "ump1_id": 5026, + "ump2_id": 6026, + "description": "sens_data[2]", + "access": "RW" + }, + { + "modbus": 27, + "address": 20507, + "ump1_id": 5027, + "ump2_id": 6027, + "description": "sens_data[3]", + "access": "RW" + }, + { + "modbus": 28, + "address": 20508, + "ump1_id": 5028, + "ump2_id": 6028, + "description": "sens_data[4]; LOAD: расчётный выход 4–20 мА, raw ×10", + "access": "RW" + }, + { + "modbus": 29, + "address": 20509, + "ump1_id": 5029, + "ump2_id": 6029, + "description": "sens_data[5]; LOAD: измеренный вход 4–20 мА, raw ×10", + "access": "RW" + }, + { + "modbus": 30, + "address": 20510, + "ump1_id": 5030, + "ump2_id": 6030, + "description": "sens_data[6]", + "access": "RW" + }, + { + "modbus": 31, + "address": 20511, + "ump1_id": 5031, + "ump2_id": 6031, + "description": "sens_data[7]", + "access": "RW" + }, + { + "modbus": 32, + "address": 20512, + "ump1_id": 5032, + "ump2_id": 6032, + "description": "sens_data[8]", + "access": "RW" + }, + { + "modbus": 33, + "address": 20513, + "ump1_id": 5033, + "ump2_id": 6033, + "description": "sens_data[9]", + "access": "RW" + }, + { + "modbus": 34, + "address": 20514, + "ump1_id": 5034, + "ump2_id": 6034, + "description": "sens_data[10]", + "access": "RW" + }, + { + "modbus": 35, + "address": 20515, + "ump1_id": 5035, + "ump2_id": 6035, + "description": "sens_data[11]", + "access": "RW" + }, + { + "modbus": 36, + "address": 20516, + "ump1_id": 5036, + "ump2_id": 6036, + "description": "sens_data[12]", + "access": "RW" + }, + { + "modbus": 37, + "address": 20517, + "ump1_id": 5037, + "ump2_id": 6037, + "description": "sens_data[13]", + "access": "RW" + }, + { + "modbus": 38, + "address": 20518, + "ump1_id": 5038, + "ump2_id": 6038, + "description": "sens_data[14]", + "access": "RW" + }, + { + "modbus": 39, + "address": 20519, + "ump1_id": 5039, + "ump2_id": 6039, + "description": "sens_data[15]", + "access": "RW" + }, + { + "modbus": 40, + "address": 20520, + "ump1_id": 5040, + "ump2_id": 6040, + "description": "sens_data[16]", + "access": "RW" + }, + { + "modbus": 41, + "address": 20521, + "ump1_id": 5041, + "ump2_id": 6041, + "description": "sens_data[17]", + "access": "RW" + }, + { + "modbus": 42, + "address": 20522, + "ump1_id": 5042, + "ump2_id": 6042, + "description": "sens_data[18]", + "access": "RW" + }, + { + "modbus": 43, + "address": 20523, + "ump1_id": 5043, + "ump2_id": 6043, + "description": "sens_data[19]", + "access": "RW" + }, + { + "modbus": 44, + "address": 20524, + "ump1_id": 5044, + "ump2_id": 6044, + "description": "sens_data[20]", + "access": "RW" + }, + { + "modbus": 45, + "address": 20525, + "ump1_id": 5045, + "ump2_id": 6045, + "description": "sens_data[21]", + "access": "RW" + }, + { + "modbus": 46, + "address": 20526, + "ump1_id": 5046, + "ump2_id": 6046, + "description": "sens_data[22]", + "access": "RW" + }, + { + "modbus": 47, + "address": 20527, + "ump1_id": 5047, + "ump2_id": 6047, + "description": "sens_data[23]", + "access": "RW" + }, + { + "modbus": 48, + "address": 20528, + "ump1_id": 5048, + "ump2_id": 6048, + "description": "sens_hi_edge[0]", + "access": "RW" + }, + { + "modbus": 49, + "address": 20529, + "ump1_id": 5049, + "ump2_id": 6049, + "description": "sens_hi_edge[1]", + "access": "RW" + }, + { + "modbus": 50, + "address": 20530, + "ump1_id": 5050, + "ump2_id": 6050, + "description": "sens_hi_edge[2]", + "access": "RW" + }, + { + "modbus": 51, + "address": 20531, + "ump1_id": 5051, + "ump2_id": 6051, + "description": "sens_hi_edge[3]", + "access": "RW" + }, + { + "modbus": 52, + "address": 20532, + "ump1_id": 5052, + "ump2_id": 6052, + "description": "sens_hi_edge[4]", + "access": "RW" + }, + { + "modbus": 53, + "address": 20533, + "ump1_id": 5053, + "ump2_id": 6053, + "description": "sens_hi_edge[5]", + "access": "RW" + }, + { + "modbus": 54, + "address": 20534, + "ump1_id": 5054, + "ump2_id": 6054, + "description": "sens_hi_edge[6]", + "access": "RW" + }, + { + "modbus": 55, + "address": 20535, + "ump1_id": 5055, + "ump2_id": 6055, + "description": "sens_hi_edge[7]", + "access": "RW" + }, + { + "modbus": 56, + "address": 20536, + "ump1_id": 5056, + "ump2_id": 6056, + "description": "sens_hi_edge[8]", + "access": "RW" + }, + { + "modbus": 57, + "address": 20537, + "ump1_id": 5057, + "ump2_id": 6057, + "description": "sens_hi_edge[9]", + "access": "RW" + }, + { + "modbus": 58, + "address": 20538, + "ump1_id": 5058, + "ump2_id": 6058, + "description": "sens_hi_edge[10]", + "access": "RW" + }, + { + "modbus": 59, + "address": 20539, + "ump1_id": 5059, + "ump2_id": 6059, + "description": "sens_hi_edge[11]", + "access": "RW" + }, + { + "modbus": 60, + "address": 20540, + "ump1_id": 5060, + "ump2_id": 6060, + "description": "sens_hi_edge[12]", + "access": "RW" + }, + { + "modbus": 61, + "address": 20541, + "ump1_id": 5061, + "ump2_id": 6061, + "description": "sens_hi_edge[13]", + "access": "RW" + }, + { + "modbus": 62, + "address": 20542, + "ump1_id": 5062, + "ump2_id": 6062, + "description": "sens_hi_edge[14]", + "access": "RW" + }, + { + "modbus": 63, + "address": 20543, + "ump1_id": 5063, + "ump2_id": 6063, + "description": "sens_hi_edge[15]", + "access": "RW" + }, + { + "modbus": 64, + "address": 20544, + "ump1_id": 5064, + "ump2_id": 6064, + "description": "sens_hi_edge[16]", + "access": "RW" + }, + { + "modbus": 65, + "address": 20545, + "ump1_id": 5065, + "ump2_id": 6065, + "description": "sens_hi_edge[17]", + "access": "RW" + }, + { + "modbus": 66, + "address": 20546, + "ump1_id": 5066, + "ump2_id": 6066, + "description": "sens_hi_edge[18]", + "access": "RW" + }, + { + "modbus": 67, + "address": 20547, + "ump1_id": 5067, + "ump2_id": 6067, + "description": "sens_hi_edge[19]", + "access": "RW" + }, + { + "modbus": 68, + "address": 20548, + "ump1_id": 5068, + "ump2_id": 6068, + "description": "sens_hi_edge[20]", + "access": "RW" + }, + { + "modbus": 69, + "address": 20549, + "ump1_id": 5069, + "ump2_id": 6069, + "description": "sens_hi_edge[21]", + "access": "RW" + }, + { + "modbus": 70, + "address": 20550, + "ump1_id": 5070, + "ump2_id": 6070, + "description": "sens_hi_edge[22]", + "access": "RW" + }, + { + "modbus": 71, + "address": 20551, + "ump1_id": 5071, + "ump2_id": 6071, + "description": "sens_hi_edge[23]", + "access": "RW" + }, + { + "modbus": 72, + "address": 20552, + "ump1_id": 5072, + "ump2_id": 6072, + "description": "sens_lo_edge[0]", + "access": "RW" + }, + { + "modbus": 73, + "address": 20553, + "ump1_id": 5073, + "ump2_id": 6073, + "description": "sens_lo_edge[1]", + "access": "RW" + }, + { + "modbus": 74, + "address": 20554, + "ump1_id": 5074, + "ump2_id": 6074, + "description": "sens_lo_edge[2]", + "access": "RW" + }, + { + "modbus": 75, + "address": 20555, + "ump1_id": 5075, + "ump2_id": 6075, + "description": "sens_lo_edge[3]", + "access": "RW" + }, + { + "modbus": 76, + "address": 20556, + "ump1_id": 5076, + "ump2_id": 6076, + "description": "sens_lo_edge[4]", + "access": "RW" + }, + { + "modbus": 77, + "address": 20557, + "ump1_id": 5077, + "ump2_id": 6077, + "description": "sens_lo_edge[5]", + "access": "RW" + }, + { + "modbus": 78, + "address": 20558, + "ump1_id": 5078, + "ump2_id": 6078, + "description": "sens_lo_edge[6]", + "access": "RW" + }, + { + "modbus": 79, + "address": 20559, + "ump1_id": 5079, + "ump2_id": 6079, + "description": "sens_lo_edge[7]", + "access": "RW" + }, + { + "modbus": 80, + "address": 20560, + "ump1_id": 5080, + "ump2_id": 6080, + "description": "sens_lo_edge[8]; LOAD: DAC_go — параметр начала рампы", + "access": "RW" + }, + { + "modbus": 81, + "address": 20561, + "ump1_id": 5081, + "ump2_id": 6081, + "description": "sens_lo_edge[9]; LOAD: DAC_stop — параметр конца рампы", + "access": "RW" + }, + { + "modbus": 82, + "address": 20562, + "ump1_id": 5082, + "ump2_id": 6082, + "description": "sens_lo_edge[10]; LOAD: LOAD_CAN_TIMEOUT, мс", + "access": "RW; LOAD: 1…60000" + }, + { + "modbus": 83, + "address": 20563, + "ump1_id": 5083, + "ump2_id": 6083, + "description": "sens_lo_edge[11]", + "access": "RW" + }, + { + "modbus": 84, + "address": 20564, + "ump1_id": 5084, + "ump2_id": 6084, + "description": "sens_lo_edge[12]", + "access": "RW" + }, + { + "modbus": 85, + "address": 20565, + "ump1_id": 5085, + "ump2_id": 6085, + "description": "sens_lo_edge[13]", + "access": "RW" + }, + { + "modbus": 86, + "address": 20566, + "ump1_id": 5086, + "ump2_id": 6086, + "description": "sens_lo_edge[14]", + "access": "RW" + }, + { + "modbus": 87, + "address": 20567, + "ump1_id": 5087, + "ump2_id": 6087, + "description": "sens_lo_edge[15]", + "access": "RW" + }, + { + "modbus": 88, + "address": 20568, + "ump1_id": 5088, + "ump2_id": 6088, + "description": "sens_lo_edge[16]", + "access": "RW" + }, + { + "modbus": 89, + "address": 20569, + "ump1_id": 5089, + "ump2_id": 6089, + "description": "sens_lo_edge[17]", + "access": "RW" + }, + { + "modbus": 90, + "address": 20570, + "ump1_id": 5090, + "ump2_id": 6090, + "description": "sens_lo_edge[18]", + "access": "RW" + }, + { + "modbus": 91, + "address": 20571, + "ump1_id": 5091, + "ump2_id": 6091, + "description": "sens_lo_edge[19]", + "access": "RW" + }, + { + "modbus": 92, + "address": 20572, + "ump1_id": 5092, + "ump2_id": 6092, + "description": "sens_lo_edge[20]", + "access": "RW" + }, + { + "modbus": 93, + "address": 20573, + "ump1_id": 5093, + "ump2_id": 6093, + "description": "sens_lo_edge[21]", + "access": "RW" + }, + { + "modbus": 94, + "address": 20574, + "ump1_id": 5094, + "ump2_id": 6094, + "description": "sens_lo_edge[22]", + "access": "RW" + }, + { + "modbus": 95, + "address": 20575, + "ump1_id": 5095, + "ump2_id": 6095, + "description": "sens_lo_edge[23]", + "access": "RW" + }, + { + "modbus": 96, + "address": 20576, + "ump1_id": 5096, + "ump2_id": 6096, + "description": "Cancount[m_FAST] — пауза быстрых посылок CAN", + "access": "RW" + }, + { + "modbus": 97, + "address": 20577, + "ump1_id": 5097, + "ump2_id": 6097, + "description": "Cancount[m_SLOW] — пауза медленных посылок CAN", + "access": "RW" + }, + { + "modbus": 98, + "address": 20578, + "ump1_id": 5098, + "ump2_id": 6098, + "description": "Brightness / Bright[0] — яркость", + "access": "RW" + }, + { + "modbus": 99, + "address": 20579, + "ump1_id": 5099, + "ump2_id": 6099, + "description": "Owncount / Bright[1]; LOAD: исходное значение АЦП", + "access": "RW" + }, + { + "modbus": 100, + "address": 20580, + "ump1_id": 5100, + "ump2_id": 6100, + "description": "Bright[2]; Current_count: исходное значение канала 0", + "access": "RW" + }, + { + "modbus": 101, + "address": 20581, + "ump1_id": 5101, + "ump2_id": 6101, + "description": "Bright[3]; Current_count: исходное значение канала 1", + "access": "RW" + }, + { + "modbus": 102, + "address": 20582, + "ump1_id": 5102, + "ump2_id": 6102, + "description": "Bright[4]; Current_count: исходное значение канала 2", + "access": "RW" + }, + { + "modbus": 103, + "address": 20583, + "ump1_id": 5103, + "ump2_id": 6103, + "description": "Bright[5]; Current_count: исходное значение канала 3", + "access": "RW" + }, + { + "modbus": 104, + "address": 20584, + "ump1_id": 5104, + "ump2_id": 6104, + "description": "lev_count[], запись из Current_count; назначение по режиму", + "access": "RW" + }, + { + "modbus": 105, + "address": 20585, + "ump1_id": 5105, + "ump2_id": 6105, + "description": "lev_count[], запись из Current_count; назначение по режиму", + "access": "RW" + }, + { + "modbus": 106, + "address": 20586, + "ump1_id": 5106, + "ump2_id": 6106, + "description": "lev_count[], запись из Current_count; назначение по режиму", + "access": "RW" + }, + { + "modbus": 107, + "address": 20587, + "ump1_id": 5107, + "ump2_id": 6107, + "description": "lev_count[], запись из Current_count; назначение по режиму", + "access": "RW" + }, + { + "modbus": 108, + "address": 20588, + "ump1_id": 5108, + "ump2_id": 6108, + "description": "lev_count[], запись из Current_count; назначение по режиму", + "access": "RW" + }, + { + "modbus": 109, + "address": 20589, + "ump1_id": 5109, + "ump2_id": 6109, + "description": "lev_count[], запись из Current_count; назначение по режиму", + "access": "RW" + }, + { + "modbus": 110, + "address": 20590, + "ump1_id": 5110, + "ump2_id": 6110, + "description": "DAC_20 — калибровка входа 20 мА", + "access": "RW" + }, + { + "modbus": 111, + "address": 20591, + "ump1_id": 5111, + "ump2_id": 6111, + "description": "DAC_04 — калибровка входа 4 мА", + "access": "RW" + }, + { + "modbus": 112, + "address": 20592, + "ump1_id": 5112, + "ump2_id": 6112, + "description": "Zero_lev[0] — нулевой уровень канала тока 0", + "access": "RW" + }, + { + "modbus": 113, + "address": 20593, + "ump1_id": 5113, + "ump2_id": 6113, + "description": "Zero_lev[1] — нулевой уровень канала тока 1", + "access": "RW" + }, + { + "modbus": 114, + "address": 20594, + "ump1_id": 5114, + "ump2_id": 6114, + "description": "Zero_lev[2] — нулевой уровень канала тока 2", + "access": "RW" + }, + { + "modbus": 115, + "address": 20595, + "ump1_id": 5115, + "ump2_id": 6115, + "description": "Zero_lev[3] — нулевой уровень канала тока 3", + "access": "RW" + }, + { + "modbus": 116, + "address": 20596, + "ump1_id": 5116, + "ump2_id": 6116, + "description": "Caliber[0]: K380_1 / KPOW_1", + "access": "RW" + }, + { + "modbus": 117, + "address": 20597, + "ump1_id": 5117, + "ump2_id": 6117, + "description": "Caliber[1]: K380_2 / KPOW_2", + "access": "RW" + }, + { + "modbus": 118, + "address": 20598, + "ump1_id": 5118, + "ump2_id": 6118, + "description": "Caliber[2]: KPOW_3", + "access": "RW" + }, + { + "modbus": 119, + "address": 20599, + "ump1_id": 5119, + "ump2_id": 6119, + "description": "Caliber[3]: KPOW_4", + "access": "RW" + }, + { + "modbus": 120, + "address": 20600, + "ump1_id": 5120, + "ump2_id": 6120, + "description": "Caliber[4] / TCaliber[0]; LOAD: DAC_max()", + "access": "RW" + }, + { + "modbus": 121, + "address": 20601, + "ump1_id": 5121, + "ump2_id": 6121, + "description": "Caliber[5] / TCaliber[1]; LOAD: DAC_min()", + "access": "RW" + }, + { + "modbus": 122, + "address": 20602, + "ump1_id": 5122, + "ump2_id": 6122, + "description": "Caliber[6] / TCaliber[2]; LOAD: DAC_cal()", + "access": "RW" + }, + { + "modbus": 123, + "address": 20603, + "ump1_id": 5123, + "ump2_id": 6123, + "description": "Caliber[7] / TCaliber[3]; LOAD: текущий 12-битный код ЦАП", + "access": "RW" + }, + { + "modbus": 124, + "address": 20604, + "ump1_id": 5124, + "ump2_id": 6124, + "description": "NormaU = Caliber[8]; LOAD: LOAD_STATUS", + "access": "RO для LOAD; иначе RW" + }, + { + "modbus": 125, + "address": 20605, + "ump1_id": 5125, + "ump2_id": 6125, + "description": "DeltaU = Caliber[9]; LOAD: LOAD_ATTEMPTS", + "access": "RO для LOAD; иначе RW" + }, + { + "modbus": 126, + "address": 20606, + "ump1_id": 5126, + "ump2_id": 6126, + "description": "LastMode", + "access": "RW" + }, + { + "modbus": 127, + "address": 20607, + "ump1_id": 5127, + "ump2_id": 6127, + "description": "Commands — битовая маска команд", + "access": "RW" + } + ] +} diff --git a/python/protocan/protocan.py b/python/protocan/protocan.py index 5a31d62..74d832a 100644 --- a/python/protocan/protocan.py +++ b/python/protocan/protocan.py @@ -17,6 +17,8 @@ from dataclasses import dataclass, field from enum import IntEnum from typing import List, Optional +from .gas_167 import assigned_metadata, describe_word + try: from .native import get_native_core _SHARED_PROTOCOL = get_native_core() @@ -114,7 +116,7 @@ MSGTYPE_RU = { MsgType.BROADCAST: "Broadcast", MsgType.DISCRETE: "Discrete", MsgType.ANALOG: "Analog", - MsgType.GENERAL_ADDRESS_SPACE: "General Address Space", + MsgType.GENERAL_ADDRESS_SPACE: "GAS (General Address Space)", MsgType.MODBUS_COIL: "Modbus Coil", MsgType.MODBUS_DISCRETE: "Modbus Discrete", MsgType.MODBUS_HOLDING: "Modbus Holding", @@ -622,11 +624,49 @@ def _decode_gas(res: Decoded) -> None: return for adr, v in res.registers: res.fields.append((" Reg 0x%04X" % adr, "0x%04X (%d)" % (v, v))) + _append_gas_metadata(res, adr) + if not vals: + _append_gas_metadata(res, start) if vals: res.summary = "GAS: %d рег. с 0x%04X = %s" % ( len(vals), start, " ".join("%04X" % v for v in vals)) else: res.summary = "GAS: запрос по адресу 0x%04X" % start + # Every monitor, manual decoder and export uses this shared summary. + # Keep names in the summary as well as in the expandable field list. + addresses = res.registers if vals else [(start, None)] + if any(assigned_metadata(address) for address, _value in addresses): + words = [] + for address, value in addresses: + entry = assigned_metadata(address) + label = "ID %d (0x%04X)" % (address, address) + if entry: + label = "УМП %d · %s · %s" % ( + entry['node'] - 4, label, entry['name']) + else: + label += " · имя не назначено" + if value is not None: + label += " = %d [0x%04X]" % (value, value) + description = describe_word(entry['modbus'], value) if entry else '' + if description: + label += " — " + description + res.fields.append((" GAS ID %d / биты" % address, description)) + words.append(label) + res.summary = ("GAS: " if vals else "GAS запрос: ") + "; ".join(words) + + +def _append_gas_metadata(res: Decoded, address: int) -> None: + entry = assigned_metadata(address) + if not entry: + return + label = " GAS ID %d" % address + res.fields += [ + (label, "УМП %d — %s" % (entry['node'] - 4, entry['name'])), + (label + " / статус", entry['status']), + (label + " / Modbus 167/v1", "0x%04X" % entry['modbus']), + (label + " / GAS 167/v1", "0x%04X" % entry['legacy_address']), + (label + " / доступ", entry['access']), + ] def _decode_modbus_bit(res: Decoded) -> None: diff --git a/python/pyproject.toml b/python/pyproject.toml index 37f1664..4486f96 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -19,4 +19,4 @@ include = ["firmware_image*", "altera_logic*", "logic_analyzer*", "set_devices*" [tool.setuptools.package-data] set_devices = ["gas_logger_maps/*.json"] -protocan = ["native/*.dll", "native/*.so", "native/*.dylib"] +protocan = ["*.json", "native/*.dll", "native/*.so", "native/*.dylib"] diff --git a/python/pysetterminal/rawprotocol.py b/python/pysetterminal/rawprotocol.py index 4738e79..249bf28 100644 --- a/python/pysetterminal/rawprotocol.py +++ b/python/pysetterminal/rawprotocol.py @@ -206,10 +206,16 @@ class RawProtocolWidget(QWidget): def init_ui(self): layout = QVBoxLayout() + layout.setProperty("fixedPanelLayout", True) + layout.setContentsMargins(4, 4, 4, 4) + layout.setSpacing(4) # Группа для ПРЯМОГО ДОСТУПА К ПАМЯТИ (PEEK/POKE) mem_group = QGroupBox("Прямой доступ к памяти (PEEK/POKE)") + mem_group.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) mem_layout = QGridLayout() + mem_layout.setContentsMargins(6, 6, 6, 6) + mem_layout.setSpacing(4) mem_layout.addWidget(QLabel("Адрес памяти (hex):"), 0, 0) self.mem_addr_edit = QLineEdit("2000") @@ -239,6 +245,9 @@ class RawProtocolWidget(QWidget): # Группа для RAW отправки raw_group = QGroupBox("RAW отправка/чтение") raw_layout = QVBoxLayout() + raw_layout.setProperty("fixedPanelLayout", True) + raw_layout.setContentsMargins(6, 6, 6, 6) + raw_layout.setSpacing(4) self.raw_send_edit = QLineEdit() self.raw_send_edit.setPlaceholderText("Введите hex данные для отправки") @@ -246,6 +255,7 @@ class RawProtocolWidget(QWidget): raw_layout.addWidget(self.raw_send_edit) hbox = QHBoxLayout() + hbox.setSpacing(4) self.raw_send_btn = QPushButton("Отправить RAW") self.raw_send_btn.clicked.connect(self.send_raw_data) hbox.addWidget(self.raw_send_btn) @@ -260,16 +270,19 @@ class RawProtocolWidget(QWidget): self.raw_output = QTextEdit() self.raw_output.setReadOnly(True) - self.raw_output.setMaximumHeight(100) - raw_layout.addWidget(self.raw_output) + self.raw_output.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + raw_layout.addWidget(self.raw_output, 1) self.raw_clear_btn = QPushButton("Очистить логи") self.raw_clear_btn.clicked.connect(self.clear_logs) raw_layout.addWidget(self.raw_clear_btn, 0, Qt.AlignLeft) + for button in (self.mem_write_btn, self.mem_read_btn, self.raw_send_btn, + self.raw_read_btn, self.raw_clear_btn): + button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) raw_group.setLayout(raw_layout) - layout.addWidget(raw_group) + layout.addWidget(raw_group, 1) self.setLayout(layout) def memory_write(self): diff --git a/python/pysetterminal/serialbus.py b/python/pysetterminal/serialbus.py index 27dc9c3..bd7499a 100644 --- a/python/pysetterminal/serialbus.py +++ b/python/pysetterminal/serialbus.py @@ -403,24 +403,38 @@ class SerialTab(QWidget): button.setFixedHeight(30) button.setStyleSheet("QPushButton { padding: 3px 10px; }") - # Прокручиваемая область для кнопок макросов - self.macros_scroll_area = QScrollArea() - self.macros_scroll_area.setWidgetResizable(True) - # Устанавливаем фиксированную высоту, чтобы вместить 3-4 строки макросов - self.macros_scroll_area.setMinimumHeight(120) # Высота для 3-4 строк - - self.macros_scroll_content = QWidget() - self.macros_scroll_layout = QGridLayout() - self.macros_scroll_content.setLayout(self.macros_scroll_layout) - self.macros_scroll_area.setWidget(self.macros_scroll_content) - self.macros_scroll_layout.setAlignment(Qt.AlignTop | Qt.AlignLeft) - self.macros_scroll_layout.setContentsMargins(6, 6, 6, 6) - self.macros_scroll_layout.setHorizontalSpacing(8) - self.macros_scroll_layout.setVerticalSpacing(6) - macros_layout.addWidget(self.macros_scroll_area) + self.macros_splitter = QSplitter(Qt.Orientation.Horizontal) + self.macros_splitter.setObjectName("macrosSplitter") + self.macros_splitter.setChildrenCollapsible(False) + self.macros_splitter.setHandleWidth(8) + self.macros_splitter.setToolTip("Перетащите разделитель, чтобы изменить ширину панелей") + self.macros_scroll_areas = [] + self.macros_scroll_layouts = [] + for side in ("Левая", "Правая"): + area = QScrollArea() + area.setAccessibleName(f"{side} панель макросов") + area.setWidgetResizable(True) + area.setMinimumSize(120, 120) + content = QWidget() + grid = QGridLayout(content) + grid.setAlignment(Qt.AlignTop | Qt.AlignLeft) + grid.setContentsMargins(6, 6, 6, 6) + grid.setVerticalSpacing(6) + area.setWidget(content) + self.macros_splitter.addWidget(area) + self.macros_scroll_areas.append(area) + self.macros_scroll_layouts.append(grid) + self.macros_splitter.setStretchFactor(0, 1) + self.macros_splitter.setStretchFactor(1, 1) + self.macros_splitter.setSizes([1, 1]) + # Keep the existing attributes available to terminal integrations. + self.macros_scroll_area = self.macros_scroll_areas[0] + self.macros_scroll_content = self.macros_scroll_area.widget() + self.macros_scroll_layout = self.macros_scroll_layouts[0] + macros_layout.addWidget(self.macros_splitter, 1) macros_group.setLayout(macros_layout) - layout.addWidget(macros_group) + layout.addWidget(macros_group, 1) # --- ВНЕ ГРУППЫ: Результаты чтения --- results_layout = QGridLayout() @@ -447,7 +461,6 @@ class SerialTab(QWidget): results_frame.setLayout(results_layout) layout.addWidget(results_frame) - layout.addStretch() self.setLayout(layout) # После создания интерфейса создаем кнопки для загруженных макросов @@ -590,7 +603,7 @@ class SerialTab(QWidget): container_layout.addWidget(delete_btn) container.setLayout(container_layout) - self.macros_scroll_layout.addWidget(container, row, col, 1, 1) # span изменен на 1 + self.macros_scroll_layouts[col].addWidget(container, row, 0) self.macro_buttons.append(container) @@ -680,7 +693,7 @@ class SerialTab(QWidget): def _set_macro_controls(self, running): self.stop_macro_btn.setEnabled(running) for widget in (self.bus_write_btn, self.bus_read_btn, self.create_macro_btn, - self.macros_scroll_area, self.raw_widget): + self.macros_splitter, self.raw_widget): widget.setEnabled(not running) def _next_macro_command(self, generation): @@ -748,10 +761,11 @@ class SerialTab(QWidget): def rebuild_macros_layout(self): """Перестроить layout макросов""" # Очищаем layout - for i in reversed(range(self.macros_scroll_layout.count())): - item = self.macros_scroll_layout.itemAt(i) - if item and item.widget(): - item.widget().setParent(None) + for grid in self.macros_scroll_layouts: + while grid.count(): + item = grid.takeAt(0) + if item.widget(): + item.widget().deleteLater() # Очищаем список кнопок self.macro_buttons.clear() diff --git a/python/set_devices/balsam_can.py b/python/set_devices/balsam_can.py index 53b7574..c0274ce 100644 --- a/python/set_devices/balsam_can.py +++ b/python/set_devices/balsam_can.py @@ -53,8 +53,8 @@ def decode(raw_id: int, data: bytes, *, ide: bool = True, "0x%04X %s" % (item.address, item.name or "регистр"), "0x%04X (%d)" % (item.value, item.signed_value), )) - if not frame.from_device and item.address == 0x7F: - result.fields.append(("Команды ПМ", frame.command_description(item.value))) + if item.address == 0x7F: + result.fields.append(("Активные биты Commands", frame.command_description(item.value))) if frame.present_mask == 0: result.warnings.append("В адресном слове не отмечен ни один регистр") return result diff --git a/python/set_devices/bus_demo.py b/python/set_devices/bus_demo.py index ee81014..92f1025 100644 --- a/python/set_devices/bus_demo.py +++ b/python/set_devices/bus_demo.py @@ -13,15 +13,59 @@ from __future__ import annotations import random +import math from datetime import datetime from . import can_transport as tr from protocan import protocan as pc +from protocan.gas_167 import REGISTERS #: Типы сообщений, которые генератор выдаёт по кругу случайно. KINDS = ("pulse", "analog", "modbus", "gas", "status", "error", "discrete") +class UmpDemoSource: + """Two simulated UMP nodes using the assigned global GAS map. + + Call next_frames every 250 ms: four words per node per tick and a + heartbeat every second. Device Type=3, Device=5/6 are demo addresses, + not discovery results or a claim about firmware 167/v1 support. + """ + + def __init__(self) -> None: + self._tick = 0 + self._seq = 0 + + def _frame(self, node: int, kind: int, body: int, data: bytes) -> bytes: + self._seq = (self._seq + 1) & 0xFF + identifier = pc.ProtoCanId.build(1, 1, 3, node, kind, body) + return tr.Frame(seq=self._seq, flags=tr.FLAG_IDE, + can_id=identifier, data=data).encode() + + def next_frames(self) -> list[bytes]: + """Return encoded bridge frames; one full map takes eight seconds.""" + packets = [] + # Show LOAD state immediately, then walk the entire dictionary. + start = (124 + self._tick * 4) % len(REGISTERS) + for node, key in ((5, "ump1_id"), (6, "ump2_id")): + if self._tick % 4 == 0: + packets.append(self._frame( + node, pc.MsgType.PULSE, 0, + bytes([(self._tick // 4) & 0xFF]))) + values = [] + for entry in REGISTERS[start:start + 4]: + offset = entry["modbus"] + value = int(2000 + 700 * math.sin(self._tick / 12 + offset / 8 + node)) + command = 0x80 if (self._tick // 32) % 2 == 0 else 0x40 + value = {82: 1000, 124: 8, 125: 0, 126: node, 127: command}.get(offset, value) + values.append(value.to_bytes(2, "little")) + packets.append(self._frame( + node, pc.MsgType.GENERAL_ADDRESS_SPACE, + REGISTERS[start][key], b"".join(values))) + self._tick += 1 + return packets + + class BusDemoSource: """@brief Источник демонстрационных кадров шины. @@ -58,11 +102,15 @@ class BusDemoSource: data = b"".join(self._rng.randint(0, 0xFFFF).to_bytes(2, "little") for _ in range(cnt)) elif kind == "gas": - adr = self._rng.randint(0, 0x400) + # Exercise the shared named map in the ordinary demo too. + dev_type, dev_id = 3, self._rng.choice((5, 6)) + key = "ump1_id" if dev_id == 5 else "ump2_id" + count = self._rng.randint(1, 4) + adr = REGISTERS[self._rng.randrange(len(REGISTERS) - count + 1)][key] cid = pc.ProtoCanId.build(0, 1, dev_type, dev_id, pc.MsgType.GENERAL_ADDRESS_SPACE, adr) data = b"".join(self._rng.randint(0, 0xFFFF).to_bytes(2, "little") - for _ in range(self._rng.randint(1, 4))) + for _ in range(count)) elif kind == "status": now = datetime.now() cid = pc.ProtoCanId.build(1, 1, dev_type, dev_id, pc.MsgType.BROADCAST, diff --git a/python/set_devices/can485_board.py b/python/set_devices/can485_board.py index 27f829e..53ad30c 100644 --- a/python/set_devices/can485_board.py +++ b/python/set_devices/can485_board.py @@ -32,6 +32,8 @@ from collections import deque from dataclasses import dataclass, field from itertools import chain from typing import Iterable +from protocan import protocan as pc +from protocan.gas_167 import REGISTERS #: Распространённые скорости UART для подключения платы и RS485-приёмника. UART_BAUDS = ( @@ -596,7 +598,14 @@ class BoardDemoSource: """ #: Идентификаторы, по которым генератор идёт по кругу. - IDS = ((True, 0x18FEE000), (True, 0x0CF00400), (False, 0x123), (False, 0x7DF)) + IDS = ( + (True, 0x18FEE000), (True, 0x0CF00400), (False, 0x123), (False, 0x7DF), + # Assigned UMP map, simulated to demonstrate the common GAS decoder. + (True, pc.ProtoCanId.build(1, 1, 3, 5, pc.MsgType.GENERAL_ADDRESS_SPACE, + REGISTERS[124]['ump1_id'])), + (True, pc.ProtoCanId.build(1, 1, 3, 6, pc.MsgType.GENERAL_ADDRESS_SPACE, + REGISTERS[124]['ump2_id'])), + ) def __init__(self, rng: random.Random | None = None) -> None: self._rng = rng or random.Random() diff --git a/python/set_devices/can_bridge.py b/python/set_devices/can_bridge.py index 2ac0add..a6d9be9 100644 --- a/python/set_devices/can_bridge.py +++ b/python/set_devices/can_bridge.py @@ -16,6 +16,7 @@ from __future__ import annotations from . import can_transport as tr from protocan import protocan as pc +from protocan.gas_167 import assigned_metadata from . import balsam_can #: Расшифровка поля LEC регистра CAN_ESR. @@ -64,8 +65,27 @@ def decode_frame(frame: tr.Frame) -> pc.Decoded: decoded_balsam = balsam_can.decode( frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) if decoded_balsam is not None: + decoded_balsam.fields.append(("Автоопределение", "Balsam 167: идентификатор legacy CAN")) return decoded_balsam - return pc.decode(frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) + result = pc.decode(frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) + if (frame.ide and not frame.rtr + and result.id.msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE + and len(frame.data) <= 8 and len(frame.data) % 2 == 0 + and result.registers is not None): + addresses = [address for address, _value in result.registers] or [result.id.body] + entries = [assigned_metadata(address) for address in addresses] + if all(entries) and len({entry['node'] for entry in entries}) == 1: + node = entries[0]['node'] - 4 + result.protocol = "УМП / ProtoCAN GAS (назначенные ID)" + result.device_label = "УМП %d" % node + result.message_label = "GAS · УМП %d" % node + result.fields.append(("Автоопределение", + "УМП %d: все GAS ID входят в назначенную карту; поддержка прошивкой не подтверждена" % node)) + return result + result.fields.append(("Автоопределение", "Разбор ProtoCAN; профиль прибора не определён")) + if result.id.msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE: + result.summary += " · профиль/узел не определены — выберите протокол вручную" + return result dec = pc.Decoded(id=pc.ProtoCanId.parse(frame.can_id), dlc=len(frame.data), data=frame.data, ide=frame.ide, rtr=frame.rtr) diff --git a/python/set_devices/can_monitor.py b/python/set_devices/can_monitor.py index c76cda1..70ad7b1 100644 --- a/python/set_devices/can_monitor.py +++ b/python/set_devices/can_monitor.py @@ -10,14 +10,33 @@ from .can_bridge import decode_frame PROTOCOLS = (("auto", "Авто (ProtoCAN / Balsam)"), ("devboard", "DevBoard_V1 / SETCAN"), - ("deif", "DEIF XDi-192 / CANopen")) + ("deif", "DEIF XDi-192 / CANopen"), + ("protocan", "ProtoCAN / GAS"), + ("ump_balsam", "УМП / Balsam 167 (legacy CAN)"), + ("ump1_gas167", "УМП 1 / ProtoCAN — карта GAS 167/v1"), + ("ump2_gas167", "УМП 2 / ProtoCAN — карта GAS 167/v1"), + ("ump_gas", "УМП / ProtoCAN GAS — новые ID 5000/6000")) def decode_protocol(frame, protocol="auto"): if protocol == "deif": from .deif_xdi import decode return decode(frame) - if protocol == "devboard": + if protocol == "ump_balsam": + from .balsam_can import decode + result = decode(frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) + if result is not None: + return result + result = pc.Decoded(pc.ProtoCanId.parse(frame.can_id), len(frame.data), + bytes(frame.data), ide=frame.ide, rtr=frame.rtr, + protocol="BALZAM 167", message_label="Не Balsam 167") + result.summary = "УМП / Balsam 167: CAN ID или формат кадра не соответствует протоколу" + result.warnings.append(result.summary) + return result + if protocol in ("ump1_gas167", "ump2_gas167"): + from .ump_can import decode_gas167 + return decode_gas167(frame, node=1 if protocol == "ump1_gas167" else 2) + if protocol in ("devboard", "protocan", "ump_gas"): return pc.decode(frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) return decode_frame(frame) diff --git a/python/set_devices/qt_ports/can_monitor.py b/python/set_devices/qt_ports/can_monitor.py index 311c350..6c13b5c 100644 --- a/python/set_devices/qt_ports/can_monitor.py +++ b/python/set_devices/qt_ports/can_monitor.py @@ -22,6 +22,12 @@ class MonitorControls(QWidget): self.protocol = QComboBox() for key, label in PROTOCOLS: self.protocol.addItem(label, key) + self.protocol.setMinimumContentsLength(28) + self.protocol.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) + self.protocol.setToolTip( + "Выберите формат CAN вручную. УМП / Balsam — legacy CAN; " + "карта 167/v1 — имена слов 0…127 и 0x5000…0x507F в ProtoCAN; " + "новые ID — назначенные диапазоны 5000…5127 и 6000…6127.") self.protocol.setCurrentIndex(self.protocol.findData(default)) layout.addWidget(QLabel("Протокол")) layout.addWidget(self.protocol) diff --git a/python/set_devices/ump_can.py b/python/set_devices/ump_can.py new file mode 100644 index 0000000..10cd4bb --- /dev/null +++ b/python/set_devices/ump_can.py @@ -0,0 +1,50 @@ +"""Explicit interpretation of ProtoCAN registers with the UMP 167/v1 map. + +This is a manually selected dictionary, not detection of the legacy service +CAN packet format or a claim that a particular firmware implements ProtoCAN. +""" +from protocan import protocan as pc +from protocan.gas_167 import REGISTERS, describe_word + + +def decode_gas167(frame, node): + result = pc.decode(frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) + result.device_label = "УМП %d (выбран вручную)" % node + result.protocol = "УМП %d / ProtoCAN GAS 167/v1" % node + if not frame.ide or frame.rtr or frame.is_error: + return result + if result.id.msg_type not in (pc.MsgType.GENERAL_ADDRESS_SPACE, + pc.MsgType.MODBUS_HOLDING): + return result + if result.id.msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE: + start = result.id.body + else: + start, _count = pc.split_modbus(result.id.body) + words = result.registers + if words is None: + return result + labels = [] + for address, value in words or [(start, None)]: + offset = address if 0 <= address < 128 else address - 0x5000 + label = "0x%04X" % address + if 0 <= offset < len(REGISTERS): + entry = REGISTERS[offset] + label += " · " + entry['description'] + result.fields += [ + (" УМП 167/v1 0x%04X" % address, entry['description']), + (" Назначенные ID УМП 1/2", "%d / %d" % (entry['ump1_id'], entry['ump2_id'])), + (" Доступ", entry['access']), + ] + else: + label += " · вне карты 167/v1" + if value is not None: + label += " = %d [0x%04X]" % (value, value) + description = describe_word(offset, value) + if description: + label += " — " + description + result.fields.append((" Биты 0x%04X" % address, description)) + labels.append(label) + result.summary = "УМП %d · GAS 167/v1%s: %s" % ( + node, " запрос" if not words else "", "; ".join(labels)) + result.fields.append((" Карта", "167/v1 выбрана вручную")) + return result From bbb4bc2b9d9cc106e894a124384d7a9801969f23 Mon Sep 17 00:00:00 2001 From: Andrey Kruchinkin Date: Mon, 12 Oct 2026 00:48:15 +0300 Subject: [PATCH 04/12] =?UTF-8?q?=D0=A3=D1=82=D0=BE=D1=87=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D1=83=20=D0=BF=D0=BB=D0=BE=D1=82=D0=BD=D1=8B=D1=85=20=D1=82?= =?UTF-8?q?=D1=80=D0=B5=D0=BD=D0=B4=D0=BE=D0=B2=20=D0=B8=20=D0=B2=D0=BE?= =?UTF-8?q?=D1=81=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D0=B8=D0=B3=D0=BD=D0=B0=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/set-protocol/include/set_plot.h | 3 +- c/set-protocol/include/set_signal.h | 1 + c/set-protocol/src/set_plot.c | 7 +++-- c/set-protocol/src/set_signal.c | 2 +- c/set-protocol/tests/fixtures/plot-v1.json | 2 +- python/set_devices/can_log_trends.py | 3 +- python/set_devices/plot_processing.py | 28 +++++++++++++++++-- python/set_devices/qt_ports/plot_dual_axis.py | 6 +++- .../set_devices/qt_ports/plot_processing.py | 6 ++-- python/set_devices/signal_reconstruction.py | 6 ++-- python/set_devices/trend_limits.py | 5 ++++ python/tests/test_plot.py | 15 ++++++++++ python/tests/test_plot_processing.py | 14 ++++++++++ python/tests/test_plot_processing_qt.py | 7 +++++ 14 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 python/set_devices/trend_limits.py diff --git a/c/set-protocol/include/set_plot.h b/c/set-protocol/include/set_plot.h index ed91f87..ded4ca3 100644 --- a/c/set-protocol/include/set_plot.h +++ b/c/set-protocol/include/set_plot.h @@ -31,7 +31,8 @@ enum set_plot_operation { PCAN_ABI_API uint32_t set_plot_abi_version(void); /** Evaluates one operation. Returns output count, or 0 for invalid arguments. * TRANSFORM rejects malformed viewports; invalid gesture values return the - * unchanged viewport. Zoom is restricted to 1..128, with focus anchoring. + * unchanged viewport. Zoom is restricted to 1..10000000 on X and 1..128 on Y, + * with focus anchoring. * Screen fractions increase downwards; set inverted=1 for the Y value axis. */ PCAN_ABI_API size_t set_plot_eval(uint32_t operation, const double *input, diff --git a/c/set-protocol/include/set_signal.h b/c/set-protocol/include/set_signal.h index 5626c97..cf2a768 100644 --- a/c/set-protocol/include/set_signal.h +++ b/c/set-protocol/include/set_signal.h @@ -13,6 +13,7 @@ extern "C" { #endif enum { SET_SIGNAL_POLYNOMIAL, SET_SIGNAL_LINEAR, SET_SIGNAL_PCHIP, SET_SIGNAL_SPLINE }; /* Caller-owned workspace: at least 14*count+128 doubles. No heap or globals. + * Bounds: 2..100000 input points, 2..1000000 output points. * Inputs may be unsorted; duplicate times are averaged. No extrapolation. * meta[0..2] = original count, unique count, RMSE at original measurements. * endpoint=1 includes the last time; 0 samples a cyclic period [first,last). diff --git a/c/set-protocol/src/set_plot.c b/c/set-protocol/src/set_plot.c index 37e17ea..2bd8b0d 100644 --- a/c/set-protocol/src/set_plot.c +++ b/c/set-protocol/src/set_plot.c @@ -7,6 +7,9 @@ #include "set_plot.h" #include +/* Allow sample-level X navigation in multi-million-point recordings. */ +#define MIN_VIEW_WIDTH (1.0 / 10000000) + static double clamp(double v, double lo, double hi) { return fmin(hi, fmax(lo, v)); } static int finite_values(const double *v, size_t n) { size_t i; @@ -23,12 +26,12 @@ size_t set_plot_eval(uint32_t op, const double *v, size_t n, double *out, size_t cap < (op == SET_PLOT_TRANSFORM || op == SET_PLOT_LIMITS ? 4U : 1U)) return 0; if (op == SET_PLOT_TRANSFORM) { double w, h, fx, fy; - if (!finite_values(v, 4) || v[2] < 1.0/128 || v[2] > 1 || + if (!finite_values(v, 4) || v[2] < MIN_VIEW_WIDTH || v[2] > 1 || v[3] < 1.0/128 || v[3] > 1 || v[0] < 0 || v[1] < 0 || v[0] + v[2] > 1.000000000001 || v[1] + v[3] > 1.000000000001) return 0; out[0] = v[0]; out[1] = v[1]; out[2] = v[2]; out[3] = v[3]; if (!finite_values(v + 4, 6) || v[4] <= 0 || v[5] <= 0) return 4; - w = clamp(v[2] / v[4], 1.0/128, 1); + w = clamp(v[2] / v[4], MIN_VIEW_WIDTH, 1); h = clamp(v[3] / v[5], 1.0/128, 1); fx = clamp(v[8], 0, 1); fy = clamp(v[9], 0, 1); out[0] = clamp(v[0] + (v[2] - w) * fx - v[6] * w, 0, 1 - w); diff --git a/c/set-protocol/src/set_signal.c b/c/set-protocol/src/set_signal.c index 45b9b7c..96a0533 100644 --- a/c/set-protocol/src/set_signal.c +++ b/c/set-protocol/src/set_signal.c @@ -40,7 +40,7 @@ int set_signal_reconstruct(const double *input_x,const double *input_y,size_t co double coef[6]={0},r[6][6]={{0}},origin,span,scale=1,rmse=0; size_t i,j,k,n=0; unsigned pass; if(!input_x||!input_y||!out_x||!out_y||!meta||!work || count<2||count>100000 - ||output_count<2||output_count>10000||work_count<14*count+128 + ||output_count<2||output_count>1000000||work_count<14*count+128 ||method<0||method>3||(endpoint!=0&&endpoint!=1)) return 1; pairs=(point *)work; x=work+2*count; y=x+count; d=y+count; h=d+count; s=h+count; q=s+count; column=q+6*count; diff --git a/c/set-protocol/tests/fixtures/plot-v1.json b/c/set-protocol/tests/fixtures/plot-v1.json index a06e11f..62ed262 100644 --- a/c/set-protocol/tests/fixtures/plot-v1.json +++ b/c/set-protocol/tests/fixtures/plot-v1.json @@ -4,7 +4,7 @@ {"name":"zoom_x_anchor","op":0,"input":[0,0,1,1,2,1,0,0,0.25,0.5],"output":[0.125,0,0.5,1]}, {"name":"zoom_y_anchor","op":0,"input":[0,0,1,1,1,4,0,0,0.5,0.75],"output":[0,0.5625,1,0.25]}, {"name":"pan_clamp","op":0,"input":[0.25,0.25,0.5,0.5,1,1,20,-20,0.5,0.5],"output":[0,0.5,0.5,0.5]}, - {"name":"zoom_limit","op":0,"input":[0,0,1,1,1000,1000,0,0,0.5,0.5],"output":[0.49609375,0.49609375,0.0078125,0.0078125]}, + {"name":"zoom_limit","op":0,"input":[0,0,1,1,1000,1000,0,0,0.5,0.5],"output":[0.4995,0.49609375,0.001,0.0078125]}, {"name":"ignore_invalid_zoom","op":0,"input":[0.25,0.25,0.5,0.5,0,1,0,0,0.5,0.5],"output":[0.25,0.25,0.5,0.5]}, {"name":"horizontal_spread","op":1,"input":[100,2,8],"output":[1]}, {"name":"vertical_contract","op":1,"input":[2,-100,8],"output":[2]}, diff --git a/python/set_devices/can_log_trends.py b/python/set_devices/can_log_trends.py index 6ba5cbc..27d752d 100644 --- a/python/set_devices/can_log_trends.py +++ b/python/set_devices/can_log_trends.py @@ -10,6 +10,7 @@ from dataclasses import dataclass from protocan.legacycan import PROJECTS, LegacyCanFormat, decode from .can485_board import BoardFrame, SdLogImport, parse_sd_log +from .trend_limits import MAX_TOTAL_POINTS @dataclass @@ -63,7 +64,7 @@ def _values(frame: BoardFrame): def read_can_log(lines, *, reference_timestamp: float, capacity: int, - max_total_points: int = 1_000_000, + max_total_points: int = MAX_TOTAL_POINTS, frame_limit: int = 100_000) -> tuple[list[CanLogChannel], SdLogImport]: imported = parse_sd_log(lines, reference_timestamp, limit=frame_limit) channels = {} diff --git a/python/set_devices/plot_processing.py b/python/set_devices/plot_processing.py index ef4fa9a..c128c39 100644 --- a/python/set_devices/plot_processing.py +++ b/python/set_devices/plot_processing.py @@ -9,11 +9,35 @@ are separate objects, never channels in the acquisition or measurement model. """ from __future__ import annotations import csv +from bisect import bisect_left, bisect_right +from operator import itemgetter from dataclasses import dataclass from datetime import datetime, timezone from .signal_reconstruction import METHODS, reconstruct +class FrozenPoints(tuple): + """Normalized immutable samples, reusable across processing requests.""" + + def __new__(cls, points): + if isinstance(points, cls): + return points + result = super().__new__(cls, ((float(x), float(y)) for x, y in points)) + result.ordered = all(result[i - 1][0] <= result[i][0] for i in range(1, len(result))) + return result + + def between(self, left, right): + if self.ordered: + start = bisect_left(self, left, key=itemgetter(0)) + stop = bisect_right(self, right, key=itemgetter(0)) + if start == 0 and stop == len(self): + return self + result = tuple.__new__(type(self), self[start:stop]) + result.ordered = True + return result + return FrozenPoints((x, y) for x, y in self if left <= x <= right) + + @dataclass(frozen=True) class Axis: label: str = "Время" @@ -36,7 +60,7 @@ class Series: def __post_init__(self): # A source may reuse mutable buffers immediately after publication. - object.__setattr__(self, "points", tuple((float(x), float(y)) for x, y in self.points)) + object.__setattr__(self, "points", FrozenPoints(self.points)) @dataclass(frozen=True) @@ -103,7 +127,7 @@ def prepare(snapshot, key, method="pchip", output_count=1000, degree=2): if snapshot.x_range is not None: left, right = snapshot.x_range selected = Series(selected.key, selected.label, - tuple((x, y) for x, y in selected.points if left <= x <= right), + selected.points.between(left, right), y_unit=selected.y_unit) return Request(selected, snapshot.axis, snapshot.source, method, output_count, degree, snapshot.x_range) diff --git a/python/set_devices/qt_ports/plot_dual_axis.py b/python/set_devices/qt_ports/plot_dual_axis.py index e1606f5..f57dfc7 100644 --- a/python/set_devices/qt_ports/plot_dual_axis.py +++ b/python/set_devices/qt_ports/plot_dual_axis.py @@ -11,6 +11,9 @@ from protocan.plot import Bounds, Viewport def small_amplitude(values, threshold=30): + extent = getattr(values, "finite_extent", None) + if extent is not None: + return max(abs(extent[0]), abs(extent[1])) <= threshold magnitude = max((abs(v) for v in values if math.isfinite(v)), default=None) return magnitude is not None and magnitude <= threshold @@ -52,7 +55,8 @@ class DualAxisPlot: for series in self._series: if series.visible and not series.discrete: groups[series.key in self.right_axis_keys].extend( - v for v in series.values if math.isfinite(v)) + getattr(series.values, "finite_extent", None) or + (v for v in series.values if math.isfinite(v))) ranges = [] for values in groups: low, high = (min(values), max(values)) if values else (0, 1) diff --git a/python/set_devices/qt_ports/plot_processing.py b/python/set_devices/qt_ports/plot_processing.py index 9fb49ca..a328bd2 100644 --- a/python/set_devices/qt_ports/plot_processing.py +++ b/python/set_devices/qt_ports/plot_processing.py @@ -21,7 +21,7 @@ except ImportError: QVBoxLayout, QWidget, ) -from set_devices.signal_reconstruction import METHODS +from set_devices.signal_reconstruction import MAX_OUTPUT_POINTS, METHODS from set_devices.plot_processing import Snapshot, prepare, process, write_csv RESULT_COLORS = ("#FF70D0", "#50D5FF", "#FFD166", "#83E377", "#B99AFF", "#FF9870") @@ -88,8 +88,8 @@ class SignalProcessingPanel(QWidget): row.addWidget(self.degree) row.addWidget(QLabel("Точек результата")) self.count = QSpinBox() - self.count.setRange(2, 10000) - self.count.setValue(1000) + self.count.setRange(2, MAX_OUTPUT_POINTS) + self.count.setValue(10000) row.addWidget(self.count) self.apply_button = QPushButton("Рассчитать") self.apply_button.clicked.connect(self.calculate) diff --git a/python/set_devices/signal_reconstruction.py b/python/set_devices/signal_reconstruction.py index 470c031..cbaadc0 100644 --- a/python/set_devices/signal_reconstruction.py +++ b/python/set_devices/signal_reconstruction.py @@ -9,6 +9,8 @@ from dataclasses import dataclass from functools import lru_cache from protocan.native import NativeProtocol +MAX_OUTPUT_POINTS = 1_000_000 + METHODS = {"polynomial": "Аппроксимация: полином МНК", "linear": "Интерполяция: линейная", "pchip": "Интерполяция: PCHIP", "spline": "Восстановление: кубический сплайн"} @@ -35,8 +37,8 @@ def library(): raise ValueError("Пересоберите SETProtocol с set_signal.c и set_wavegen.c") from error def reconstruct(points, method="pchip", output_count=1000, degree=2, *, endpoint=True, with_model=False): - if method not in METHODS or type(output_count) is not int or not 2 <= output_count <= 10000: - raise ValueError("Неизвестный метод или число выходных точек вне 2…10000") + if method not in METHODS or type(output_count) is not int or not 2 <= output_count <= MAX_OUTPUT_POINTS: + raise ValueError(f"Неизвестный метод или число выходных точек вне 2…{MAX_OUTPUT_POINTS}") count = len(points) if not 2 <= count <= 100000 or type(degree) is not int or not 1 <= degree <= 5: raise ValueError("Нужно 2…100000 исходных точек, степень 1…5") diff --git a/python/set_devices/trend_limits.py b/python/set_devices/trend_limits.py new file mode 100644 index 0000000..569d515 --- /dev/null +++ b/python/set_devices/trend_limits.py @@ -0,0 +1,5 @@ +"""Shared limits for host-side trend history buffers.""" + +DEFAULT_CAPACITY = 100_000 +MAX_CAPACITY = 5_000_000 +MAX_TOTAL_POINTS = 10_000_000 diff --git a/python/tests/test_plot.py b/python/tests/test_plot.py index 142b547..11f14f1 100644 --- a/python/tests/test_plot.py +++ b/python/tests/test_plot.py @@ -53,6 +53,21 @@ class PlotTests(unittest.TestCase): crossed = markers.move(Marker.A, 1900).move(Marker.B, 1100) self.assertEqual(-800, self.core.delta(crossed.a, crossed.b)) + def test_deep_x_zoom_preserves_anchor_and_allows_pan_and_zoom_out(self): + view = Viewport() + for _ in range(65): + view = view.transform(self.core, zoom_x=1.25, focus_x=.3) + self.assertAlmostEqual(.3, view.x + .3 * view.width) + self.assertLess(view.width * 5_000_000, 3) + moved = view.transform(self.core, pan_x=.2) + self.assertLess(moved.x, view.x) + self.assertEqual(view.width, moved.width) + expanded = moved.transform(self.core, zoom_x=.8) + self.assertGreater(expanded.width, moved.width) + limited = view.transform(self.core, zoom_x=1e10) + self.assertEqual(1e-7, limited.width) + self.assertEqual(limited, limited.transform(self.core, zoom_x=2)) + def test_invalid_numeric_inputs_do_not_escape_to_painter(self): for value in (math.nan, math.inf, -math.inf): self.assertEqual(Viewport(), Viewport().transform(self.core, zoom_x=value)) diff --git a/python/tests/test_plot_processing.py b/python/tests/test_plot_processing.py index 37cd575..ac83b7a 100644 --- a/python/tests/test_plot_processing.py +++ b/python/tests/test_plot_processing.py @@ -21,6 +21,20 @@ from set_devices.signal_reconstruction import METHODS class PlotProcessingTests(unittest.TestCase): + def test_million_output_points_for_all_methods(self): + snapshot = Snapshot([Series("a", "A", [(0, 1), (1, 3), (2, 5)])]) + for method in METHODS: + with self.subTest(method=method): + curve = process(prepare(snapshot, "a", method, 1_000_000, 1)) + self.assertEqual(1_000_000, len(curve.points)) + self.assertEqual((0., 2.), (curve.points[0][0], curve.points[-1][0])) + for x, y in curve.points[::10000]: + self.assertAlmostEqual(1 + 2 * x, y) + self.assertAlmostEqual(5., curve.points[-1][1]) + self.assertTrue(curve.pieces) + with self.assertRaises(ValueError): + process(prepare(snapshot, "a", "linear", 1_000_001)) + def test_snapshot_copies_mutable_samples_and_excludes_hidden_and_digital(self): points = [[0, 0], [1, 1]] channel = Series("a", "Analog", points) diff --git a/python/tests/test_plot_processing_qt.py b/python/tests/test_plot_processing_qt.py index b0194e8..9d3e50d 100644 --- a/python/tests/test_plot_processing_qt.py +++ b/python/tests/test_plot_processing_qt.py @@ -56,6 +56,7 @@ class ProcessingQtTests(unittest.TestCase): self.panel.method.setCurrentIndex(self.panel.method.findData(method)) self.calculate() self.assertEqual(method, self.panel.curve.request.method) + self.panel.count.setValue(self.panel.count.value() + 1) self.assertEqual(index + 1, len(self.panel.curves)) self.assertTrue(self.panel.export_button.isEnabled()) @@ -67,6 +68,12 @@ class ProcessingQtTests(unittest.TestCase): self.assertEqual((), self.panel.curves) self.assertIsNone(self.panel.curve) + def test_large_output_count_reaches_worker(self): + self.assertEqual(10000, self.panel.count.value()) + self.panel.count.setValue(1_000_000) + self.calculate() + self.assertEqual(1_000_000, len(self.panel.curve.points)) + def test_repeated_request_does_not_duplicate_curve(self): self.calculate() self.calculate() From 95c8b8ac7d3de4a67de1d3ac5a1af81896c9547f Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 12 Oct 2026 12:26:37 +0300 Subject: [PATCH 05/12] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B0=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B5=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8?= =?UTF-8?q?=20=D0=BB=D0=BE=D0=B3=D0=B3=D0=B5=D1=80=D0=B0=20=D0=A3=D0=9C?= =?UTF-8?q?=D0=9F=20v4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Разрешить 12-словные записи в запросах RTU и CAN. Распознавать статус v4 и декодировать оставшиеся сигналы с сохранением поддержки архивов v2/v3. --- c/set-protocol/src/ump_protocol.c | 3 +- python/set_devices/ump_logger.py | 99 +++++++++++----------------- python/set_devices/ump_logger_can.py | 2 +- 3 files changed, 40 insertions(+), 64 deletions(-) diff --git a/c/set-protocol/src/ump_protocol.c b/c/set-protocol/src/ump_protocol.c index 0aaf7e9..e4e3cc2 100644 --- a/c/set-protocol/src/ump_protocol.c +++ b/c/set-protocol/src/ump_protocol.c @@ -18,7 +18,8 @@ unsigned ump_validate(unsigned fn, uint16_t a, uint16_t n, int can) return can ? ((a == UMP_FIRMWARE_INFO && n == UMP_FIRMWARE_INFO_WORDS) ? 0 : 2) : ((n && n <= UMP_FIRMWARE_INFO + UMP_FIRMWARE_INFO_WORDS - a) ? 0 : 2); if (can) return ((a == UMP_BASE && n == 16) || - (a == UMP_DATA && (n == 40 || n == 80 || n == 120 || n == 42 || n == 84)) || + /* Разрешает целые 12-словные записи v4 до 120 слов; размеры v2/v3 сохраняются для прежних устройств. */ + (a == UMP_DATA && (n == 40 || n == 80 || n == 42 || n == 84 || (n && n <= 120 && !(n % 12U)))) || (a == UMP_LIVE && n == 124)) ? 0 : 2; if (!n || n > 125) return 2; return ((a >= UMP_BASE && a < UMP_BASE+16 && n <= UMP_BASE+16-a) || diff --git a/python/set_devices/ump_logger.py b/python/set_devices/ump_logger.py index def1a43..dd5e312 100644 --- a/python/set_devices/ump_logger.py +++ b/python/set_devices/ump_logger.py @@ -22,6 +22,12 @@ FAST_CAPABILITY = 0x1220 FAST_DATA = 0x2000 WORDS = 40 CAPACITY = 64000 // (2 * WORDS) +# Компактная запись v4 имеет 12 слов; старые 40/42 слова остаются поддержанными для чтения архивов. +COMPACT_WORDS = 12 +# Ёмкость 760 точек сохраняет прежнее число записей постинтервала и поведение кольцевых банков. +COMPACT_CAPACITY = 760 +# Ключи соответствуют индексам оставшихся полей v2/v3, значения — индексам этих же каналов в компактном v4. +COMPACT_INDEX = {2: 2, 3: 3, 4: 4, 5: 5, 9: 6, 24: 7, 25: 8, 40: 9, 41: 10} FIELDS = ( ('off_trigger', 'Событие отключения', 2, 8), ('post_truncated', 'Усечение постинтервала', 2, 9), @@ -33,68 +39,37 @@ FIELDS = ( ('start_out', 'Выход START_DPTB', 5, 0), ('stop_out', 'Выход STOP_DPTB', 5, 1), ('res_out', 'Выход RES_OUT_2', 5, 2), - ('impulse', 'Остаток импульса, мс', 6, None), - ('wake', 'Инициализация ЦАП, тики ЦАП', 7, None), - ('dac', 'Код ЦАП', 8, None), ('current', 'Расчётное задание тока, мА', 9, None), - ('sensor0', 'Измерение 0', 10, None), - ('sensor1', 'Измерение 1', 11, None), - ('sensor2', 'Измерение 2', 12, None), - ('sensor3', 'Измерение 3', 13, None), - ('error0', 'Ошибки 0 (маска)', 14, None), - ('error1', 'Ошибки 1 (маска)', 15, None), - ('error2', 'Ошибки 2 (маска)', 16, None), - ('error3', 'Ошибки 3 (маска)', 17, None), - ('can_header', 'CAN адрес/маска', 18, None), - ('can0', 'CAN слово 0', 19, None), - ('can1', 'CAN слово 1', 20, None), - ('can2', 'CAN слово 2', 21, None), - ('can_count', 'Количество CAN RX (mod 65536)', 22, None), - ('can_timeout', 'Таймауты CAN TX (mod 65536)', 23, None), - ('commands', 'Команды (маска)', 3, None), ('go', 'Начальная уставка, мА', 24, None), ('stop', 'Конечная уставка, мА', 25, None), - ('dac_min', 'Код калибровки 4 мА', 26, None), - ('dac_max', 'Код калибровки 20 мА', 27, None), - ('dac_cal', 'Калибровочный код ЦАП', 28, None), - ('dac04', 'DAC_04 (регистр)', 29, None), - ('dac20', 'DAC_20 (регистр)', 30, None), - ('ramp', 'Счётчик разгона', 31, None), - ('duration', 'Длительность разгона, тики ЦАП', 32, None), - ('effective_go', 'Начальная уставка после ограничений, мА', 33, None), - ('effective_stop', 'Конечная уставка после ограничений, мА', 34, None), - ('position', 'Положение разгона (kod)', 35, None), - ('adc0', 'АЦП канал 0', 36, None), - ('adc1', 'АЦП канал 1', 37, None), - ('adc2', 'АЦП канал 2', 38, None), - ('adc3', 'АЦП канал 3', 39, None), ('zpt1', 'ЗПТ1: U1 + U2 (ПМ67, рег. 306)', 40, None), ('zpt2', 'ЗПТ2: U3 + U4 (ПМ67, рег. 9)', 41, None), ) -def request(controller: int, function: int, address: int, value: int, *, record_words: int = WORDS) -> bytes: - if not 0 <= controller <= 255 or not 0 <= value <= 65535: - raise ValueError('Недопустимый адрес контроллера или значение') - if record_words not in (40, 42): - raise ValueError('Неверный размер записи логгера') - capacity = {40: 800, 42: 760}[record_words] - if function == 3: - valid = ((address == PROTECTION and value == 8) or (address == BASE and value == 16) or - (address == DATA and 1 <= value <= 120 and (value % WORDS == 0 or value in (42, 84))) or (address == LIVE and value == 124) or (address == EMU_CONTROL and value == 4) - or (address == FAST_CAPABILITY and value == 4) - or (FAST_DATA <= address < FAST_DATA + capacity * record_words - and (address - FAST_DATA) % record_words == 0 - and 1 <= value <= 120 and value % record_words == 0 - and address + value <= FAST_DATA + capacity * record_words)) - else: - valid = function == 6 and ((address == PROTECTION + 2 and value in (0, 1, 2, 3)) or - (address == PROTECTION + 3 and 1 <= value <= 60000) or - address in (BASE, BASE + 1, BASE + 2, BASE + 3) or - (address == EMU_CONTROL + 2 and value in (0, 1))) - if not valid: - raise ValueError('Недопустимый запрос логгера УМП') - return protocol.with_crc(bytes((controller, function)) + address.to_bytes(2, 'big') + value.to_bytes(2, 'big')) +def request(controller: int, function: int, address: int, value: int, *, record_words: int = WORDS) -> bytes: # Проверяет запрос с учётом ширины записи, прочитанной из статуса платы. + if not 0 <= controller <= 255 or not 0 <= value <= 65535: # Ограничивает адрес одним октетом, значение — 16-битным словом. + raise ValueError('Недопустимый адрес контроллера или значение') # Запрещает усечение входных параметров при упаковке. + if record_words not in (COMPACT_WORDS, 40, 42): # Допускает только известные компактный и прежние форматы записи. + raise ValueError('Неверный размер записи логгера') # Не позволяет строить адреса по неизвестной ширине. + capacity = {COMPACT_WORDS: COMPACT_CAPACITY, 40: 800, 42: 760}[record_words] # Выбирает реальную границу банка по формату. + if function == 3: # Разрешает только существующие диагностические блоки чтения. + valid = ((address == PROTECTION and value == 8) or (address == BASE and value == 16) # Читает полный блок защиты либо дескриптор журнала. + or (address == DATA and 1 <= value <= 120 and (value % COMPACT_WORDS == 0 or value in (40, 80, 42, 84))) # Принимает целые записи v4 и исторические блоки v2/v3. + or (address == LIVE and value == 124) or (address == EMU_CONTROL and value == 4) # Сохраняет фиксированные размеры онлайн-блока и управления эмуляцией. + or (address == FAST_CAPABILITY and value == 4) # Проверяет возможность ускоренного архивного чтения. + or (FAST_DATA <= address < FAST_DATA + capacity * record_words # Ограничивает адрес началом и концом реального банка. + and (address - FAST_DATA) % record_words == 0 # Требует начала блока на границе записи. + and 1 <= value <= 120 and value % record_words == 0 # Передаёт до 120 слов, содержащих целое число записей. + and address + value <= FAST_DATA + capacity * record_words)) # Исключает пересечение конца банка. + else: # Запись разрешена только прежним управляющим адресам. + valid = function == 6 and ((address == PROTECTION + 2 and value in (0, 1, 2, 3)) # Проверяет маску эмуляции защиты. + or (address == PROTECTION + 3 and 1 <= value <= 60000) # Проверяет тайм-аут свежести CAN в миллисекундах. + or address in (BASE, BASE + 1, BASE + 2, BASE + 3) # Оставляет команды управления журналом без запуска УМП. + or (address == EMU_CONTROL + 2 and value in (0, 1))) # Сохраняет двоичное включение эмулятора. + if not valid: # Запрещает запросы вне согласованных адресов и размеров. + raise ValueError('Недопустимый запрос логгера УМП') # Возвращает прежнее понятное сообщение вызывающему коду. + return protocol.with_crc(bytes((controller, function)) + address.to_bytes(2, 'big') + value.to_bytes(2, 'big')) # Передаёт 16-битный адрес и добавляет общий Modbus CRC. @dataclass(frozen=True) @@ -114,27 +89,27 @@ class Status: @classmethod def decode(cls, words): if (len(words) != 16 or words[0] != 0x554D or - (words[1], words[4], words[5]) not in ((2, 40, 800), (3, 42, 760))): - raise ValueError('Прошивка не поддерживает логгер УМП v2/v3') + (words[1], words[4], words[5]) not in ((2, 40, 800), (3, 42, 760), (4, COMPACT_WORDS, COMPACT_CAPACITY))): # Проверяет согласованные версию, ширину и ёмкость. + raise ValueError('Прошивка не поддерживает логгер УМП v2/v3/v4') # Перечисляет известные форматы без разрешения неизвестной прошивки. if words[9] != 6: raise ValueError('Логгер УМП доступен только на плате нагрузки dsk_LOAD') - if words[2] not in (0, 1, 2, 3) or words[3] > words[5] or not 1 <= words[6] <= 1000 or words[11] != 1000 or words[13] > words[5] or words[14] > 1000 or words[15] not in (0, 1, 3): + post_limit = max(1000, min(65535, words[5] // 10 * words[6])) if words[1] >= 3 else 1000 # Постинтервал v3/v4 занимает 10% точек; при 760 точках и 20 мс его оценка достигает 1520 мс. + if words[2] not in (0, 1, 2, 3) or words[3] > words[5] or not 1 <= words[6] <= 1000 or words[11] != 1000 or words[13] > words[5] or words[14] > post_limit or words[15] not in (0, 1, 3): raise ValueError('Повреждён статус логгера') return cls(words[2], words[3], words[6], words[10], words[11], *words[12:16], words[4], words[5]) def sample(words, frequency=1000): - if len(words) not in (40, 42) or frequency <= 0: + if len(words) not in (COMPACT_WORDS, 40, 42) or frequency <= 0: # Допускает только известную ширину записи и положительную частоту времени. raise ValueError('Неверная запись логгера') result = {'time_ms': (words[0] | words[1] << 16) * 1000 / frequency, 'event': words[2]} for key, _label, index, bit in FIELDS: - value = words[index] if index < len(words) else float('nan') + physical_index = COMPACT_INDEX[index] if len(words) == COMPACT_WORDS else index # Выбирает индекс оставшегося поля по фактической версии записи. + value = words[physical_index] if physical_index < len(words) else float('nan') # ЗПТ в старых 40-словных архивах остаётся неизвестным. if bit is not None: value = (value >> bit) & 1 - elif 10 <= index <= 13 and value >= 32768: - value -= 65536 # Физические единицы приводим здесь, одинаково для CSV и графика. - if key in ('current', 'effective_go', 'effective_stop'): + if key == 'current': # Сохранившееся задание имеет масштаб 0,1 мА; уставки и напряжения передаются целыми единицами. value /= 10.0 result[key] = value return result diff --git a/python/set_devices/ump_logger_can.py b/python/set_devices/ump_logger_can.py index 6e23c5e..01262c1 100644 --- a/python/set_devices/ump_logger_can.py +++ b/python/set_devices/ump_logger_can.py @@ -27,7 +27,7 @@ def build_request(mode, token, function, address, value): if not 1 <= token <= 255: raise ValueError('Неверный номер CAN-запроса') valid = ((function == 3 and ((address == PROTECTION and value == 8) or (address == BASE and value == 16) or - (address == DATA and value in (40, 80, 120, 42, 84)) or + (address == DATA and (value in (40, 80, 42, 84) or 0 < value <= 120 and value % 12 == 0)) or # Читает целые компактные записи и прежние архивы. (address == LIVE and value == MAX_WORDS) or (address == EMU_CONTROL and value == 4))) or (function == 6 and ((BASE <= address <= BASE+3 and 0 <= value <= 65535) or (address == PROTECTION+2 and value in (0, 1, 2, 3)) or From a5e46d46275782bdd931f97a735ece69526f12c4 Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 17 Oct 2026 14:36:14 +0300 Subject: [PATCH 06/12] =?UTF-8?q?=D0=A0=D0=B0=D1=81=D1=88=D0=B8=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BE=D0=B1=D0=BC=D0=B5=D0=BD=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D1=88=D0=B8=D0=BD=D0=B0=D0=BC,=20CAN-=D0=B0=D0=B4?= =?UTF-8?q?=D0=B0=D0=BF=D1=82=D0=B5=D1=80=D1=8B=20=D0=B8=20=D0=BE=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D1=83=20=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавить очереди операций PBUS/SBUS, общую консоль, настройки Candle и SLCAN, декодеры DSView и обработку плотных графиков. Обновить протокол Бальзам и проверки общих компонентов. --- c/candle/CMakeLists.txt | 2 +- c/candle/candle.c | 153 +++- c/candle/candle.def | 12 + c/candle/candle.h | 7 + c/candle/candle_ctrl_req.c | 25 +- c/candle/candle_ctrl_req.h | 2 + c/set-protocol/README.md | 10 + .../setprotocol/balsam/BalsamCanProtocol.kt | 7 +- c/set-protocol/src/balsam_can.c | 27 +- c/set-protocol/src/set_plot.c | 11 +- c/set-protocol/tests/fixtures/plot-v1.json | 2 +- python/README.md | 7 + python/examples/console_examples.py | 46 ++ python/logic_analyzer/decoders/set_can.py | 15 +- .../decoders/template_protocols.py | 63 ++ python/logic_analyzer/decoders/tms_uart.py | 29 + python/protocan/balsam.py | 55 +- python/pysetterminal/README.md | 116 +++ python/pysetterminal/bus_operations.py | 113 +++ python/pysetterminal/exchange_queue.py | 144 ++++ python/pysetterminal/mainterm.py | 2 +- python/pysetterminal/panel.py | 76 +- python/pysetterminal/pbus_panel.py | 346 +++++++++ python/pysetterminal/rawprotocol.py | 89 +-- python/pysetterminal/serialbus.py | 685 +++++++++++------- python/set_devices/background_work.py | 29 + python/set_devices/balsam_can.py | 10 +- python/set_devices/can_adapter_settings.py | 147 ++++ python/set_devices/can_monitor.py | 57 +- python/set_devices/oscilloscope.py | 39 +- python/set_devices/plot_decimation.py | 81 ++- python/set_devices/plot_envelope_index.py | 174 +++++ python/set_devices/plot_processing.py | 7 +- python/set_devices/plot_ticks.py | 10 + python/set_devices/qt_ports/CONSOLE.md | 68 ++ .../set_devices/qt_ports/can_frame_builder.py | 175 +++++ python/set_devices/qt_ports/can_monitor.py | 191 +++-- python/set_devices/qt_ports/candle_adapter.py | 191 ++++- python/set_devices/qt_ports/console.py | 180 +++++ python/set_devices/qt_ports/plot_drag.py | 6 +- python/set_devices/qt_ports/plot_dual_axis.py | 33 +- .../set_devices/qt_ports/plot_navigation.py | 3 +- python/set_devices/qt_ports/plot_workers.py | 42 +- .../qt_ports/qcustomplot_renderer.py | 21 +- python/set_devices/qt_ports/slcan_adapter.py | 212 +++++- .../qt_ports/viewport_navigation.py | 10 +- python/set_devices/tms_terminal.py | 4 +- python/tests/test_byte_work_panel.py | 37 +- python/tests/test_console.py | 77 ++ python/tests/test_plot.py | 22 +- tools/dsview/PLATES_BUSES.md | 123 ++++ tools/dsview/README.md | 54 ++ tools/dsview/build.py | 26 +- tools/dsview/decoder-panel.patch | 4 +- tools/dsview/decoders/plates_pbus/__init__.py | 2 + tools/dsview/decoders/plates_pbus/pd.py | 140 ++++ tools/dsview/decoders/plates_sbus/__init__.py | 2 + tools/dsview/decoders/plates_sbus/pd.py | 172 +++++ tools/dsview/decoders/set_can/pd.py | 129 ++-- tools/dsview/decoders/set_uart/pd.py | 29 +- tools/dsview/decoders/tms_uart/__init__.py | 1 + tools/dsview/decoders/tms_uart/pd.py | 18 + tools/dsview/install_decoders.ps1 | 47 +- tools/dsview/protocol-files.json | 17 + tools/dsview/setgui-host.patch | 6 +- tools/dsview/tests/test_decoders.py | 82 ++- tools/dsview/tests/test_install_decoders.py | 39 +- tools/dsview/tests/test_plates_buses.py | 322 ++++++++ tools/dsview/tests/test_runtime.py | 12 +- 69 files changed, 4413 insertions(+), 682 deletions(-) create mode 100644 python/examples/console_examples.py create mode 100644 python/logic_analyzer/decoders/template_protocols.py create mode 100644 python/logic_analyzer/decoders/tms_uart.py create mode 100644 python/pysetterminal/bus_operations.py create mode 100644 python/pysetterminal/exchange_queue.py create mode 100644 python/pysetterminal/pbus_panel.py create mode 100644 python/set_devices/background_work.py create mode 100644 python/set_devices/can_adapter_settings.py create mode 100644 python/set_devices/plot_envelope_index.py create mode 100644 python/set_devices/plot_ticks.py create mode 100644 python/set_devices/qt_ports/CONSOLE.md create mode 100644 python/set_devices/qt_ports/can_frame_builder.py create mode 100644 python/set_devices/qt_ports/console.py create mode 100644 python/tests/test_console.py create mode 100644 tools/dsview/PLATES_BUSES.md create mode 100644 tools/dsview/decoders/plates_pbus/__init__.py create mode 100644 tools/dsview/decoders/plates_pbus/pd.py create mode 100644 tools/dsview/decoders/plates_sbus/__init__.py create mode 100644 tools/dsview/decoders/plates_sbus/pd.py create mode 100644 tools/dsview/decoders/tms_uart/__init__.py create mode 100644 tools/dsview/decoders/tms_uart/pd.py create mode 100644 tools/dsview/protocol-files.json create mode 100644 tools/dsview/tests/test_plates_buses.py diff --git a/c/candle/CMakeLists.txt b/c/candle/CMakeLists.txt index 1b11f4a..0332f39 100644 --- a/c/candle/CMakeLists.txt +++ b/c/candle/CMakeLists.txt @@ -9,5 +9,5 @@ if(NOT WIN32) endif() add_library(candle SHARED candle.c candle_ctrl_req.c candle.def) target_compile_definitions(candle PRIVATE UNICODE _UNICODE) -target_link_libraries(candle PRIVATE setupapi winusb ole32 advapi32) +target_link_libraries(candle PRIVATE setupapi winusb ole32 advapi32 cfgmgr32) # Configuration Manager сопоставляет интерфейсы CAN и DFU по родительскому USB-узлу. target_include_directories(candle PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/c/candle/candle.c b/c/candle/candle.c index afba292..40ce0ff 100644 --- a/c/candle/candle.c +++ b/c/candle/candle.c @@ -34,6 +34,86 @@ #include "candle_defs.h" #include "candle_ctrl_req.h" #include "ch_9.h" +#include /* Сопоставляет интерфейсы CAN и DFU по общему родительскому USB-устройству Windows. */ + +static DWORD candle_dfu_parent(const wchar_t *path, DEVINST *parent) /* Возвращает родителя интерфейса, чтобы команда не попала в другой подключённый адаптер. */ +{ /* Начало поиска физического USB-устройства по пути выбранного CAN-интерфейса. */ + HDEVINFO devices = SetupDiCreateDeviceInfoList(NULL, NULL); /* Создаёт временный набор SetupAPI без перечисления посторонних устройств. */ + if (devices == INVALID_HANDLE_VALUE) return GetLastError(); /* Сохраняет причину отказа создания набора Windows. */ + SP_DEVICE_INTERFACE_DATA iface = {0}; /* Подготавливает описание интерфейса для открытия по точному пути. */ + iface.cbSize = sizeof(iface); /* Передаёт SetupAPI размер структуры текущей разрядности процесса. */ + SP_DEVINFO_DATA info = {0}; /* Получает идентификатор узла PnP выбранного интерфейса. */ + info.cbSize = sizeof(info); /* Указывает размер структуры устройства согласно контракту SetupAPI. */ + DWORD size = 0, error = ERROR_SUCCESS; /* Хранит требуемое число байтов и итоговый код Windows. */ + if (!SetupDiOpenDeviceInterfaceW(devices, path, 0, &iface)) error = GetLastError(); /* Открывает только заданный путь, сохраняя ошибку исчезнувшего устройства. */ + if (!error) SetupDiGetDeviceInterfaceDetailW(devices, &iface, NULL, 0, &size, NULL); /* Узнаёт объём буфера переменной длины для пути USB-интерфейса. */ + PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail = size ? malloc(size) : NULL; /* Выделяет буфер только после успешного определения его размера. */ + if (!error && !detail) error = size ? ERROR_NOT_ENOUGH_MEMORY : GetLastError(); /* Отличает нехватку памяти от ошибки поиска описания. */ + if (detail) { /* Обрабатывает описание только при наличии выделенного буфера. */ + detail->cbSize = sizeof(*detail); /* Согласует размер заголовка с архитектурой Win32 или Win64. */ + if (!SetupDiGetDeviceInterfaceDetailW(devices, &iface, detail, size, NULL, &info)) error = GetLastError(); /* Получает узел интерфейса из SetupAPI. */ + else if (CM_Get_Parent(parent, info.DevInst, 0) != CR_SUCCESS) error = ERROR_NOT_FOUND; /* Получает общий родительский узел составного USB-адаптера. */ + free(detail); /* Освобождает описание после получения идентификатора родителя. */ + } /* Завершает работу с описанием интерфейса. */ + SetupDiDestroyDeviceInfoList(devices); /* Освобождает набор SetupAPI при любом результате поиска. */ + return error; /* Возвращает ноль при успехе либо причину отказа Windows. */ +} /* Завершает сопоставление интерфейса с физическим USB-устройством. */ + +uint32_t __stdcall candle_dev_enter_dfu(const wchar_t *can_path, uint8_t status[6]) /* Возвращает код Windows и шестибайтовый DFU_GETSTATUS согласно DFU 1.1. */ +{ /* Начало отдельного сеанса управляющего интерфейса обновления. */ + if (!can_path || !status) return ERROR_INVALID_PARAMETER; /* Запрещает отсутствие точного пути адаптера или выходного буфера статуса. */ + memset(status, 0, 6); /* Исключает использование неинициализированных полей ответа при ошибке USB. */ + DEVINST wanted_parent = 0; /* Запоминает физический адаптер, выбранный пользователем до остановки CAN. */ + DWORD error = candle_dfu_parent(can_path, &wanted_parent); /* Ищет родителя по сохранённому пути CAN, не заменяя его первым найденным устройством. */ + if (error) return error; /* Прерывает переход, если выбранный адаптер уже исчез из PnP. */ + GUID guid = {0xc25b4308, 0x04d3, 0x11e6, {0xb3, 0xea, 0x60, 0x57, 0x18, 0x9e, 0x64, 0x43}}; /* GUID интерфейса обновления из дескриптора CANable 2.5. */ + HDEVINFO devices = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); /* Перечисляет только подключённые интерфейсы обновления CANable 2.5. */ + if (devices == INVALID_HANDLE_VALUE) return GetLastError(); /* Возвращает отказ SetupAPI без попытки послать команду. */ + error = ERROR_NOT_FOUND; /* Отсутствие интерфейса обновления не считается успешным входом в DFU. */ + for (DWORD index = 0; ; ++index) { /* Проверяет интерфейсы до точного совпадения физического устройства. */ + SP_DEVICE_INTERFACE_DATA iface = {0}; /* Создаёт независимое описание очередного DFU-интерфейса. */ + iface.cbSize = sizeof(iface); /* Задаёт обязательный размер структуры SetupAPI. */ + if (!SetupDiEnumDeviceInterfaces(devices, NULL, &guid, index, &iface)) { /* Завершает обход либо сообщает ошибку перечисления. */ + if (GetLastError() != ERROR_NO_MORE_ITEMS) error = GetLastError(); /* Отличает штатный конец списка от отказа Windows. */ + break; /* Выходит из обхода после исчерпания интерфейсов или ошибки. */ + } /* Завершает проверку результата перечисления. */ + DWORD size = 0; /* Хранит размер описания очередного интерфейса в байтах. */ + SetupDiGetDeviceInterfaceDetailW(devices, &iface, NULL, 0, &size, NULL); /* Определяет буфер для полного пути интерфейса обновления. */ + if (!size) { error = GetLastError(); break; } /* Не продолжает работу с неполным результатом SetupAPI. */ + PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail = malloc(size); /* Выделяет описание с достаточным местом для USB-пути. */ + if (!detail) { error = ERROR_NOT_ENOUGH_MEMORY; break; } /* Не допускает обращения к отсутствующему буферу. */ + detail->cbSize = sizeof(*detail); /* Сохраняет ABI описания интерфейса Windows. */ + if (!SetupDiGetDeviceInterfaceDetailW(devices, &iface, detail, size, NULL, NULL)) { /* Получает путь, который можно передать CreateFileW. */ + error = GetLastError(); free(detail); break; /* Сохраняет ошибку и освобождает буфер перед выходом. */ + } /* Завершает чтение пути интерфейса. */ + DEVINST parent = 0; /* Хранит родителя текущего кандидата на обновление. */ + if (candle_dfu_parent(detail->DevicePath, &parent) || parent != wanted_parent) { /* Исключает каждый интерфейс другого физического адаптера. */ + free(detail); continue; /* Освобождает описание неподходящего кандидата и продолжает поиск. */ + } /* Завершает проверку принадлежности выбранному USB-адаптеру. */ + HANDLE file = CreateFileW(detail->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); /* Эксклюзивно открывает интерфейс обновления выбранного устройства для WinUSB. */ + free(detail); /* Путь больше не нужен после открытия системного дескриптора. */ + if (file == INVALID_HANDLE_VALUE) { error = GetLastError(); break; } /* Не скрывает отсутствие доступа или занятость интерфейса. */ + WINUSB_INTERFACE_HANDLE usb = NULL; /* Хранит отдельный WinUSB-сеанс интерфейса обновления без CAN bulk endpoint. */ + error = ERROR_SUCCESS; /* Сбрасывает исходное отсутствие интерфейса после точного совпадения устройства. */ + if (!WinUsb_Initialize(file, &usb)) error = GetLastError(); /* Проверяет наличие рабочего WinUSB-драйвера DFU runtime. */ + USB_INTERFACE_DESCRIPTOR descriptor = {0}; /* Получает реальный номер и класс открытого интерфейса. */ + if (!error && !WinUsb_QueryInterfaceSettings(usb, 0, &descriptor)) error = GetLastError(); /* Не предполагает, что произвольный WinUSB-интерфейс поддерживает DFU. */ + if (!error && (descriptor.bInterfaceClass != 0xFE || descriptor.bInterfaceSubClass != 1 || descriptor.bInterfaceProtocol != 1)) error = ERROR_NOT_SUPPORTED; /* Проверяет класс приложения, подкласс DFU и runtime-протокол по DFU 1.1. */ + ULONG timeout = 500, transferred = 0; /* Ограничивает управляющий USB-запрос 500 миллисекундами и учитывает длину ответа. */ + if (!error && !WinUsb_SetPipePolicy(usb, 0, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout)) error = GetLastError(); /* Устанавливает тайм-аут endpoint 0, чтобы отсутствующий ответ не блокировал программу. */ + WINUSB_SETUP_PACKET packet = {0}; /* Обнуляет поля USB SETUP перед запросом перехода в загрузчик. */ + packet.RequestType = 0x21; packet.Request = 0; packet.Value = 1000; packet.Index = descriptor.bInterfaceNumber; /* DFU_DETACH: class/interface OUT, запрос 0, ожидаемое время отключения 1000 мс. */ + if (!error && !WinUsb_ControlTransfer(usb, packet, NULL, 0, &transferred, NULL)) error = GetLastError(); /* Отправляет DETACH и требует подтверждённой USB-транзакции. */ + packet.RequestType = 0xA1; packet.Request = 3; packet.Value = 0; packet.Length = 6; /* DFU_GETSTATUS: class/interface IN, запрос 3, ответ ровно 6 байт по DFU 1.1. */ + if (!error && !WinUsb_ControlTransfer(usb, packet, status, 6, &transferred, NULL)) error = GetLastError(); /* Проверяет результат до отложенного перехода прошивки через 300 мс. */ + if (!error && transferred != 6) error = ERROR_INVALID_DATA; /* Не трактует укороченный ответ как подтверждение входа в загрузчик. */ + if (usb) WinUsb_Free(usb); /* Освобождает WinUSB до появления загрузчика с другим VID/PID. */ + CloseHandle(file); /* Освобождает файловый дескриптор после успеха и при любой ошибке USB. */ + break; /* Не отправляет DETACH повторно и не переключается на другой адаптер при отказе. */ + } /* Завершает поиск и обработку единственного выбранного адаптера. */ + SetupDiDestroyDeviceInfoList(devices); /* Освобождает перечень интерфейсов при любом результате. */ + return error; /* Статус прошивки возвращается отдельно от системной ошибки USB. */ +} /* Завершает управление DFU runtime без записи flash или изменения образа. */ static bool candle_dev_interal_open(candle_handle hdev); @@ -656,6 +736,30 @@ bool __stdcall DLL candle_dev_open(candle_handle hdev) } +bool __stdcall DLL candle_dev_get_product(candle_handle hdev, wchar_t *product, uint32_t capacity) /* Читает USB Product String открытого адаптера в буфер UTF-16; capacity измеряется в wchar_t, включая завершающий ноль. */ +{ /* Начало чтения отображаемого имени без изменения режима CAN. */ + if (!product || !capacity) return false; /* Не пишет в отсутствующий либо пустой выходной буфер. */ + product[0] = 0; /* Сохраняет пустую строку при любом отказе чтения дескриптора. */ + candle_device_t *dev = (candle_device_t*)hdev; /* Получает уже открытый WinUSB-сеанс выбранного физического адаптера. */ + if (!dev || !dev->winUSBHandle) return false; /* Не открывает устройство заново и не обращается к закрытому интерфейсу. */ + USB_DEVICE_DESCRIPTOR descriptor = {0}; /* Получает индекс строки продукта из стандартного дескриптора устройства. */ + ULONG received = 0; /* Хранит фактически полученное количество байтов управляющего ответа. */ + if (!WinUsb_GetDescriptor(dev->winUSBHandle, 1, 0, 0, (PUCHAR)&descriptor, sizeof(descriptor), &received) || received != sizeof(descriptor)) return false; /* Тип 1 обозначает Device Descriptor по USB 2.0; неполный ответ не используется. */ + UCHAR string_index = descriptor.iProduct; /* Для обычных адаптеров использует объявленный устройством индекс USB Product String. */ + if (descriptor.idVendor == 0x1D50 && descriptor.idProduct == 0x606F) string_index = 2; /* В CANable Candlelight имя продукта имеет индекс 2; WinUSB может подменять iProduct индексом имени интерфейса, как описано в штатном примере проекта. */ + if (!string_index) return false; /* Нулевой iProduct означает, что устройство не предоставляет имя продукта. */ + UCHAR raw[256] = {0}; /* Буфер вмещает строковый дескриптор USB, чей однобайтовый bLength ограничен 255 байтами. */ + USHORT language = 0x0409; /* Использует английский идентификатор USB как резервный вариант для устройств без списка языков. */ + if (WinUsb_GetDescriptor(dev->winUSBHandle, 3, 0, 0, raw, sizeof(raw), &received) && received >= 4 && raw[0] >= 4 && raw[1] == 3) language = (USHORT)(raw[2] | ((USHORT)raw[3] << 8)); /* Тип 3 и индекс 0 возвращают список LANGID; выбирает первый язык, предоставленный адаптером. */ + if (!WinUsb_GetDescriptor(dev->winUSBHandle, 3, string_index, language, raw, sizeof(raw), &received)) return false; /* Читает именно строку продукта на поддерживаемом устройством языке. */ + if (received < 2 || raw[1] != 3 || raw[0] < 2 || raw[0] > received || (raw[0] & 1)) return false; /* Проверяет тип, размер и чётное число байтов UTF-16 перед копированием в выходной буфер. */ + uint32_t count = (raw[0] - 2) / 2; /* Исключает двухбайтовый заголовок и переводит длину UTF-16LE из байтов в число кодовых единиц. */ + if (count >= capacity) return false; /* Не обрезает индивидуальный номер в конце имени и оставляет место для завершающего нуля. */ + for (uint32_t index = 0; index < count; ++index) product[index] = (wchar_t)(raw[2 + index * 2] | ((USHORT)raw[3 + index * 2] << 8)); /* Явно собирает кодовые единицы UTF-16LE без предположений о выравнивании массива байтов. */ + product[count] = 0; /* Завершает строку для безопасного чтения через ctypes и отображения в Qt. */ + return count > 0; /* Пустое имя оставляет интерфейсу стандартную резервную подпись адаптера. */ +} /* Завершает получение настоящего имени из прошивки USB-адаптера. */ + bool __stdcall DLL candle_dev_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us) { return candle_ctrl_get_timestamp(hdev, timestamp_us); @@ -823,6 +927,38 @@ bool __stdcall DLL candle_channel_stop(candle_handle hdev, uint8_t ch) return candle_ctrl_set_device_mode(dev, ch, CANDLE_DEVMODE_RESET, 0); } +bool __stdcall DLL candle_channel_start_configured(candle_handle hdev, uint8_t ch, uint32_t flags) /* Новый вход сохраняет прежний ABI start и позволяет отключать HW_TIMESTAMP. */ +{ /* Явно выбранные Python-флаги должны попасть в прошивку без автоматического дополнения. */ + return candle_ctrl_set_device_mode((candle_device_t*)hdev, ch, CANDLE_DEVMODE_START, flags); /* Передаём точную маску после проверки возможностей на уровне транспорта. */ +} /* Завершение запуска с явно заданными параметрами. */ + +bool __stdcall DLL candle_channel_get_data_capabilities(candle_handle hdev, uint8_t ch, candle_capability_t *cap) /* Экспортируем чтение FD-пределов для расчёта тайминга на любой частоте CAN. */ +{ /* Общая форма capability позволяет повторно использовать валидатор номинального тайминга. */ + return candle_ctrl_data_capability((candle_device_t*)hdev, ch, cap); /* USB-запрос возвращает реальные пределы выбранного канала. */ +} /* Завершение получения возможностей быстрой фазы. */ + +bool __stdcall DLL candle_channel_set_termination(candle_handle hdev, uint8_t ch, uint32_t state) /* Значения 0 и 1 соответствуют OFF и ON стандарта gs_usb. */ +{ /* Проверка исключает отправку неопределённого состояния в прошивку. */ + return state <= 1 && candle_ctrl_termination((candle_device_t*)hdev, ch, &state, true); /* Выполняем запись только для допустимого состояния. */ +} /* Завершение переключения терминатора. */ + +bool __stdcall DLL candle_channel_get_termination(candle_handle hdev, uint8_t ch, uint32_t *state) /* Чтение состояния не меняет топологию CAN. */ +{ /* Используем тот же формат 32-битного значения, что и при записи. */ + return candle_ctrl_termination((candle_device_t*)hdev, ch, state, false); /* false выбирает USB_DIR_IN и GET_TERMINATION. */ +} /* Завершение чтения терминатора. */ + +bool __stdcall DLL candle_channel_get_diagnostics(candle_handle hdev, uint8_t ch, uint32_t *state, uint32_t *rxerr, uint32_t *txerr) /* Сохраняем счётчики, которые старый get_state отбрасывал. */ +{ /* Диагностика выполняется только для уже открытого устройства. */ + candle_device_state_t data = {0}; /* Полная структура протокола содержит три слова: состояние, RX и TX. */ + if (!candle_ctrl_get_state((candle_device_t*)hdev, ch, &data)) { /* Не возвращаем нулевые счётчики как будто запрос был успешным. */ + return false; /* Причина USB-отказа уже записана управляющим запросом. */ + } /* Дальнейшее копирование относится только к подтверждённому ответу. */ + *state = data.state; /* Сохраняем состояние Error-active, Warning, Passive, Bus-off, Stopped или Sleeping. */ + *rxerr = data.rxerr; /* Счётчик ошибок приёма измеряется в единицах CAN-контроллера. */ + *txerr = data.txerr; /* Счётчик ошибок передачи помогает отличать отсутствие ACK от ошибок приёма. */ + return true; /* Все три выходных значения относятся к одному USB-ответу. */ +} /* Завершение расширенной диагностики канала. */ + /* Write len bytes from buf to the OUT pipe, aborting after 300 ms. * Writes are serialised by writeMutex in CandleApiInterface so dev->txEvent * is never accessed by two threads simultaneously. */ @@ -1017,14 +1153,13 @@ bool __stdcall DLL candle_fd_frame_read(candle_handle hdev, candle_fd_frame_t *f } dev->rxurbs[urb_num].pending = false; - /* Minimum: classic CAN header (12 bytes) + at least 8 data bytes = 20 bytes */ - static const DWORD classic_min = sizeof(candle_frame_t) - 4; - if (bytes_transfered < classic_min) { + const DWORD header_size = 12; /* Заголовок gs_usb занимает 12 байт в Classic и FD; короткий FD может не содержать восьми байтов данных. */ + if (bytes_transfered < header_size) { /* До чтения flags и DLC проверяем наличие полного заголовка. */ candle_prepare_read(dev, urb_num); candle_logf(L"fd read too small urb=%u bytes=%lu min=%lu", urb_num, bytes_transfered, - classic_min); + header_size); /* Минимальная длина здесь относится к заголовку, а payload проверяется после определения формата. */ dev->last_error = CANDLE_ERR_READ_SIZE; return false; } @@ -1047,6 +1182,11 @@ bool __stdcall DLL candle_fd_frame_read(candle_handle hdev, candle_fd_frame_t *f if (is_fd_frame) { /* can_dlc is at byte offset 8 in both classic and FD wire frames. */ const uint8_t raw_dlc = dev->rxurbs[urb_num].buf[8]; + if (raw_dlc > 15) { /* FD DLC является четырёхбитным кодом и не может содержать значения выше 15. */ + candle_prepare_read(dev, urb_num); /* Повреждённый USB-пакет не должен останавливать последующий приём. */ + dev->last_error = CANDLE_ERR_READ_SIZE; /* Неверный DLC считается ошибкой формата входного кадра. */ + return false; /* Не превращаем повреждённый DLC в пустой успешный FD-кадр. */ + } /* Далее длина безопасно вычисляется по таблице CAN FD. */ const DWORD data_len = candle_dlc_to_len(raw_dlc); const DWORD min_size = 12 + data_len; /* header + data, without timestamp */ @@ -1077,6 +1217,11 @@ bool __stdcall DLL candle_fd_frame_read(candle_handle hdev, candle_fd_frame_t *f } /* else: timestamp stays zero from memset above */ } else { + if (bytes_transfered < sizeof(candle_frame_t) - sizeof(uint32_t)) { /* Classic-пакет обязан содержать весь восьмибайтовый буфер данных, даже при меньшем DLC. */ + candle_prepare_read(dev, urb_num); /* Возобновляем соответствующий URB после отклонения неполного пакета. */ + dev->last_error = CANDLE_ERR_READ_SIZE; /* Не допускаем чтение неполученных данных из локальной структуры. */ + return false; /* Повреждённый Classic-пакет не попадает в Python через FD API. */ + } /* Минимальный размер Classic теперь проверен отдельно от коротких FD. */ /* Classic CAN frame — copy into FD struct, fixing the timestamp position */ candle_frame_t classic; DWORD copy_len = (bytes_transfered < sizeof(classic)) ? bytes_transfered : sizeof(classic); diff --git a/c/candle/candle.def b/c/candle/candle.def index e4321b6..19434bf 100644 --- a/c/candle/candle.def +++ b/c/candle/candle.def @@ -3,6 +3,8 @@ ; прикладные регистры SETProtocol. EXPORTS + candle_dev_get_product ; Имя продукта из USB-дескриптора прошивки для списка адаптеров SETGUI. + candle_dev_enter_dfu ; Переход через отдельный DFU runtime-интерфейс того же физического USB-адаптера. candle_list_scan candle_list_free candle_list_length @@ -31,3 +33,13 @@ EXPORTS candle_frame_data candle_frame_timestamp_us candle_dev_last_error + candle_channel_start_configured ; Точная маска запуска с управляемыми аппаратными метками. + candle_channel_get_data_capabilities ; Пределы тайминга быстрой фазы CAN FD. + candle_channel_set_termination ; Переключение встроенного терминатора. + candle_channel_get_termination ; Чтение состояния встроенного терминатора. + candle_channel_get_diagnostics ; Состояние и счётчики ошибок CAN. + candle_channel_set_data_timing ; Тайминг фазы данных CAN FD. + candle_fd_frame_send ; Отправка полного кадра CAN FD до 64 байт. + candle_fd_frame_read ; Приём FD и Classic без обрезания данных. + candle_fd_frame_type ; Различение RX, TX echo и ошибок FD. + candle_fd_frame_id ; Получение CAN ID из структуры FD. diff --git a/c/candle/candle.h b/c/candle/candle.h index 9f063d4..3c96e9e 100644 --- a/c/candle/candle.h +++ b/c/candle/candle.h @@ -246,7 +246,9 @@ bool __stdcall DLL candle_list_length(candle_list_handle list, uint8_t *len); bool __stdcall DLL candle_dev_get(candle_list_handle list, uint8_t dev_num, candle_handle *hdev); bool __stdcall DLL candle_dev_get_state(candle_handle hdev, candle_devstate_t *state); wchar_t * __stdcall DLL candle_dev_get_path(candle_handle hdev); +bool __stdcall DLL candle_dev_get_product(candle_handle hdev, wchar_t *product, uint32_t capacity); /* Возвращает USB Product String в UTF-16; capacity включает завершающий ноль и измеряется в wchar_t. */ bool __stdcall DLL candle_dev_open(candle_handle hdev); +uint32_t __stdcall DLL candle_dev_enter_dfu(const wchar_t *can_path, uint8_t status[6]); /* Переводит выбранный физический адаптер в DFU и возвращает Win32-код плюс ответ DFU_GETSTATUS. */ bool __stdcall DLL candle_dev_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us); bool __stdcall DLL candle_dev_close(candle_handle hdev); bool __stdcall DLL candle_dev_free(candle_handle hdev); @@ -259,6 +261,11 @@ bool __stdcall DLL candle_channel_set_timing(candle_handle hdev, uint8_t ch, can bool __stdcall DLL candle_channel_set_bitrate(candle_handle hdev, uint8_t ch, uint32_t bitrate); bool __stdcall DLL candle_channel_start(candle_handle hdev, uint8_t ch, uint32_t flags); bool __stdcall DLL candle_channel_stop(candle_handle hdev, uint8_t ch); +bool __stdcall DLL candle_channel_start_configured(candle_handle hdev, uint8_t ch, uint32_t flags); /* Запускаем с точной маской без принудительного включения аппаратных меток. */ +bool __stdcall DLL candle_channel_get_data_capabilities(candle_handle hdev, uint8_t ch, candle_capability_t *cap); /* Возвращаем пределы тайминга быстрой фазы FD. */ +bool __stdcall DLL candle_channel_set_termination(candle_handle hdev, uint8_t ch, uint32_t state); /* Состояние терминатора: 0 — выключен, 1 — включён. */ +bool __stdcall DLL candle_channel_get_termination(candle_handle hdev, uint8_t ch, uint32_t *state); /* Чтение не меняет подключение встроенного резистора. */ +bool __stdcall DLL candle_channel_get_diagnostics(candle_handle hdev, uint8_t ch, uint32_t *state, uint32_t *rxerr, uint32_t *txerr); /* Передаём состояние CAN и оба счётчика ошибок без потери данных ответа. */ bool __stdcall DLL candle_frame_send(candle_handle hdev, uint8_t ch, candle_frame_t *frame); bool __stdcall DLL candle_frame_read(candle_handle hdev, candle_frame_t *frame, uint32_t timeout_ms); diff --git a/c/candle/candle_ctrl_req.c b/c/candle/candle_ctrl_req.c index 1bbfe41..47484e4 100644 --- a/c/candle/candle_ctrl_req.c +++ b/c/candle/candle_ctrl_req.c @@ -39,8 +39,10 @@ enum { CANDLE_TIMESTAMP_GET = 6, /* 7: IDENTIFY, 8: GET_USER_ID, 9: SET_USER_ID (not used here) */ CANDLE_BREQ_DATA_BITTIMING = 10, - /* 11: SET_TERMINATION, not used here */ - CANDLE_BREQ_GET_STATE = 12, + CANDLE_BREQ_BT_CONST_EXT = 11, /* Расширенные пределы номинальной и быстрой фазы согласно gs_usb. */ + CANDLE_BREQ_SET_TERMINATION = 12, /* Запрос gs_usb 12 переключает встроенный резистор окончания шины. */ + CANDLE_BREQ_GET_TERMINATION = 13, /* Запрос gs_usb 13 читает текущее состояние терминатора. */ + CANDLE_BREQ_GET_STATE = 14, /* Стандартный GET_STATE имеет номер 14; номер 12 принадлежит терминатору. */ CANDLE_BREQ_BUS_OFF_RECOVERY = 32, }; @@ -237,3 +239,22 @@ bool candle_ctrl_bus_off_recover(candle_device_t *dev, uint8_t channel) dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_SET_DEVICE_MODE; return rc; } + +bool candle_ctrl_data_capability(candle_device_t *dev, uint8_t channel, candle_capability_t *cap) /* Структура gs_usb BT_CONST_EXT содержит десять общих и восемь быстрых полей uint32. */ +{ /* Используем массив, поскольку протокол содержит только однородные 32-битные значения без отступов. */ + uint32_t fields[18] = {0}; /* 18 полей по 4 байта образуют стандартный ответ размером 72 байта. */ + bool rc = usb_control_msg(dev->winUSBHandle, CANDLE_BREQ_BT_CONST_EXT, USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, channel, 0, fields, sizeof(fields)); /* Запрашиваем пределы именно выбранного CAN-канала. */ + if (rc) { /* Выходная структура должна меняться только после успешного USB-ответа. */ + memcpy(cap, fields, 2 * sizeof(uint32_t)); /* Маска функций и частота CAN общие для обеих фаз. */ + memcpy(&cap->tseg1_min, &fields[10], 8 * sizeof(uint32_t)); /* Поля DTSEG1…DBRP_INC заменяют номинальные пределы структуры capability. */ + } /* При отказе вызывающий код получит false и не использует нулевые пределы. */ + dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_GET_BITTIMING_CONST; /* Сохраняем диагностический код чтения аппаратных ограничений. */ + return rc; /* Успех означает наличие полной структуры пределов быстрой фазы. */ +} /* Завершение запроса расширенных возможностей FD. */ + +bool candle_ctrl_termination(candle_device_t *dev, uint8_t channel, uint32_t *state, bool write) /* Переключение терминатора использует стандартные SET=12 и GET=13. */ +{ /* Состояние передаётся одним 32-битным словом согласно протоколу gs_usb. */ + bool rc = usb_control_msg(dev->winUSBHandle, write ? CANDLE_BREQ_SET_TERMINATION : CANDLE_BREQ_GET_TERMINATION, (write ? USB_DIR_OUT : USB_DIR_IN)|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, channel, 0, state, sizeof(*state)); /* Номер CAN-канала передаётся в wValue, а wIndex равен нулю по спецификации. */ + dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_SET_DEVICE_MODE; /* Ошибка настройки доступна Python через candle_dev_last_error. */ + return rc; /* Не выдаём успешное переключение при отказе USB-контроллера. */ +} /* Завершение управления встроенным окончанием шины. */ diff --git a/c/candle/candle_ctrl_req.h b/c/candle/candle_ctrl_req.h index 2ba23d6..97761b6 100644 --- a/c/candle/candle_ctrl_req.h +++ b/c/candle/candle_ctrl_req.h @@ -51,4 +51,6 @@ bool candle_ctrl_set_data_bittiming(candle_device_t *dev, uint8_t channel, candl bool candle_ctrl_get_timestamp(candle_device_t *dev, uint32_t *current_timestamp); bool candle_ctrl_get_state(candle_device_t *dev, uint8_t channel, candle_device_state_t *data); bool candle_ctrl_bus_off_recover(candle_device_t *dev, uint8_t channel); +bool candle_ctrl_data_capability(candle_device_t *dev, uint8_t channel, candle_capability_t *cap); /* Читаем пределы быстрой фазы CAN FD отдельным запросом расширенной структуры. */ +bool candle_ctrl_termination(candle_device_t *dev, uint8_t channel, uint32_t *state, bool write); /* Передаём состояние терминатора: 0 — выключен, 1 — включён. */ diff --git a/c/set-protocol/README.md b/c/set-protocol/README.md index 170cc1b..81dfaf2 100644 --- a/c/set-protocol/README.md +++ b/c/set-protocol/README.md @@ -6,6 +6,16 @@ `include/balsam167_eeprom_layout.h`; PEEK, CRC и порядок байтов реализованы в `src/periph28335.c`. Проверка полного диапазона — `test_periph28335_eeprom`. +Декодер `balsam_can` знает служебные слова heartbeat периферии Бальзам-167: +`0x0100` — счётчик секунд по модулю 65536, `0x0101` — аппаратный Mode, +`0x0102` — код типа платы Desk. Назначения соответствуют `CAN_HEARTBEAT_ADDR` +и ветке `CAN_send` в `Balsam_167_periph/Source/Internal/ecan.c`. +Python-адаптер `set_devices.balsam_can` выделяет ответ с адресом `0x0100` +и маской `111` как `BALZAM Heartbeat`, сохраняя исходные регистры и маршрут. +Пример: `0x00BA0017`, `00 08 00 04 E1 00 00 5A` — heartbeat задатчика, +90 секунд, Mode=8, Desk=4. Счётчик отображается без знака, в том числе +при значениях `0x8000–0xFFFF`; обычные технологические int16 сохраняют знак. + Универсальные сервисы эмуляторов: [адресное пространство, API и порт новой платы](docs/EMULATOR_SERVICES.md). `set_regmap` объединяет УМП, 2812, IGBT и DAC за общим API для RTU, CAN и других оболочек. diff --git a/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/balsam/BalsamCanProtocol.kt b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/balsam/BalsamCanProtocol.kt index 2d9a488..61e1ef2 100644 --- a/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/balsam/BalsamCanProtocol.kt +++ b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/balsam/BalsamCanProtocol.kt @@ -152,14 +152,17 @@ object BalsamCanProtocol { fun deviceName(device: Int): String = if (NativeSetProtocol.available) { NativeSetProtocol.nativeBalsamDeviceName(device) } else listOf( - "Трансформатор 1", "Трансформатор 2", "Силовой блок 1", "Силовой блок 2", - "УМП 1", "УМП 2", "Двигатель", "ВЭП", "Задатчик", "Узел 10", "Узел 11", + "Трансформатор 1", "Трансформатор 2", "Силовой 1", "Силовой 2", // Имена узлов 1..4 повторяют таблицу адресов 167 и общее C-ядро. + "УМП 1", "УМП 2", "Двигатель", "Задатчик", "ВЭП", "ПМУ", "Узел 11", // Узлы 5..10 соответствуют таблице, включая ПМУ на паре 0xBA0009/0xBA0019; узел 11 остаётся служебным. "Узел 12", "Терминал", ).getOrElse(device - 1) { "Неизвестный узел" } fun registerName(device: Int, address: Int): String = if (NativeSetProtocol.available) NativeSetProtocol.nativeBalsamRegisterName(device, address) else when { + address == 0x0100 -> "Heartbeat: счётчик, с" // CAN_HEARTBEAT_ADDR из ecan.c содержит беззнаковый секундный счётчик по модулю 65536. + address == 0x0101 -> "Heartbeat: Mode" // Второе слово служебного пакета передаёт аппаратный номер Mode платы. + address == 0x0102 -> "Heartbeat: тип платы (Desk)" // Третье слово передаёт Desk, чтобы Android без JNI использовал названия общего C-ядра. device in 1..2 && address in 0x18..0x2B -> "Показания T° ${address - 0x17}" device in 3..4 && address in 0x18..0x27 -> "Показания T° ${address - 0x17}" device == 7 && address in 0x18..0x1F -> "Показания T° ${address - 0x17}" diff --git a/c/set-protocol/src/balsam_can.c b/c/set-protocol/src/balsam_can.c index a8644bd..0e46c42 100644 --- a/c/set-protocol/src/balsam_can.c +++ b/c/set-protocol/src/balsam_can.c @@ -61,7 +61,7 @@ int balsam_can_decode(uint32_t can_id, const uint8_t *data, size_t size, relative = can_id - BALSAM_CAN_BASE_ID; output->direction = relative >= BALSAM_CAN_DATA_OFFSET ? BALSAM_CAN_FROM_NODE : BALSAM_CAN_TO_NODE; - output->device = (uint8_t)((relative & 0x0FU) + 1U); + output->device = (uint8_t)((relative & 0x0FU) + 1U); /* В ecan.c перед сборкой CAN ID выполняется DevNum--; маска 0x0F выделяет индекс 0..12, а +1 восстанавливает номер Mode. */ if (can_id == 0x00745009UL || can_id == 0x00745019UL) { output->device = 10U; output->direction = can_id == 0x00745019UL @@ -80,9 +80,9 @@ int balsam_can_decode(uint32_t can_id, const uint8_t *data, size_t size, const char *balsam_can_device_name(uint8_t device) { static const char *const names[BALSAM_CAN_NODE_COUNT] = { - "Трансформатор 1", "Трансформатор 2", "Силовой блок 1", - "Силовой блок 2", "УМП 1", "УМП 2", "Двигатель", "ВЭП", - "Задатчик", "Пульт (МПУ)", "Узел 11", "Узел 12", "Терминал" + "Трансформатор 1", "Трансформатор 2", "Силовой 1", /* Первые три узла соответствуют строкам 1..3 предоставленной таблицы адресов 167. */ + "Силовой 2", "УМП 1", "УМП 2", "Двигатель", "Задатчик", /* Строки 4..8 таблицы; VPU1_CAN_DEVICE=8 соответствует задатчику, а не ВЭП. */ + "ВЭП", "ПМУ", "Узел 11", "Узел 12", "Терминал" /* Строка 9 — ВЭП, пара 0xBA0009/0xBA0019 — ПМУ; служебные узлы 11..13 сохраняют прежние назначения. */ }; return (device >= 1U && device <= BALSAM_CAN_NODE_COUNT) ? names[device - 1U] : "Неизвестный узел"; @@ -91,6 +91,13 @@ const char *balsam_can_device_name(uint8_t device) size_t balsam_can_register_name(uint8_t device, uint16_t address, char *output, size_t output_size) { + if (address == 0x0100U) /* CAN_HEARTBEAT_ADDR в ecan.c периферии 167 задаёт служебный адрес вне технологической карты R0..R127. */ + return copy_name("Heartbeat: счётчик, с", output, output_size); /* Первое слово hiword содержит секунды после запуска по модулю 65536. */ + if (address == 0x0101U) /* Следующее слово heartbeat соответствует старшим 16 битам loword в CAN_send. */ + return copy_name("Heartbeat: Mode", output, output_size); /* Прошивка передаёт аппаратный Mode без уменьшения на единицу, применяемого только к CAN ID. */ + if (address == 0x0102U) /* Третье слово heartbeat соответствует младшим 16 битам loword. */ + return copy_name("Heartbeat: тип платы (Desk)", output, output_size); /* Значение Desk задаёт тип платы и отличается от номера Mode и номера CAN-узла. */ + if ((device == 1U || device == 2U) && address < 20U) return indexed_name("Диагностика T°", address + 1U, output, output_size); if ((device == 1U || device == 2U) && address >= 0x18U && address <= 0x2BU) @@ -139,7 +146,7 @@ size_t balsam_can_register_name(uint8_t device, uint16_t address, if (device == 7U && address >= 0x18U && address <= 0x1FU) return indexed_name("Показания T°", address - 0x17U, output, output_size); - if (device == 8U) { + if (device == 9U) { /* Карта напряжений принадлежит ВЭП с adr_SHKF=9; задатчик с номером 8 использует другую карту. */ static const char *const vep_names[] = { "Диагностика 380В Ф1", "Диагностика 380В Ф2", "Диагностика 31В Ф1", "Диагностика 31В Ф2", @@ -164,15 +171,15 @@ size_t balsam_can_register_name(uint8_t device, uint16_t address, return copy_name("Дискретные датчики (14 бит)", output, output_size); } - if (device == 9U && address == 0U) + if (device == 8U && address == 0U) /* У VPU1_CAN_DEVICE=8 слово 0 передаёт обороты ГЭД, а не диагностику ВЭП. */ return copy_name("Обороты ГЭД, об/мин", output, output_size); - if (device == 9U && address == 1U) + if (device == 8U && address == 1U) /* Слово 1 той же платы задатчика содержит обороты гребного вала. */ return copy_name("Обороты ГВ, об/мин", output, output_size); - if (device == 9U && address == 2U) + if (device == 8U && address == 2U) /* ADR_CAN_LAMPS_ON_VPU=2 задаёт регистр первой группы ламп задатчика. */ return copy_name("Лампы (8 бит)", output, output_size); - if (device == 9U && address == 3U) + if (device == 8U && address == 3U) /* ADR_CAN_LAMPS_2_ON_VPU=3 задаёт регистр второй группы индикаторов задатчика. */ return copy_name("Диоды (16 бит)", output, output_size); - if (device == 9U && address == 0x10U) + if (device == 8U && address == 0x10U) /* ADR_CAN_KEY_ON_VPU=16, то есть 0x10, задаёт слово кнопок VPU; адрес не перенумеровывается. */ return copy_name("Кнопки (12 бит)", output, output_size); if (address == 0x16U) diff --git a/c/set-protocol/src/set_plot.c b/c/set-protocol/src/set_plot.c index 2bd8b0d..3516186 100644 --- a/c/set-protocol/src/set_plot.c +++ b/c/set-protocol/src/set_plot.c @@ -7,8 +7,7 @@ #include "set_plot.h" #include -/* Allow sample-level X navigation in multi-million-point recordings. */ -#define MIN_VIEW_WIDTH (1.0 / 10000000) +#define MIN_VIEW_SPAN 1e-12 /* Минимальная безразмерная доля полного диапазона по X и Y задаёт увеличение до 10^12 раз; запас относительно точности double сохраняет различимые границы нормированной области. */ static double clamp(double v, double lo, double hi) { return fmin(hi, fmax(lo, v)); } static int finite_values(const double *v, size_t n) { @@ -26,13 +25,13 @@ size_t set_plot_eval(uint32_t op, const double *v, size_t n, double *out, size_t cap < (op == SET_PLOT_TRANSFORM || op == SET_PLOT_LIMITS ? 4U : 1U)) return 0; if (op == SET_PLOT_TRANSFORM) { double w, h, fx, fy; - if (!finite_values(v, 4) || v[2] < MIN_VIEW_WIDTH || v[2] > 1 || - v[3] < 1.0/128 || v[3] > 1 || v[0] < 0 || v[1] < 0 || + if (!finite_values(v, 4) || v[2] < MIN_VIEW_SPAN || v[2] > 1 || /* Проверяем конечность смещений и размеров, разрешая ширину до триллионной доли исходного диапазона X. */ + v[3] < MIN_VIEW_SPAN || v[3] > 1 || v[0] < 0 || v[1] < 0 || /* Такой же предел для Y сохраняет возможность дальнейшего перемещения и увеличения уже приближённой области. */ v[0] + v[2] > 1.000000000001 || v[1] + v[3] > 1.000000000001) return 0; out[0] = v[0]; out[1] = v[1]; out[2] = v[2]; out[3] = v[3]; if (!finite_values(v + 4, 6) || v[4] <= 0 || v[5] <= 0) return 4; - w = clamp(v[2] / v[4], MIN_VIEW_WIDTH, 1); - h = clamp(v[3] / v[5], 1.0/128, 1); + w = clamp(v[2] / v[4], MIN_VIEW_SPAN, 1); /* Делим текущую долю X на положительный коэффициент приближения; ограничиваем результат между новым пределом и полным диапазоном. */ + h = clamp(v[3] / v[5], MIN_VIEW_SPAN, 1); /* Аналогично масштабируем Y, снимая прежнее ограничение 128 раз и сохраняя ненулевую высоту для координатных преобразований. */ fx = clamp(v[8], 0, 1); fy = clamp(v[9], 0, 1); out[0] = clamp(v[0] + (v[2] - w) * fx - v[6] * w, 0, 1 - w); out[1] = clamp(v[1] + (v[3] - h) * fy - v[7] * h, 0, 1 - h); diff --git a/c/set-protocol/tests/fixtures/plot-v1.json b/c/set-protocol/tests/fixtures/plot-v1.json index 62ed262..c16c234 100644 --- a/c/set-protocol/tests/fixtures/plot-v1.json +++ b/c/set-protocol/tests/fixtures/plot-v1.json @@ -4,7 +4,7 @@ {"name":"zoom_x_anchor","op":0,"input":[0,0,1,1,2,1,0,0,0.25,0.5],"output":[0.125,0,0.5,1]}, {"name":"zoom_y_anchor","op":0,"input":[0,0,1,1,1,4,0,0,0.5,0.75],"output":[0,0.5625,1,0.25]}, {"name":"pan_clamp","op":0,"input":[0.25,0.25,0.5,0.5,1,1,20,-20,0.5,0.5],"output":[0,0.5,0.5,0.5]}, - {"name":"zoom_limit","op":0,"input":[0,0,1,1,1000,1000,0,0,0.5,0.5],"output":[0.4995,0.49609375,0.001,0.0078125]}, + {"name":"zoom_limit","op":0,"input":[0,0,1,1,1e15,1e15,0,0,0.5,0.5],"output":[0.4999999999995,0.4999999999995,1e-12,1e-12]}, {"name":"ignore_invalid_zoom","op":0,"input":[0.25,0.25,0.5,0.5,0,1,0,0,0.5,0.5],"output":[0.25,0.25,0.5,0.5]}, {"name":"horizontal_spread","op":1,"input":[100,2,8],"output":[1]}, {"name":"vertical_contract","op":1,"input":[2,-100,8],"output":[2]}, diff --git a/python/README.md b/python/README.md index 4e2b50d..30ba13f 100644 --- a/python/README.md +++ b/python/README.md @@ -24,6 +24,13 @@ Saleae SDK подключается при обращении к устройс в приложении. Общая панель обработки графиков размещена в `qt_ports.plot_processing`: [контракт, подключение нового графика и примеры](../c/set-protocol/docs/PLOT_PROCESSING.md). +Конструкторы CAN-адаптера, CAN DevBoard и RS485 DevBoard используют общий +компонент `set_devices.qt_ports.can_frame_builder.CanFrameFields`. Он задаёт +одинаковые поля и исходный режим «Обычный CAN — ID / DLC / Data», сохраняет +альтернативный режим SETCAN и сообщает об изменениях сигналом `changed`. +`frame_values()` возвращает проверенные ID, IDE, Data и необязательный Body; +упаковка конкретного транспорта и отправка остаются у приложения. + Пути к нативным библиотекам задаёт потребитель перед импортом: `SETPROTOCOL_LIBRARY`, при необходимости `ALTERA_LOGIC_LIBRARY`, `CANDLE_LIBRARY`. Порты не ищут DLL в каталогах SETGUI. C99-ядро собирается из `c/set-protocol`, diff --git a/python/examples/console_examples.py b/python/examples/console_examples.py new file mode 100644 index 0000000..1453266 --- /dev/null +++ b/python/examples/console_examples.py @@ -0,0 +1,46 @@ +"""Три автономных примера общей консоли templates без подключения к аппаратуре.""" # Примеры показывают служебный текст, CAN и двоичный RS485 на одном компоненте. +import argparse # Ключ --kind выбирает один пример для отдельного запуска. +import time # Время в модели кадра соответствует обычному источнику пакетов приложения. +from set_devices.can485_board import BoardFrame # Штатная модель строит RS485-пакет с настоящим CRC. +from set_devices.can_monitor import decode_protocol # CAN расшифровывается действующим декодером templates. +from set_devices.can_transport import build_frame # Транспортный кадр не собирается вручную в UI. +from set_devices.qt_ports.console import ConsoleView # Все примеры используют ту же консоль, что SETGUI. +try: # Выбираем доступную версию Qt без зависимости от приложения SETGUI. + from PySide6.QtWidgets import QApplication, QTabWidget # Вкладки позволяют сравнить три независимых журнала. +except ImportError: # Сохраняем совместимость примера с портом Qt 5. + from PySide2.QtWidgets import QApplication, QTabWidget # Интерфейс запуска одинаков для обеих версий Qt. + + +def create_examples(): # Фабрика доступна также тесту и генератору снимков интерфейса. + service = ConsoleView(limit=4000) # Первый журнал показывает служебные ответы и команды платы. + service.append_message(">>> V", direction="TX", color="#8fd18f") # Метка отправки демонстрирует независимый фильтр TX. + service.append_message("#OK driver started", direction="RX", color="#6fa8dc") # Ответ устройства показывает цвет и фильтр RX. + service.append_message("#ERR transmit failed (no ack / bus busy)", color="#ff7b7b") # Ошибка остаётся видна независимо от фильтров направления. + can = ConsoleView(limit=4000, payloads=True) # Второй пример добавляет переключение представления настоящих байтов CAN. + frame = build_frame(0x701, b"\x05", ide=False, rtr=False) # ID 0x701 и байт 05 задают heartbeat CANopen узла 1 в Operational. + decoded = decode_protocol(frame, "deif") # Подпись события берётся из штатного протокольного декодера. + can.append_message("RX CAN 0x701 · " + decoded.summary, direction="RX", payload=b"\x05") # Исходный payload позволяет сравнить режимы HEX и ASCII. + rs485 = ConsoleView(limit=4000, payloads=True) # Третий пример показывает транспортный пакет платы отдельно от прикладного CAN. + packet = BoardFrame(time.time(), False, 0x701, False, 1, b"\x05", "RS485").rs485_packet() # Пакет AA55 и CRC8 формируются кодеком templates. + rs485.append_message("RX RS485 · пакет CAN485", direction="RX", payload=packet) # Консоль отображает байты, не повторяя алгоритм разбора пакета. + for console in (can, rs485): # Двоичные примеры сразу демонстрируют одновременно байты и печатное представление. + console.display.setCurrentText("HEX + ASCII") # Пользователь может вернуться к исходной подписи или выбрать один формат. + return (("Служебная консоль", service), ("CAN", can), ("RS485", rs485)) # Каждый журнал владеет своей историей и настройками просмотра. + + +def main(): # Точка входа запускается обычным Python с установленным Qt-портом templates. + parser = argparse.ArgumentParser(description=__doc__) # Справка объясняет назначение примеров без отдельного приложения. + parser.add_argument("--kind", choices=("all", "service", "can", "rs485"), default="all") # Один пример каждого источника доступен отдельной командой. + args = parser.parse_args() # Пользователь выбирает источник до создания окна. + app = QApplication.instance() or QApplication([]) # Одно приложение Qt обслуживает все примеры. + window = QTabWidget() # Общий просмотр не связывает состояния независимых консолей. + for key, (title, console) in zip(("service", "can", "rs485"), create_examples()): # Стабильные ключи соответствуют значениям --kind. + if args.kind in ("all", key): window.addTab(console.panel, title) # Выбранные примеры добавляются с общей панелью инструментов. + window.setWindowTitle("Примеры консоли templates") # Заголовок явно отличает демонстрацию от подключения к плате. + window.resize(1100, 480) # Начальный размер в логических пикселях позволяет видеть все инструменты. + window.show() # Окно появляется только при прямом запуске примера. + return app.exec() # Цикл Qt обрабатывает поиск, паузу, экспорт и изменение масштаба. + + +if __name__ == "__main__": # Импорт фабрики в тестах не должен открывать окно или запускать цикл событий. + raise SystemExit(main()) # Код завершения Qt возвращается вызывающему процессу. diff --git a/python/logic_analyzer/decoders/set_can.py b/python/logic_analyzer/decoders/set_can.py index f0d0867..eab299e 100644 --- a/python/logic_analyzer/decoders/set_can.py +++ b/python/logic_analyzer/decoders/set_can.py @@ -16,20 +16,9 @@ BOOT = dict(enumerate(('IDENTIFY ENTER_BOOT BEGIN_IMAGE BEGIN_COMPAT ERASE VERIF def legacy(ident, data, profile='protocan'): if not 0 <= ident <= 0x1fffffff or len(data) > 8: raise ValueError('Invalid classic CAN frame') - relative = ident - 0xba0000 if profile == 'balsam': - if not (0 <= relative < 13 or 16 <= relative < 29): - return None - if len(data) != 8: - raise ValueError('Balsam requires DLC=8') - header = number(data[:2], 'big') - address, mask = header & 0x1fff, header >> 13 - registers = [(address + i, number(data[2+i*2:4+i*2], 'big')) - for i in range(3) if mask & (4 >> i)] - return dict(protocol='Balsam', registers=registers, summary= - 'Balsam node=%d %s mask=%X %s' % ((relative & 15) + 1, - 'data' if relative >= 16 else 'command', mask, - ' '.join('R%04X=%04X' % pair for pair in registers))) + from .template_protocols import decode_can # Единая реализация templates знает порядок value2/value3/header/value1 и специальные ID пульта. + return decode_can(ident, data, 'balsam') # Старый публичный вызов получает исправленную расшифровку без второго варианта wire-формата. msg, body = (ident >> 16) & 15, ident & 0xffff result = dict(protocol='ProtoCAN', priority=(ident >> 28) & 1, route=(ident >> 27) & 1, device_type=(ident >> 24) & 7, diff --git a/python/logic_analyzer/decoders/template_protocols.py b/python/logic_analyzer/decoders/template_protocols.py new file mode 100644 index 0000000..6a65894 --- /dev/null +++ b/python/logic_analyzer/decoders/template_protocols.py @@ -0,0 +1,63 @@ +from pathlib import Path # Путь к поставляемым библиотекам вычисляется относительно ядра декодера, независимо от рабочего каталога DSView. +import sys # Встроенному Python требуется путь к переносимым пакетам, которые поставляются вместе с декодерами. +from types import SimpleNamespace # Общим CAN-парсерам нужен только набор свойств кадра, без подключения транспорта или Qt. + +_vendor = Path(__file__).with_name('templates') # Установщик помещает исходные пакеты templates в закрытый подкаталог общего ядра. +if _vendor.is_dir() and str(_vendor) not in sys.path: # При запуске из исходников используются штатные пакеты; установленный DSView получает собственные копии. + sys.path.insert(0, str(_vendor)) # Локальные версии пакетов имеют приоритет и не требуют установленного SETGUI или внешнего Python. + +from protocan import balsam, legacycan, protocan as pc # Форматы ID, порядок слов и каталоги проектов берутся из действующих библиотек templates. +from set_devices import deif_xdi, ump_can # Профиль DEIF и словарь УМП используются теми же функциями, что в CAN-мониторе. + +CAN_PROFILES = ('protocan', 'auto', 'devboard', 'balsam', 'ump-protocan', 'deif', 'legacy', 'set-v2') # Старые ключи сохранены для ранее настроенных записей DSView. +LEGACY_PROJECTS = tuple(project.name for project in legacycan.PROJECTS) # Список выбора обновляется вместе с единым каталогом исторических проектов. + +def _decoded(result): # Преобразует нейтральную модель CAN-монитора в словарь событий анализатора. + return dict(protocol=result.protocol, summary=result.summary, fields=list(result.fields), registers=result.registers, warnings=list(result.warnings), device=result.device_label) # Копии списков исключают изменение результата другим слоем декодирования. + +def _balsam(ident, payload): # Разбирает фактический порядок слов Balsam 167 вместо упрощённого заголовка в начале данных. + result = balsam.decode(ident, payload, native=pc._SHARED_PROTOCOL) if pc._SHARED_PROTOCOL is not None else balsam._decode_fallback(ident, payload) # Без DLL используется существующий переносимый разбор; повторный поиск DLL на каждом кадре исключён. + if result is None: # Чужой идентификатор не должен получать подпись Balsam. + return None # Отсутствие подходящего кадра не создаёт ложную ошибку на общей шине. + registers = [(item.address, item.value) for item in result.registers] # Общий парсер уже применил маску присутствия и восстановил порядок трёх слов. + fields = [('Узел', result.device_name), ('Маршрут', result.route), ('Начальный адрес', '0x%04X' % result.start_address), ('Маска слов', format(result.present_mask, '03b'))] # Адрес имеет ширину 13 бит, а маска содержит три признака из wire-формата Balsam. + return dict(protocol='Balsam', summary=result.summary, registers=registers, fields=fields, warnings=[]) # Сохраняет совместимое имя протокола и полную сводку с командами общего парсера. + +def decode_can(ident, payload, profile='protocan', *, extended=True, ump_map='gas167', ump_node=1, project=LEGACY_PROJECTS[0]): # Явные настройки предотвращают угадывание несовместимых карт регистров по содержимому данных. + payload = bytes(payload) # Парсеры получают неизменяемые байты вне зависимости от контейнера, переданного sigrok. + if not 0 <= ident <= (0x1fffffff if extended else 0x7ff) or len(payload) > 8: # Classic CAN допускает 29-битный EXT либо 11-битный STD ID и не более восьми байт. + raise ValueError('Invalid classic CAN frame') # Повреждённый ID или DLC отклоняется до интерпретации прикладных полей. + if profile not in CAN_PROFILES or profile == 'set-v2': # Сегментированный SET v2 обрабатывается отдельной машиной состояний с тайм-аутом. + raise ValueError('Unsupported CAN profile: ' + profile) # Неизвестный профиль не подменяется ProtoCAN молча. + if not extended and profile != 'deif': # Все поставляемые профили SET используют EXT; DEIF работает со стандартными CANopen ID. + return None # Стандартный кадр не интерпретируется как адресное поле ProtoCAN. + frame = SimpleNamespace(can_id=ident, data=payload, ide=extended, rtr=False, is_error=False) # Минимальный кадр соответствует контракту общих функций CAN-монитора. + if profile == 'deif': # CANopen/DEIF использует собственную адресацию и проверку селектора. + return _decoded(deif_xdi.decode(frame)) # Поля, физические единицы и замечания полностью определяет имеющийся парсер. + if profile == 'balsam' or profile == 'auto' and balsam.is_balsam_id(ident): # В автоматическом режиме Balsam распознаётся только по его документированным идентификаторам. + return _balsam(ident, payload) # Включает отдельную пару CAN ID пульта, присутствующую в общей библиотеке. + if profile == 'legacy': # Старые проектные форматы требуют явного проекта, поскольку диапазоны ID могут пересекаться. + selected = next((item for item in legacycan.PROJECTS if item.name == project), None) # Поиск использует общий каталог без копирования ID в анализатор. + if selected is None: # Ошибка выбора не должна давать расшифровку другого проекта. + raise ValueError('Unknown legacy CAN project: ' + project) # Сообщение остаётся видимым на дорожке ошибок. + node = selected.node_for(ident) # Маршрутизация зависит от формата: точный ID либо старшие биты ID. + if node is None: # На общей шине допустимы кадры других устройств и проектов. + return None # Чужие ID остаются только в дорожках базового CAN-декодера. + packet = legacycan.decode(selected.format, node, ident, payload) # Общая реализация восстанавливает адрес, маску и слова с нужным порядком байтов. + if packet is None: # Известный ID с неподходящим DLC обозначает повреждённый кадр выбранного проекта. + raise ValueError('Invalid legacy CAN payload') # Некорректные данные не выдаются как достоверные регистры. + registers = list(packet.present_values) # Получает только отмеченные маской слова в исходном адресном порядке. + commands = ['%s: %s' % ('R%04X' % address, ', '.join(selected.command_names[bit] for bit in range(16) if value & (1 << bit))) for address, value in registers if address == 127] # Регистр 127 хранит 16 командных битов с названиями выбранного проекта. + summary = '%s · %s · %s · %s' % (project, node.name, packet.source.value, ' '.join('R%04X=%04X' % pair for pair in registers)) # Краткая подпись связывает проект, устройство, направление и значения слов. + return dict(protocol='Legacy CAN', summary=summary, fields=[('Проект', project), ('Устройство', node.name), ('Направление', packet.source.value)] + [('Команды', text) for text in commands], registers=registers, warnings=[]) # Все подробности доступны на самостоятельных дорожках DSView. + if profile == 'ump-protocan' and ump_map == 'gas167': # Текущая карта 167/v1 назначается вручную и не смешивается с новыми глобальными ID. + if ump_node not in (1, 2): # В профиле имеются два УМП; номер не извлекается из локального адреса регистра. + raise ValueError('UMP node must be 1 or 2') # Ошибочный номер узла должен быть исправлен в настройках. + return _decoded(ump_can.decode_gas167(frame, ump_node)) # Имена параметров и активные биты берутся из действующей карты templates. + if profile == 'ump-protocan' and ump_map != 'assigned': # Назначенная глобальная карта обрабатывается штатным ProtoCAN ниже. + raise ValueError('Unknown UMP map: ' + ump_map) # Неизвестную карту нельзя интерпретировать как другую раскладку регистров. + from .set_can import legacy # Поздний импорт сохраняет совместимость существующего ядра и предотвращает циклическую загрузку модулей. + result = legacy(ident, payload) # Сохраняет строгие проверки DLC GAS/Boot, сегментных длин и старые структурированные поля событий. + application = _decoded(pc.decode(ident, payload)) # Общий ProtoCAN добавляет имена устройств, GAS, Settings, дискретов и служебных полей. + result.update(fields=application['fields'], warnings=application['warnings'], summary=result['summary'] + ' · ' + application['summary']) # Старые поля сохраняются, а полная прикладная расшифровка становится доступной на осциллограмме. + return result # Кадр выдаётся только после проверки wire-формата обоими существующими уровнями. diff --git a/python/logic_analyzer/decoders/tms_uart.py b/python/logic_analyzer/decoders/tms_uart.py new file mode 100644 index 0000000..6b41528 --- /dev/null +++ b/python/logic_analyzer/decoders/tms_uart.py @@ -0,0 +1,29 @@ +from collections import deque # Кольцевой буфер хранит только координаты одного максимального кадра. +from . import template_protocols # Подключает поставляемые пакеты templates в отдельном Python-процессе DSView. +from set_devices import tms_terminal as tms # Раскладки, CRC и потоковый поиск границ используются из действующего парсера терминала. + +LAYOUTS = tuple(tms.PRESETS) + ('custom',) # Имена готовых раскладок совпадают с настройками терминала SETGUI. + +class TmsStreamParser: # Адаптирует общий байтовый парсер к событиям с координатами sigrok. + def __init__(self, preset=tms.DEFAULT_PRESET, digit_bytes=38, analog_count=34, crc='MODBUS'): # Значения 38/34 соответствуют штатной раскладке message2.h. + selected = tms.PRESETS[preset] if preset != 'custom' else tms.Layout(digit_bytes, analog_count, crc) # Индивидуальная раскладка проверяется существующей моделью Layout. + self.layout = tms.Layout(selected.digit_bytes, selected.analog_count, crc) # CRC выбирается отдельно, поскольку в источниках есть MODBUS и CCITT-FALSE. + self.parser = tms.TmsParser(self.layout) # Поиск границ и подтверждение CRC выполняет общий парсер. + self.positions = deque(maxlen=self.layout.frame_size) # Число хранимых координат ограничено длиной одного кадра в байтах. + + def flush(self): # Пауза либо ошибка UART запрещает объединять части разных посылок. + self.parser.reset() # Общий парсер отбрасывает недособранные байты и состояние синхронизации. + self.positions.clear() # Координаты старого хвоста также исключаются из следующего события. + return [] # Формат без сигнатуры не позволяет отличить неполный кадр от произвольного шума. + + def feed(self, value, ss, es): # Один UART-байт приходит вместе с точными границами в отсчётах. + self.positions.append((ss, es)) # Последние frame_size позиций соответствуют окну поиска общего парсера. + events = [] # За один байт может завершиться один кадр фиксированной длины. + for record in self.parser.feed(bytes([value])): # Только CRC-подтверждённые записи выдаются прикладному слою. + fields = [('Команда', record.command), ('Адрес', str(record.address)), ('CRC', '%04X' % record.crc_frame)] # Служебные поля берутся из готовой модели TmsRecord. + fields += [(tms.analog_name(index), str(word)) for index, word in enumerate(record.analogs)] # Имена аналогов и знаковые int16 совпадают с терминалом SETGUI. + fields += [('Дискреты', ', '.join(record.set_bits()) or 'нет активных битов')] # Активные биты выдаются с исходной нумерацией байтов и битов. + result = dict(protocol='TMS UART', summary=record.summary, payload=record.raw[2:-3], raw=record.raw, fields=fields, analogs=record.analogs, digits=record.digits) # CRC и завершающий байт исключены из полезной нагрузки по контракту TMS_TO_TERMINAL. + events.append((self.positions[0][0], es, result, None)) # Начало подтверждённого окна сохраняется даже после пропущенного шума. + self.positions.clear() # Координаты завершённого кадра не удерживаются до следующей посылки. + return events # События имеют тот же контракт, что парсер SET UART. diff --git a/python/protocan/balsam.py b/python/protocan/balsam.py index 0ce27ab..c5c536c 100644 --- a/python/protocan/balsam.py +++ b/python/protocan/balsam.py @@ -15,6 +15,19 @@ DATA_OFFSET = 0x10 NODE_COUNT = 13 PULT_COMMAND_ID = 0x00745009 PULT_DATA_ID = 0x00745019 +HEARTBEAT_ADDRESS = 0x0100 # CAN_HEARTBEAT_ADDR в ecan.c периферии 167 начинает три служебных слова вне технологической карты R0..R127. +HEARTBEAT_NAMES = { # Назначения слов соответствуют hiword и loword ветки CAN_send для CAN_HEARTBEAT_ADDR. + HEARTBEAT_ADDRESS: "Heartbeat: счётчик, с", # Первое слово содержит секунды после запуска по модулю 65536, а не знаковое измерение. + HEARTBEAT_ADDRESS + 1: "Heartbeat: Mode", # Второе слово передаёт аппаратный номер Mode платы без преобразования CAN-индекса. + HEARTBEAT_ADDRESS + 2: "Heartbeat: тип платы (Desk)", # Третье слово содержит код Desk из прошивки, без подмены его именем CAN-узла. +} # Все три адреса общие для поддерживаемых узлов периферии 167. +COMMON_REGISTER_NAMES = { # Общие назначения подтверждены package.h; единицы времени зависят от версии планировщика CAN. + 0x60: "Настройка быстрого потока CAN", # Cancount[m_FAST]: в новом планировщике ноль отключает поток, ненулевое значение включает его. + 0x61: "Настройка медленного потока CAN", # Cancount[m_SLOW]: исторический период нельзя переводить в миллисекунды без версии прошивки. + 0x62: "Яркость индикации", # Brightness в package.h содержит исходный уровень яркости, а не подтверждённый процент. + 0x7E: "Последний режим", # LastMode хранится в предпоследнем слове технологической карты R0–R127. + 0x7F: "Команды", # Commands — битовая маска, которую дополнительно расшифровывает command_description. +} # Таблица доступна с любой версией DLL и при использовании резервного Python-декодера. @dataclass(frozen=True) @@ -38,10 +51,21 @@ class BalsamFrame: present_mask: int registers: tuple[BalsamRegister, ...] - @property - def route(self) -> str: - return ("%s → ПМ" % self.device_name if self.from_device - else "ПМ → %s" % self.device_name) + @property # Признак доступен адаптерам монитора и общей текстовой расшифровке без повторного разбора байтов. + def is_heartbeat(self) -> bool: # Штатный CAN_heartbeat_service передаёт ответ с адресом 0x0100 и всеми тремя словами. + return self.from_device and self.start_address == HEARTBEAT_ADDRESS and self.present_mask == 7 # Маска 111 из ecan.c исключает команды и неполные служебные пакеты. + + @property # Имя отправителя определяется направлением кадра, тогда как device_name сохраняет имя периферийного узла. + def sender_name(self) -> str: # Все устройства 167 подписываются по источнику кадра, как в предоставленной таблице адресов. + return self.device_name if self.from_device else "TMS" # Команды базового диапазона передаёт TMS, а ответы со смещением 0x10 — соответствующий периферийный узел. + + @property # Получатель дополняет отправителя, чтобы подробная расшифровка совпадала с подписью CAN ID. + def recipient_name(self) -> str: # Имя адресата нужно для обоих направлений каждой пары устройств. + return "TMS" if self.from_device else self.device_name # Периферия возвращает данные в TMS; получателем команды остаётся узел, выбранный CAN ID. + + @property # Краткий маршрут используется также в сводке и истории CAN-монитора. + def route(self) -> str: # Собираем направление из тех же имён, которые показаны в подробностях кадра. + return "%s → %s" % (self.sender_name, self.recipient_name) # Единые подписи исключают различия между строкой ID и полями отправителя и получателя. def command_description(self, value: int) -> str: """Command register 127; named UMP bits from BALZAM_167 automats.h.""" @@ -56,11 +80,14 @@ class BalsamFrame: for bit in range(16) if value & (1 << bit)) @property - def summary(self) -> str: - direction = "данные" if self.from_device else "команда" - values = ", ".join( - "%s=0x%04X (%d)" % (item.name or "R%04X" % item.address, - item.value, item.signed_value) + def summary(self) -> str: # Сводка показывает служебный пакет компактно, а технологические регистры — с адресами и известными назначениями. + if self.is_heartbeat: # Только полный ответ с адреса 0x0100 содержит три служебных слова в гарантированном порядке. + seconds, mode, desk = (item.value for item in self.registers) # Значения heartbeat беззнаковые; счётчик циклически проходит 0–65535 секунд. + return "BALZAM · %s · Heartbeat · %d с · Mode=%d · Desk=%d" % (self.route, seconds, mode, desk) # Один heartbeat получает одну подпись; исходные HEX остаются в байтах и подробных полях. + direction = "данные" if self.from_device else "команда" # Направление технологического кадра определяется диапазоном CAN ID. + values = ", ".join( # Каждое отмеченное маской слово выводится ровно один раз вместе с его назначением. + "R%d=0x%04X (%d)" % (item.address, item.value, item.signed_value) # Десятичный адрес совпадает с таблицей R0–R127, HEX сохраняет точное исходное слово. + + (" — " + item.name if item.name else "") # Для неизвестного адреса сохраняем только достоверные номер и значение, не придумывая назначение. + (" — " + self.command_description(item.value) if item.address == 0x7F else "") for item in self.registers @@ -93,7 +120,7 @@ def decode(can_id: int, data: bytes, native=None) -> BalsamFrame | None: device, direction, mask, start, values = decoded registers = tuple( BalsamRegister(start + index, values[index], - native.balsam_register_name(device, start + index)) + HEARTBEAT_NAMES.get(start + index) or COMMON_REGISTER_NAMES.get(start + index) or native.balsam_register_name(device, start + index)) # Общие настройки получают одинаковые подписи со старой DLL; назначения каналов определяет C-ядро. for index in range(3) if mask & (4 >> index) ) return BalsamFrame(can_id & 0x1FFFFFFF, device, @@ -107,7 +134,7 @@ def _decode_fallback(can_id: int, data: bytes) -> BalsamFrame | None: if len(data) != 8: raise ValueError("BALZAM CAN frame must contain exactly 8 data bytes") relative = (can_id & 0x1FFFFFFF) - BASE_ID - device = (relative & 0x0F) + 1 + device = (relative & 0x0F) + 1 # Прошивка ecan.c уменьшает DevNum перед сборкой ID; маска выделяет нулевой CAN-индекс, а +1 возвращает номер Mode. from_device = relative >= DATA_OFFSET if can_id & 0x1FFFFFFF in (PULT_COMMAND_ID, PULT_DATA_ID): device = 10 @@ -117,12 +144,12 @@ def _decode_fallback(can_id: int, data: bytes) -> BalsamFrame | None: for offset in (6, 0, 2)) names = { 1: "Трансформатор 1", 2: "Трансформатор 2", - 3: "Силовой блок 1", 4: "Силовой блок 2", 5: "УМП 1", 6: "УМП 2", - 7: "Двигатель", 8: "ВЭП", 9: "Задатчик", 10: "Пульт (МПУ)", 13: "Терминал", + 3: "Силовой 1", 4: "Силовой 2", 5: "УМП 1", 6: "УМП 2", # Названия силовых узлов и УМП соответствуют строкам 3..6 предоставленной таблицы адресов 167. + 7: "Двигатель", 8: "Задатчик", 9: "ВЭП", 10: "ПМУ", 13: "Терминал", # Таблица задаёт задатчик 8, ВЭП 9 и ПМУ для пары 0xBA0009/0xBA0019; служебный терминал сохраняет номер 13. } start, mask = header & 0x1FFF, (header >> 13) & 7 registers = tuple(BalsamRegister(start + i, values[i], - "Команды" if start + i == 0x7F else "") + HEARTBEAT_NAMES.get(start + i) or COMMON_REGISTER_NAMES.get(start + i, "")) # Без DLL сохраняем подтверждённые назначения heartbeat и общих настроек, оставляя неизвестные каналы без подписи. for i in range(3) if mask & (4 >> i)) return BalsamFrame(can_id & 0x1FFFFFFF, device, names.get(device, "Узел %d" % device), diff --git a/python/pysetterminal/README.md b/python/pysetterminal/README.md index f15c4f3..cbce5c6 100644 --- a/python/pysetterminal/README.md +++ b/python/pysetterminal/README.md @@ -86,3 +86,119 @@ self.byte_page.set_status("Чтение завершено") Каждому независимому соединению нужен собственный протокол. Если вкладки используют одно соединение, владелец транспорта должен запрещать одновременные запросы и маршрутизировать ответы. В SETGUI это делает существующая очередь TMS2812. + +## PBUS, SBUS и общие макросы + +В SETGUI, на странице «Работа с байтом → Команды / макросы», слева находится +«SBUS (Сериальная шина)», справа — «PBUS (Параллельная шина)». Под обоими +блоками расположен единственный общий список макросов на всю ширину. +Один макрос может содержать команды обеих шин в произвольном порядке. +Создание, редактирование, удаление, запуск и остановка макросов сохранены. +Отдельных нижних полей «Ответ контроллера» и «Считанное слово» нет. + +SBUS сохраняет прежние чтение и запись через `0x200A`, `0x200B`, `0x200F`. +Старый JSON без поля `bus` исполняется как SBUS, новые команды явно +сохраняют `bus: "sbus"` или `bus: "pbus"`. Публичные элементы `bus_*` +по-прежнему относятся к SBUS. Таблица результатов доступна как `pbus_table`. + +В PBUS достаточно ввести адрес платы и регистр, затем нажать «Добавить в +таблицу» или Enter. Таблица показывает плату, регистр, HEX, DEC и состояние +считывания. Повторное добавление того же источника не создаёт дубликат. +«Убрать из таблицы» и Delete удаляют выделенные строки; Ctrl и Shift +позволяют удалить несколько источников сразу. После удаления оставшиеся +регистры уплотняются и заново записываются в аппаратную таблицу с правильными +адресами буфера. «Изменить строку» заменяет выбранную строку адресом и +регистром из полей выше. После удаления последнего регистра список +становится пустым, аппаратный и фоновый опрос остаются остановленными; +прежнее содержимое аппаратного буфера не используется как результат. + +В блоке PBUS поле «Порог ошибок (1–15)» задаёт число допустимых ошибок. +Начальное значение — 10 (`0xA`), поэтому две записи запускаются словом +`0x8A01`. Выбранный порог применяется при добавлении, изменении таблицы +или нажатии «Обновить». Обычный фоновый цикл использует уже применённые +параметры и передаёт только запросы чтения памяти. Команда макроса может +явно задать свой порог; новое редактирование поля во время обмена не +меняет снимок уже поставленной команды. + +Перенастройка выполняется одной операцией общей очереди: остановка через +`0x200C`, полная запись всех пар индекса `0x200D` и дескриптора `0x200E`, +затем запуск через `0x200C`. Остановка сохраняет порог и последний индекс +ранее подтверждённой активной таблицы, сбрасывая только бит 15. Запуск +содержит новый последний индекс `N-1` в младшем байте и порог в битах 11:8. +Для пустого списка выполняется только остановка, без переполнения `N-1` +и без команд запуска, включая `0x80FE`. + +Дескриптор равен `(плата << 12) | (регистр << 8) | CD`. Индекс таблицы +независим от CD, а результат читается по словному адресу `0x2000 | CD`, +без умножения на размер слова. При обычном добавлении CD начинается с +`0x40`, поэтому строки читаются из `0x2040`, `0x2041` и далее. Полный +снимок настройки может содержать явный `cd` у каждой записи: это назначение +сохраняется при редактировании и перестройке таблицы. Максимум — 64 записи. +Регистр `0x2012` не читается для проверки состояния или блокировки данных. + +После подтверждения запуска выдерживается поле «После запуска» в +миллисекундах; начальное значение — 100 мс. Оно настраивается по времени +обновления аппаратного буфера отдельно от периода чтения. До окончания +паузы и успешного первого чтения таблица не считается применённой и +прежние значения не показываются. Ошибка записи останавливает дальнейшие +шаги и запрещает автоматическое применение или повторный запуск. + +Пример двух регистров платы `0xE` с порогом `0xA`: + +```text +write(0x200C, 0x0A01) +write(0x200D, 0x0000) +write(0x200E, 0xE040) +write(0x200D, 0x0001) +write(0x200E, 0xE141) +write(0x200C, 0x8A01) +ожидание аппаратного обновления +read(0x2040) +read(0x2041) +``` + +«Обновить» получает значения списка. «Циклическое чтение» повторяет чтение +PBUS с выбранным периодом в миллисекундах и сохраняет выделение строк. +Циклическое чтение передаёт только ReadMemory назначений 20CD, не меняет +таблицу и не перезапускает шину. При выключении галочки отменяются будущие +повторы и неотправленные чтения; после завершения текущего пакета или +логической операции в очередь передаётся остановка `0x200C` с очищенным +битом 15 и сохранёнными параметрами активной таблицы. Повторное включение +галочки запускает аппаратно остановленную таблицу перед чтением её буфера. При изменённой или неподтверждённой +таблице необходимо явное нажатие «Обновить» для полного применения. +Изменение адреса контроллера останавливает опрос до явного применения +списка к новому устройству. В SBUS собственные галочка и период повторяют +чтение устройства и регистра из текущих полей; изменения применяются к +следующему запросу, уже отправленные параметры сохраняются. + +Кнопки и поля остаются доступными во время обмена. Нажатия фиксируют +параметры и становятся в общую очередь соединения. В одной логической +операции подготовка регистра и получение результата выполняются целиком, +без перемешивания с другой операцией. Проверка записанного слова чтением +также удерживает соединение до завершения. Ручные действия обслуживаются +раньше следующего фонового задания. Периодический источник имеет не более +одного ожидающего или выполняющегося запуска; пропущенные циклы не копятся. + +Макросы размещаются слева направо с переносом по ширине панели и +вертикальной прокруткой, сохраняя прежнюю высоту и естественную ширину. +Длинное имя увеличивает ширину кнопки. У каждого макроса есть галочка +«Циклически»; поле «Период повторения» в редакторе сохраняется как +`period_ms` в его JSON. Старые макросы получают период 1000 мс. +Включение сразу запускает макрос, период отсчитывается между реальными +началами повторов. Незавершённый запуск того же макроса исключает повтор, +а однократная кнопка выполнения остаётся доступной отдельно. + +Общий редактор команд PBUS поддерживает `add`, `remove`, `poll`, `start` +и `stop`. Команды и будущий размер списка проверяются до первого запроса. +Ошибки порта, CRC, неверный ответ и таймаут прекращают оставшиеся команды +соответствующего запуска. Остановка снимает будущие повторения и ещё +не отправленные команды выбранного задания; текущий пакет завершается +ответом или штатным таймаутом. Отключение порта очищает всю очередь. +Уже переданные аппаратные записи не откатываются. + +Рабочие панели SETGUI используют существующие `QDockWidget` и +`QMainWindow`: перемещаются влево, вправо, вверх, вниз и в общую группу +вкладок со штатной подсветкой области вставки. Разделители меняют размеры. +Перенос сохраняет экземпляры панелей, соединение и выполняемые задания. +Раскладка сохраняется между запусками; «Сбросить раскладку» возвращает +стандартное расположение без пересоздания содержимого. diff --git a/python/pysetterminal/bus_operations.py b/python/pysetterminal/bus_operations.py new file mode 100644 index 0000000..1398388 --- /dev/null +++ b/python/pysetterminal/bus_operations.py @@ -0,0 +1,113 @@ +"""Операции PBUS по myXilinx/x_parallel_bus.c прошивки TMS2812 / 22220.""" + +from .exchange_queue import ExchangeDelay # Пауза после запуска остаётся внутри одной атомарной операции общей очереди. + +PBUS_SETTLE_MS = 100 # Начальная настраиваемая пауза обновления аппаратного буфера после старта, миллисекунды. +PBUS_COMMAND = 0x200C # Spartan2E_Adr.h: управление запуском циклического опроса параллельной шины. +PBUS_TABLE_INDEX = 0x200D # Spartan2E_Adr.h: выбор изменяемой строки таблицы опроса FPGA. +PBUS_TABLE_DATA = 0x200E # Spartan2E_Adr.h: дескриптор строки, содержащий адрес платы, регистр и адрес буфера. +PBUS_BUFFER = 0x2040 # Spartan2E_Adr.h: ADR_FIRST_FREE, первое слово буфера результатов циклического опроса. +PBUS_CAPACITY = 64 # Spartan2E_Adr.h: буфер 0x2040–0x207F содержит 64 слова, поэтому ограничиваем число строк таблицы. +PBUS_ERROR_LIMIT = 0xA # Начальный порог SETGUI соответствует рабочему ручному запуску 0x8Axx; пользователь может задать от 1 до 15 ошибок. + + +def validate_command(command): # Проверяем все параметры до передачи, чтобы неверный макрос не выполнился частично. + if not isinstance(command, dict): # Повреждённый JSON не должен приводить к исключению интерфейса вместо понятного отказа валидации. + raise ValueError("Команда макроса должна содержать именованные параметры") # Останавливаем всю последовательность до передачи первого управляющего запроса. + bus = command.get("bus", "sbus") # Старые JSON-макросы без поля bus относятся к существовавшей последовательной шине. + if bus not in ("pbus", "sbus"): # Не допускаем исполнения повреждённого имени шины другим алгоритмом. + raise ValueError("Неизвестная шина макроса") # Сообщаем причину отказа до передачи управляющих данных. + operations = ("add", "remove", "poll", "configure", "write", "read", "start", "stop") if bus == "pbus" else ("write", "read") # PBUS управляет общим списком регистров; прежние команды сохраняются для совместимости JSON. + if command["type"] not in operations: # Направление операции должно явно поддерживаться выбранной шиной. + raise ValueError("Неизвестная команда макроса") # Не превращаем неизвестную команду в чтение. + limits = (("tetrad", 15 if bus == "pbus" else 14), ("register", 15), ("data", 0xFFFF)) # PBUS имеет четырёхбитный адрес, прежний SBUS сохраняет диапазон 0–14; данные — 16 бит. + if bus == "pbus" and command["type"] in ("write", "read", "start", "stop"): # Только прежние команды явно задают индекс и длину аппаратной таблицы. + limits += (("slot", PBUS_CAPACITY - 1), ("count", PBUS_CAPACITY), ("errors", 15)) # Индекс буфера — 0–63, число строк — 1–64, порог — четыре бита. + defaults = {"data": 0, "slot": 0, "count": 1, "errors": PBUS_ERROR_LIMIT} # Стабильные значения позволяют сохранять компактные команды PBUS. + for name, maximum in limits: # Проверяем все значения одним правилом до упаковки битовых полей. + value = command.get(name, defaults[name]) if name in defaults else command[name] # Адрес и регистр обязательны, параметры таблицы имеют штатные значения. + minimum = 1 if name in ("count", "errors") else 0 # Пустую таблицу и нулевой порог запрещаем: библиотека считает count_error >= 0 ошибкой. + if not isinstance(value, int) or not minimum <= value <= maximum: # Исключаем строки, отрицательные числа и переполнение аппаратных полей. + raise ValueError(f"{name}: допустим диапазон {minimum}…{maximum}") # Указываем конкретный неверный параметр и его пределы. + if bus == "pbus" and (not isinstance(command.get("errors", PBUS_ERROR_LIMIT), int) or not 1 <= command.get("errors", PBUS_ERROR_LIMIT) <= 15): # Новые команды также сохраняют целочисленный четырёхбитный ненулевой порог ошибки PBUS. + raise ValueError("errors: допустим диапазон 1…15") # Нулевой порог иначе сделал бы любой статус аппаратной ошибкой. + if bus == "pbus" and command["type"] in ("write", "read", "start", "stop") and command.get("slot", 0) >= command.get("count", 1): # Проверяем явную адресацию только у прежнего формата команды. + raise ValueError("PBUS: индекс строки должен быть меньше числа строк таблицы") # Не запускаем опрос, который исключает выбранный результат. + if bus == "pbus" and "entries" in command: # Явная замена таблицы валидируется целиком до постановки макроса в очередь. + validated_entries(command["entries"]) # Повреждённая поздняя строка исключает передачу начала перенастройки. + if bus == "pbus" and "settle_ms" in command and (not isinstance(command["settle_ms"], int) or not 1 <= command["settle_ms"] <= 60000): # Пауза обновления задаётся в положительных миллисекундах. + raise ValueError("PBUS: пауза после запуска должна быть 1…60000 мс") # Отказываем до любого WriteMemory контроллеру. + return bus # Возвращаем проверенную шину для выбора алгоритма и адресного отображения результата. + + +def pbus_result_address(entry, index): # Номер записи таблицы и CD её результата являются разными полями аппаратного протокола. + cd = entry.get("cd", (PBUS_BUFFER & 0xFF) + index) # При отсутствии явного CD сохраняем обычное размещение результатов с младшего байта 0x40. + if not isinstance(cd, int) or not 0 <= cd <= 0xFF: # Поле CD занимает ровно восемь бит дескриптора. + raise ValueError("PBUS: CD должен быть в диапазоне 00…FF") # Не допускаем усечения адреса результата при упаковке дескриптора. + return 0x2000 | cd # Адрес памяти словный: страница 0x2000 объединяется с CD без умножения на размер слова. + + +def pbus_descriptor(slave, register, cd): # Формируем дескриптор отдельно от индекса записи, записываемого в 0x200D. + return (slave << 12) | (register << 8) | cd # Четыре бита платы, четыре бита регистра и восемь бит CD соответствуют заданному формату 0x200E. + + +def pbus_control(count, errors): # Управляющее слово содержит параметры таблицы без бита запуска. + if not isinstance(count, int) or not 0 <= count <= PBUS_CAPACITY or not isinstance(errors, int) or not 1 <= errors <= 15: # Проверяем ёмкость таблицы и четырёхбитный аппаратный порог до отправки. + raise ValueError("PBUS: неверный размер таблицы или порог ошибок") # Неверные параметры не меняют работающую шину. + return (errors << 8) | (count - 1 if count else 0) # Для пустой таблицы младший байт равен нулю, выражение N-1 не вычисляется с переполнением. + + +def validated_entries(entries): # Проверяем полный снимок таблицы до её остановки и возвращаем независимые адреса источников. + if not isinstance(entries, (list, tuple)) or len(entries) > PBUS_CAPACITY: # Аппаратный буфер штатной панели ограничен шестьюдесятью четырьмя источниками. + raise ValueError("PBUS: в таблице нет места, максимум 64 регистра") # Ошибка поздней строки не должна вызвать частичную перенастройку. + result = [] # Снимок не содержит считанных значений и временных состояний интерфейса. + for index, entry in enumerate(entries): # Каждый индекс таблицы проверяется независимо от CD результата. + validate_command({"bus": "pbus", "type": "add", "tetrad": entry["tetrad"], "register": entry["register"]}) # Плата и регистр должны помещаться в свои четырёхбитные поля. + pbus_result_address(entry, index) # Явный CD также проверяется до первой аппаратной записи. + result.append({name: entry[name] for name in ("tetrad", "register", "cd") if name in entry}) # Явное отображение CD сохраняется при добавлении и удалении других строк. + return result # Полный снимок используется очередью на протяжении всей перенастройки. + + +def table_entries_after(entries, command): # Вычисляем список регистров до передачи, чтобы целиком проверить общий макрос. + result = validated_entries(command.get("entries", entries)) # Сохраняем адреса без устаревших считанных значений и промежуточных статусов. + key = (command["tetrad"], command["register"]) # Одна пара плата/регистр однозначно определяет источник PBUS. + if command["type"] == "add" and key not in [(entry["tetrad"], entry["register"]) for entry in result]: # Повторное добавление уже наблюдаемого регистра не создаёт дубликат. + result.append({"tetrad": key[0], "register": key[1], **({"cd": command["cd"]} if "cd" in command else {})}) # Явный CD сохраняется независимо от индекса новой строки, без него буфер выбирается последовательно. + if command["type"] == "remove": # Удаление по адресам не зависит от смещения строк после предыдущих удалений. + removed = set(tuple(item) for item in command.get("remove_keys", [key])) # Кнопка и Delete могут удалить сразу несколько выделенных регистров. + for slave, register in removed: # Проверяем также параметры множественного удаления, приходящие из JSON. + validate_command({"bus": "pbus", "type": "remove", "tetrad": slave, "register": register}) # Недопустимая пара исключает исполнение всей последовательности заранее. + result = [entry for entry in result if (entry["tetrad"], entry["register"]) not in removed] # Оставшиеся источники уплотняются, сохраняя порядок отображения. + if len(result) > PBUS_CAPACITY: # Ограничиваем число строк реальным буфером 0x2040–0x207F. + raise ValueError("PBUS: в таблице нет места, максимум 64 регистра") # Переполнение не должно отправлять частичную аппаратную конфигурацию. + return validated_entries(result) # Все CD и адреса новой полной таблицы проверены ещё до постановки аппаратных команд в очередь. + + +def pbus_table_steps(entries, errors=PBUS_ERROR_LIMIT, *, configure=True, stop_control=None, settle_ms=PBUS_SETTLE_MS, on_control=None): # Перенастройка и ожидание свежего буфера выполняются одной последовательной операцией очереди. + entries = validated_entries(entries) # Фиксируем все платы, регистры, порядок и CD до первой записи управления. + control = pbus_control(len(entries), errors) # Для новой таблицы младший байт задаёт её последний используемый индекс. + if not isinstance(settle_ms, int) or not 1 <= settle_ms <= 60000: # Пауза аппаратного обновления явно задаётся в миллисекундах, от одной до минуты. + raise ValueError("PBUS: пауза после запуска должна быть 1…60000 мс") # Некорректное время не допускает запуска таблицы с немедленным чтением старого буфера. + if configure: # Изменение любой строки требует полной остановки и переписи всей новой таблицы. + stopped = (control if stop_control is None else stop_control) & 0x7FFF # У активной таблицы сохраняем порог и последний индекс, сбрасывая только бит 15. + yield PBUS_COMMAND, stopped # Ждём подтверждения остановки прежде, чем менять индекс или дескриптор. + if on_control is not None: # Панель отслеживает только уже подтверждённые управляющие записи. + on_control(stopped) # После ошибки следующей записи прежняя таблица остаётся известной как остановленная. + if not entries: # Пустая таблица не содержит последнего индекса и не должна запускаться для очистки. + return {"entries": [], "rows": [], "control": stopped} # Оставляем PBUS остановленной без 0x80FE, переполнения N-1 и чтения прежнего буфера. + for index, entry in enumerate(entries): # Переписываем все записи, даже если изменилась только одна из них. + yield PBUS_TABLE_INDEX, index # Индекс таблицы нумеруется с нуля и не подменяется адресом результата. + cd = pbus_result_address(entry, index) & 0xFF # CD извлекается из фактического адреса чтения этой строки на странице 0x2000. + yield PBUS_TABLE_DATA, pbus_descriptor(entry["tetrad"], entry["register"], cd) # Дескриптор хранит плату, регистр и CD выбранной записи в 0x200E. + yield PBUS_COMMAND, control | 0x8000 # Только подтверждение всех пар 0x200D/0x200E разрешает запуск новой длины N-1. + if on_control is not None: # Успешный ответ запуска фиксирует реальные параметры работающей таблицы. + on_control(control | 0x8000) # Последующая остановка сохранит именно этот порог и последний индекс. + yield ExchangeDelay(settle_ms) # Не читаем старые слова буфера сразу после подтверждения запуска: ждём настроенный аппаратный интервал. + rows = [] # Результаты соответствуют порядку снимка, но их адреса определяются полем CD. + for index, entry in enumerate(entries): # Обычное обновление не отправляет ни одной управляющей записи и не перезапускает PBUS. + address = pbus_result_address(entry, index) # Полный словный адрес равен 0x2000 | CD независимо от номера платы и регистра. + reply = yield address, None # Существующий ReadMemory возвращает одно шестнадцатибитное слово контроллера TMS. + if not isinstance(reply, dict) or not isinstance(reply.get("value"), int) or not 0 <= reply["value"] <= 0xFFFF: # Проверяем реальный формат результата чтения, не обращаясь к статусу 0x2012. + raise ValueError(f"PBUS: некорректный ответ памяти 0x{address:04X}") # Ошибка указывает фактический адрес CD, а не индекс строки. + rows.append(reply) # HEX и DEC каждого результата будут заполнены только после успешного цикла. + return {"entries": entries, "rows": rows, "control": control | 0x8000 if entries and configure else stop_control} # Заполненная таблица подтверждается данными после паузы, пустая остаётся остановленной. diff --git a/python/pysetterminal/exchange_queue.py b/python/pysetterminal/exchange_queue.py new file mode 100644 index 0000000..5bb5c82 --- /dev/null +++ b/python/pysetterminal/exchange_queue.py @@ -0,0 +1,144 @@ +"""Последовательная очередь логических операций одного соединения UART.""" # Все панели разделяют владение портом на протяжении многошагового действия. +from collections import deque # Две очереди обеспечивают приоритет ручных действий без перестановки их порядка. +from PySide6.QtCore import QObject, QTimer, Qt # Точный таймер сохраняет аппаратную паузу без преждевременного чтения памяти контроллера. + + +class ExchangeDelay: # Пауза аппаратного обновления является частью той же операции, а не отдельным обменом UART. + def __init__(self, milliseconds): # Время ожидания задаётся явно вызывающим алгоритмом в миллисекундах. + self.milliseconds = milliseconds # Очередь сохраняет владение операцией, пока контроллер обновляет буфер результатов. + + +class ExchangeQueue(QObject): # Один экземпляр привязан к протоколу и используется всеми рабочими панелями. + def __init__(self, protocol): # Протокол остаётся ответственным за кодирование, CRC и таймаут отдельного пакета. + super().__init__() # Таймеры очереди принадлежат объекту Qt с тем же временем жизни. + self.protocol, self.active = protocol, None # Активная операция удерживает порт до завершения всех своих шагов. + self.manual, self.background = deque(), deque() # Пользовательские действия выбираются раньше следующего фонового задания. + self.timer = QTimer(self) # Таймер также позволяет дождаться ранее начатого внешнего обмена. + self.timer.setSingleShot(True) # Каждое продолжение назначается однократно, исключая накопление событий. + self.timer.timeout.connect(self._pump) # Новая операция выбирается только после освобождения соединения. + + def contains(self, key): # Периодический источник проверяет наличие своего предыдущего задания. + return any(job["key"] == key for job in ([self.active] if self.active else []) + list(self.manual) + list(self.background)) # Проверка охватывает ожидание и выполнение, поэтому пропущенные циклы не копятся. + + def submit_external(self, start, pending, callback, *, key=None, background=False, immediate=False): # Прежние обработчики SETGUI выполняются под тем же владением соединением. + def wait(done): # Адаптер удерживает очередь до завершения внешнего асинхронного обработчика. + start() # Параметры внешней операции уже зафиксированы вызывающей панелью. + def poll(): # Проверяем завершение через события Qt, не блокируя UART и интерфейс. + if pending(): # Прежний обработчик ещё получает ответ или выполняет следующий шаг проверки записи. + QTimer.singleShot(10, poll) # Период проверки в миллисекундах не порождает дубликатов команд. + else: # Внешний обмен завершился и самостоятельно отобразил результат или ошибку. + done(True, None) # Следующая логическая операция теперь может владеть портом. + poll() # Синхронное действие без ожидаемого ответа освобождает очередь сразу. + def steps(): # Общий исполнитель использует одинаковое завершение обычных и внешних операций. + yield wait # Callable получает callback и удерживает очередь до его вызова. + return None # Результат внешнего действия уже обработан его существующей панелью. + accepted = self.submit(steps, None, callback, key=key, background=background) # Сохраняем приоритет и защиту от повторов для общего соединения. + if accepted and immediate: # Прежние обработчики могут сохранить немедленную отправку при свободном соединении. + self._pump() # Занятый порт всё равно оставляет действие ожидающим в общей очереди. + return accepted # Возвращаем факт принятия задания либо подавления периодического дубликата. + + def submit(self, factory, controller, callback, *, key=None, background=False): # Фабрика создаёт генератор при начале операции, параметры передаются уже зафиксированными. + if key is not None and self.contains(key): # Один периодический источник допускает только одно незавершённое повторение. + return False # Не добавляем дубликат в очередь и не создаём отложенного повторения. + job = {"factory": factory, "controller": controller, "callback": callback, "key": key, "cancelled": False, "waiting": False, "iterator": None} # Снимок контроллера принадлежит всей логической операции. + (self.background if background else self.manual).append(job) # Фоновая операция не вытесняет уже ожидающее нажатие пользователя. + self.timer.start(0) # Запуск откладывается до следующего события Qt, оставляя интерфейс отзывчивым. + return True # Вызывающий код может отличить постановку задания от подавленного дубликата. + + def cancel(self, key): # Остановка задания удаляет будущие команды, сохраняя текущий пакет до ответа или таймаута. + for pending in (self.manual, self.background): # Удаляем задания из обеих очередей независимо от их приоритета. + removed = [job for job in pending if job["key"] == key] # Сохраняем callbacks отменённых заданий для завершения состояния владельца. + pending_copy = [job for job in pending if job["key"] != key] # Остальные источники продолжают ожидать в прежнем порядке. + pending.clear() # Пересобираем только контейнер очереди, не изменяя задания других панелей. + pending.extend(pending_copy) # Возвращаем ожидающие операции, которые не принадлежат остановленному источнику. + for job in removed: # Каждый владелец получает однозначное уведомление об отмене своего ожидания. + job["callback"](False, "Остановлено") # Ни один пакет снятой операции ещё не был отправлен. + if self.active and self.active["key"] == key: # Выполняющееся задание прекращаем после уже отправленного пакета. + self.active["cancelled"] = True # Следующий шаг генератора не будет отправлен, даже при успешном ответе. + if not self.active["waiting"]: # Между пакетами отмена может завершиться немедленно. + self._complete(False, "Остановлено") # Освобождаем порт без искусственного транспортного таймаута. + + def clear(self): # Отключение соединения удаляет все задания и будущие продолжения. + keys = {job["key"] for job in list(self.manual) + list(self.background) + ([self.active] if self.active else [])} # Снимок ключей не меняется при вызове callbacks отмены. + for key in keys: # Применяем одинаковую отмену ко всем источникам данного соединения. + self.cancel(key) # Активный пакет корректно завершится либо будет отменён транспортом при закрытии порта. + + def _transport_busy(self): # Учитываем прежние операции встроенного окна, начатые до использования очереди. + host = getattr(self.protocol, "host", None) # В SETGUI протокол использует общий QSerialPort родительской вкладки. + return bool(getattr(self.protocol, "_callback", None) or getattr(self.protocol, "callback", None) or getattr(self.protocol, "_loop", None) or (host and host._pending_address is not None)) # Занятый внешний обмен нельзя замещать новым callback. + + def _pump(self): # Выбираем операцию только между целостными чтениями или записями регистра. + if self.active: # Пока генератор удерживает соединение, очередь не начинает другие операции. + return # Продолжение активной операции приходит через её транспортный callback. + if not self.manual and not self.background: # Пустая очередь не создаёт периодических событий сама по себе. + return # Отсутствие заданий позволяет соединению оставаться полностью свободным. + if self._transport_busy(): # Ждём завершения внешней операции вместо отказа пользователю. + self.timer.start(10) # Короткое ожидание в миллисекундах не блокирует обработку UART и интерфейса. + return # Параметры ожидающих нажатий при этом остаются неизменными. + self.active = (self.manual if self.manual else self.background).popleft() # FIFO ручных действий имеет приоритет над следующим фоновым циклом. + self._advance(None) # Первый шаг генератора отправляется только после получения владения соединением. + + def _advance(self, reply): # Генератор выдаёт следующий запрос только после завершения предыдущего. + job = self.active # Сохраняем владельца, чтобы поздний ответ не продолжил другую операцию. + if job is None: # Очередь могла быть очищена отключением соединения. + return # Без владельца никакие команды не отправляются. + delay = job.pop("delay_timer", None) # Завершившийся таймер аппаратного ожидания больше не нужен текущему генератору. + if delay is not None: # Обычные UART-продолжения не создают отдельного таймера аппаратной паузы. + delay.stop() # Завершённое или отменённое ожидание не назначает повторного события. + delay.deleteLater() # Освобождаем QObject после обработки текущего события Qt. + if job["cancelled"]: # Остановка отменяет все шаги, которые ещё не переданы контроллеру. + self._complete(False, "Остановлено") # Текущий пакет к этому моменту уже получил ответ или таймаут. + return # Не возобновляем остановленный генератор. + try: # Ошибки параметров и результата завершают логическую операцию без повреждения очереди. + if job["iterator"] is None: # Фабрика использует актуальную таблицу PBUS при зафиксированном действии пользователя. + job["iterator"] = job["factory"]() # Генератор создаётся один раз на целую операцию. + request = next(job["iterator"]) # Первое чтение не получает фиктивного ответа предыдущей операции. + else: # Последующие шаги получают реальное подтверждение или считанное слово. + request = job["iterator"].send(reply) # Запись подготовки и чтение результата не могут перемешаться с другим заданием. + except StopIteration as completed: # Генератор закончил все шаги одной логической операции. + self._complete(True, completed.value) # Возвращаем итог владельцу и освобождаем соединение. + return # Завершённый генератор больше не используется. + except (ValueError, RuntimeError, TypeError, KeyError) as error: # Неверные параметры или подтверждения не должны разрывать цикл событий Qt. + self._complete(False, str(error)) # Сохраняем действительную причину ошибки в панели инициатора. + return # Следующая ожидающая операция сможет продолжить обмен. + if isinstance(request, ExchangeDelay): # После запуска PBUS аппаратуре даётся время обновить слова памяти до первого чтения. + delay = QTimer(self) # Отдельный таймер принадлежит данной аппаратной паузе, а не планировщику выбора операций. + delay.setSingleShot(True) # Одна пауза заканчивается одним продолжением генератора. + delay.setTimerType(Qt.PreciseTimer) # Штатный грубый таймер может сработать раньше, что недопустимо перед чтением нового буфера PBUS. + delay.timeout.connect(lambda: self._advance(None) if self.active is job else None) # Продолжение остаётся связано с владельцем всей перенастройки. + job["delay_timer"] = delay # Остановка задания сможет немедленно отменить его ещё не завершённую паузу. + delay.start(request.milliseconds) # Ожидаем заданное время в миллисекундах после подтверждения запуска контроллером. + return # UART-пакет не отправляется; остановка может немедленно отменить эту паузу и все следующие команды. + job["waiting"] = True # До вызова транспорта отмечаем ожидание, включая синхронный отказ отключённого порта. + try: # Защищаем очередь также от исключения драйвера при отправке. + if callable(request): # Прежняя операция SETGUI или RAW выполняется только после получения общего владения UART. + request(lambda ok, result: self._reply(job, ok, result)) # Внешний обработчик завершает ожидание через тот же callback очереди. + return # Не трактуем внешнее действие как адрес памяти PEEK/POKE. + address, value = request # Формат PEEK/POKE остаётся прежним для обеих шин. + self.protocol.request_async(address, value, job["controller"], lambda ok, result: self._reply(job, ok, result)) # Существующий протокол проверяет ответ и задаёт таймаут пакета. + except (ValueError, RuntimeError, OSError) as error: # Ошибка порта завершает текущую операцию и освобождает очередь. + self._reply(job, False, str(error)) # Используем тот же путь, что для асинхронного отказа обмена. + + def _reply(self, job, success, result): # Ответ всегда относится к владельцу пакета, а не к последнему нажатию. + if self.active is not job: # Поздний callback закрытого соединения не меняет новое задание. + return # Исключаем продвижение чужого генератора устаревшим ответом. + job["waiting"] = False # Порт освободился после полного ответа либо обработанного таймаута. + if job["cancelled"] or not success: # Остановка и реальная ошибка запрещают отправку следующих пакетов. + self._complete(False, "Остановлено" if job["cancelled"] else result) # Отмена не маскируется как успешное чтение. + return # Остальные команды остановленного задания не попадут в UART. + QTimer.singleShot(0, lambda: self._advance(result) if self.active is job else None) # Даём обработать остановку между пакетами, удерживая владение операцией. + + def _complete(self, success, result): # Завершение освобождает соединение до уведомления владельца операции. + job, self.active = self.active, None # Callback может поставить следующую команду макроса в общую очередь. + delay = job.pop("delay_timer", None) # Пользовательская остановка может завершить операцию прямо во время аппаратной паузы. + if delay is not None: # Завершение обычного пакета не содержит такого таймера. + delay.stop() # Отменённая пауза больше не продолжит чтение не применённой таблицы. + delay.deleteLater() # Освобождаем временный QObject вместе с завершённым заданием. + job["callback"](success, result) # Результат отображается только инициатором данной операции. + self.timer.start(0) # Между командами макроса выбираем ожидающее ручное действие раньше фонового продолжения. + + +def exchange_queue(protocol): # Общая очередь создаётся лениво для существующих и тестовых протоколов. + if not hasattr(protocol, "operation_queue"): # Панели одного соединения должны получать один и тот же экземпляр. + protocol.operation_queue = ExchangeQueue(protocol) # Владение протоколом сохраняется без изменения формата пакетов. + return protocol.operation_queue # Возвращаем единый планировщик ручного обмена и периодических заданий. diff --git a/python/pysetterminal/mainterm.py b/python/pysetterminal/mainterm.py index 720e88b..d63ef61 100644 --- a/python/pysetterminal/mainterm.py +++ b/python/pysetterminal/mainterm.py @@ -155,7 +155,7 @@ class MainWindow(QMainWindow): QMessageBox.warning(self, "Ошибка", f"Ошибка подключения: {e}") def closeEvent(self, event): - self.serial_tab.stop_macro() + self.serial_tab.stop() # Отключение протокола прекращает общий макрос и последующие фоновые чтения PBUS. self.raw_protocol.cancel_async() self.raw_protocol.disconnect() super().closeEvent(event) diff --git a/python/pysetterminal/panel.py b/python/pysetterminal/panel.py index 4fa8540..98387d7 100644 --- a/python/pysetterminal/panel.py +++ b/python/pysetterminal/panel.py @@ -30,7 +30,8 @@ class ByteWorkPanel(QScrollArea): self.device_address = device_address self._start_word = start_word self._word_running = False - self._word_generation = 0 + self._word_generation = 0 # Поколение сохраняет совместимость с прежними обработчиками результатов. + self._word_keys = set() # Каждый принятый запрос слова получает независимый ключ отмены. self.setWidgetResizable(True) content = QWidget() self.setWidget(content) @@ -112,9 +113,6 @@ class ByteWorkPanel(QScrollArea): self.byte_read_binary.setText(self._binary(value)) def start_byte(self, write): - if self._word_running: - self._report("Дождитесь завершения текущего обмена") - return try: field = self.byte_write_address if write else self.byte_read_address text = field.text().strip() @@ -132,46 +130,42 @@ class ByteWorkPanel(QScrollArea): if self._start_word is not None: self._start_word(write, address, value) return - controller = self.device_address() if callable(self.device_address) else self.device_address - self._word_generation += 1 - generation = self._word_generation - self._set_word_running(True) - self._report("Запись и проверка чтением…" if write else "Чтение…") - self.protocol.request_async(address, value, controller, - lambda success, result: self._word_reply(generation, address, value, controller, success, result)) + controller = self.device_address() if callable(self.device_address) else self.device_address # Адрес контроллера фиксируется до ожидания занятого соединения. + key = object() # Повторное нажатие создаёт самостоятельное действие, а не заменяет предыдущее. + self._word_keys.add(key) # Все ожидающие слова учитываются для остановки страницы. + self._set_word_running(True) # Признак состояния не меняет доступность полей и кнопок. + self.bus_widget.queue.submit(lambda: self._word_steps(address, value), controller, lambda ok, reply: self._word_done(key, address, value, ok, reply), key=key) # Запись и проверка чтением выполняются целиком без вмешательства другой шины. - def _word_reply(self, generation, address, expected, controller, success, result): - if generation != self._word_generation or not self._word_running: - return - if not success: - self._set_word_running(False) - self._report(str(result)) - return - if expected is not None and "value" not in result: - self.protocol.request_async(address, None, controller, - lambda ok, reply: self._word_reply(generation, address, expected, controller, ok, reply)) - return - value = result["value"] - self.set_read_value(address, value) - self._set_word_running(False) - if expected is not None and value != expected: - self._report(f"Запись 0x{address:08X} не подтверждена: прочитано {value:04X}, ожидалось {expected:04X}") - else: - self._report("Запись проверена чтением" if expected is not None else "Чтение завершено") + def _word_steps(self, address, value): # Существующий протокол сохраняет проверку записанного слова чтением того же адреса. + if value is not None: # Чистое чтение не требует предварительного WriteMemory. + yield address, value # Подтверждение записи должно прийти до запроса проверки. + result = yield address, None # ReadMemory возвращает одно шестнадцатибитное слово по выбранному адресу. + if not isinstance(result, dict) or not isinstance(result.get("value"), int) or not 0 <= result["value"] <= 0xFFFF: # Неверный ответ не выдаётся за прочитанное слово. + raise ValueError("Некорректный ответ чтения памяти") # Ошибка формата остаётся доступна в статусе страницы. + return result # Только финальный ответ используется для отображения HEX и BIN. - def _set_word_running(self, running): - self._word_running = running - self.byte_write_button.setEnabled(not running) - self.byte_read_button.setEnabled(not running) + def _word_done(self, key, address, expected, success, result): # Результат связан с параметрами конкретного нажатия, а не с изменёнными полями. + if key not in self._word_keys: # Поздний callback закрытой страницы не перезаписывает её значения. + return # Остановленное действие не продолжает обмен. + self._word_keys.remove(key) # Этот запрос слова больше не ожидает соединение. + self._set_word_running(bool(self._word_keys)) # Признак учитывает остальные принятые нажатия. + if not success: # Таймаут, ошибка CRC или отключение отображаются как действительные ошибки связи. + self._report(str(result)) # Пользователь видит причину отказа данного запроса. + return # Не показываем недостоверное слово памяти. + value = result["value"] # Проверенное слово принадлежит завершённому ReadMemory. + self.set_read_value(address, value) # Заполняем имеющиеся поля HEX и BIN без пересоздания панели. + if expected is not None and value != expected: # Прежняя проверка записи сохраняется для несовпадающего прочитанного значения. + self._report(f"Запись 0x{address:08X} не подтверждена: прочитано {value:04X}, ожидалось {expected:04X}") # Указываем адрес, фактическое слово и ожидаемое значение. + else: # Успешное чтение либо совпадающая проверка записи завершают действие. + self._report("Запись проверена чтением" if expected is not None else "Чтение завершено") # Сохраняем понятный итог операции. - def stop(self): - """Cancel this page's scheduled work before closing its connection.""" - self.bus_widget.stop_macro() - if self._word_running: - self._word_generation += 1 - self._set_word_running(False) - self.protocol.cancel_async() - self._report("Обмен прерван; переданные команды могли быть выполнены") + def _set_word_running(self, running): # Состояние обмена хранится отдельно от доступности интерфейса. + self._word_running = running # Кнопки и поля принимают новые действия даже во время текущего обмена. + + def stop(self): # Отключение страницы отменяет задания всего общего соединения. + self._word_keys.clear() # Поздние результаты отключения не меняют поля закрываемой страницы. + self._set_word_running(False) # Завершаем состояние ожидания собственных запросов слова. + self.bus_widget.stop() # Общая очередь снимает неотправленные задания и отменяет текущий транспорт при закрытии соединения. def closeEvent(self, event): self.stop() diff --git a/python/pysetterminal/pbus_panel.py b/python/pysetterminal/pbus_panel.py new file mode 100644 index 0000000..28a2c47 --- /dev/null +++ b/python/pysetterminal/pbus_panel.py @@ -0,0 +1,346 @@ +"""Таблица наблюдаемых регистров PBUS внутри общей панели команд SETGUI.""" + +from PySide6.QtCore import Qt, QEvent, QTimer, QItemSelectionModel, QSize, QRect # Геометрия Qt позволяет компактно переносить связанные элементы в узком доке. +from PySide6.QtGui import QIntValidator # Проверяем четырёхбитные адреса платы и регистра ещё при вводе. +from PySide6.QtWidgets import QWidget, QLayout, QSizePolicy, QGroupBox, QVBoxLayout, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QSpinBox, QCheckBox, QTableWidget, QTableWidgetItem, QAbstractItemView, QHeaderView, QPlainTextEdit # Адаптивная строка сохраняет компактные действия независимо от ширины таблицы результатов. +from .bus_operations import table_entries_after, pbus_table_steps, pbus_control, pbus_result_address, PBUS_COMMAND, PBUS_SETTLE_MS, PBUS_ERROR_LIMIT # Полная конфигурация, адреса CD и остановка используют единый формат слов памяти TMS. + + +class _FlowLayout(QLayout): # Связанные элементы располагаются рядом и переносятся целиком при недостатке ширины. + def __init__(self, parent, spacing): # Промежуток задаётся в пикселях одинаково для горизонтального и вертикального переноса. + super().__init__(parent) # Компоновка принадлежит только своему компактному контейнеру. + self.items = [] # Храним порядок полей и действий без изменения их владельцев при переносе. + self.setContentsMargins(0, 0, 0, 0) # Контейнер не добавляет второго слоя отступов формы. + self.setSpacing(spacing) # Сохраняем небольшое постоянное расстояние между связанными элементами. + self.setProperty("fixedPanelLayout", True) # Общий менеджер панелей не должен заменять перенос элементов сплиттером. + + def addItem(self, item): # Qt вызывает этот метод при добавлении виджета в адаптивную строку. + self.items.append(item) # Сохраняем порядок элементов, заданный формой пользователя. + + def count(self): # Предоставляем Qt фактическое число элементов компоновки. + return len(self.items) # Перенос не создаёт дополнительных или скрытых копий действий. + + def itemAt(self, index): # Менеджер геометрии получает элемент по индексу без удаления. + return self.items[index] if 0 <= index < len(self.items) else None # Невалидный индекс завершает стандартный обход компоновки. + + def takeAt(self, index): # Qt извлекает элемент при удалении или уничтожении контейнера. + return self.items.pop(index) if 0 <= index < len(self.items) else None # Ссылки на элементы удаляются вместе с компоновкой. + + def expandingDirections(self): # Свободное пространство не должно растягивать промежутки между действиями. + return Qt.Orientations(0) # Элементы используют собственные размеры, оставляя лишнюю ширину справа. + + def hasHeightForWidth(self): # Высота зависит от числа строк после переноса по доступной ширине. + return True # Владелец учитывает дополнительную строку, не обрезая кнопку или результат. + + def heightForWidth(self, width): # Измеряем необходимую высоту до назначения окончательной геометрии. + return self._arrange(QRect(0, 0, width, 0), False) # Расчёт не перемещает виджеты при измерении размеров. + + def minimumSize(self): # Узкий док должен вмещать самый широкий отдельный элемент, а не сумму всех кнопок. + size = QSize(0, 0) # Начальная минимальная область не занимает места до добавления элементов. + for item in self.items: # Каждая кнопка или карточка переносится целиком и сохраняет читаемость. + size = size.expandedTo(item.minimumSize()) # Минимальная ширина равна самому широкому элементу, высота — минимальной строке. + return size # Перенос позволяет сохранить равные доли ширины команд и RAW-панели. + + def sizeHint(self): # Естественный размер подстраивается к ширине, которую даст внешний контейнер. + return self.minimumSize() # Дополнительная высота вычисляется через heightForWidth при реальном размещении. + + def setGeometry(self, rect): # Qt назначает доступную область адаптивной строки. + super().setGeometry(rect) # Сохраняем стандартную геометрию компоновки для родительского виджета. + self._arrange(rect, True) # Размещаем элементы по строкам внутри выделенной области. + + def _arrange(self, rect, apply): # Один расчёт используется измерением и реальным размещением элементов. + left, x, y, row_height = rect.x(), rect.x(), rect.y(), 0 # Начинаем каждую строку у левого края контейнера. + for item in self.items: # Порядок управления сохраняется при любом размере дока. + size = item.sizeHint().expandedTo(item.minimumSize()) # Не сжимаем подписи, стрелки интервала или считанное слово. + if x > left and x + size.width() > left + rect.width(): # Элемент переносится, если целиком не помещается после предыдущего. + x, y, row_height = left, y + row_height + self.spacing(), 0 # Следующая строка начинается без пустого промежутка слева. + if apply: # Во время измерения геометрия виджетов остаётся неизменной. + item.setGeometry(QRect(x, y, size.width(), size.height())) # Поля и действия занимают свою естественную ширину рядом друг с другом. + x += size.width() + self.spacing() # Следующий элемент получает только небольшой постоянный промежуток. + row_height = max(row_height, size.height()) # Высота строки вмещает самый высокий её элемент. + return y + row_height - rect.y() # Внешняя компоновка получает общую высоту всех занятых строк. + + +class CompactControls(QWidget): # Компактная строка переносит связанные поля, карточки или действия без растягивания по краям окна. + def __init__(self, widgets, parent=None, spacing=8): # По умолчанию элементы разделены восьмью пикселями. + super().__init__(parent) # Контейнер остаётся частью существующего блока своей шины. + policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) # Доступная ширина используется для переноса, высота соответствует содержимому. + policy.setHeightForWidth(True) # Узкий док выделяет высоту для следующей строки вместо увеличения минимальной ширины окна. + self.setSizePolicy(policy) # Внешняя область корректно учитывает адаптивную высоту формы. + layout = _FlowLayout(self, spacing) # Все элементы используют один расчёт переноса и минимального размера. + for widget in widgets: # Связанные действия добавляются в пользовательском порядке. + layout.addWidget(widget) # Перенос не изменяет обработчики команд и результаты операции. + + +class PbusPanel(QGroupBox): # Хранит один общий список источников PBUS и результаты их считывания. + def __init__(self, owner): # Владелец предоставляет единую очередь PBUS, SBUS и смешанных макросов. + super().__init__("PBUS (Параллельная шина)", owner) # Русская подпись обозначает правый блок существующей панели SETGUI. + self.owner, self.entries, self.applied = owner, [], False # Видимый список отдельно учитывает подтверждение его аппаратной конфигурации. + self.controller = None # Таблица считается применённой только для контроллера, которому отправлена конфигурация. + self._controls, self._applied_signature = {}, None # Последние подтверждённые управляющие слова хранятся отдельно для каждого контроллера. + self.table_errors = PBUS_ERROR_LIMIT # Начальный аппаратный порог равен десяти ошибкам, как в рабочем слове запуска 0x8Axx. + self.setObjectName("pbusGroup") # Стабильное имя сохраняет поиск панели в интеграциях и проверках интерфейса. + layout = QVBoxLayout(self) # Таблица и журнал получают свободную область независимо от ширины полей добавления. + layout.setContentsMargins(10, 14, 10, 10) # Отступы в пикселях совпадают с соседним блоком SBUS. + layout.setSpacing(8) # Параметры, действия и результаты образуют плотные связанные области. + layout.setProperty("fixedPanelLayout", True) # Общий менеджер панелей не должен превращать компактные формы в растягиваемые области. + controls = QWidget(self) # Адрес платы и регистр не делят столбцы с широкой таблицей результатов. + controls.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) # Контейнер ограничивается естественной шириной подписей и полей. + form = QGridLayout(controls) # Два компактных столбца сохраняют значения рядом с подписями. + form.setContentsMargins(0, 0, 0, 0) # Вложенная форма не добавляет второго уровня внешних отступов. + form.setHorizontalSpacing(10) # Подпись и её поле разделены десятью пикселями вместо ширины всей панели. + form.setVerticalSpacing(6) # Строки адреса и регистра остаются визуально связанными. + form.setProperty("fixedPanelLayout", True) # Форма сохраняет компактную геометрию при применении общей раскладки приложения. + self.controls = {} # Публичные элементы доступны владельцу без копирования их состояния. + for row, (name, caption) in enumerate((("tetrad_edit", "Адрес платы (0–15):"), ("register_edit", "Регистр (0–15):"))): # Для добавления достаточно указать источник данных, индексы буфера вычисляются автоматически. + field = QLineEdit("0") # Начальное значение позволяет добавить первый регистр без заполнения дополнительных аппаратных полей. + field.setValidator(QIntValidator(0, 15, field)) # Каждый адрес занимает одну тетраду дескриптора x_parallel_bus_add_table. + field.setFixedWidth(90) # Девяносто пикселей достаточно для адреса; поле не уезжает к правому краю широкого дока. + form.addWidget(QLabel(caption), row, 0) # Подпись объясняет допустимый адрес платы или регистра. + form.addWidget(field, row, 1) # Поле находится непосредственно рядом со своей подписью. + self.controls[name] = field # Сохраняем адресные поля для кнопки добавления и внешних проверок. + field.returnPressed.connect(self.add_register) # Enter в адресных полях добавляет регистр без перемещения к кнопке. + self.error_limit = QSpinBox(self) # Отдельный параметр правой колонки задаёт аппаратный порог ошибок PBUS. + self.error_limit.setRange(1, 15) # Порог занимает четыре бита управляющего слова; допустимы целые значения от одного до пятнадцати. + self.error_limit.setValue(PBUS_ERROR_LIMIT) # Значение десять соответствует шестнадцатеричному порогу 0xA. + self.error_limit.setFixedWidth(90) # Поле порога выровнено с существующими компактными адресными полями. + self.error_limit.setToolTip("Порог в битах 11:8 регистра 0x200C. 10 = 0xA. Применяется при добавлении, изменении таблицы или нажатии «Обновить».") # Пользователь видит единицы и момент аппаратного применения выбранного числа ошибок. + form.addWidget(QLabel("Порог ошибок (1–15):"), 2, 0) # Подпись отличает аппаратный порог от периода чтения и паузы после запуска. + form.addWidget(self.error_limit, 2, 1) # Настройка находится в блоке PBUS рядом с платой и регистром. + self.controls["error_limit"] = self.error_limit # Порог доступен владельцу как pbus_error_limit вместе с остальными элементами PBUS. + layout.addWidget(controls, 0, Qt.AlignLeft) # Компактная форма начинается слева и не растягивается вместе с таблицей. + self.add_btn, self.remove_btn = QPushButton("Добавить в таблицу"), QPushButton("Убрать из таблицы") # Подписи соответствуют работе со списком вместо ручного чтения и записи. + self.edit_btn = QPushButton("Изменить строку", self) # Адрес и регистр выделенной строки заменяются значениями полей без ручного удаления и добавления. + self.edit_btn.setFixedHeight(30) # Действие сохраняет существующую высоту кнопок управления таблицей. + self.edit_btn.setToolTip("Заменить выделенную строку адресом платы и регистром из полей выше.") # Пользователь видит, какие параметры будут применены к выбранному источнику. + self.edit_btn.clicked.connect(self.edit_selected) # Редактирование ставит полную перенастройку в ту же очередь памяти контроллера. + self.add_btn.clicked.connect(self.add_register) # Добавление само применяет таблицу и получает первое считанное значение. + self.remove_btn.clicked.connect(self.remove_selected) # Кнопка удаляет все выделенные строки независимо от текущей ячейки. + layout.addWidget(CompactControls((self.add_btn, self.edit_btn, self.remove_btn), self)) # Действия находятся рядом под адресом и переносятся в узком доке вместо сжатия RAW-панели. + self.auto_update = QCheckBox("Циклическое чтение") # Переключатель управляет запросами буфера, а не созданием независимого макроса. + self.auto_update.setChecked(True) # После явного добавления регистра таблица продолжает показывать текущие считанные значения. + self.interval = QSpinBox() # Интервал ограничивает частоту запросов ПК к контроллеру. + self.interval.setRange(1, 3600000) # Период чтения задаётся в миллисекундах от одной до одного часа. # Интервал от 100 мс до 60 с позволяет выбрать удобную частоту обновления без непрерывного цикла Qt. + self.interval.setValue(1000) # По умолчанию обновляем результаты раз в секунду, не перегружая последовательное соединение. + self.interval.setSuffix(" мс") # Единицы измерения видны непосредственно в поле интервала. + self.interval.setFixedWidth(120) # Сто двадцать пикселей вмещают число, единицы и стрелки темы без растягивания поля по всей панели. + self.startup_delay = QSpinBox(self) # Отдельная пауза относится только к аппаратному обновлению после запуска новой таблицы. + self.startup_delay.setRange(1, 60000) # Пользователь задаёт ожидание контроллера от одной миллисекунды до минуты. + self.startup_delay.setValue(PBUS_SETTLE_MS) # Начальное ожидание составляет сто миллисекунд и не заменяет период чтения. + self.startup_delay.setSuffix(" мс") # Поле явно обозначает единицу измерения задержки. + self.startup_delay.setFixedWidth(120) # Пауза занимает компактное место рядом со своей подписью. + self.startup_delay.setToolTip("После подтверждения запуска PBUS ждать аппаратного обновления памяти; прежние значения буфера до этого не показываются.") # Подсказка объясняет отличие от периода обычного опроса. + self.refresh_btn = QPushButton("Обновить") # Ручное обновление полезно при выключенном автоопросе или после подключения порта. + self.refresh_btn.clicked.connect(self.refresh) # Получаем все слова текущего списка одной последовательностью запросов. + for widget in (self.auto_update, self.interval, self.refresh_btn): # Размещаем все средства обновления в одной строке. + widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) # Переключатель и действия занимают необходимую ширину вместо распределения по краям окна. + layout.addWidget(CompactControls((self.auto_update, self.interval, self.refresh_btn), self)) # Средства обновления остаются компактной группой и переносятся при недостатке ширины. + layout.addWidget(CompactControls((QLabel("После запуска:"), self.startup_delay), self)) # Пауза настройки отделена от строки периодического чтения буфера. + self.table = QTableWidget(0, 5) # Одна строка соответствует одному добавленному регистру PBUS. + self.table.setObjectName("pbusResultsTable") # Имя позволяет проверять и находить новую таблицу результатов в SETGUI. + self.table.setHorizontalHeaderLabels(["Плата", "Регистр", "HEX", "DEC", "Состояние"]) # Показываем источник, оба представления слова и достоверность результата. + self.table.setSelectionBehavior(QAbstractItemView.SelectRows) # Выделение целой строки делает удаление регистра однозначным. + self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) # Shift и Ctrl позволяют удалить несколько регистров одним действием. + self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) # Изменение считанных значений не должно подменять аппаратный результат. + self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) # Короткие адреса и значения занимают только необходимую ширину. + self.table.horizontalHeader().setStretchLastSection(True) # Состояние использует оставшуюся ширину, не обрезая описание ошибки. + self.table.setMinimumHeight(150) # Таблица остаётся пригодной для нескольких источников даже в компактной раскладке доков. + self.table.installEventFilter(self) # Клавиша Delete удаляет выбранные источники, когда таблица имеет фокус. + self.table.itemSelectionChanged.connect(self._selection_changed) # Доступность удаления соответствует текущему выделению строк. + layout.addWidget(self.table, 1) # Таблица результатов получает свободную высоту внутри блока PBUS. + self.result_label = QLabel("Добавьте регистры для считывания") # Начальный статус объясняет первое действие пользователя. + self.result_label.setWordWrap(True) # Диагностика остаётся внутри правого блока при изменении размера окна. + layout.addWidget(self.result_label) # Последнее состояние относится непосредственно к таблице PBUS. + self.output = QPlainTextEdit() # Собственный небольшой журнал сохраняет результаты изменения таблицы и пакеты ответов. + self.output.setReadOnly(True) # Пользователь может копировать ответы без изменения истории операций. + self.output.setMaximumBlockCount(200) # Ограничиваем историю, чтобы автообновление не увеличивало память бесконечно. + self.output.setFixedHeight(55) # Две-три строки журнала не вытесняют общую область макросов. + layout.addWidget(self.output) # Ответы PBUS сохраняются в правом блоке, без общей нижней панели результатов. + self.timer = QTimer(self) # Таймер принадлежит панели и прекращает существование вместе с ней. + self.timer.setTimerType(Qt.PreciseTimer) # Период циклического чтения не должен сокращаться из-за неточности таймера. + self.timer.timeout.connect(self._poll_tick) # Каждый такт читает только уже применённую аппаратную таблицу. + self.interval.valueChanged.connect(self._update_timer) # Новый интервал применяется к следующим циклам считывания. + self.auto_update.toggled.connect(self._auto_changed) # Пользователь может остановить обновление, не удаляя источники таблицы. + self.controls.update({"add_btn": self.add_btn, "remove_btn": self.remove_btn, "table": self.table, "result_label": self.result_label, "output": self.output}) # Экспортируем единственную таблицу и её действия для владельца. + self._selection_changed() # До выделения первой строки удаление недоступно. + + def command(self, operation, **parameters): # Создаём одинаковые команды для ручных действий и общего исполнителя макросов. + return {"bus": "pbus", "type": operation, "tetrad": 0, "register": 0, "errors": self.error_limit.value(), "settle_ms": self.startup_delay.value(), **parameters} # Действие фиксирует текущие параметры таблицы и паузу при постановке в очередь. + + def add_register(self): # Добавляем заданный адрес платы и регистра, не требуя номера строки буфера. + try: # Пустое поле не должно запускать аппаратную запись с неверным адресом. + command = self.command("add", tetrad=int(self.controls["tetrad_edit"].text()), register=int(self.controls["register_edit"].text())) # Фиксируем источник перед асинхронным обменом. + self.owner._start_commands([command], macro=False) # Таблица применяется через тот же транспорт, что SBUS и общие макросы. + except ValueError as error: # Ошибка ввода остаётся в области PBUS и не влияет на другой блок. + self.result_label.setText(f"PBUS: проверьте адрес и регистр: {error}") # Пользователь видит причину отказа непосредственно возле таблицы. + + def edit_selected(self): # Одна выбранная строка заменяется целым снимком таблицы с сохранением остальных источников и CD. + selected = self.table.selectionModel().selectedRows() # Фиксируем выделение в момент нажатия до ожидания очереди. + if len(selected) != 1: # Множественное выделение не должно случайно заменить несколько регистров одним адресом. + return # Пользователь должен выбрать конкретную редактируемую строку. + try: # Проверяем новые адреса ещё до остановки аппаратного опроса. + entries = [dict(entry) for entry in self.entries] # Полный снимок сохраняет порядок и явные CD всех остальных записей. + entries[selected[0].row()].update(tetrad=int(self.controls["tetrad_edit"].text()), register=int(self.controls["register_edit"].text())) # Меняются только плата и регистр выбранной строки, индекс и назначение результата сохраняются. + self.replace_entries(entries) # Очередь выполнит остановку, перепись всех записей и запуск как одну операцию. + except (ValueError, TypeError) as error: # Неверный ввод не меняет подтверждённую аппаратную таблицу. + self.result_label.setText(f"PBUS: проверьте адрес и регистр: {error}") # Причина отказа остаётся в собственной области PBUS. + + def remove_selected(self): # Удаляем все выделенные регистры кнопкой или клавишей Delete. + selected = sorted({index.row() for index in self.table.selectionModel().selectedRows()}) # Множественное выделение собираем один раз до переписи списка. + if not selected: # При отсутствии выделения список и аппаратная конфигурация остаются прежними. + return # Не создаём пустую аппаратную операцию удаления. + keys = [(self.entries[row]["tetrad"], self.entries[row]["register"]) for row in selected] # Удаление фиксируется по адресам, поэтому смещение индексов не удалит соседний регистр. + self.owner._start_commands([self.command("remove", remove_keys=keys)], macro=False) # Оставшиеся строки уплотняются и заново записываются в аппаратную таблицу. + + def eventFilter(self, watched, event): # Обеспечиваем привычное удаление строк клавишей Delete в таблице результатов. + if watched is self.table and event.type() == QEvent.KeyPress and event.key() == Qt.Key_Delete: # Обрабатываем Delete только внутри своей таблицы PBUS. + self.remove_selected() # Используем то же действие, что кнопка удаления выделенных строк. + event.accept() # Исключаем дополнительную обработку Delete таблицей Qt. + return True # Событие полностью обработано удалением выбранных регистров. + return super().eventFilter(watched, event) # Остальные клавиши сохраняют штатное выделение и навигацию таблицы. + + def _selection_changed(self): # Согласуем кнопку удаления с реальным выделением таблицы. + self.remove_btn.setEnabled(bool(self.table.selectionModel().selectedRows())) # Пользователь сразу видит, когда выбран регистр для удаления. + self.edit_btn.setEnabled(len(self.table.selectionModel().selectedRows()) == 1) # Изменение строки доступно для единственного выделенного источника, независимо от занятости UART. + + def _render_entries(self): # Индексы видимой таблицы всегда соответствуют порядку аппаратного буфера после переписи. + selected = {(self.table.item(index.row(), 0).text(), self.table.item(index.row(), 1).text()) for index in self.table.selectionModel().selectedRows() if self.table.item(index.row(), 0) is not None} # Сохраняем выделение по адресам, чтобы обновление и уплотнение не выбирали другой регистр. + self.table.blockSignals(True) # Промежуточное заполнение не должно сбрасывать доступность удаления несколько раз за цикл. + self.table.setRowCount(len(self.entries)) # Добавление и удаление изменяют единую таблицу результатов. + self.table.clearSelection() # Старые числовые индексы после удаления могут относиться уже к другой плате. + for row, entry in enumerate(self.entries): # Каждая строка содержит стабильные адреса платы и регистра. + values = (str(entry["tetrad"]), str(entry["register"]), "—", "—", "Ожидает считывания") # До подтверждения новой таблицы не показываем старое слово как свежие данные. + for column, text in enumerate(values): # Заполняем источник, два представления значения и начальный статус. + self.table.setItem(row, column, QTableWidgetItem(text)) # Ячейки доступны для выделения и копирования без редактирования результата. + if (str(entry["tetrad"]), str(entry["register"])) in selected: # Сохраняем только те выделенные источники, которые ещё присутствуют в списке. + self.table.selectionModel().select(self.table.model().index(row, 0), QItemSelectionModel.Select | QItemSelectionModel.Rows) # Восстанавливаем также множественное выделение после фонового считывания. + self.table.blockSignals(False) # Возвращаем обработку пользовательского изменения выделения. + self._selection_changed() # Кнопка удаления снова соответствует восстановленному выделению. + + def _signature(self, entries, errors): # Отпечаток содержит именно аппаратно значимые поля и порядок всей таблицы. + return (errors, tuple((entry["tetrad"], entry["register"], pbus_result_address(entry, index)) for index, entry in enumerate(entries))) # Различаем индекс записи и фактический адрес 20CD каждой строки. + + def replace_entries(self, entries): # Изменение состава, порядка или адресов передаётся как полный снимок новой таблицы. + self.owner._start_commands([self.command("configure", entries=[dict(entry) for entry in entries])], macro=False) # Повторный макрос и фоновый опрос не смогут вмешаться в атомарную перепись всего снимка. + + def sequence(self, command): # Одна логическая операция очереди охватывает остановку, все пары таблицы, запуск, паузу и первое чтение. + operation = command["type"] # Действие определяет изменение таблицы либо чтение уже подтверждённого буфера. + updated = table_entries_after(self.entries, command) # Полный снимок сохраняет явные CD и проверяет все источники до остановки. + if updated != self.entries: # Любое изменение источника, порядка или CD требует применения всей новой таблицы. + self.entries, self.applied = updated, False # Старый результат не подтверждает новые дескрипторы аппаратного опроса. + self._render_entries() # Очищаем отображение прежних слов ещё до начала первой управляющей записи. + controller, errors = self.owner._macro_controller, command.get("errors", self.table_errors) # Контроллер и аппаратный порог фиксируются для всей операции очереди. + signature = self._signature(self.entries, errors) # Сравниваем полный порядок и адреса, а не только длину списка. + configure = not self.applied or self.controller != controller or self._applied_signature != signature or operation in ("configure", "start") # Простое чтение не переписывает неизменённую применённую таблицу. + if command.get("read_only") and configure: # Периодическое обновление не имеет права автоматически переписывать неподтверждённую таблицу. + raise ValueError("PBUS: таблица изменена или не применена; выполните явное обновление") # Ошибка не отправляет ни управления, ни запуска контроллеру. + if configure: # До первого WriteMemory таблица перестаёт считаться успешно применённой. + self.applied, self.table_errors = False, errors # При отказе любая автоматическая попытка запуска останется запрещённой. + self._render_entries() # При явном повторном запуске старое слово также не выдаётся за подтверждение новой настройки. + self.result_label.setText("Применение таблицы; ожидание обновления аппаратного буфера…") # Состояние объясняет отсутствие прежних значений во время паузы. + def confirmed_control(value): # Вызывается только после успешного подтверждения соответствующей записи 0x200C. + self._controls[controller] = value # Следующая остановка сохранит реальные параметры прежней активной таблицы. + result = yield from pbus_table_steps(self.entries, errors, configure=configure, stop_control=self._controls.get(controller), settle_ms=command.get("settle_ms", self.startup_delay.value()), on_control=confirmed_control) # Существующий транспорт подтверждает каждый пакет, очередь удерживает всю перенастройку целиком. + result["controller"], result["signature"] = controller, signature # Применённость относится к точному снимку и тому контроллеру, который подтвердил обмен. + result["configured"], result["form_errors"] = configure, command.get("_form_errors", errors) # Сохраняем начало редактирования порога, чтобы не затереть более новое пользовательское значение завершением старой операции. + result["operation"], result["key"] = operation, (command["tetrad"], command["register"]) # Видимая строка добавления выбирается по исходным параметрам действия. + return result # Отображение подтверждается только после успешного чтения обновлённого аппаратного буфера. + + def stop_sequence(self, command): # Остановка сохраняет всю текущую таблицу и аппаратные параметры, сбрасывая только бит запуска. + self.timer.stop() # Будущие периодические чтения остановленной шины больше не назначаются. + self._set_cycle_checked(False) # Неотправленные фоновые шаги снимаются обработчиком переключателя. + controller = self.owner._macro_controller # Используем тот же контроллер, что зафиксирован общей очередью для этого действия. + control = self._controls.get(controller, pbus_control(len(self.entries), self.table_errors)) & 0x7FFF # Подтверждённые порог и последний индекс сохраняются даже при изменённом списке интерфейса. + reply = yield PBUS_COMMAND, control # Ждём реального подтверждения остановки через существующий WriteMemory. + self._controls[controller] = control # Только подтверждённая запись переводит аппаратное состояние в остановленное. + return reply # Считанные значения прежней таблицы не переобъявляются результатом новой конфигурации. + + def show_result(self, result): # Применяем считанные слова к тем строкам, чьи адреса подтверждены аппаратной конфигурацией. + self.entries = result["entries"] # Список из завершённого цикла соответствует порядку прочитанных слов буфера. + self.applied, self.controller = True, result["controller"] # Подтверждённая таблица допускает дальнейшее чтение без повторной записи дескрипторов. + self._applied_signature = result.get("signature", self._signature(self.entries, self.table_errors)) # Дальнейшие чтения разрешены только для того же состава, порядка и CD. + if result.get("configured") and self.error_limit.value() == result.get("form_errors"): # Явный порог выполненного макроса отражается в форме только при отсутствии более нового ввода пользователя. + self.error_limit.setValue(self.table_errors) # Поле показывает реально применённый порог, не заставляя следующее ручное действие возвращаться к старому значению. + self._render_entries() # Перестраиваем ячейки после добавления, удаления или смены контроллера. + for row, reply in enumerate(result["rows"]): # Каждое считанное слово отображается рядом с собственным источником. + value = reply["value"] # Получаем 16-битное слово из стандартного ответа PEEK транспорта TMS2812. + self.table.item(row, 2).setText(f"{value:04X}") # HEX занимает четыре цифры, как данные SBUS. + self.table.item(row, 3).setText(str(value)) # Десятичное значение помогает читать числовые регистры без ручного перевода. + self.table.item(row, 4).setText("OK") # Успешный цикл подтверждает достоверность слова для данного источника. + self.table.item(row, 2).setToolTip(reply.get("raw_response", {}).get("raw", b"").hex(" ").upper()) # Пакет конкретного чтения доступен в подсказке своей строки. + if result.get("operation") == "add" and not self.owner._macro_is_macro: # Ручное добавление позволяет сразу выделить новый источник для копирования или Delete. + for row, entry in enumerate(self.entries): # Находим добавленный регистр по адресу, независимо от числа уже наблюдаемых строк. + if (entry["tetrad"], entry["register"]) == result["key"]: # Выделяем именно выбранный источник, включая повторное добавление существующей строки. + self.table.selectRow(row) # Следующая клавиша Delete относится к добавленному или найденному регистру. + self.table.setFocus() # Удобное удаление не требует дополнительного щелчка после добавления кнопкой. + break # Источник уникален, поэтому поиск завершается после первой найденной строки. + self._update_timer() # Возобновляем обновление только для применённого непустого списка регистров. + + def show_error(self, message): # Ошибка аппаратной записи или чтения не должна оставлять прежние слова выглядеть новыми. + self.applied = False # После ошибки явное обновление повторно применяет список перед считыванием. + self.timer.stop() # Исключаем автоматические повторные записи после ошибки или неопределённого исхода операции. + self._set_cycle_checked(False) # Состояние переключателя честно показывает остановку фоновых запросов. + for row in range(self.table.rowCount()): # Недостоверность отображается в каждой затронутой строке общей таблицы. + self.table.item(row, 2).setText("—") # HEX не сохраняет устаревшее слово после отказа обмена. + self.table.item(row, 3).setText("—") # Десятичное значение также очищается, чтобы представления оставались согласованными. + self.table.item(row, 4).setText("Ошибка") # Краткий статус остаётся виден рядом с адресом регистра. + self.table.item(row, 4).setToolTip(message) # Полная причина доступна для конкретной строки при наведении. + + def refresh(self): # Обновление получает все текущие регистры, повторяя настройку только когда она не подтверждена. + self.owner._start_commands([self.command("poll")], macro=False) # Используем единую очередь, поэтому ручное обновление не вмешивается в другой макрос. + + def _update_timer(self, *unused): # Таймер сохраняет период от начала чтения, не перезапускаясь после каждого результата. + if self.auto_update.isChecked() and self.entries and self.applied: # Автоматическое чтение разрешено только для подтверждённой непустой таблицы. + if not self.timer.isActive() or self.timer.interval() != self.interval.value(): # Завершение текущего чтения не сдвигает уже отсчитываемый период. + self.timer.start(self.interval.value()) # Новый интервал применяется при включении или изменении настройки. + else: # Пустая таблица и выключенное задание не создают новых чтений. + self.timer.stop() # Отменяем дальнейшие срабатывания таймера этого источника. + + def _set_cycle_checked(self, checked): # Внутреннее изменение галочки не является новым нажатием пользователя и не порождает повторных управляющих записей. + previous = self.auto_update.blockSignals(True) # Отключение из обработки ошибки или закрытия не должно рекурсивно планировать WriteMemory. + self.auto_update.setChecked(checked) # Видимое состояние соответствует фактически разрешённым повторениям. + self.auto_update.blockSignals(previous) # Возвращаем прежний режим доставки пользовательских сигналов Qt. + self._update_timer() # Таймер согласуется с программно установленным состоянием. + if not checked: # Неотправленные периодические чтения больше не нужны выключенному источнику. + self.owner._cancel_source(self.owner._pbus_key) # Текущий UART-пакет завершится корректно, последующие шаги этого цикла не отправляются. + + def _auto_changed(self, checked): # Пользовательский переключатель управляет также аппаратной остановкой PBUS. + self._update_timer() # Будущие программные повторы выключаются сразу, до ожидания общего порта. + if not checked: # Выключение галочки должно прекратить и обновление интерфейса, и опрос самой параллельной шины. + controller = self.owner.device_address() if callable(self.owner.device_address) else self.owner.device_address # Остановка относится к выбранному соединению контроллера. + active = bool(self._controls.get(controller, 0) & 0x8000) # Подтверждённый бит запуска показывает, что аппаратный PBUS ещё работает. + pending_configuration = any(run["controller"] == controller and any(command.get("bus") == "pbus" and command["type"] in ("add", "remove", "configure", "start") for command in run["jobs"][run["index"]:]) for run in self.owner._runs) # Уже принятая полная настройка может ещё завершить запуск перед очередью остановки. + self.owner._cancel_source(self.owner._pbus_key) # Снимаем ожидающий цикл и ещё не переданные чтения, не повреждая текущий пакет UART. + if active or pending_configuration: # Начальное выключение пустой панели не должно отправлять беспричинный управляющий запрос. + self.owner._start_commands([self.command("stop")], macro=False) # Очередь дождётся текущей логической операции и очистит только бит 15 подтверждённых параметров активной таблицы. + elif self.entries and self.applied: # Включение ранее остановленной настроенной таблицы должно возобновлять также аппаратный опрос. + if not self._controls.get(self.controller, 0) & 0x8000: # После аппаратной остановки одного чтения буфера недостаточно для возобновления обмена. + self.owner._start_commands([self.command("start")], macro=False) # Явное включение пользователя полностью применяет таблицу и выбранный порог перед началом чтения. + else: # Уже работающая применённая таблица не требует перезапуска для включения периодического чтения интерфейса. + self._poll_tick() # Первый обычный цикл читает только назначения результатов 20CD. + elif self.entries: # Неподтверждённая после ошибки таблица по-прежнему требует явного применения. + self.result_label.setText("Нажмите «Обновить», чтобы применить таблицу перед циклическим чтением.") # Выключенный аппаратный опрос не маскируется чтением старых значений памяти. + + def _poll_tick(self): # Один источник добавляет не более одного незавершённого чтения таблицы PBUS. + controller = self.owner.device_address() if callable(self.owner.device_address) else self.owner.device_address # Адрес контроллера снимается для нового цикла. + if self.applied and controller != self.controller: # Таблица прежнего контроллера не применяется другому устройству автоматически. + self.timer.stop() # Смена адреса прекращает фоновые чтения, сохраняя известные параметры других контроллеров. + self.applied = False # Новый контроллер требует явного подтверждения своей таблицы. + self._set_cycle_checked(False) # Галочка отражает остановку опроса прежнего устройства. + self.result_label.setText("Адрес контроллера изменён. Нажмите «Обновить», чтобы применить таблицу.") # Сообщаем необходимое действие рядом с результатами. + return # Новый контроллер не получает неподтверждённую конфигурацию от таймера. + if self.applied and self._applied_signature != self._signature(self.entries, self.table_errors): # Изменение порядка, источников или CD не должно пройти незамеченным фоновым чтением. + self.applied = False # Старые подтверждения относятся к другому снимку таблицы. + self.timer.stop() # Периодическое обновление не пытается автоматически запустить новый список. + self._render_entries() # Прежние слова не показываются как результат изменённых строк. + self.result_label.setText("Таблица изменена. Нажмите «Обновить», чтобы применить её.") # Пользователь явно подтверждает аппаратную перенастройку. + if self.entries and self.applied and self.auto_update.isChecked(): # Чтение буфера использует только подтверждённые строки таблицы. + self.owner._start_commands([self.command("poll", read_only=True, errors=self.table_errors)], macro=False, background=True, key=self.owner._pbus_key) # Занятость ставит один цикл в очередь, повторные такты подавляются ключом задания. + + def stop_updates(self): # Отключение и команда остановки запрещают будущие запросы данного источника. + self._set_cycle_checked(False) # Отключение соединения не создаёт новую команду остановки уже закрываемому порту. + self.timer.stop() # Больше не назначаем периодические чтения. + self.owner._cancel_source(self.owner._pbus_key) # Отменяем неотправленные шаги циклического чтения без повреждения UART. + self.applied = False # После нового подключения таблица требует явного применения. + self._controls.clear() # После отключения нельзя считать прежние управляющие слова состоянием нового соединения. + self._applied_signature = None # Новое подключение должно подтвердить весь снимок таблицы заново. diff --git a/python/pysetterminal/rawprotocol.py b/python/pysetterminal/rawprotocol.py index 249bf28..2c18150 100644 --- a/python/pysetterminal/rawprotocol.py +++ b/python/pysetterminal/rawprotocol.py @@ -3,7 +3,8 @@ from PySide6.QtWidgets import * from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtSerialPort import QSerialPort -from protocan import tms_terminal as memory +from protocan import tms_terminal as memory # Существующий кодек сохраняет формат запросов памяти и проверку CRC. +from .exchange_queue import exchange_queue # RAW и обращения памяти разделяют очередь с шинами и макросами. class RawProtocol: @@ -33,8 +34,10 @@ class RawProtocol: self.port.setBaudRate(baudrate) return self.port.open(QIODevice.ReadWrite) - def disconnect(self): - self.port.close() + def disconnect(self): # Отключение снимает все задания данного соединения. + exchange_queue(self).clear() # Неотправленные операции не должны перейти на новое соединение. + self.cancel_async("COM отключён") # Ожидающий callback завершается реальной ошибкой закрытия порта. + self.port.close() # После завершения состояния обмена закрываем существующий UART. def _receive(self): self.feed(bytes(self.port.readAll())) @@ -138,7 +141,6 @@ class RawProtocol: self._settle.setSingleShot(True) self._settle.timeout.connect(loop.quit) if self.host: - self.host.byte_page.setEnabled(False) self.host._pending_address = self._controller self.host._pending_kind = "pysetterminal" self.host._log("TX", request) @@ -162,7 +164,6 @@ class RawProtocol: self._loop = None if self.host: self.host._pending_address = self.host._pending_kind = None - self.host.byte_page.setEnabled(True) def poke(self, mem_address, data_value, device_address=None): return self._exchange(mem_address, data_value, device_address) @@ -285,54 +286,44 @@ class RawProtocolWidget(QWidget): layout.addWidget(raw_group, 1) self.setLayout(layout) - def memory_write(self): - """Запись в память (POKE)""" - try: - device_addr = self.device_address() if callable(self.device_address) else self.device_address - mem_addr = int(self.mem_addr_edit.text(), 16) - data = int(self.mem_data_edit.text(), 16) + def memory_write(self): # Фиксируем адрес и слово при нажатии без блокировки других элементов. + self._memory_action(True) # Запись занимает одну логическую операцию общей очереди. - success, result = self.raw_protocol.poke(mem_addr, data, device_addr) + def memory_read(self): # Ручное чтение памяти принимается даже во время циклического опроса шин. + self._memory_action(False) # Параметры текущего поля снимаются до ожидания соединения. - if success: - self.raw_output.append(f"POKE 0x{mem_addr:04X} = 0x{data:04X}") - self.raw_output.append(f"Ответ: {result['raw'].hex()}") - else: - self.raw_output.append(f"Ошибка POKE: {result}") + def _memory_action(self, write): # Оба направления памяти используют прежний протокол через общий планировщик. + try: # Проверка ввода выполняется до передачи любого пакета контроллеру. + controller = self.device_address() if callable(self.device_address) else self.device_address # Контроллер сохраняется на момент нажатия. + address = int(self.mem_addr_edit.text(), 16) # Адрес фиксируется независимо от последующего редактирования поля. + value = int(self.mem_data_edit.text(), 16) if write else None # Значение участвует только в WriteMemory. + if not 0 <= address <= 0xFFFFFFFF or (value is not None and not 0 <= value <= 0xFFFF): # Сохраняем разрядность адреса и шестнадцатибитного слова. + raise ValueError("Проверьте адрес и данные памяти") # Неверные поля не создают задания UART. + except ValueError as error: # Промежуточный неправильный ввод остаётся локальной ошибкой интерфейса. + self.mem_result_label.setText(str(error)) # Пользователь видит причину прямо возле результата памяти. + return # Очередь текущего соединения не изменяется. + def steps(): # Одна операция возвращает итог существующего PEEK или POKE. + result = yield address, value # Направление обмена определяется прежним соглашением None для чтения. + return result # Результат отправляется только виджету инициатора действия. + exchange_queue(self.raw_protocol).submit(steps, controller, lambda ok, reply: self._memory_done(address, value, ok, reply)) # Запрос ожидает завершения текущей логической операции шин или макроса. - except ValueError as e: - self.raw_output.append(f"Ошибка в данных: {e}") + def _memory_done(self, address, value, success, result): # Результат отображается по сохранённым параметрам конкретного нажатия. + if not success: # Ошибка CRC, таймаут и отключение не подменяются успешным результатом. + self.mem_result_label.setText(f"Ошибка: {result}") # Показываем отказ непосредственно в области памяти. + self.raw_output.append(f"Ошибка памяти: {result}") # История сохраняет причину неудачной операции. + elif value is None: # ReadMemory должен вернуть проверенное шестнадцатибитное слово. + word = result["value"] # Слово декодировано существующим кодеком протокола. + self.mem_result_label.setText(f"0x{word:04X} ({word})") # Показываем HEX и DEC одного результата чтения. + self.raw_output.append(f"PEEK 0x{address:04X} = 0x{word:04X}") # Адрес отражает выполненное действие, даже если поле уже изменилось. + else: # Подтверждённая запись сохраняет прежний формат диагностического журнала. + self.raw_output.append(f"POKE 0x{address:04X} = 0x{value:04X}") # Отображаем записанное слово и адрес снимка параметров. - def memory_read(self): - """Чтение из памяти (PEEK)""" - try: - device_addr = self.device_address() if callable(self.device_address) else self.device_address - mem_addr = int(self.mem_addr_edit.text(), 16) - - success, result = self.raw_protocol.peek(mem_addr, device_addr) - - if success: - value = result['value'] - self.mem_result_label.setText(f"0x{value:04X} ({value})") - self.raw_output.append(f"PEEK 0x{mem_addr:04X} = 0x{value:04X}") - self.raw_output.append(f"Ответ: {result['raw_response']['raw'].hex()}") - else: - self.mem_result_label.setText(f"Ошибка: {result}") - self.raw_output.append(f"Ошибка PEEK: {result}") - - except ValueError as e: - self.mem_result_label.setText(f"Ошибка: {e}") - self.raw_output.append(f"Ошибка в данных: {e}") - - def send_raw_data(self): - """Отправка сырых данных""" - hex_str = self.raw_send_edit.text() - success, result = self.raw_protocol.send_raw(hex_str) - - if success: - self.raw_output.append(result) - else: - self.raw_output.append(f"Ошибка: {result}") + def send_raw_data(self): # Произвольная ручная отправка также ждёт завершения целой операции шины. + text = self.raw_send_edit.text() # HEX-пакет фиксируется при нажатии кнопки отправки. + def send(): # Отправка выполняется после получения общей очередью свободного UART. + success, result = self.raw_protocol.send_raw(text) # Существующий RAW-протокол сохраняет формат и обработку ошибки порта. + self.raw_output.append(result if success else f"Ошибка: {result}") # Итог принадлежит сохранённому пакету данного нажатия. + exchange_queue(self.raw_protocol).submit_external(send, lambda: False, lambda ok, reply: None) # RAW не ожидает типизированного ответа, сохраняя прежнее поведение панели. def read_raw_data(self): """Чтение сырых данных""" diff --git a/python/pysetterminal/serialbus.py b/python/pysetterminal/serialbus.py index bd7499a..7301783 100644 --- a/python/pysetterminal/serialbus.py +++ b/python/pysetterminal/serialbus.py @@ -6,6 +6,9 @@ from copy import deepcopy from PySide6.QtWidgets import * from PySide6.QtCore import * from PySide6.QtGui import * +from .bus_operations import validate_command, table_entries_after, PBUS_ERROR_LIMIT # Обе шины и общий макрос используют один проверенный алгоритм адресации. +from .pbus_panel import PbusPanel, CompactControls, _FlowLayout # Макросы используют существующий перенос элементов слева направо. +from .exchange_queue import exchange_queue # Один протокол разделяет одну очередь между шинами, макросами и памятью. class _MacroActionIcon(QIconEngine): @@ -69,7 +72,7 @@ class SerialBus: else self.raw.poke(address, value, device_address)) if not success: return False, result - return True, "Запись в шину подтверждена" if write else result + return True, result # Сохраняем пакет последнего POKE также для отображения подтверждения записи в собственном журнале SBUS. def write_bus(self, data_word, address_tetrad, register_num=0, device_address=1): return self._execute(True, address_tetrad, register_num, data_word, device_address) @@ -96,13 +99,24 @@ class MacroCommandDialog(QDialog): type_layout = QHBoxLayout() type_layout.addWidget(QLabel("Тип команды:")) self.cmd_type = QComboBox() - self.cmd_type.addItems(["Запись", "Чтение"]) + self.cmd_type.addItem("Запись", "write") # Сохраняем код операции отдельно от русской подписи редактора. + self.cmd_type.addItem("Чтение", "read") # Код чтения используется общим макросом независимо от языка интерфейса. type_layout.addWidget(self.cmd_type) layout.addLayout(type_layout) + bus_layout = QHBoxLayout() # Отдельный выбор шины позволяет смешивать PBUS и SBUS в одном макросе. + bus_layout.addWidget(QLabel("Шина:")) # Подпись объясняет назначение переключателя для каждой команды. + self.bus_type = QComboBox() # Выбор хранится в команде, независимо от последней ручной операции. + self.bus_type.addItem("SBUS (Сериальная шина)", "sbus") # Существующая последовательная шина остаётся первой в выборе общей команды. + self.bus_type.addItem("PBUS (Параллельная шина)", "pbus") # Вторая шина управляет тем же общим макросом и таблицей регистров справа. + self.bus_type.setCurrentIndex(self.bus_type.findData(self.command.get("bus", "sbus"))) # Старые команды без поля bus сохраняют принадлежность SBUS. + bus_layout.addWidget(self.bus_type) # Размещаем выбор шины перед адресом платы и регистра. + layout.addLayout(bus_layout) # Добавляем строку выбора в общую форму редактора. + # Адрес устройства addr_layout = QHBoxLayout() - addr_layout.addWidget(QLabel("Адрес устройства (0-14):")) + self.device_addr_label = QLabel("Адрес устройства (0–14):") # Диапазон подписи расширяется до 0–15 при выборе новой PBUS. + addr_layout.addWidget(self.device_addr_label) # Сохраняем подпись для синхронизации с допустимым адресом. self.device_addr = QSpinBox() self.device_addr.setRange(0, 14) addr_layout.addWidget(self.device_addr) @@ -124,18 +138,23 @@ class MacroCommandDialog(QDialog): data_layout.addWidget(self.data_label) data_layout.addWidget(self.data_edit) layout.addLayout(data_layout) - - # Загружаем данные команды, если она передана - if self.command: - if self.command.get('type') == 'write': - self.cmd_type.setCurrentText("Запись") - self.device_addr.setValue(self.command.get('tetrad', 0)) - self.register_num.setValue(self.command.get('register', 0)) - self.data_edit.setText(f"{self.command.get('data', 0):04X}") - else: - self.cmd_type.setCurrentText("Чтение") - self.device_addr.setValue(self.command.get('tetrad', 0)) - self.register_num.setValue(self.command.get('register', 0)) + table_form = QGridLayout() # Для PBUS пользователь задаёт источник; индексы и длину таблицы рассчитывает панель автоматически. + self.pbus_error_label, self.pbus_errors = QLabel("Порог ошибок (1–15):"), QSpinBox() # Единственный дополнительный параметр соответствует порогу x_parallel_bus.h. + self.pbus_errors.setRange(1, 15) # Порог занимает четыре бита и не допускает нуля, который объявил бы любой статус ошибкой. + self.pbus_errors.setValue(self.command.get("errors", PBUS_ERROR_LIMIT)) # Новая команда использует порог 0xA, явно сохранённое значение существующего макроса сохраняется. + table_form.addWidget(self.pbus_error_label, 0, 0) # Подпись описывает аппаратное условие остановки опроса PBUS. + table_form.addWidget(self.pbus_errors, 0, 1) # Поле применяется к добавлению, удалению и обновлению таблицы. + layout.addLayout(table_form) # Дополнительный параметр находится под адресом платы и регистра. + self.bus_type.currentIndexChanged.connect(self.on_bus_changed) # Выбор шины меняет набор команд в общем редакторе, не создавая отдельного макроса. + self.on_bus_changed() # Применяем диапазоны и допустимые операции до восстановления сохранённой команды. + if self.command: # При редактировании восстанавливаем источник и код операции из общего JSON. + operation = self.command.get("type", "read") # Старые макросы SBUS продолжают использовать коды read и write. + if self.bus_type.currentData() == "pbus": # Ранее сохранённые одиночные операции PBUS переводятся к действиям таблицы. + operation = {"write": "add", "read": "poll"}.get(operation, operation) # Запись соответствует добавлению, чтение — обновлению значений общей таблицы. + self.cmd_type.setCurrentIndex(self.cmd_type.findData(operation)) # Выбираем операцию по коду, без зависимости от порядка или русской подписи. + self.device_addr.setValue(self.command.get("tetrad", 0)) # Восстанавливаем адрес платы для добавления или удаления регистра. + self.register_num.setValue(self.command.get("register", 0)) # Восстанавливаем номер наблюдаемого регистра. + self.data_edit.setText(f"{self.command.get('data', 0):04X}") # Данные прежней команды записи SBUS сохраняются без изменения. # Подключаем изменение типа команды self.cmd_type.currentTextChanged.connect(self.on_cmd_type_changed) @@ -153,9 +172,27 @@ class MacroCommandDialog(QDialog): self.setLayout(layout) + def on_bus_changed(self): # Переключаем отдельную команду внутри одного общего макроса PBUS и SBUS. + parallel = self.bus_type.currentData() == "pbus" # У PBUS доступны операции над общей таблицей наблюдаемых регистров. + maximum = 15 if parallel else 14 # PBUS использует четырёхбитный адрес, SBUS сохраняет прежний диапазон 0–14. + self.device_addr.setRange(0, maximum) # Исключаем адреса, неподдерживаемые алгоритмом выбранной шины. + self.device_addr_label.setText(f"Адрес устройства (0–{maximum}):") # Подпись соответствует реальному ограничению адресного поля. + previous = self.cmd_type.currentData() # Сохраняем код прежней операции независимо от надписи в списке. + self.cmd_type.blockSignals(True) # Не обновляем форму для промежуточного пустого набора операций. + self.cmd_type.clear() # Удаляем операции предыдущей шины перед добавлением нового набора. + operations = (("Добавить в таблицу", "add"), ("Убрать из таблицы", "remove"), ("Обновить значения", "poll"), ("Запуск опроса", "start"), ("Остановка опроса", "stop")) if parallel else (("Запись", "write"), ("Чтение", "read")) # PBUS работает со списком, SBUS сохраняет ручное чтение и запись слова. + for caption, code in operations: # Коды действий хранятся отдельно от русских названий элементов интерфейса. + self.cmd_type.addItem(caption, code) # Общий редактор использует один список команд выбранной шины. + index = self.cmd_type.findData(previous) # Проверяем, поддерживается ли прежняя операция новой шиной. + self.cmd_type.setCurrentIndex(max(0, index)) # Если прежнее действие недоступно, выбираем первое допустимое действие. + self.cmd_type.blockSignals(False) # Возвращаем обработку обычного изменения операции пользователем. + self.pbus_error_label.setVisible(parallel) # Порог ошибок PBUS не загромождает редактирование команды SBUS. + self.pbus_errors.setVisible(parallel) # Поле сохраняется в команде только для параллельной шины. + self.on_cmd_type_changed(self.cmd_type.currentText()) # Видимость данных согласуется с окончательным выбором операции. + def on_cmd_type_changed(self, text): """Показать/скрыть поле данных в зависимости от типа команды""" - if text == "Запись": + if self.bus_type.currentData() == "sbus" and self.cmd_type.currentData() == "write": # Данные периферии доступны только при записи существующей SBUS. self.data_label.show() self.data_edit.show() else: @@ -163,7 +200,7 @@ class MacroCommandDialog(QDialog): self.data_edit.hide() def _accept_command(self): - if self.cmd_type.currentText() == "Запись": + if self.bus_type.currentData() == "sbus" and self.cmd_type.currentData() == "write": # Проверяем HEX-слово лишь для операции, которая действительно передаёт данные. try: value = int(self.data_edit.text(), 16) if not 0 <= value <= 0xFFFF: @@ -171,24 +208,32 @@ class MacroCommandDialog(QDialog): except ValueError: QMessageBox.warning(self, "Ошибка", "Данные должны быть в диапазоне 0000…FFFF") return - self.accept() + try: # Проверяем взаимосвязь строки и длины таблицы до сохранения команды макроса. + validate_command(self.get_command()) # Одна проверка используется редактором и исполнителем команд обеих шин. + except (KeyError, ValueError, TypeError) as error: # Некорректная команда остаётся открытой для исправления. + QMessageBox.warning(self, "Ошибка", str(error)) # Показываем конкретный неверный параметр пользователю редактора. + return # Не сохраняем команду, которая остановит выполнение макроса. + self.accept() # Закрываем редактор только после полной проверки команды. def get_command(self): """Получить команду из диалога""" - cmd_type = 'write' if self.cmd_type.currentText() == "Запись" else 'read' + cmd_type = self.cmd_type.currentData() # Код выбранного действия сохраняется в общем JSON независимо от русской подписи. command = { 'type': cmd_type, 'tetrad': self.device_addr.value(), 'register': self.register_num.value() } - if cmd_type == 'write': + if cmd_type == 'write' and self.bus_type.currentData() == "sbus": # Поле data относится только к записи данных последовательной шины. try: command['data'] = int(self.data_edit.text(), 16) except ValueError: command['data'] = 0 - return command + command['bus'] = self.bus_type.currentData() # Сохраняем шину в JSON, чтобы повторный запуск и редактирование использовали тот же алгоритм. + if command["bus"] == "pbus": # Запоминаем настройки таблицы независимо от последнего состояния ручной панели. + command["errors"] = self.pbus_errors.value() # Номера строк и размер таблицы вычисляются автоматически из общего списка регистров PBUS. + return command # Возвращаем адрес, регистр, данные и выбранную шину как одну команду макроса. class MacroEditorDialog(QDialog): @@ -211,6 +256,14 @@ class MacroEditorDialog(QDialog): self.macro_name = QLineEdit(self.macro.get('name', 'Новый макрос')) name_layout.addWidget(self.macro_name) layout.addLayout(name_layout) + period_layout = QHBoxLayout() # Каждый макрос сохраняет собственный период повторения в редакторе. + period_layout.addWidget(QLabel("Период повторения:")) # Подпись обозначает время между началами повторных запусков. + self.repeat_period = QSpinBox(self) # Значение хранится в настройках данного макроса, независимо от шин. + self.repeat_period.setRange(1, 3600000) # Период задаётся в миллисекундах от одной до одного часа. + self.repeat_period.setSuffix(" мс") # Единица измерения доступна непосредственно при редактировании. + self.repeat_period.setValue(self.macro.get("period_ms", 1000)) # Старые макросы получают период одной секунды без изменения команд. + period_layout.addWidget(self.repeat_period) # Поле расположено рядом с подписью в одной строке. + layout.addLayout(period_layout) # Период относится ко всему макросу и расположен перед списком команд. # Список команд layout.addWidget(QLabel("Команды:")) @@ -260,11 +313,14 @@ class MacroEditorDialog(QDialog): """Загрузить команды в список""" self.commands_list.clear() for cmd in self.macro['commands']: - if cmd['type'] == 'write': + if cmd.get("bus", "sbus") == "pbus": # Команды таблицы требуют собственного описания вместо HEX-данных SBUS. + action = {"add": "Добавить в таблицу", "remove": "Убрать из таблицы", "poll": "Обновить значения", "write": "Добавить в таблицу", "read": "Обновить значения", "start": "Запуск опроса", "stop": "Остановка опроса"}.get(cmd["type"], "Неизвестная команда") # Общий макрос явно показывает действия со списком параллельной шины. + text = f"{action}: плата {cmd['tetrad']}, регистр {cmd['register']}" if cmd["type"] in ("add", "remove", "write") else action # Добавление и удаление задают источник; остальные операции относятся ко всему списку PBUS. + elif cmd['type'] == 'write': # Существующие команды записи SBUS сохраняют прежнее отображение данных. text = f"Запись: устр.{cmd['tetrad']}, рег.{cmd['register']}, 0x{cmd['data']:04X}" else: text = f"Чтение: устр.{cmd['tetrad']}, рег.{cmd['register']}" - self.commands_list.addItem(text) + self.commands_list.addItem(f"{cmd.get('bus', 'sbus').upper()}: {text}") # Показываем шину каждой строки; старые команды обозначаем существовавшей SBUS. def add_command(self): """Добавить новую команду""" @@ -311,14 +367,15 @@ class MacroEditorDialog(QDialog): def get_macro(self): """Получить макрос из диалога""" return { - 'name': self.macro_name.text(), + 'name': self.macro_name.text(), # Имя используется кнопкой выполнения и сохраняется при редактировании. + 'period_ms': self.repeat_period.value(), # Независимый период сохраняется в JSON данного макроса в миллисекундах. 'commands': self.macro['commands'].copy() } class SerialTab(QWidget): - """Вкладка для работы с серийной шиной (ТОЛЬКО операции с шиной)""" + """Два независимых блока PBUS и SBUS с общей областью управления макросами.""" # Историческое имя класса сохранено для совместимости встраиваемых панелей. MACROS_FILE = "macros.json" # Файл для сохранения макросов @@ -333,6 +390,11 @@ class SerialTab(QWidget): self.macro_buttons = [] # Список кнопок макросов self._macro_running = False self._macro_generation = 0 + self._background = False # Фоновые чтения таблицы отличаются от общего макроса и уступают ручным действиям. + self._macro_is_macro = False # Совместимое состояние показывает наличие выполняемого макроса. + self.queue = exchange_queue(raw_protocol) # Все панели данного соединения используют один планировщик UART. + self._runs, self._macro_cycles = [], {} # Запуски и независимые таймеры сохраняют собственное состояние. + self._sbus_key, self._pbus_key = (id(self), "sbus"), (id(self), "pbus") # По одному ключу на каждое периодическое задание исключают дубликаты. from pathlib import Path self.MACROS_FILE = str(macros_file if macros_file is not None else @@ -343,54 +405,133 @@ class SerialTab(QWidget): self.init_ui() + def _build_bus_group(self, bus, title): # Создаём левую область существующей SBUS с собственными результатами. + group = QGroupBox(title) # Русская подпись однозначно обозначает последовательную шину. + group.setObjectName(bus + "Group") # Стабильное имя сохраняет поиск блока для встраивающего приложения. + outer, panel = QVBoxLayout(group), {} # Широкий журнал и компактные поля получают независимые области компоновки. + outer.setContentsMargins(10, 14, 10, 10) # Отступы в пикселях отделяют содержимое от рамки, сохраняя компактность панели. + outer.setSpacing(8) # Между формой, статусом и журналом оставляем одинаковые небольшие промежутки. + outer.setProperty("fixedPanelLayout", True) # Автоматическое преобразование панелей не должно растягивать эту пользовательскую форму. + controls = QWidget(group) # Отдельный контейнер не делит столбцы полей с широким журналом результатов. + controls.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) # Форма занимает только необходимую ширину и высоту даже в полноэкранном доке. + form = QGridLayout(controls) # Подпись и её поле остаются рядом в двух компактных столбцах. + form.setContentsMargins(0, 0, 0, 0) # У вложенной формы нет лишнего второго слоя отступов. + form.setHorizontalSpacing(10) # Между подписью и полем оставляем десять пикселей вместо свободной ширины всей панели. + form.setVerticalSpacing(6) # Строки параметров образуют плотный визуально связанный блок. + form.setProperty("fixedPanelLayout", True) # Поля остаются формой при изменении размера и применении общего менеджера панелей. + fields = (("Данные (HEX):", "data_edit", "0000"), ("Адрес (0–14):", "tetrad_edit", "0"), ("Регистр (0–15):", "register_edit", "0")) # Сохраняем прежние параметры и допустимые диапазоны SBUS. + for row, (caption, name, default) in enumerate(fields): # Размещаем параметры в едином порядке без изменения аппаратных операций. + form.addWidget(QLabel(caption), row, 0) # Подпись находится непосредственно слева от соответствующего поля. + field = QLineEdit(default) # Исходные нули сохраняют прежнее поведение ручных команд. + field.setFixedWidth(100) # Сто пикселей достаточно для шестнадцатибитного HEX и двухзначного адреса. + field.setValidator(QRegularExpressionValidator(QRegularExpression("[0-9A-Fa-f]{1,4}"), field) if name == "data_edit" else QIntValidator(0, 15 if name == "register_edit" else 14, field)) # Данные и адреса проверяются до аппаратной передачи. + panel[name] = field # Прежние ссылки bus_* остаются совместимыми с существующими вкладками SETGUI. + form.addWidget(field, row, 1) # Значение остаётся рядом с подписью независимо от ширины журнала. + buttons = QHBoxLayout() # Действия следуют сразу за компактными параметрами одной шины. + buttons.setSpacing(6) # Кнопки чтения и записи воспринимаются как одна группа действий. + for write, name, caption in ((True, "write_btn", "Записать"), (False, "read_btn", "Прочитать")): # Каждая кнопка сохраняет своё направление аппаратной операции. + button = QPushButton(caption) # Краткие подписи не добавляют лишнего текста в рабочую форму. + button.clicked.connect(lambda checked=False, writing=write: self._manual_bus_operation("sbus", writing)) # Выполнение по-прежнему использует существующий протокол SBUS. + panel[name] = button # Публичные элементы и блокировка общего макроса остаются прежними. + buttons.addWidget(button) # Оба действия расположены под адресными полями. + buttons.addStretch(1) # Свободная ширина располагается после кнопок, не раздвигая их друг от друга. + form.addLayout(buttons, 3, 0, 1, 2) # Кнопки занимают ширину только компактной формы управления. + self.sbus_cycle = QCheckBox("Циклическое чтение", group) # Повторное чтение работает одновременно с доступными ручными кнопками. + self.sbus_interval = QSpinBox(group) # Период SBUS задаётся отдельно от PBUS и макросов. + self.sbus_interval.setRange(1, 3600000) # Миллисекундный период допускает значения до одного часа. + self.sbus_interval.setValue(1000) # Начальный период повторения составляет одну секунду. + self.sbus_interval.setSuffix(" мс") # Поле явно обозначает единицу измерения времени. + self.sbus_interval.setFixedWidth(120) # Форма сохраняет компактную ширину при растяжении панели. + cycle_controls = CompactControls((self.sbus_cycle, self.sbus_interval), group) # Галочка и период используют ширину панели, а не узкую двухколоночную форму адресов. + self.sbus_timer = QTimer(self) # Таймер порождает задания общего планировщика без параллельного обмена. + self.sbus_timer.setTimerType(Qt.PreciseTimer) # Таймер не начинает повтор раньше выбранного интервала в миллисекундах. + self.sbus_timer.timeout.connect(self._sbus_tick) # Новый цикл снимает актуальный адрес и регистр из полей панели. + self.sbus_cycle.toggled.connect(self._sbus_cycle_changed) # Выключение отменяет будущие циклы и неотправленные шаги. + self.sbus_interval.valueChanged.connect(self._sbus_period_changed) # Изменение периода применяется к дальнейшему планированию. + card = QFrame(group) # Считанное слово выделяется отдельной карточкой внутри SBUS. + card.setObjectName("sbusReadCard") # Локальный стиль не изменяет остальные подписи и результаты приложения. + card.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) # Карточка остаётся рядом с параметрами и не превращается в широкую пустую область. + card.setMinimumWidth(260) # Ширина 260 пикселей вмещает крупное шестнадцатибитное слово и его десятичное представление. + card.setStyleSheet("QFrame#sbusReadCard { background: #0d2a29; border: 1px solid #287e6a; border-radius: 8px; } QLabel { background: transparent; border: none; color: #b6d7cf; } QLabel#sbusReadValue { color: #90aaa3; font-size: 24px; font-weight: 600; } QLabel#sbusReadValue[busValueState=ready] { color: #61f0bc; } QLabel#sbusReadValue[busValueState=error] { color: #ff8b8b; }") # Тёмный зелёный фон и яркое слово сохраняют высокий контраст в светлой и тёмной теме; размер значения — 24 пикселя. + card_layout = QVBoxLayout(card) # Краткая подпись и крупное слово образуют одну заметную область результата. + card_layout.setContentsMargins(14, 10, 14, 12) # Внутренние отступы отделяют цифры от рамки без избыточной пустоты. + card_layout.setSpacing(4) # Подпись расположена близко к считанному значению. + card_layout.addWidget(QLabel("Считано", card)) # Короткая подпись описывает последнее успешное чтение. + panel["read_value_label"] = QLabel("---", card) # До первого ответа не показываем фиктивное нулевое значение. + panel["read_value_label"].setObjectName("sbusReadValue") # Стиль выделяет только считанное слово этой шины. + panel["read_value_label"].setProperty("busValueState", "empty") # Пустой результат имеет спокойный цвет до успешного чтения. + panel["read_value_label"].setFont(QFont("Consolas")) # Моноширинные цифры упрощают сравнение HEX-слов при повторном считывании. + panel["read_value_label"].setTextInteractionFlags(Qt.TextSelectableByMouse) # Крупное значение остаётся доступным для выделения и копирования. + card_layout.addWidget(panel["read_value_label"]) # Считанное слово отображается сразу под подписью внутри контрастной карточки. + panel["read_card"] = card # Сохраняем карточку для проверки её расположения и визуальной доступности. + self.sbus_header = CompactControls((controls, card), group, spacing=14) # Форма и карточка остаются рядом в широком доке и переносятся целиком в узком. + outer.addWidget(self.sbus_header) # Параметры и карточка не делят столбцы с широким журналом. + outer.addWidget(cycle_controls) # Настройки циклического чтения располагаются одной компактной строкой сразу под параметрами и карточкой результата. + panel["result_label"] = QLabel("Нет операций") # Под карточкой сохраняем краткую диагностику текущей операции. + panel["result_label"].setWordWrap(True) # Ошибка переносится в пределах своего блока без растягивания формы. + outer.addWidget(panel["result_label"]) # Статус располагается сразу после связанных параметров и значения. + panel["output"] = QPlainTextEdit() # Журнал использует оставшуюся область SBUS и не определяет расстояния между полями. + panel["output"].setReadOnly(True) # История ответов сохраняет возможность копирования без редактирования. + panel["output"].setMaximumBlockCount(200) # Повторное выполнение команд не увеличивает память журнала без ограничений. + panel["output"].setMinimumHeight(100) # Несколько строк ответа видны и в компактном доке. + outer.addWidget(panel["output"], 1) # Свободная высота выделяется истории, а не промежуткам между параметрами. + self.bus_panels[bus] = panel # Регистрируем единственный набор элементов последовательной шины. + return group # Владелец размещает этот блок слева от таблицы PBUS. + + def _show_bus_result(self, bus, message, result=None, *, failed=False): # Единая точка отображения предотвращает смешивание ответов PBUS и SBUS. + panel = self.bus_panels[bus] # Выбираем только элементы шины, выполнившей текущую команду. + panel["result_label"].setText(message) # Последний статус или ошибка видны без открытия RAW. + if bus == "pbus": # Параллельная шина отображает все значения в единственной таблице наблюдаемых регистров. + if failed: # Аппаратная ошибка делает неподтверждённые слова таблицы недостоверными. + self.pbus_group.show_error(message) # Причина отказа остаётся в каждой строке и в правом блоке PBUS. + elif isinstance(result, dict) and "entries" in result: # Успешный цикл возвращает список источников и отдельные ответы их буфера. + self.pbus_group.show_result(result) # Обновляем HEX, DEC и статус каждой строки общей таблицы PBUS. + elif failed: # После неудачной SBUS прежнее слово не должно выглядеть новым результатом. + panel["read_value_label"].setText("---") # Убираем недостоверное слово только у затронутой последовательной шины. + panel["read_value_label"].setProperty("busValueState", "error") # Цвет карточки сообщает об отказе вместо сохранения прежнего успешного значения. + elif result is not None and "value" in result: # SBUS сохраняет одиночное считанное слово непосредственно в своём блоке. + value = result["value"] # Сохраняем декодированное 16-битное слово ответа контроллера. + panel["read_value_label"].setText(f"0x{value:04X} ({value})") # HEX помогает сверять маски, десятичное представление — числовые значения. + panel["read_value_label"].setProperty("busValueState", "ready") # Успешное чтение выделяется ярким зелёным словом на контрастном фоне. + if bus == "sbus": # Локальный стиль результата должен обновиться при переходе между пустым, успешным и ошибочным состоянием. + label = panel["read_value_label"] # Перерисовываем только считанное слово, сохраняя остальные стили приложения. + label.style().unpolish(label) # Снимаем прежнее оформление динамического свойства состояния. + label.style().polish(label) # Применяем контрастный цвет, соответствующий текущему результату. + label.update() # Обновлённый результат становится видимым сразу после ответа контроллера. + raw = result.get("raw_response", result).get("raw", b"") if isinstance(result, dict) else b"" # Поддерживаем структуру ответов чтения и подтверждений записи RawProtocol. + text = message + ("\nRX: " + raw.hex(" ").upper() if raw else "") # Пакет ответа остаётся в журнале своей шины вместе с смыслом операции. + panel["output"].appendPlainText(text) # История позволяет видеть все команды смешанного макроса по соответствующим шинам. + self.last_result = text # Сохраняем совместимость с вызывающими приложениями, запрашивающими последний результат. + self.raw_widget.append_text(text) # Общая отладочная RAW-панель продолжает получать журнал обмена. + def init_ui(self): layout = QVBoxLayout() - # Группа для операций с шиной - bus_group = QGroupBox("Операции с шиной (через регистры 0x200A/0x200B/0x200F)") - bus_layout = QGridLayout() - - bus_layout.addWidget(QLabel("Данные для шины (hex):"), 0, 0) - self.bus_data_edit = QLineEdit("0000") - self.bus_data_edit.setMaximumWidth(100) - bus_layout.addWidget(self.bus_data_edit, 0, 1) - - bus_layout.addWidget(QLabel("Адреса (0-14):"), 0, 2) - self.bus_tetrad_edit = QLineEdit("0") - self.bus_tetrad_edit.setMaximumWidth(50) - bus_layout.addWidget(self.bus_tetrad_edit, 0, 3) - - bus_layout.addWidget(QLabel("Регистр (0-15):"), 0, 4) - self.bus_register_edit = QLineEdit("0") - self.bus_register_edit.setMaximumWidth(50) - bus_layout.addWidget(self.bus_register_edit, 0, 5) - - self.bus_write_btn = QPushButton("Записать в шину") - self.bus_write_btn.clicked.connect(self.write_to_bus) - - self.bus_read_btn = QPushButton("Прочитать из шину") - self.bus_read_btn.clicked.connect(self.read_from_bus) - bus_buttons = QHBoxLayout() - bus_buttons.setSpacing(6) - bus_buttons.addWidget(self.bus_write_btn) - bus_buttons.addWidget(self.bus_read_btn) - bus_buttons.addStretch(1) - bus_layout.addLayout(bus_buttons, 1, 0, 1, 6) - - bus_layout.setColumnStretch(6, 1) - bus_group.setLayout(bus_layout) - layout.addWidget(bus_group) + self.bus_panels = {} # Каждая шина владеет собственными полями, результатом и журналом операций. + buses_layout = QHBoxLayout() # Горизонтальный контейнер удерживает PBUS и SBUS рядом в верхней части окна. + self.sbus_group = self._build_bus_group("sbus", "SBUS (Сериальная шина)") # Существующая последовательная шина располагается слева согласно выбранному пользователем порядку. + self.pbus_group = PbusPanel(self) # Таблица наблюдаемых регистров PBUS становится правой частью той же панели SETGUI. + self.bus_panels["pbus"] = self.pbus_group.controls # Результаты и действия PBUS доступны общему исполнителю без второго набора макросов. + buses_layout.addWidget(self.sbus_group, 1) # Левый блок SBUS получает половину доступной ширины. + buses_layout.addWidget(self.pbus_group, 1) # Правый блок PBUS получает такую же долю ширины. + layout.addLayout(buses_layout) # Размещаем оба блока перед общей областью макросов. + for name, widget in self.bus_panels["sbus"].items(): # Прежние публичные поля относятся к существовавшей последовательной шине. + setattr(self, "bus_" + name, widget) # Имена bus_data_edit, bus_read_btn и других полей остаются совместимыми. + for name, widget in self.bus_panels["sbus"].items(): # Явные имена SBUS позволяют отличать существующую шину от добавленной PBUS. + setattr(self, "sbus_" + name, widget) # Поля SBUS никогда не ссылаются на результат PBUS. + for name, widget in self.bus_panels["pbus"].items(): # Новая параллельная шина имеет независимые доступные интеграциям элементы. + setattr(self, "pbus_" + name, widget) # Поля pbus_* не меняют старые ссылки bus_* последовательной шины. # --- Группа для макросов --- - macros_group = QGroupBox("Макросы") + macros_group = QGroupBox("Макросы") # Краткий заголовок обозначает управление макросами без пояснений внутренней организации команд. macros_layout = QVBoxLayout() # Кнопка создания нового макроса self.create_macro_btn = QPushButton("Создать новый макрос") self.create_macro_btn.clicked.connect(self.create_macro) self.stop_macro_btn = QPushButton("Остановить макрос") - self.stop_macro_btn.setEnabled(False) + self.stop_macro_btn.setEnabled(True) # Постоянная доступность остановки исключает мигание кнопки во время опроса. self.stop_macro_btn.clicked.connect(self.stop_macro) macro_actions = QHBoxLayout() macro_actions.setSpacing(6) @@ -398,69 +539,28 @@ class SerialTab(QWidget): macro_actions.addWidget(self.stop_macro_btn) macro_actions.addStretch(1) macros_layout.addLayout(macro_actions) - for button in (self.bus_write_btn, self.bus_read_btn, self.create_macro_btn, self.stop_macro_btn): + self.macros_status = QLabel("Макросы готовы к запуску") # Общий статус сообщает запуск, завершение и остановку, не дублируя результаты шин. + self.macros_status.setWordWrap(True) # Длинная ошибка макроса переносится в пределах общей панели. + macros_layout.addWidget(self.macros_status) # Статус располагается внутри управления макросами, над их списком. + for button in (self.bus_write_btn, self.bus_read_btn, self.pbus_add_btn, self.pbus_remove_btn, self.create_macro_btn, self.stop_macro_btn): # Применяем одинаковый размер ко всем действиям обеих шин и макросов. button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) button.setFixedHeight(30) button.setStyleSheet("QPushButton { padding: 3px 10px; }") - self.macros_splitter = QSplitter(Qt.Orientation.Horizontal) - self.macros_splitter.setObjectName("macrosSplitter") - self.macros_splitter.setChildrenCollapsible(False) - self.macros_splitter.setHandleWidth(8) - self.macros_splitter.setToolTip("Перетащите разделитель, чтобы изменить ширину панелей") - self.macros_scroll_areas = [] - self.macros_scroll_layouts = [] - for side in ("Левая", "Правая"): - area = QScrollArea() - area.setAccessibleName(f"{side} панель макросов") - area.setWidgetResizable(True) - area.setMinimumSize(120, 120) - content = QWidget() - grid = QGridLayout(content) - grid.setAlignment(Qt.AlignTop | Qt.AlignLeft) - grid.setContentsMargins(6, 6, 6, 6) - grid.setVerticalSpacing(6) - area.setWidget(content) - self.macros_splitter.addWidget(area) - self.macros_scroll_areas.append(area) - self.macros_scroll_layouts.append(grid) - self.macros_splitter.setStretchFactor(0, 1) - self.macros_splitter.setStretchFactor(1, 1) - self.macros_splitter.setSizes([1, 1]) - # Keep the existing attributes available to terminal integrations. - self.macros_scroll_area = self.macros_scroll_areas[0] - self.macros_scroll_content = self.macros_scroll_area.widget() - self.macros_scroll_layout = self.macros_scroll_layouts[0] - macros_layout.addWidget(self.macros_splitter, 1) + self.macros_scroll_area = QScrollArea() # Единственная область содержит все макросы независимо от используемых шин. + self.macros_scroll_area.setAccessibleName("Макросы") # Доступное имя повторяет краткий заголовок, который видит пользователь. + self.macros_scroll_area.setWidgetResizable(True) # Общий список занимает всю доступную ширину под обоими блоками. + self.macros_scroll_area.setMinimumHeight(120) # Список остаётся доступным для прокрутки в компактном окне. + self.macros_scroll_content = QWidget() # Все кнопки макросов принадлежат одному контейнеру. + self.macros_scroll_layout = _FlowLayout(self.macros_scroll_content, 8) # Перенос выполняется по ширине, промежуток между макросами составляет восемь пикселей. + self.macros_scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # При недостаточной высоте показывается вертикальная прокрутка. + self.macros_scroll_layouts = [self.macros_scroll_layout] # Сохраняем совместимый доступ к компоновкам, теперь с единственным общим списком. + self.macros_scroll_area.setWidget(self.macros_scroll_content) # Встраиваем общий контейнер в прокручиваемую область. + macros_layout.addWidget(self.macros_scroll_area, 1) # Вся оставшаяся ширина и высота доступны общей области макросов. macros_group.setLayout(macros_layout) layout.addWidget(macros_group, 1) - # --- ВНЕ ГРУППЫ: Результаты чтения --- - results_layout = QGridLayout() - - # Считанное слово - results_layout.addWidget(QLabel("Считанное слово:"), 0, 0) - self.bus_read_value_label = QLabel("---") - self.bus_read_value_label.setStyleSheet("font-weight: bold; font-size: 14px; border: 1px solid #ccc; padding: 5px;") - results_layout.addWidget(self.bus_read_value_label, 0, 1) - - # Ответ контроллера - results_layout.addWidget(QLabel("Ответ контроллера:"), 1, 0) - self.bus_result_label = QLabel("---") - self.bus_result_label.setStyleSheet("border: 1px solid #ccc; padding: 5px; font-family: monospace;") - self.bus_result_label.setWordWrap(True) - results_layout.addWidget(self.bus_result_label, 1, 1) - - # Создаем фрейм для результатов - results_layout.setColumnStretch(2, 1) - self.bus_read_value_label.setMinimumWidth(180) - self.bus_result_label.setMaximumWidth(640) - results_frame = QFrame() - results_frame.setFrameShape(QFrame.StyledPanel) - results_frame.setLayout(results_layout) - layout.addWidget(results_frame) - self.setLayout(layout) # После создания интерфейса создаем кнопки для загруженных макросов @@ -468,69 +568,61 @@ class SerialTab(QWidget): for i, macro in enumerate(self.macros): self.add_macro_button_with_index(macro, i) - def write_to_bus(self): - """Запись в шину через регистры""" - try: - device_addr = self.device_address() if callable(self.device_address) else self.device_address - data = int(self.bus_data_edit.text(), 16) - tetrad = int(self.bus_tetrad_edit.text()) - register_num = int(self.bus_register_edit.text()) + def write_to_bus(self): # Прежний публичный метод продолжает выполнять запись существующей SBUS. + self._manual_bus_operation("sbus", True) # Выбираем последовательную шину явно, независимо от последней операции PBUS. - success, result = self.serial_bus.write_bus(data, tetrad, register_num, device_addr) + def read_from_bus(self): # Прежний публичный метод сохраняет чтение последовательной шины для вызывающих вкладок. + self._manual_bus_operation("sbus", False) # Результат направляется в SBUS и не изменяет область PBUS. - if success: - self.raw_widget.append_text(f"Запись в шину: адрес={tetrad}, рег={register_num}, данные=0x{data:04X} - OK") - self.last_result = f"Запись в шину: данные=0x{data:04X}, адрес=0x{tetrad:X}, регистр=0x{register_num:X}" - self.last_result += f"\n{result}" - else: - self.raw_widget.append_text(f"Запись в шину: адрес={tetrad}, рег={register_num} - Ошибка: {result}") - self.last_result = f"Ошибка записи в шину: {result}" + def _manual_bus_operation(self, bus, write): # Фиксируем поля при нажатии и ставим логическую операцию в общую очередь. + try: # Неверный ввод отклоняется до постановки задания и не влияет на выполняющийся обмен. + command = self._sbus_command(write) # Адрес, регистр и данные сохраняются одним снимком. + self._start_commands([command], macro=False) # Ручные чтение и запись имеют приоритет перед следующим фоновым заданием. + except (KeyError, ValueError, TypeError, RuntimeError) as error: # Ошибка поля отображается только в собственной области SBUS. + self._show_bus_result(bus, f"SBUS: ошибка: {error}", failed=True) # Протокол не получает неверную команду. - except ValueError as e: - self.raw_widget.append_text(f"Ошибка в данных: {e}") - self.last_result = f"Ошибка в данных: {e}" + def _sbus_command(self, write=False): # Параметры периодического чтения берутся заново для каждого следующего запроса. + panel = self.bus_panels["sbus"] # Используем существующие поля последовательной шины. + command = {"bus": "sbus", "type": "write" if write else "read", "tetrad": int(panel["tetrad_edit"].text()), "register": int(panel["register_edit"].text())} # Адрес и регистр фиксируются независимо от последующих изменений формы. + if write: # Данные участвуют только в ручной записи SBUS. + command["data"] = int(panel["data_edit"].text(), 16) # Шестнадцатибитное значение считывается в момент нажатия. + validate_command(command) # Сохраняем прежние диапазоны и формат последовательного протокола. + return command # Возвращаем готовый неизменяемый для данного запуска снимок параметров. - def read_from_bus(self): - """Чтение из шины через регистры""" - try: - device_addr = self.device_address() if callable(self.device_address) else self.device_address - tetrad = int(self.bus_tetrad_edit.text()) - register_num = int(self.bus_register_edit.text()) + def _sbus_cycle_changed(self, checked): # Переключение управляет только циклическим источником SBUS. + if checked: # Включение запускает первый запрос сразу, остальные — по выбранному периоду. + self.sbus_timer.start(self.sbus_interval.value()) # Время между началами задано в миллисекундах. + self._sbus_tick() # Начальное чтение не требует ожидания целого периода. + else: # Выключение не прерывает уже переданный пакет UART. + self.sbus_timer.stop() # Будущие повторения не назначаются. + self._cancel_source(self._sbus_key) # Неотправленные команды задания снимаются с общей очереди. - success, result = self.serial_bus.read_bus(tetrad, register_num, device_addr) + def _sbus_period_changed(self, value): # Новый период относится только к дальнейшим повторениям SBUS. + if self.sbus_cycle.isChecked(): # Не запускаем таймер выключенного задания изменением поля. + self.sbus_timer.start(value) # Перезапускаем интервал в миллисекундах без накопления пропущенных циклов. - if success: - # result теперь словарь с данными - hex_str = ' '.join(f'{b:02X}' for b in result['raw_response']['raw']) - self.bus_result_label.setText(f"{hex_str}") + def _sbus_tick(self): # Один такт ставит не более одного чтения выбранной пары устройство/регистр. + if not self.sbus_cycle.isChecked() or self._source_pending(self._sbus_key): # Ожидающий или выполняющийся цикл исключает ещё один запуск. + return # Пропущенное повторение не добавляется в очередь задним числом. + try: # Изменённые пользователем поля применяются к следующему успешно созданному запросу. + self._start_commands([self._sbus_command()], macro=False, background=True, key=self._sbus_key) # Фоновое чтение уступает уже ожидающим ручным действиям. + except (ValueError, TypeError, KeyError) as error: # Промежуточный неверный ввод не вызывает неверного пакета UART. + self.bus_result_label.setText(f"SBUS: проверьте адрес и регистр: {error}") # Диагностика остаётся в области последовательной шины. - # Извлекаем считанное слово - read_word = result['value'] - self.bus_read_value_label.setText(f"0x{read_word:04X} ({read_word})") - - self.raw_widget.append_text(f"Чтение из шины: адрес={tetrad}, рег={register_num} = 0x{read_word:04X}") - - self.last_result = f"Чтение из шины: адрес=0x{tetrad:X}, регистр=0x{register_num:X}" - self.last_result += f"\nСчитано: 0x{read_word:04X} ({read_word})" - self.last_result += f"\nОтвет контроллера: {hex_str}" - else: - self.bus_result_label.setText(f"Ошибка: {result}") - self.bus_read_value_label.setText("---") - self.raw_widget.append_text(f"Чтение из шины: адрес={tetrad}, рег={register_num} - Ошибка: {result}") - self.last_result = f"Ошибка чтения из шины: {result}" - - except ValueError as e: - self.bus_result_label.setText(f"Ошибка: {e}") - self.bus_read_value_label.setText("---") - self.raw_widget.append_text(f"Ошибка в данных: {e}") - self.last_result = f"Ошибка в данных: {e}" - - except ValueError as e: - self.bus_result_label.setText(f"Ошибка: {e}") - self.bus_read_value_label.setText("---") - error_text = f"Ошибка в данных: {e}" - self.raw_widget.append_text(f"✗ {error_text}") - self.last_result = error_text + def _command_summary(self, command, result): # Формируем единое понятное описание ручной операции и команды макроса. + if isinstance(result, dict) and "entries" in result: # PBUS возвращает целую таблицу источников и результатов вместо одного прочитанного слова. + action = {"add": "Регистр добавлен", "remove": "Выделенные регистры удалены", "poll": "Значения обновлены", "configure": "Таблица применена", "start": "Опрос запущен"}.get(command["type"], "Таблица обновлена") # Статус описывает действие над единственным списком PBUS. + if not result["entries"]: # Успешная пустая таблица означает остановленную шину, даже при исходной команде start. + action = "таблица пуста, опрос остановлен" # Сообщение не должно объявлять запуск аппаратуры, которой отправили только остановку. + return f"PBUS: {action}; регистров {len(result['entries'])}" # Значения отдельных источников остаются в соответствующих строках таблицы. + bus, operation = command.get("bus", "sbus"), command["type"] # Старые макросы без поля bus продолжают принадлежать SBUS. + if bus == "pbus": # Остановка аппаратной таблицы возвращает подтверждение без отдельного считанного слова. + return f"PBUS: опрос остановлен; регистров {len(self.pbus_group.entries)}" # Состояние относится к текущему видимому списку, а не к прежнему ручному числу строк. + context = f"плата={command['tetrad']}, регистр={command['register']}" # Показываем источник данных в каждой записи журнала соответствующей шины. + if operation == "read": # Успешное чтение всегда включает считанное слово и его источник. + return f"{bus.upper()}: {context}, считано 0x{result['value']:04X}" # Представление HEX удобно для сопоставления с документацией регистров. + if operation == "write": # Запись последовательной шины и подготовка таблицы PBUS имеют разные аппаратные результаты. + return f"SBUS: {context}, запись 0x{command['data']:04X} подтверждена" # Данные и подтверждение последовательной записи остаются в собственной области результатов. def create_macro(self): """Создать новый макрос""" @@ -550,20 +642,18 @@ class SerialTab(QWidget): def add_macro_button_with_index(self, macro, index): """Добавить кнопку макроса в интерфейс с указанным индексом""" - items_per_row = 2 - row = len(self.macro_buttons) // items_per_row - col = len(self.macro_buttons) % items_per_row + # Создаем контейнер для кнопки и кнопки редактирования container = QWidget() container_layout = QHBoxLayout() container_layout.setContentsMargins(0, 0, 0, 0) container_layout.setSpacing(4) - container.setMaximumWidth(360) - container.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) + container.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) # Элемент макроса сохраняет естественную ширину у левого края панели. # Основная кнопка макроса macro_btn = QPushButton(macro['name']) + macro_btn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) # Название макроса и его действия остаются рядом вместо растягивания кнопки на всю ширину окна. macro_btn.setFixedHeight(30) macro_btn.setMinimumWidth(120) macro_btn.setToolTip(macro["name"]) @@ -601,9 +691,13 @@ class SerialTab(QWidget): container_layout.addWidget(macro_btn) container_layout.addWidget(edit_btn) container_layout.addWidget(delete_btn) + cycle = QCheckBox("Циклически", container) # Каждый макрос имеет независимый переключатель повторения. + cycle.setChecked(id(macro) in self._macro_cycles) # Перестроение списка сохраняет состояние таймера по объекту макроса. + cycle.toggled.connect(lambda checked, item=macro: self._macro_cycle_changed(item, checked)) # Связь с объектом сохраняется при удалении соседних макросов. + container_layout.addWidget(cycle) # Галочка расположена рядом с кнопками выполнения, редактирования и удаления. container.setLayout(container_layout) - self.macros_scroll_layouts[col].addWidget(container, row, 0) + self.macros_scroll_layout.addWidget(container) # FlowLayout размещает элемент без растягивания и пересчитывает перенос при изменении ширины. self.macro_buttons.append(container) @@ -616,7 +710,7 @@ class SerialTab(QWidget): def execute_macro_by_index(self, macro_index): """Выполнить макрос по индексу""" if 0 <= macro_index < len(self.macros): - self.execute_macro_commands(self.macros[macro_index]['commands']) + self._start_commands(self.macros[macro_index]["commands"], macro=True, source=self.macros[macro_index]) # Однократный запуск снимает параметры при нажатии независимо от режима повторения. def edit_macro_by_index(self, macro_index): """Редактировать макрос по индексу""" @@ -624,14 +718,18 @@ class SerialTab(QWidget): dialog = MacroEditorDialog(self, self.macros[macro_index]) if dialog.exec(): edited_macro = dialog.get_macro() - self.macros[macro_index] = edited_macro + original = self.macros[macro_index] # Сохраняем идентичность объекта, с которым связан таймер повторения. + original.update(edited_macro) # Уже запущенные команды используют снимок, следующие получают отредактированные значения. + self._restart_macro_timer(original) # Применяем новый период только к этому макросу. # Обновляем кнопку - находим ее по индексу if macro_index < len(self.macro_buttons): container = self.macro_buttons[macro_index] macro_btn = container.layout().itemAt(0).widget() if macro_btn: - macro_btn.setText(edited_macro['name']) + macro_btn.setText(edited_macro['name']) # Обновляем название без изменения размера остальных элементов. + container.updateGeometry() # Длина названия влияет на естественную ширину элемента. + self.macros_scroll_layout.invalidate() # Пересчитываем перенос следующих макросов по доступной ширине. self.save_macros() @@ -651,7 +749,8 @@ class SerialTab(QWidget): QMessageBox.No ) - if reply == QMessageBox.Yes: + if reply == QMessageBox.Yes: # Удаление действует только после подтверждения пользователя. + self._macro_cycle_changed(self.macros[macro_index], False) # Отменяем повторы и неотправленные команды удаляемого макроса. # Удаляем макрос из списка del self.macros[macro_index] @@ -661,80 +760,164 @@ class SerialTab(QWidget): # Сохраняем изменения self.save_macros() - def execute_macro_commands(self, commands): - """Run a macro as Qt callbacks, without loops or waiting in the UI thread.""" - if self._macro_running: - self.raw_widget.append_text("Дождитесь завершения макроса") - return - from protocan.tms_terminal import bus_steps - try: - controller = self.device_address() if callable(self.device_address) else self.device_address - jobs = [] - for command in commands: - if command['type'] not in ('write', 'read'): - raise ValueError("Неизвестная команда макроса") - jobs.extend(bus_steps(command['type'] == 'write', command['tetrad'], - command['register'], command.get('data', 0))) - except (KeyError, ValueError, RuntimeError, TypeError) as error: - self.raw_widget.append_text(f"Макрос остановлен: {error}") - return - if not jobs: - self.raw_widget.append_text("Макрос пуст") - return - self._macro_controller = controller - self._macro_jobs = jobs - self._macro_index = 0 - self._macro_running = True - self._macro_generation += 1 - self._set_macro_controls(True) - generation = self._macro_generation - QTimer.singleShot(0, lambda: self._next_macro_command(generation)) + def execute_macro_commands(self, commands): # Сохраняем публичный запуск макроса, добавляя возможность смешивать PBUS и SBUS. + self._start_commands(commands, macro=True) # Ручной PBUS и макросы используют одинаковое выполнение и защиту от поздних ответов. - def _set_macro_controls(self, running): - self.stop_macro_btn.setEnabled(running) - for widget in (self.bus_write_btn, self.bus_read_btn, self.create_macro_btn, - self.macros_splitter, self.raw_widget): - widget.setEnabled(not running) + def _sbus_sequence(self, command): # Адаптируем существующий двухшаговый SBUS к общему асинхронному исполнителю. + from protocan.tms_terminal import bus_steps # Планирование SBUS остаётся в прежнем общем C-ядре протокола TMS2812. + result = None # Итогом станет ответ последнего запроса чтения или подтверждения записи. + for request in bus_steps(command["type"] == "write", command["tetrad"], command["register"], command.get("data", 0)): # Формируем те же адреса и управляющие слова, что до добавления PBUS. + result = yield request # Ответ передаётся генератору только после завершения текущего запроса транспорта. + if command["type"] == "read" and (not isinstance(result, dict) or not isinstance(result.get("value"), int) or not 0 <= result["value"] <= 0xFFFF): # ReadMemory существующей SBUS должен вернуть одно шестнадцатибитное слово. + raise ValueError("SBUS: некорректный ответ чтения памяти") # Повреждённый ответ прекращает только текущую последовательность. + return result # Возвращаем финальное слово или подтверждение для области результатов SBUS. - def _next_macro_command(self, generation): - if not self._macro_running or generation != self._macro_generation: - return - if self._macro_index >= len(self._macro_jobs): - self._finish_macro("Макрос выполнен") - return - generation = self._macro_generation - address, value = self._macro_jobs[self._macro_index] - self.raw_protocol.request_async(address, value, self._macro_controller, - lambda success, result: self._macro_reply(generation, success, result)) + def _pbus_sequence(self, command): # Все пути PBUS используют полную таблицу, сохранённые параметры остановки и адреса CD результатов. + if command["type"] == "stop": # Остановка не вычисляет N-1 из новой или пустой таблицы интерфейса. + return (yield from self.pbus_group.stop_sequence(command)) # Единственная запись сохраняет подтверждённые параметры активного аппаратного опроса. + return (yield from self.pbus_group.sequence(command)) # Настройка и чтение исполняются общей очередью без чередования пакетов с другой операцией. - def _macro_reply(self, generation, success, result): - if not self._macro_running or generation != self._macro_generation: - return - if not success: - self._finish_macro(f"Макрос остановлен: {result}") - return - if 'value' in result: - value = result['value'] - self.bus_read_value_label.setText(f"0x{value:04X} ({value})") - self.bus_result_label.setText(result['raw_response']['raw'].hex(" ")) - self.raw_widget.append_text(f"Макрос: прочитано 0x{value:04X}") - else: - self.raw_widget.append_text("Макрос: запись подтверждена") - self._macro_index += 1 - QTimer.singleShot(0, lambda: self._next_macro_command(generation)) + def cancel_background(self): # Прежний публичный вызов больше не обрывает пакет фонового чтения. + return # Ручное действие получает приоритет очереди после завершения текущей логической операции. - def _finish_macro(self, message): - self._macro_running = False - self._set_macro_controls(False) - self.last_result = message - self.raw_widget.append_text(message) + def _source_pending(self, key): # Учитываем целый макрос между его отдельными логическими командами. + return any(run["key"] == key for run in self._runs) or self.queue.contains(key) # Одно задание не имеет одновременно ожидающего и повторного запуска. - def stop_macro(self): - if not self._macro_running: - return - self._macro_generation += 1 - self._finish_macro("Макрос остановлен пользователем; переданные команды могли быть выполнены") - self.raw_protocol.cancel_async() + def _sync_running(self): # Совместимые признаки состояния остаются доступны встраивающему SETGUI. + self._macro_running = bool(self._runs) # Признак показывает активные и ожидающие последовательности без блокировки интерфейса. + self._macro_is_macro = any(run["macro"] for run in self._runs) # Макросы отличаются от ручного чтения или записи своей последовательностью. + self._background = bool(self._runs) and all(run["background"] for run in self._runs) # Признак фонового режима не влияет на доступность кнопок. + + def _start_commands(self, commands, *, macro, background=False, key=None, source=None): # Параметры фиксируются до ожидания общей очереди соединения. + if key is not None and self._source_pending(key): # Периодические задания не накапливаются, пока прежний запуск не завершён. + return False # Пропущенный цикл не создаёт отложенного повторения. + try: # Проверяем весь макрос до его первой записи и сохраняем независимый снимок. + jobs = deepcopy(list(commands)) # Редактирование макроса или полей не меняет уже поставленное действие. + planned = deepcopy(self.pbus_group.entries) # Начальное состояние используется для проверки максимальной ёмкости таблицы. + for existing in self._runs: # Учитываем ещё не выполненные изменения таблицы из ранее принятых нажатий. + for command in existing["jobs"][existing["index"]:]: # Изменения применяются в ожидаемом порядке пользовательских действий. + if command.get("bus", "sbus") == "pbus": # SBUS не изменяет список строк параллельной шины. + planned = table_entries_after(planned, command) # Проверка сохраняет ограничение буфера из шестидесяти четырёх слов. + for command in jobs: # Ошибка даже последней команды не должна допускать частичного исполнения макроса. + validate_command(command) # Старые макросы без поля bus продолжают работать через SBUS. + if command.get("bus", "sbus") == "pbus": # Совместимые одиночные команды переводятся в существующие действия таблицы. + command.setdefault("_form_errors", self.pbus_group.error_limit.value()) # Фиксируем состояние поля при постановке команды, чтобы поздний результат макроса не затёр последующий ввод. + command["type"] = {"write": "add", "read": "add"}.get(command["type"], command["type"]) # Источник сохраняется без введения второго списка PBUS. + planned = table_entries_after(planned, command) # Проверяем диапазоны адресов, удаление и вместимость до первого запроса. + controller = self.device_address() if callable(self.device_address) else self.device_address # Контроллер фиксируется в момент нажатия или создания цикла. + except (KeyError, ValueError, TypeError, RuntimeError) as error: # Неверные параметры не затрагивают активную операцию соединения. + self.macros_status.setText(f"Макрос остановлен: {error}") # Указываем конкретную причину отказа валидации. + self.raw_widget.append_text(str(error)) # Сохраняем диагностический текст в прежнем журнале. + return False # Ни одного пакета данного задания не было отправлено. + if not jobs: # Пустой макрос не создаёт операции очереди и не запускает фоновых повторов. + self.macros_status.setText("Макрос пуст") # Показываем состояние в общей области макросов. + return False # Нет команд для передачи контроллеру. + run = {"jobs": jobs, "index": 0, "controller": controller, "macro": macro, "background": background, "key": key if key is not None else object(), "source": source, "cancelled": False, "started": False} # Каждый запуск сохраняет своё положение и владельца отмены. + self._runs.append(run) # Несколько принятых нажатий не заменяют друг друга. + self._sync_running() # Обновляем признаки выполнения, оставляя все элементы доступными. + if not background: # Фоновый цикл не подменяет последний итог явно запущенного макроса. + self.macros_status.setText("Макрос в очереди" if macro else "Команда в очереди") # Нажатие подтверждается даже при занятом соединении. + self._queue_command(run) # Первая логическая операция получает соответствующий приоритет. + return True # Периодический источник знает, что предыдущий запуск ещё ожидает или выполняется. + + def _queue_command(self, run): # Макрос передаёт команды по порядку, уступая порт между логическими операциями. + if run["cancelled"] or run not in self._runs: # Остановка запрещает позднее назначение следующей команды. + return # Завершённый или снятый запуск больше не использует UART. + command = run["jobs"][run["index"]] # Снимок команды принадлежит именно этому запуску. + self.queue.submit(lambda: self._begin_command(run, command), run["controller"], lambda ok, result: self._command_done(run, command, ok, result), key=run["key"], background=run["background"]) # Все пакеты выбранной команды выполняются атомарно относительно других операций. + + def _begin_command(self, run, command): # Фабрика вызывается после получения владения соединением общей очередью. + if run["key"] == self._sbus_key and not run["started"]: # Ожидающий циклический SBUS берёт актуальные поля при фактическом начале запроса. + command.update(self._sbus_command()) # Устройство и регистр следующего запроса меняются до отправки, параметры текущего генератора сохраняются. + self._macro_controller = run["controller"] # Существующая таблица PBUS получает зафиксированный контроллер текущей операции. + if not run["started"]: # Период измеряется от реального начала первого шага данного запуска. + run["started"] = True # Продолжения внутри макроса не меняют время начала повторения. + self._repeat_started(run) # Следующий таймер отсчитывается от начала обмена, а не завершения макроса. + return self._pbus_sequence(command) if command.get("bus", "sbus") == "pbus" else self._sbus_sequence(command) # Существующие алгоритмы шин сохраняют формат своих WriteMemory и ReadMemory. + + def _command_done(self, run, command, success, result): # Результат завершается только после всей логической операции регистра. + if run not in self._runs or run["cancelled"]: # Callback остановленного задания не продолжает его макрос. + return # Ответ отправленного пакета уже обработан протоколом безопасно для следующего обмена. + bus = command.get("bus", "sbus") # Ответ относится к шине снимка команды, независимо от изменённых полей. + if not success: # Таймаут, неверный ответ и отключение прекращают дальнейшие команды текущего макроса. + self._show_bus_result(bus, f"{bus.upper()}: ошибка: {result}", failed=True) # Реальная транспортная ошибка остаётся видна в своей области результатов. + self._finish_run(run, f"Макрос остановлен: {result}") # Освобождаем состояние запуска без отмены других независимых заданий. + return # После ошибки не выполняются следующие записи этого макроса. + self._show_bus_result(bus, self._command_summary(command, result), result) # Значения выводятся только в области соответствующей шины. + run["index"] += 1 # Продвигаем макрос после подтверждения всех пакетов текущей команды. + if run["index"] < len(run["jobs"]): # Следующая команда сохраняет заданный порядок внутри макроса. + self._queue_command(run) # Ручные действия смогут обслуживаться перед следующим фоновым шагом. + else: # Последняя команда завершила весь однократный или циклический запуск. + self._finish_run(run, "Макрос выполнен" if run["macro"] else "Команда выполнена") # Повторение планирует независимый таймер, не цепочка немедленных запусков. + + def _finish_run(self, run, message): # Удаляем состояние только завершённого запуска, сохраняя остальные задания. + if run in self._runs: # Повторный callback отмены не должен удалять чужой запуск. + self._runs.remove(run) # Периодический источник снова может поставить следующий цикл. + self._sync_running() # Состояние учитывает другие ожидающие ручные действия и независимые макросы. + if not run["background"]: # Циклическое чтение не меняет явный итог последнего макроса. + self.macros_status.setText(message) # Показываем результат явно запущенного действия. + self.raw_widget.append_text(message) # Прежний общий журнал сохраняет итог выполнения. + + def _cancel_source(self, key): # Остановка источника запрещает будущие команды всех его незавершённых запусков. + for run in list(self._runs): # Снимок позволяет безопасно удалить несколько запусков выбранного источника. + if run["key"] == key: # Остальные макросы и чтения шин не затрагиваются. + run["cancelled"] = True # Позднее подтверждение уже отправленного пакета не продолжит последовательность. + self._finish_run(run, "Остановлено") # Освобождаем состояние задания до получения транспортного ответа. + self.queue.cancel(key) # Очередь снимет неотправленные шаги и дождётся ответа текущего пакета. + + def _repeat_started(self, run): # Период отсчитывается между реальными началами повторов. + if run["key"] == self._sbus_key and self.sbus_cycle.isChecked(): # Старт чтения SBUS задаёт начало следующего периода только этой шины. + self.sbus_timer.start(self.sbus_interval.value()) # Таймер не зависит от продолжительности текущего обмена. + elif run["key"] == self._pbus_key and self.pbus_group.auto_update.isChecked(): # Циклический PBUS использует собственное поле периода. + self.pbus_group.timer.start(self.pbus_group.interval.value()) # Отсчёт начинается от начала чтения таблицы. + elif run["source"] is not None and run["background"]: # Циклический макрос получает независимый таймер своего владельца. + self._restart_macro_timer(run["source"]) # Пропущенные повторы не создают дополнительного запуска. + + def _restart_macro_timer(self, macro): # Период одного макроса применяется отдельно от всех других заданий. + timer = self._macro_cycles.get(id(macro)) # Таймер сохраняется по идентичности макроса при переносе и перестроении списка. + if timer is not None: # Редактирование выключенного макроса не запускает циклическое выполнение. + timer.start(int(macro.get("period_ms", 1000))) # Старые JSON-макросы получают штатный период одной секунды. + + def _macro_cycle_changed(self, macro, checked): # Галочка управляет повторениями только выбранного макроса. + identity, key = id(macro), (id(self), "macro", id(macro)) # Общая очередь получает независимый ключ источника повторов. + if checked and identity not in self._macro_cycles: # Повторное включение не создаёт второго таймера. + timer = QTimer(self) # Таймер принадлежит существующей панели и не зависит от положения дока. + timer.setTimerType(Qt.PreciseTimer) # Индивидуальный период макроса отсчитывается без преждевременного срабатывания. + timer.timeout.connect(lambda item=macro: self._macro_tick(item)) # Следующий цикл берёт актуальную сохранённую последовательность макроса. + self._macro_cycles[identity] = timer # Сохраняем таймер до выключения галочки или удаления макроса. + self._restart_macro_timer(macro) # Период берётся из индивидуальных настроек этого макроса. + self._macro_tick(macro) # Первый запуск происходит сразу после включения. + elif not checked: # Выключение немедленно запрещает будущие повторы и ещё не переданные команды. + timer = self._macro_cycles.pop(identity, None) # Удаляем только таймер выбранного макроса. + if timer is not None: # Галочка может выключаться также при удалении никогда не запускавшегося макроса. + timer.stop() # Новые периодические события больше не назначаются. + timer.deleteLater() # Освобождаем объект Qt после обработки текущих событий. + self._cancel_source(key) # Текущий пакет завершится корректно, остальные шаги задания отменяются. + + def _macro_tick(self, macro): # Периодический запуск не допускает перекрытия с незавершённым запуском того же макроса. + key = (id(self), "macro", id(macro)) # Ключ одинаков для всех повторов одного выбранного макроса. + if id(macro) not in self._macro_cycles or any(run["source"] is macro for run in self._runs) or self.queue.contains(key): # Учитываем также ещё завершающийся пакет остановленного задания. + return # Пропущенные циклы не копятся ни в таймере, ни в очереди. + self._start_commands(macro["commands"], macro=True, background=True, key=key, source=macro) # Команды исполняются в заданном порядке с фоновым приоритетом. + + def stop_macro(self): # Общая кнопка останавливает макросы, оставляя ручное чтение шин доступным. + for macro in list(self.macros): # Галочки снимаются у всех сохранённых циклических макросов. + self._macro_cycle_changed(macro, False) # Отменяем будущие повторения выбранного источника безопасно для текущего пакета. + for run in list(self._runs): # Однократные макросы также могут ожидать или выполнять очередную команду. + if run["macro"]: # Ручные действия SBUS и PBUS не являются остановленным макросом. + self._cancel_source(run["key"]) # Отменяем только ещё не переданные шаги данного запуска. + for container in self.macro_buttons: # Видимое состояние галочек отражает остановку независимых таймеров. + container.findChild(QCheckBox).setChecked(False) # Повторный обработчик выключения безопасен и не запускает обмен. + + def stop(self): # Закрытие страницы или отключение порта очищает очередь всего соединения. + self.sbus_cycle.setChecked(False) # Циклический SBUS больше не ставит запросов отключаемому порту. + self.sbus_timer.stop() # Таймер останавливается также при уже выключенной галочке. + self.pbus_group.stop_updates() # Прекращаем дальнейшие чтения аппаратного буфера PBUS. + self.stop_macro() # Макросы не продолжаются после отключения соединения. + for run in list(self._runs): # Снимаем оставшиеся ручные действия панели. + self._cancel_source(run["key"]) # Поздние ответы не продвигают отключённые задания. + self.queue.clear() # Операции памяти и остальных панелей того же соединения также отменяются. + self.raw_protocol.cancel_async() # При закрытии соединения текущий транспортный запрос завершается отказом. def load_macros(self): """Загрузить макросы из файла""" diff --git a/python/set_devices/background_work.py b/python/set_devices/background_work.py new file mode 100644 index 0000000..9e67465 --- /dev/null +++ b/python/set_devices/background_work.py @@ -0,0 +1,29 @@ +import time # Монотонные часы и короткое ожидание позволяют фоновому Python-коду регулярно освобождать GIL для обработчиков Qt. + + +class WorkBudget: # Длинный расчёт добровольно уступает процессор, чтобы поток интерфейса не ждал GIL после каждого вызова Qt. + def __init__(self, cancelled=None): # Необязательное threading.Event отменяет устаревшее задание без зависимости общего алгоритма от Qt. + self.cancelled = cancelled # Событие принадлежит одному заданию; его установку проверяем до и после уступки интерфейсу. + self.deadline = time.perf_counter() + .002 # Две миллисекунды непрерывной работы ограничивают конкуренцию с короткими Python-обработчиками GUI. + + def __call__(self): # Рабочие проходы вызывают контрольную точку примерно раз в тысячу элементов, без проверки часов на каждом отсчёте. + if self.cancelled is not None and self.cancelled.is_set(): # Запрос отмены должен действовать даже до истечения бюджета вычислений. + raise InterruptedError("Фоновое задание отменено") # Вызывающий worker освобождает ресурсы и не публикует частичный результат. + if time.perf_counter() < self.deadline: # Несколько быстрых контрольных точек не должны создавать лишние ожидания. + return # Продолжаем текущую небольшую порцию вычислений до исчерпания её бюджета. + if self.cancelled is None: # Неотменяемая подготовка также обязана оставлять время главному потоку. + time.sleep(.001) # Пауза в одну миллисекунду освобождает GIL; sleep(0) не гарантирует времени для цепочки обработчиков Qt. + elif self.cancelled.wait(.001): # Ожидание освобождает GIL и немедленно заканчивается при отмене вместо полной паузы. + raise InterruptedError("Фоновое задание отменено") # Не продолжаем вычисление после отмены, полученной во время уступки интерфейсу. + self.deadline = time.perf_counter() + .002 # Новый бюджет начинается после ожидания, чтобы не накапливать пропущенные интервалы. + + +def work_items(items, checkpoint): # Оборачиваем полный последовательный проход без копирования и без потери исходных элементов. + if checkpoint is None: # Обычные синхронные вызовы сохраняют прежнее поведение и не получают искусственных задержек. + yield from items # Передаём значения в неизменном порядке без счётчика контрольных точек. + return # Ветвь без фонового бюджета не выполняет проверки часов. + for index, item in enumerate(items): # Счётчик определяет небольшие порции независимо от типа исходного контейнера. + if index % 1024 == 0: # Не более 1024 элементов между проверками ограничивают задержку отмены и удержание GIL. + checkpoint() # Уступаем время интерфейсу либо прерываем устаревшее задание. + yield item # Отдаём каждый исходный элемент ровно один раз, сохраняя точность и порядок измерений. + checkpoint() # Последняя проверка не допускает публикации результата, отменённого в конце короткого блока. diff --git a/python/set_devices/balsam_can.py b/python/set_devices/balsam_can.py index c0274ce..574aeac 100644 --- a/python/set_devices/balsam_can.py +++ b/python/set_devices/balsam_can.py @@ -34,16 +34,16 @@ def decode(raw_id: int, data: bytes, *, ide: bool = True, pm=1 if frame.from_device else 0, priority=0, ) result = pc.Decoded(pid, len(data), bytes(data), ide=ide, rtr=rtr, - protocol="BALZAM 167", device_label=frame.device_name, - message_label=("BALZAM данные" if frame.from_device + protocol="BALZAM 167", device_label=frame.sender_name, # Все CAN ID 167 подписываются источником: команды — TMS, ответы — именем устройства из таблицы адресов. + message_label=("BALZAM Heartbeat" if frame.is_heartbeat else "BALZAM данные" if frame.from_device # Тип сообщения явно выделяет heartbeat по адресу и маске, сохраняя имя отправителя. else "BALZAM команды")) result.summary = frame.summary result.fields = [ ("Протокол", "BALZAM 167 legacy eCAN"), ("Узел", "%d — %s" % (frame.device, frame.device_name)), ("Направление", frame.route), - ("Отправитель", frame.device_name if frame.from_device else "ПМ"), - ("Получатель", "ПМ" if frame.from_device else frame.device_name), + ("Отправитель", frame.sender_name), # Используем ту же подпись источника, что в маршруте и имени кадра любого устройства 167. + ("Получатель", frame.recipient_name), # Показываем адресата отдельно, сохраняя имя периферийного узла в поле «Узел». ("Начальный адрес", "0x%04X" % frame.start_address), ("Маска трёх слов", "0b%s" % format(frame.present_mask, "03b")), ] @@ -51,7 +51,7 @@ def decode(raw_id: int, data: bytes, *, ide: bool = True, for item in frame.registers: result.fields.append(( "0x%04X %s" % (item.address, item.name or "регистр"), - "0x%04X (%d)" % (item.value, item.signed_value), + "0x%04X (%d)" % (item.value, item.value if frame.is_heartbeat else item.signed_value), # Счётчик секунд и идентификаторы heartbeat беззнаковые, в отличие от технологических int16. )) if item.address == 0x7F: result.fields.append(("Активные биты Commands", frame.command_description(item.value))) diff --git a/python/set_devices/can_adapter_settings.py b/python/set_devices/can_adapter_settings.py new file mode 100644 index 0000000..2e484e8 --- /dev/null +++ b/python/set_devices/can_adapter_settings.py @@ -0,0 +1,147 @@ +"""Проверяемые настройки физических CAN-адаптеров без зависимости от Qt.""" # Общая модель используется транспортами и редактором настроек. + +from __future__ import annotations # Отложенная оценка объединений типов сохраняет импорт в сборке Python 3.8 для Windows 7. +from dataclasses import dataclass # Неизменяемые значения исключают смену режима во время работающего сеанса. + +FD_LENGTHS = (0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64) # Таблица DLC стандарта CAN FD переводит четырёхбитный код в число байтов. + + +@dataclass(frozen=True) # Полный тайминг передаётся в драйвер одной согласованной структурой. +class CanTiming: # Сегменты измеряются в квантах времени CAN, BRP задаёт делитель тактовой частоты. + prop_seg: int = 1 # Квант компенсации задержки распространения входит в TSEG1. + phase_seg1: int = 12 # Вместе с PROP_SEG даёт TSEG1=13 для обычного тайминга 48 МГц. + phase_seg2: int = 2 # Два кванта после точки выборки дают суммарно 16 квантов на бит. + sjw: int = 1 # Один квант ограничивает коррекцию при ресинхронизации. + brp: int = 6 # 48 МГц / 6 / 16 соответствует скорости 500 кбит/с. + + def validate(self, cap, bitrate: int) -> None: # Проверяем ограничения, реально объявленные выбранным каналом. + if cap.fclk_can <= 0 or cap.brp_min < 1 or self.brp < 1: # Нулевая частота или делитель означают повреждённый ответ либо ошибочный ручной ввод. + raise ValueError("Некорректная частота CAN или нулевой BRP") # Не допускаем деления на ноль при диагностике скорости. + tseg1 = self.prop_seg + self.phase_seg1 # Контроллер ограничивает суммарный сегмент перед выборкой. + if self.prop_seg < 0 or self.phase_seg1 < 1: # Нулевая задержка допустима, но фазовый сегмент обязан существовать. + raise ValueError("PROP_SEG ≥ 0, PHASE_SEG1 ≥ 1") # Не отправляем в USB недопустимые сегменты. + if not cap.tseg1_min <= tseg1 <= cap.tseg1_max or not cap.tseg2_min <= self.phase_seg2 <= cap.tseg2_max: # Пределы различаются для номинальной и быстрой фазы. + raise ValueError("Сегменты тайминга вне диапазона адаптера") # Сообщаем об аппаратном ограничении до запуска канала. + if not 1 <= self.sjw <= min(cap.sjw_max, self.phase_seg2): # SJW не должен превышать второй фазовый сегмент. + raise ValueError("SJW превышает предел адаптера или PHASE_SEG2") # Исключаем некорректную ресинхронизацию. + if not cap.brp_min <= self.brp <= cap.brp_max or (self.brp - cap.brp_min) % max(1, cap.brp_inc): # Делитель учитывает шаг аппаратного регистра. + raise ValueError("BRP вне диапазона или шага адаптера") # Не округляем вручную заданный делитель. + actual = cap.fclk_can / (self.brp * (1 + tseg1 + self.phase_seg2)) # Единицы результата — бит/с; дополнительный квант относится к SYNC_SEG. + if abs(actual - bitrate) > max(1, bitrate * 0.0001): # Допуск 0,01 % позволяет записать 83 333 вместо периодической дроби. + raise ValueError(f"Тайминг задаёт {actual:g} бит/с вместо {bitrate}") # Статус и запись захвата не должны сообщать ложную скорость. + + +def calculate_timing(cap, bitrate: int, sample_point: float = 87.5) -> CanTiming: # Подбираем тайминг по частоте и пределам канала вместо фиксированной таблицы 48 МГц. + if cap.fclk_can <= 0 or not 1 <= cap.brp_min <= cap.brp_max <= 65536 or cap.tseg1_min < 1 or cap.tseg2_min < 1: # Ограничиваем также объём поиска при повреждённом ответе USB. + raise ValueError("Адаптер вернул некорректные пределы тайминга") # Не выдаём мусорные аппаратные поля за рабочую конфигурацию. + if bitrate <= 0 or not 50 <= sample_point <= 95: # Процент выборки ограничен практически полезным диапазоном. + raise ValueError("Скорость должна быть положительной, точка выборки — 50…95 %") # Не запускаем поиск с бессмысленными параметрами. + best = None # Сохраняем наиболее точное приближение скорости и точки выборки. + for brp in range(cap.brp_min, cap.brp_max + 1, max(1, cap.brp_inc)): # Рассматриваем только допустимые делители аппаратной частоты. + total = round(cap.fclk_can / (brp * bitrate)) # Число квантов в бите включает синхронизацию и оба сегмента. + if total < 3: # Минимум нужен для SYNC_SEG и двух ненулевых фазовых сегментов. + continue # Этот делитель не позволяет получить корректную структуру бита. + lower, upper = max(cap.tseg2_min, total - 1 - cap.tseg1_max), min(cap.tseg2_max, total - 1 - cap.tseg1_min) # Допустимый TSEG2 одновременно ограничивается обоими аппаратными сегментами. + if lower > upper: # Выбранное число квантов не раскладывается на допустимые TSEG1 и TSEG2. + continue # Другой делитель может дать ту же точную скорость при корректных сегментах. + tseg2 = min(upper, max(lower, round(total * (1 - sample_point / 100)))) # Выбираем ближайшую достижимую точку внутри пересечения аппаратных ограничений. + tseg1 = total - 1 - tseg2 # Оставшийся бюджет квантов принадлежит сегменту перед выборкой. + if not cap.tseg1_min <= tseg1 <= cap.tseg1_max: # Проверяем аппаратные пределы до вычисления оценки. + continue # Не пытаемся отправлять неподдерживаемую комбинацию сегментов. + error = abs(cap.fclk_can / (brp * total) - bitrate) / bitrate # Относительная ошибка скорости важнее ошибки точки выборки. + score = (error, abs((1 + tseg1) / total * 100 - sample_point), -total) # При равенстве предпочитаем больше квантов для точной синхронизации. + if best is None or score < best[0]: # Сравнение кортежей сохраняет установленный приоритет критериев. + best = (score, CanTiming(0, tseg1, tseg2, 1, brp)) # PROP_SEG=0 допустим в gs_usb: драйвер использует суммарный TSEG1. + if best is None or best[0][0] > 0.0001: # Не разрешаем скрытое округление к другой скорости шины. + raise ValueError(f"Адаптер не может точно установить {bitrate} бит/с") # Пользователь должен выбрать достижимую скорость. + best[1].validate(cap, bitrate) # Одинаково проверяем автоматический и ручной путь установки. + return best[1] # Возвращаем параметры, готовые для управляющего USB-запроса. + + +@dataclass(frozen=True) # Настройки SLCAN фиксируются до отправки первой команды конфигурации. +class SlcanOptions: # Различия команд выбираются явным профилем прошивки. + profile: str = "lawicel" # Lawicel использует подтверждения CR/BEL и команду L для пассивного режима. + loopback: bool = False # Команда l доступна только у прошивок, реализующих это расширение Lawicel. + retransmit: bool | None = None # None сохраняет настройку прошивки; A0/A1 применяются только для CANable. + timestamps: bool | None = None # None не записывает EEPROM Lawicel и оставляет текущее состояние Z. + acceptance_code: int | None = None # Регистр M задаётся вместе с маской и только у Lawicel. + acceptance_mask: int | None = None # Биты маски имеют семантику прошивки Lawicel, а не экранного фильтра ID. + btr: str = "" # Четыре HEX-цифры BTR0/BTR1 включают нестандартную скорость через команду s. + command_timeout_ms: int = 500 # Полсекунды ограничивает ожидание подтверждения отдельной команды. + fd: bool = False # Расширенные команды d/D/b/B поддерживает профиль CANable 2.0. + data_bitrate: int = 2_000_000 # В документированной CANable 2.0 доступны быстрая фаза 2 или 5 Мбит/с. + + def commands(self, bitrate: int, listen_only: bool) -> list[str]: # Формируем весь план до открытия COM, чтобы ошибка не меняла аппаратное состояние. + if self.profile not in ("lawicel", "canable", "canable2") or not 10 <= self.command_timeout_ms <= 10000: # Ограничиваем профиль и тайм-аут 10 мс…10 с. + raise ValueError("Неверный профиль SLCAN или тайм-аут команды") # Произвольные команды через настройки не исполняются. + if self.loopback and (listen_only or self.profile != "lawicel"): # Для SLCAN нужны отдельные команды открытия l и L. + raise ValueError("Loopback требует профиль Lawicel и отключённый режим только приёма") # Не подменяем молча выбранный пользователем режим. + rates = {10000: "S0", 20000: "S1", 50000: "S2", 100000: "S3", 125000: "S4", 250000: "S5", 500000: "S6", 1000000: "S8"} # Общая часть стандартных скоростей задана спецификацией ASCII-команд. + rates[800000 if self.profile == "lawicel" else 750000] = "S7" # Одинаковая команда означает разные скорости в двух семействах прошивок. + if self.profile == "canable2": # Дополнительная скорость описана только для CANable 2.0. + rates[83333] = "S9" # Целое значение соответствует округлённым 83,333 кбит/с. + if self.btr: # Ручной тайминг имеет приоритет над выбором стандартного Sn. + if self.profile != "lawicel" or len(self.btr) != 4 or any(c not in "0123456789abcdefABCDEF" for c in self.btr): # Разрешаем ровно два байта регистров SJA1000. + raise ValueError("BTR0/BTR1: четыре HEX-цифры, только профиль Lawicel") # Исключаем внедрение дополнительных строк в команду. + speed = "s" + self.btr.upper() # Прошивка сама интерпретирует регистры тайминга своего контроллера. + btr0, btr1 = int(self.btr[:2], 16), int(self.btr[2:], 16) # В классическом Lawicel SJA1000 работает от генератора 16 МГц. + actual = 16_000_000 / (2 * ((btr0 & 63) + 1) * (3 + (btr1 & 15) + ((btr1 >> 4) & 7))) # SJA1000 делит частоту на 2·BRP и число квантов SYNC+TSEG1+TSEG2. + if abs(actual - bitrate) > max(1, bitrate * 0.0001): # Сохраняем честную скорость в статусе и захвате даже при ручном BTR. + raise ValueError(f"BTR задаёт {actual:g} бит/с при 16 МГц; выберите эту скорость подключения") # Не маскируем рассогласование ручных регистров и выбранного битрейта. + else: # Обычный путь требует наличия точной скорости в выбранном профиле. + speed = rates.get(bitrate) # Не используем S7 от другого семейства адаптеров. + if speed is None: # Произвольная скорость без BTR не имеет команды в этом профиле. + raise ValueError(f"Профиль {self.profile} не поддерживает {bitrate} бит/с") # Сообщаем профиль вместе с отклонённой скоростью. + result = [speed] # Настройка начинается после закрытия прежнего канала командой C. + if self.profile != "lawicel": # CANable выбирает режим до открытия O и не использует L. + result.append("M1" if listen_only else "M0") # Явно сбрасываем сохранённый silent при активном подключении. + if self.retransmit is not None: # Сохраняем поведение прошивки, пока пользователь не выбрал A0/A1. + result.append("A1" if self.retransmit else "A0") # Отключение повторов даёт однократную попытку передачи. + elif self.retransmit is not None: # Буква A у Lawicel имеет другую семантику и не должна отправляться как CANable. + raise ValueError("Управление повторами A0/A1 доступно только в профиле CANable") # Предотвращаем смешивание диалектов. + if self.timestamps is not None: # Команда Z может сохраняться прошивкой в EEPROM. + if self.profile != "lawicel": # CANable не документирует поддержку этого управления. + raise ValueError("Временные метки Z0/Z1 доступны только в профиле Lawicel") # Не игнорируем пользовательскую настройку. + result.append("Z1" if self.timestamps else "Z0") # Состояние задаётся только при явном выборе. + if self.acceptance_code is not None or self.acceptance_mask is not None: # Фильтр задаётся атомарной парой регистров. + if self.profile != "lawicel" or any(v is None or not 0 <= v <= 0xFFFFFFFF for v in (self.acceptance_code, self.acceptance_mask)): # Каждый регистр содержит ровно 32 бита. + raise ValueError("Фильтр Lawicel требует код и маску в диапазоне 00000000…FFFFFFFF") # M0/M1 CANable не должны трактоваться как фильтры. + result.extend((f"M{self.acceptance_code:08X}", f"m{self.acceptance_mask:08X}")) # Порядок байтов регистра соответствует документации Lawicel. + if self.fd: # Для FD требуется документированное расширение CANable 2.0. + if self.profile != "canable2" or self.data_bitrate not in (2_000_000, 5_000_000): # Y2/Y5 — единственные поддержанные этой прошивкой скорости данных. + raise ValueError("CAN FD требует CANable 2.0 и скорость данных 2 либо 5 Мбит/с") # Не открываем несовместимый канал. + result.append("Y2" if self.data_bitrate == 2_000_000 else "Y5") # Настраиваем быструю фазу до открытия CAN. + result.append("l" if self.loopback else "L" if listen_only and self.profile == "lawicel" else "O") # Выбираем одну команду открытия без опасного возврата к активному режиму. + return result # Последовательный транспорт проверит ответ на каждый этап там, где прошивка выдаёт подтверждения. + + +@dataclass(frozen=True) # Флаги запуска Candle хранятся вместе с таймингами и настройкой терминатора. +class CandleOptions: # Все расширения проверяются по маске возможностей конкретного канала. + loopback: bool = False # Приём собственных кадров нужен для диагностики контроллера. + one_shot: bool = False # Одна попытка передачи вместо автоматических повторов при отсутствии ACK. + triple_sample: bool = False # Тройная выборка применяется только при аппаратной поддержке. + hardware_timestamp: bool | None = None # None сохраняет автоматическое включение аппаратных меток. + termination: bool | None = None # None сохраняет состояние встроенного терминатора, не меняя топологию сети. + sample_point: float = 87.5 # Целевой процент номинального бита для автоматического расчёта. + timing: CanTiming | None = None # Ручные сегменты заменяют автоматический расчёт номинального тайминга. + fd: bool = False # Разрешает FD только после проверки возможности и настройки быстрой фазы. + data_bitrate: int = 2_000_000 # Скорость быстрой фазы задаётся в бит/с. + data_sample_point: float = 80.0 # Для быстрой фазы обычно нужна более ранняя точка выборки. + data_timing: CanTiming | None = None # Ручной тайминг быстрой фазы проверяется по расширенным пределам. + bus_errors: bool = True # Сохраняем сообщения об ошибках на шине при наличии управляемого режима. + + def flags(self, listen_only: bool, features: int) -> int: # Маска gs_usb объединяет независимо выбираемые режимы. + flags = (1 if listen_only else 0) | (2 if self.loopback else 0) | (4 if self.triple_sample else 0) | (8 if self.one_shot else 0) | (256 if self.fd else 0) # Значения битов заданы протоколом gs_usb. + if self.hardware_timestamp is True: # Явный выбор требует возможности аппаратных временных меток. + flags |= 16 # Бит 4 означает HW_TIMESTAMP. + elif self.hardware_timestamp is None: # Автоматический режим включает метки только при поддержке устройства. + flags |= features & 16 # Отсутствие возможности не является ошибкой автоматической настройки. + if self.bus_errors: # Старые прошивки выдают ошибки всегда и не требуют этого флага. + flags |= features & 4096 # Управляемый BERR_REPORTING включается лишь при объявленном бите 12. + elif not features & 4096: # У старых прошивок нет подтверждаемого выключателя сообщений об ошибках. + raise ValueError("Прошивка не поддерживает отключение сообщений об ошибках CAN") # Не показываем фактически невыполнимую настройку как применённую. + if flags & ~features: # Ни один явный запрос не должен тихо исчезнуть из маски запуска. + raise ValueError(f"Канал не поддерживает выбранные режимы: 0x{flags & ~features:X}") # Маска помогает сопоставить отказ с диагностикой адаптера. + if self.termination is not None and not features & 2048: # Встроенный переключаемый терминатор объявляется битом 11. + raise ValueError("Адаптер не поддерживает программное управление терминатором") # Внешний резистор программой не переключается. + return flags # Готовая маска передаётся в CANDLE_DEVMODE_START. diff --git a/python/set_devices/can_monitor.py b/python/set_devices/can_monitor.py index 70ad7b1..6e26f32 100644 --- a/python/set_devices/can_monitor.py +++ b/python/set_devices/can_monitor.py @@ -8,17 +8,18 @@ from pathlib import Path from protocan import protocan as pc from .can_bridge import decode_frame -PROTOCOLS = (("auto", "Авто (ProtoCAN / Balsam)"), - ("devboard", "DevBoard_V1 / SETCAN"), - ("deif", "DEIF XDi-192 / CANopen"), - ("protocan", "ProtoCAN / GAS"), - ("ump_balsam", "УМП / Balsam 167 (legacy CAN)"), - ("ump1_gas167", "УМП 1 / ProtoCAN — карта GAS 167/v1"), - ("ump2_gas167", "УМП 2 / ProtoCAN — карта GAS 167/v1"), - ("ump_gas", "УМП / ProtoCAN GAS — новые ID 5000/6000")) +PROTOCOLS = (("auto", "Авто (ProtoCAN / Balsam)"), # Автоматический разбор выбирает формат по кадру, не требуя ручного указания прибора. + ("devboard", "DevBoard_V1 / SETCAN"), # Формат DevBoard сохраняет самостоятельный пункт для существующих мониторов платы. + ("deif", "DEIF XDi-192 / CANopen"), # Прибор DEIF использует собственные правила CANopen и остаётся отдельным форматом. + ("protocan", "ProtoCAN / GAS"), # Общий ProtoCAN разбирает кадры без ручного назначения карты технологических слов УМП. + ("ump_balsam", "УМП / Balsam 167 (legacy CAN)"), # Старый Balsam имеет другой формат кадра и требует отдельного декодера. + ("ump_protocan", "УМП / ProtoCAN GAS")) # Единый формат УМП отделяет выбор карты адресов и номера устройства от протокола. + +UMP_MAPS = (("gas167", "167/v1 (текущая)"), # Действующая карта использует слова 0…127 и окно 0x5000…0x507F из профиля прошивки 167/v1. + ("assigned", "Новые ID 5000/6000 (планируется)")) # Десятичные базы 5000 и 6000 назначены документацией, но ещё не реализованы прошивкой. -def decode_protocol(frame, protocol="auto"): +def decode_protocol(frame, protocol="auto", *, ump_map="gas167", ump_node=1): # Карта 167/v1 и УМП 1 служат исходным выбором единого формата; параметры карты и узла передаются по имени. if protocol == "deif": from .deif_xdi import decode return decode(frame) @@ -36,6 +37,13 @@ def decode_protocol(frame, protocol="auto"): if protocol in ("ump1_gas167", "ump2_gas167"): from .ump_can import decode_gas167 return decode_gas167(frame, node=1 if protocol == "ump1_gas167" else 2) + if protocol == "ump_protocan": # Новые элементы интерфейса используют единый формат, а старые ключи выше сохраняют прежний разбор. + if ump_map == "gas167": # Действующие локальные адреса сами не определяют номер УМП, поэтому он задаётся отдельно. + from .ump_can import decode_gas167 # Словарь 167/v1 подключается только при явном выборе этой карты. + return decode_gas167(frame, node=ump_node) # Один декодер разбирает технологические слова обоих УМП с выбранной подписью устройства. + if ump_map == "assigned": # Планируемая сквозная карта определяет УМП по десятичным диапазонам 5000…5127 и 6000…6127. + return pc.decode(frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) # Общий ProtoCAN уже содержит имена назначенных ID и не требует ручного номера УМП. + raise ValueError("Неизвестная карта адресов УМП: %s" % ump_map) # Ошибочный ключ карты не должен молча давать расшифровку другого профиля. if protocol in ("devboard", "protocan", "ump_gas"): return pc.decode(frame.can_id, frame.data, ide=frame.ide, rtr=frame.rtr) return decode_frame(frame) @@ -63,6 +71,36 @@ def parse_filter(text): raise ValueError("Введите CAN ID в hex, например 701 или 0x701, 201") from None +def parse_gas_filter(text): # GAS ID вводятся десятичными числами либо в HEX с явным префиксом 0x. + if not text.strip(): # Пустое поле не добавляет ограничений к независимому фильтру CAN ID. + return None # Значение None обозначает отсутствие условия, а не пустой набор разрешённых адресов. + try: # Ошибки ввода превращаются в понятное сообщение общей панели монитора. + parts = [part.strip() for part in text.replace(";", ",").split(",")] # Поддерживаем те же разделители списка, что и у существующего CAN-фильтра. + addresses = {int(part, 16 if part.lower().startswith("0x") else 10) for part in parts} # Число 5000 означает назначенный десятичный GAS ID, а 0x5000 — адрес локального окна. + if any(address < 0 or address > 0xFFFF for address in addresses): # Поле Body ProtoCAN содержит 16-битный адрес слова GAS в диапазоне 0…65535. + raise ValueError() # Выход за пределы адресного пространства отклоняется вместе с остальными ошибками формата. + return addresses # Повторяющиеся адреса объединяются без изменения логики отбора кадров. + except ValueError: # Неполные, отрицательные и некорректно записанные значения не должны проходить фильтр молча. + raise ValueError("Введите GAS ID: 5000, 5127 или 0x5000; диапазон 0…65535") from None # Сообщаем систему счисления и допустимые границы непосредственно рядом с фильтром. + + +def matches_filters(identifier, data, extended, rtr=False, *, can_ids=None, gas_ids=None): # Оба условия объединяются по И, а значения внутри одного списка — по ИЛИ. + if can_ids is not None and identifier not in can_ids: # Быстрый отбор по CAN ID выполняется до декодирования полезной нагрузки. + return False # Несовпадение любого включённого ограничения исключает кадр. + if gas_ids is None: # При выключенном или пустом GAS-фильтре сохраняется прежний отбор CAN-кадров всех форматов. + return True # CAN ID уже проверен либо не ограничен. + if not extended or rtr or len(data) > 8 or len(data) % 2: # GAS использует расширенный кадр данных с полными 16-битными словами и DLC не больше 8 байт. + return False # STD, RTR и повреждённая нагрузка не обозначают достоверные GAS-регистры. + if pc.ProtoCanId.parse(identifier).msg_type != pc.MsgType.GENERAL_ADDRESS_SPACE: # Совпадение младших битов ID другого типа сообщения не является совпадением адреса GAS. + return False # Остальные протоколы остаются видимыми только при выключенном GAS-условии. + decoded = pc.decode(identifier, data, ide=extended, rtr=rtr) # Общий декодер определяет все регистры кадра и отличает их от текстового GAS-отклика. + if not data: # Пустой кадр данных GAS представляет запрос по начальному адресу Body. + return decoded.id.body in gas_ids # Запрос учитывается только для указанного в нём адреса. + if not decoded.registers or any(address > 0xFFFF for address, _value in decoded.registers): # Отклоняем служебный текст и пакет, выходящий за конец 16-битного пространства. + return False # Такие кадры не содержат допустимого набора регистров для адресного фильтра. + return any(address in gas_ids for address, _value in decoded.registers) # Совпадение второго, третьего или четвёртого слова выбирает весь исходный кадр. + + class CanSession: """All frames spool to disk; retain recent frames and unique-frame totals. @@ -93,6 +131,7 @@ class CanSession: self.unique_frames[key] = (row, previous[1] + 1 if previous else 1) if self.output is not None: csv.writer(self.output, delimiter=";").writerow(row) + return key # Возвращаем ключ уникального кадра, чтобы интерфейс обновлял только поступившие записи без повторного обхода сессии. def start(self, directory): directory = Path(directory) / datetime.now().strftime("session_%Y%m%d_%H%M%S_%f") diff --git a/python/set_devices/oscilloscope.py b/python/set_devices/oscilloscope.py index a2b6db2..1369400 100644 --- a/python/set_devices/oscilloscope.py +++ b/python/set_devices/oscilloscope.py @@ -2,28 +2,45 @@ from __future__ import annotations import math +from itertools import islice # Блоки по 1024 элемента ограничивают задержку отмены длинных измерений без изменения порядка суммирования. +from set_devices.plot_ticks import tick_precision # Общая точность подписей позволяет различать малые деления времени на фоне большого абсолютного смещения. -def time_label(milliseconds): +def time_label(milliseconds, step=None): # Необязательный шаг в миллисекундах повышает точность только для подписей шкалы; остальные вызовы сохраняют прежний вид. """Readable time without rounding nanosecond divisions to zero.""" magnitude = abs(milliseconds) + precision = tick_precision(milliseconds, step, 6) if step is not None else 6 # Шесть значащих цифр остаются стандартом; малый шаг требует дополнительных разрядов до точности double. if magnitude < .001: - return f"{milliseconds * 1e6:.6g} нс" + return f"{milliseconds * 1e6:.{precision}g} нс" # В миллисекунде 10^6 наносекунд; выбранная точность сохраняет различие соседних малых делений. if magnitude < 1: - return f"{milliseconds * 1000:.6g} мкс" + return f"{milliseconds * 1000:.{precision}g} мкс" # В миллисекунде 1000 микросекунд; шаг и координата масштабируются одинаково, поэтому число значащих цифр не меняется. if magnitude < 1000: - return f"{milliseconds:.6g} мс" - return f"{milliseconds / 1000:.6g} с" + return f"{milliseconds:.{precision}g} мс" # Средние интервалы остаются в исходных миллисекундах с точностью, достаточной для текущего шага шкалы. + return f"{milliseconds / 1000:.{precision}g} с" # Деление на 1000 переводит миллисекунды в секунды без потери нужных значащих цифр. -def measurements(points): - values = [value for _, value in points if math.isfinite(value)] +def _measurement_items(items, check_cancelled): # Добавляем необязательную отмену к любому проходу статистики, сохраняя все исходные элементы и их порядок. + if check_cancelled is None: # Обычные вызовы измерений сохраняют прежний контракт без дополнительных проверок отмены. + yield from items # Передаём исходную последовательность без копирования всего ряда или численных преобразований. + return # Не создаём блоки для синхронных измерений, которым не передано средство отмены. + source = iter(items) # Один итератор обеспечивает последовательный обход без повторов на границах блоков. + while True: # Продолжаем обработку до исчерпания исходной последовательности или исключения отмены. + check_cancelled() # Новый жест навигации прерывает даже этап среднего, СКЗ или поиска экстремумов. + block = tuple(islice(source, 1024)) # Не более 1024 элементов между проверками удерживают задержку отмены малой на многомиллионной записи. + if not block: # Пустой блок означает, что все исходные отсчёты уже переданы численной операции. + return # Последняя проверка отмены выполнена до завершения прохода. + yield from block # Сохраняем порядок элементов для прежней точности math.fsum и поиска пересечений. + + +def measurements(points, check_cancelled=None): # Необязательный обработчик отмены расширяет API, не меняя существующие вызовы с одним аргументом. + values = [value for _, value in _measurement_items(points, check_cancelled) if math.isfinite(value)] # Проверяем отмену и при отборе конечных амплитуд, включая полностью нечисловой ряд. if not values: return None - low, high = min(values), max(values) - mean = math.fsum(value / len(values) for value in values) + low = min(_measurement_items(values, check_cancelled)) # Точный минимум вычисляется по всем конечным значениям с ограниченной задержкой отмены. + high = max(_measurement_items(values, check_cancelled)) # Точный максимум сохраняет прежнюю семантику, в том числе порядок равных значений. + mean = math.fsum(value / len(values) for value in _measurement_items(values, check_cancelled)) # Отмена проверяется внутри суммирования; порядок и нормировка слагаемых остаются прежними. scale = max(abs(low), abs(high)) - rms = scale * math.sqrt(math.fsum((value / scale) ** 2 for value in values) / len(values)) if scale else 0. + rms = scale * math.sqrt(math.fsum((value / scale) ** 2 for value in _measurement_items(values, check_cancelled)) / len(values)) if scale else 0. # Прерываем длинный расчёт СКЗ без потери прежней защиты от переполнения. # Hysteresis rejects small excursions around the midpoint. Frequency is # only reported after two complete rising crossings, never from one edge. middle = (low + high) / 2 @@ -32,7 +49,7 @@ def measurements(points): crossings = [] previous = None if high > low: - for stamp, value in points: + for stamp, value in _measurement_items(points, check_cancelled): # Проверяем отмену и при полном проходе поиска частоты, сохраняя исходную гистерезисную обработку пропусков. if value < middle - hysteresis: armed = True if armed and previous and previous[1] < middle <= value and stamp > previous[0]: diff --git a/python/set_devices/plot_decimation.py b/python/set_devices/plot_decimation.py index a3ce466..77ba7be 100644 --- a/python/set_devices/plot_decimation.py +++ b/python/set_devices/plot_decimation.py @@ -1,19 +1,31 @@ """Pixel-column envelope for drawing; measurement samples are never changed.""" import math from bisect import bisect_left, bisect_right +from .background_work import work_items # Фоновая подготовка длинных временных массивов должна уступать GIL во время заполнения и проверки порядка. + + +class PointTimes: # Представление координат X для bisect без параметра key, отсутствующего в Python 3.8 сборки Win7. + def __init__(self, points): # Принимаем индексируемые пары (X, Y), порядок которых проверяется вызывающим кодом. + self.points = points # Храним ссылку на исходные точки, чтобы не копировать большой ряд при каждом изменении окна. + + def __len__(self): # Предоставляем bisect длину исходного ряда для определения границ двоичного поиска. + return len(self.points) # Получаем размер за постоянное время без перебора измерений. + + def __getitem__(self, index): # Извлекаем одну координату по индексу, выбранному алгоритмом двоичного поиска. + return self.points[index][0] # В паре (X, Y) индекс 0 обозначает время или частоту; значения Y не участвуют в сравнении. class IndexedTimes(list): """Random-access timestamps, with ordering validated once when loaded.""" - def __init__(self, points): - super().__init__(points) - self.ordered = all(math.isfinite(x) and (i == 0 or self[i-1] <= x) - for i, x in enumerate(self)) + def __init__(self, points, checkpoint=None): # Необязательная контрольная точка включает кооперативную подготовку только для фоновых файловых заданий. + super().__init__(work_items(points, checkpoint)) # Заполняем полный массив, регулярно освобождая GIL при наличии фонового бюджета. + self.ordered = all(math.isfinite(x) and (i == 0 or self[i-1] <= x) # Конечность и порядок проверяются по всем исходным меткам без прореживания. + for i, x in work_items(enumerate(self), checkpoint)) # Второй длинный проход также уступает интерфейсу и реагирует на отмену. def viewport_samples(timestamps, values, left, right, neighbours=False, budget=None): """Select only the viewport in logarithmic time for indexed records.""" - if isinstance(timestamps, (list, tuple, range)) and getattr(timestamps, "ordered", True): + if getattr(timestamps, "ordered", isinstance(timestamps, (list, tuple, range))): # Проверенные индексируемые представления со смещением X также допускают двоичный поиск без копирования меток времени. start = bisect_left(timestamps, left) stop = bisect_right(timestamps, right) if neighbours: @@ -37,6 +49,10 @@ def pixel_envelope(timestamps, values, left, right, width): and zooming retain lines crossing the viewport boundaries. """ width = max(1, int(width)) + index = getattr(values, "envelope_index", None) # Подготовленный файловый ряд содержит индекс точных экстремумов для быстрого выбора экранных столбцов. + if index is not None and index.count == len(values) and getattr(timestamps, "ordered", isinstance(timestamps, (list, tuple, range))): # Индекс применим к неизменённым значениям и проверенным координатам, включая ленивое смещение короткой развёртки. + yield from index.points(timestamps, left, right, width) # Выдаём не более четырёх конечных точек на пиксель плюс соседей для отсечения краёв. + return # Исключаем повторное линейное сканирование миллионов измерений при каждом изменении масштаба. scale = width / (right - left) if right > left else 1. bucket = None first = low = high = last = None @@ -73,6 +89,61 @@ def pixel_envelope(timestamps, values, left, right, width): yield from emit() +def render_envelope(timestamps, values, left, right, width): # Экранная огибающая ограничивает плотный упорядоченный ряд двумя экстремумами на логический пиксель, сохраняя исходные измерения отдельно. + width = max(1, int(width)) # Вызывающий виджет передаёт логическую ширину области: увеличение DPI не должно умножать число почти совпадающих вершин. + ordered = getattr(timestamps, 'ordered', isinstance(timestamps, (list, tuple, range))) # Двоичный поиск и экранные столбцы применимы только к проверенному порядку временных координат. + if not ordered: # Неупорядоченный поток нельзя безопасно переставлять по экранным столбцам или обрезать двоичным поиском. + yield from pixel_envelope(timestamps, values, left, right, width) # Сохраняем прежнюю последовательность и разрывы для нестандартного источника без предположения об упорядоченности. + return # Новый ограниченный экранный режим не меняет семантику неупорядоченных данных. + count = min(len(timestamps), len(values)) # Общая длина исключает обращения за границу при несовпадающих размерах координат и амплитуд. + start, stop = bisect_left(timestamps, left, 0, count), bisect_right(timestamps, right, 0, count) # Находим точное число исходных отсчётов видимого окна без полного обхода файла. + if stop - start <= width: # При сильном увеличении все измерения помещаются в экранный бюджет и не требуют никакого сокращения. + for position in range(max(0, start - 1), min(count, stop + 1)): # Сохраняем по одному соседу для линий, пересекающих края видимого окна. + stamp, value = timestamps[position], values[position] # Извлекаем точную исходную пару, включая нечисловые амплитуды между конечными отсчётами. + yield (stamp, value) if math.isfinite(stamp) and math.isfinite(value) else None # Все конечные точки остаются без изменений, а NaN и бесконечности разрывают путь. + return # Разреженный зум не должен проходить через экстремумы столбцов и терять близкие исходные точки. + index = getattr(values, 'envelope_index', None) # Подготовленный файловый ряд позволяет выбирать экстремумы без повторного линейного обхода миллионов значений. + if index is not None and index.count == len(values): # Индекс допустим только для исходной неизменённой длины ряда. + yield from index.points(timestamps, left, right, width, extrema_only=True) # Сохраняем максимум два экстремума на столбец, два конца окна и два внешних соседа. + return # Быстрый запрос не должен дополнительно запускать линейный запасной путь. + columns = {} # Для неиндексированного ряда храним лишь пару экстремумов на экранный столбец, а не полную запись. + first_visible = last_visible = None # Дополнительно сохраняем два конца видимой линии для правильного соединения с внешними соседями. + segment = 0 # Каждый нечисловой отсчёт увеличивает номер непрерывного участка; разные номера запрещают соединять выбранные точки. + seen = False # Полностью нечисловое окно должно вернуть один разрыв, а пустая запись не создаёт искусственных точек. + scale = width / (right - left) if right > left else 1. # Масштаб переводит время в столбцы; совпадающие временные координаты не допускают деления на ноль. + for ordinal, (stamp, value) in enumerate(viewport_samples(timestamps, values, left, right, neighbours=True)): # Запасной путь читает каждый исходный отсчёт окна ровно один раз и поэтому также сохраняет одиночные пики. + seen = True # Фиксируем наличие хотя бы одного конечного либо нечислового исходного измерения. + if not math.isfinite(stamp) or not math.isfinite(value): # Пропуски не участвуют в экстремумах, но должны разделять любые выбранные точки по разные стороны. + segment += 1 # Номер участка переносит информацию о пропуске без хранения каждого маркера плотного ряда. + continue # Нечисловая амплитуда не имеет экранной координаты кривой. + column = -1 if stamp < left else width if stamp > right else min(width - 1, int((stamp - left) * scale)) # Соседи вынесены в два отдельных столбца за пределами видимой области. + point = (ordinal, stamp, value, segment) # Исходный порядок и номер участка позволяют вернуть экстремумы без ложных соединений через NaN. + pair = columns.get(column) # В каждом экранном столбце сохраняются только точные минимум и максимум. + if pair is None: # Первый конечный отсчёт одновременно задаёт обе роли нового столбца. + columns[column] = [point, point] # Два совпадающих индекса позднее объединяются в одну вершину. + else: # Дальнейшие измерения меняют только действительно достигнутые экстремумы. + if value < pair[0][2]: # Строгое сравнение сохраняет первое вхождение равного минимума. + pair[0] = point # Одиночный отрицательный выброс остаётся в экранной огибающей. + if value > pair[1][2]: # Строгое сравнение сохраняет первое вхождение равного максимума. + pair[1] = point # Одиночный положительный выброс также остаётся видимым при любом сжатии. + if left <= stamp <= right: # Внешние соседи не подменяют начало и конец собственно видимых измерений. + first_visible = point if first_visible is None else first_visible # Первый конечный видимый отсчёт сохраняется один раз независимо от числа столбцов. + last_visible = point # Последний конечный видимый отсчёт обновляется до правого края окна. + selected = {point[0]: point for pair in columns.values() for point in pair} # Уникальные исходные индексы устраняют совпадение ролей без изменения времени или амплитуды. + for point in (first_visible, last_visible): # Всего две дополнительные конечные точки сохраняют соединения на краях видимого окна. + if point is not None: # Полностью нечисловое окно не имеет конечных краевых измерений. + selected[point[0]] = point # Повторное добавление совпавшего экстремума не увеличивает экранный бюджет. + previous_segment = 0 # Нулевой участок соответствует началу исходной последовательности до первого NaN. + for ordinal in sorted(selected): # Возвращаем выбранные точки в исходном порядке, включая совпадающие метки времени. + _, stamp, value, current_segment = selected[ordinal] # Экранная вершина сохраняет исходные координаты и номер непрерывного участка. + if current_segment != previous_segment: # Различные номера подтверждают хотя бы один NaN между выбранными конечными отсчётами. + yield None # Маркер разрыва запрещает рисовать линию через отсутствующие измерения. + yield stamp, value # Амплитуда и время возвращаются точно, без усреднения и сдвига коротких пиков. + previous_segment = current_segment # Следующая вершина сравнивается с участком предыдущего выбранного измерения. + if seen and (not selected or previous_segment != segment): # Сохраняем полностью нечисловое окно и разрыв после последней конечной точки. + yield None # Длинная последовательность хвостовых пропусков ограничивается одним экранным маркером. + + def preview_window_count(requested, preview_count, original_count): """Translate a raw-sample window to a display-envelope window.""" if not original_count or original_count <= preview_count: diff --git a/python/set_devices/plot_envelope_index.py b/python/set_devices/plot_envelope_index.py new file mode 100644 index 0000000..0e4d6a4 --- /dev/null +++ b/python/set_devices/plot_envelope_index.py @@ -0,0 +1,174 @@ +import math # Проверяем конечность измерений, чтобы пропуски не соединялись линиями и не участвовали в экстремумах. +from array import array # Храним индексы в компактных массивах вместо отдельных объектов Python для каждого узла дерева. +from bisect import bisect_left, bisect_right # Находим границы пиксельных столбцов двоичным поиском по упорядоченным меткам времени. + + +class EnvelopeIndex: # Индекс неизменяемого ряда позволяет выбирать точные экстремумы без повторного обхода миллионов отсчётов. + BLOCK_SIZE = 32 # Лист дерева содержит 32 отсчёта: крайние неполные блоки малы, а индекс занимает около 2,5 байта на отсчёт. + EMPTY = (-1, -1, -1, -1, 0) # Первые четыре поля обозначают индексы первого, минимального, максимального и последнего отсчёта; пятое считает пропуски. + + def __init__(self, values, checkpoint=None): # Необязательная контрольная точка сохраняет отзывчивость Qt при первоначальном построении большого индекса. + self.values = values # Сохраняем исходные значения по ссылке; сам индекс не сокращает и не изменяет измерения. + self.count = len(values) # Запоминаем размер снимка для проверки пригодности индекса после очистки графика. + blocks = (self.count + self.BLOCK_SIZE - 1) // self.BLOCK_SIZE # Округление вверх включает неполный последний блок записи. + self.leaves = 1 # Для обычного двоичного дерева число листьев должно быть степенью двух. + while self.leaves < blocks: # Добавляем пустые листья только до ближайшей степени двух, не удваивая размер без необходимости. + self.leaves *= 2 # Два дочерних узла соответствуют объединённому диапазону родителя. + self.nodes = tuple(array('q', [field]) * (2 * self.leaves) for field in self.EMPTY) # Пять знаковых 64-битных массивов содержат индексы, включая признак отсутствия -1. + for block in range(blocks): # Полный обход исходных значений нужен только при первоначальном построении индекса. + if checkpoint is not None and block % 32 == 0: # Тридцать два листа по 32 отсчёта дают контроль примерно через 1024 исходных значения. + checkpoint() # Отпускаем GIL и проверяем отмену между ограниченными порциями подготовки экстремумов. + start = block * self.BLOCK_SIZE # Переводим номер блока в начальный индекс исходного отсчёта. + self._store(self.leaves + block, self._scan(start, min(self.count, start + self.BLOCK_SIZE))) # Сводка листа сохраняет точные экстремумы и число нечисловых отсчётов. + for node in range(self.leaves - 1, 0, -1): # Строим родителей снизу вверх, когда сводки обоих детей уже готовы. + if checkpoint is not None and node % 1024 == 0: # Объединение большого дерева также делится на порции по 1024 узла. + checkpoint() # Не допускаем непрерывного удержания GIL после завершения чтения исходных измерений. + self._store(node, self._merge(self._load(2 * node), self._load(2 * node + 1))) # Родитель объединяет соседние диапазоны с сохранением временного порядка. + + def _store(self, node, summary): # Записываем одну сводку в параллельные компактные массивы дерева. + for column, field in zip(self.nodes, summary): # Каждое поле имеет одинаковый номер узла во всех пяти массивах. + column[node] = field # Индексы ссылаются на исходный ряд, поэтому значения Y не дублируются в памяти. + + def _load(self, node): # Читаем сводку готового узла без обращения ко всем его исходным отсчётам. + first, low, high, last, gaps = self.nodes # Разбираем пять массивов один раз, исключая создание генератора при каждом посещении узла дерева. + return first[node], low[node], high[node], last[node], gaps[node] # Возвращаем те же пять полей напрямую; тысячи запросов кадра не создают промежуточных итераторов. + + def _scan(self, start, stop): # Сканируем полуинтервал только при построении листа либо на неполных краях запроса. + first = low = high = last = -1 # Отрицательный индекс означает, что конечное значение ещё не найдено. + gaps = 0 # Подсчёт пропусков позволяет проверять разрыв линии между выбранными экстремумами. + values, isfinite = self.values, math.isfinite # Локальные ссылки исключают повторный поиск атрибутов для каждого отсчёта неполного края блока. + low_value = high_value = 0. # Значения обоих экстремумов устанавливаются первым конечным отсчётом; ноль не участвует в сравнении до этого момента. + for index in range(start, stop): # Полуинтервал исключает stop и совпадает с правилами срезов Python. + value = values[index] # Читаем исходное измерение ровно один раз, сохраняя значение для обоих сравнений экстремумов. + if not isfinite(value): # NaN и бесконечности должны разрывать путь, а не менять масштаб или экстремумы. + gaps += 1 # Учитываем пропуск даже в диапазоне, где совсем нет конечных значений. + continue # Исключаем нечисловой отсчёт из поиска первого, последнего, минимального и максимального значений. + if first < 0: # Первый конечный отсчёт одновременно задаёт оба начальных экстремума. + first = low = high = index # Все три индекса указывают на одно измерение до появления следующих точек. + low_value = high_value = value # Сохраняем амплитуды начальных экстремумов, чтобы следующие отсчёты не читали их повторно из большого ряда. + else: # Для остальных отсчётов обновляем только реально изменившиеся экстремумы. + if value < low_value: # Строгое сравнение с сохранённой амплитудой сохраняет первый по времени минимум при равных значениях. + low = index # Запоминаем точный индекс минимального исходного значения. + low_value = value # Обновляем амплитуду вместе с индексом, исключая отдельное чтение минимума на следующей итерации. + if value > high_value: # Первый по времени максимум также остаётся стабильным при равенстве значений. + high = index # Запоминаем точный индекс максимального исходного значения. + high_value = value # Сохраняем амплитуду нового максимума для дальнейших сравнений без обращения к исходному контейнеру. + last = index # Последний конечный отсчёт нужен для правильного соединения соседних пиксельных столбцов. + return first, low, high, last, gaps # Сводка содержит только индексы и счётчик; измерения остаются в исходном ряду. + + def _merge(self, before, after): # Объединяем сводки соседних диапазонов, расположенных в исходном временном порядке. + gaps = before[4] + after[4] # Число пропусков аддитивно и не зависит от расположения экстремумов. + if before[0] < 0: # Левый диапазон может быть пустым либо полностью состоять из пропусков. + return (*after[:4], gaps) # Сохраняем конечные точки правого диапазона и пропуски обоих диапазонов. + if after[0] < 0: # Пустой правый диапазон не меняет конечные точки левого диапазона. + return (*before[:4], gaps) # Добавляем только число пропусков справа. + low = after[1] if self.values[after[1]] < self.values[before[1]] else before[1] # При равных минимумах сохраняем более ранний отсчёт. + high = after[2] if self.values[after[2]] > self.values[before[2]] else before[2] # При равных максимумах также сохраняем более ранний отсчёт. + return before[0], low, high, after[3], gaps # Крайние точки берём из внешних границ объединённого диапазона. + + def between(self, start, stop): # Возвращаем точную сводку произвольного диапазона индексов без полного сканирования ряда. + start, stop = max(0, start), min(self.count, stop) # Ограничиваем запрос существующими измерениями снимка. + if stop <= start: # Пустое или обратное окно не содержит ни точек, ни пропусков. + return self.EMPTY # Единый пустой результат упрощает объединение диапазонов на границах записи. + if not self.nodes[4][1] and isinstance(self.values, (list, tuple, array)): # Нулевой счётчик пропусков корня доказывает конечность всего неизменяемого ряда; обычные контейнеры допускают короткие срезы краёв. + return self._finite_between(start, stop) # Плотные записи без NaN обходятся без пяти-польных сводок и проверок конечности на каждом кадре. + first_block = (start + self.BLOCK_SIZE - 1) // self.BLOCK_SIZE # Находим первый полностью включённый блок после левого неполного края. + last_block = stop // self.BLOCK_SIZE # Этот блок уже не входит целиком в запрос и задаёт начало правого края. + if first_block >= last_block: # Короткий запрос дешевле прочитать напрямую, чем обходить дерево. + return self._scan(start, stop) # Здесь читается не более двух неполных блоков исходных отсчётов. + before = self._scan(start, first_block * self.BLOCK_SIZE) # Получаем сводку левого неполного края, максимум из 31 отсчёта. + after = self._scan(last_block * self.BLOCK_SIZE, stop) # Получаем сводку правого неполного края, также максимум из 31 отсчёта. + left, right = self.leaves + first_block, self.leaves + last_block # Переводим границы полных блоков в номера листьев дерева. + while left < right: # За логарифмическое число шагов выбираем узлы, полностью покрывающие внутренний диапазон. + if left % 2: # Правый ребёнок слева включается отдельно, чтобы не захватить отсчёты перед запросом. + before = self._merge(before, self._load(left)) # Добавляем очередной диапазон после уже выбранной левой части. + left += 1 # Переходим к следующему соседнему узлу перед подъёмом к родителю. + if right % 2: # Правая исключённая граница позволяет включить её левого соседа отдельно. + right -= 1 # Перемещаем границу к последнему целиком включённому узлу текущего уровня. + after = self._merge(self._load(right), after) # Добавляем узел перед уже выбранной правой частью, сохраняя порядок. + left //= 2 # Поднимаем левую границу на уровень объединённых диапазонов. + right //= 2 # Правая граница поднимается на тот же уровень дерева. + return self._merge(before, after) # Соединяем выбранные части в одну точную сводку запрошенного полуинтервала. + + def _finite_between(self, start, stop): # Быстрый запрос применяется только после проверки отсутствия NaN и бесконечностей во всём исходном ряду. + values = self.values # Сохраняем локальную ссылку на полные исходные амплитуды, не создавая их копию. + first_block = (start + self.BLOCK_SIZE - 1) // self.BLOCK_SIZE # Левый неполный край заканчивается перед первым целиком включённым блоком. + last_block = stop // self.BLOCK_SIZE # Последний целый блок предшествует правому неполному краю запроса. + if first_block >= last_block: # Короткий диапазон занимает не более двух блоков по 32 отсчёта и не требует обхода дерева. + chunk = values[start:stop] # Временный срез содержит максимум 63 исходных амплитуды, независимо от полного размера лога. + return start, start + chunk.index(min(chunk)), start + chunk.index(max(chunk)), stop - 1, 0 # Встроенные операции находят точные первые экстремумы на C; первый, последний и нулевые пропуски уже известны. + low = high = start # Любой непустой конечный диапазон имеет допустимое начальное измерение на левой границе. + low_value = high_value = values[start] # Амплитуды экстремумов храним локально, чтобы не перечитывать их из большого массива после каждого узла. + for begin, end in ((start, first_block * self.BLOCK_SIZE), (last_block * self.BLOCK_SIZE, stop)): # Сканируем только два неполных края, каждый не длиннее 31 исходного отсчёта. + if begin < end: # Совпадение с границей блока исключает создание пустого среза и вызов min/max без элементов. + chunk = values[begin:end] # Короткий временный срез позволяет выполнить поиск экстремумов встроенными операциями C. + minimum, maximum = min(chunk), max(chunk) # Исходные конечные амплитуды сравниваются без повторной проверки math.isfinite. + if minimum < low_value: # Края идут слева направо, поэтому при равенстве оставляем уже найденный более ранний минимум. + low, low_value = begin + chunk.index(minimum), minimum # index возвращает первое вхождение точного минимума внутри неполного края. + if maximum > high_value: # При равенстве максимумов также сохраняем более раннее измерение. + high, high_value = begin + chunk.index(maximum), maximum # Индекс исходной амплитуды вычисляется смещением от начала короткого среза. + lows, highs = self.nodes[1], self.nodes[2] # Для конечного ряда нужны только индексы минимумов и максимумов; остальные три массива не читаются. + left, right = self.leaves + first_block, self.leaves + last_block # Переводим полуинтервал целых блоков в номера листьев компактного дерева. + while left < right: # Как и общий алгоритм, выбираем лишь логарифмическое число готовых сводок диапазона. + if left % 2: # Отдельный правый ребёнок слева входит в запрос целиком, а его сосед остаётся за границей. + candidate = lows[left] # Готовый индекс минимума узла ссылается непосредственно на исходный ряд. + value = values[candidate] # Читаем только амплитуду найденного в узле минимума. + if value < low_value or (value == low_value and candidate < low): # Узлы посещаются не строго слева направо, поэтому равные значения сравниваем и по исходному индексу. + low, low_value = candidate, value # Обновляем точное первое вхождение минимума без создания промежуточной сводки. + candidate = highs[left] # Второй готовый индекс узла соответствует точному исходному максимуму. + value = values[candidate] # Амплитуда максимума также читается один раз на выбранный узел. + if value > high_value or (value == high_value and candidate < high): # Равные максимумы должны сохранять прежний выбор самого раннего отсчёта. + high, high_value = candidate, value # Обновляем максимум и его амплитуду вместе для следующего сравнения. + left += 1 # Исключаем уже обработанный узел перед подъёмом обеих границ на следующий уровень. + if right % 2: # Левый сосед исключённой правой границы входит в диапазон полностью. + right -= 1 # Получаем номер последнего целиком включённого узла текущего уровня дерева. + candidate = lows[right] # Читаем индекс готового минимума правого узла без распаковки пяти полей сводки. + value = values[candidate] # Только выбранный минимум требует обращения к исходной амплитуде. + if value < low_value or (value == low_value and candidate < low): # Порядок обхода не влияет на первый по времени минимум при равенстве амплитуд. + low, low_value = candidate, value # Сохраняем лучший исходный минимум для объединённого запроса. + candidate = highs[right] # Индекс максимума берём из второго массива готовых экстремумов. + value = values[candidate] # Читаем точную амплитуду исходного максимума правого узла. + if value > high_value or (value == high_value and candidate < high): # При одинаковых амплитудах выбираем наименьший исходный индекс. + high, high_value = candidate, value # Объединяем максимум напрямую, исключая вызовы _load и _merge на каждом узле. + left //= 2 # Переходим от листьев или текущих узлов к покрывающим их родителям. + right //= 2 # Правая исключённая граница поднимается на тот же уровень дерева. + return start, low, high, stop - 1, 0 # Все точки конечны, поэтому внешние отсчёты и отсутствие пропусков не требуют отдельного вычисления. + + def points(self, timestamps, left, right, width, *, extrema_only=False): # Обычная огибающая сохраняет четыре роли на столбец, а отдельный экранный режим оставляет только точные минимум и максимум. + count = min(len(timestamps), self.count) # Общий размер защищает от несовпадающих длин координат и значений. + start, stop = bisect_left(timestamps, left, 0, count), bisect_right(timestamps, right, 0, count) # Оба края видимого временного окна включаются полностью. + ranges = [] # Список содержит только диапазоны пикселей и по одному соседнему отсчёту для отсечения на краях. + if start: # Сосед слева сохраняет линию, пересекающую левую границу без отсчёта непосредственно внутри окна. + ranges.append((start - 1, start)) # Только один внешний отсчёт нужен для правильного геометрического отсечения. + if right <= left: # Совпадающие границы X могут содержать много отсчётов с одной меткой времени, но не допускают деления на ширину окна. + if stop > start: # Пустое окно не создаёт искусственный диапазон измерений. + ranges.append((start, stop)) # Экстремумы всех совпадающих меток времени ограничены четырьмя точками одного столбца. + else: # Любое окно делим по экранным координатам, чтобы неравномерные и повторяющиеся метки также соблюдали бюджет на столбец. + edge = start # Первый пиксель начинается с первого отсчёта внутри видимого окна. + for column in range(width): # Число итераций зависит только от ширины изображения в физических пикселях. + boundary = left + (right - left) * ((column + 1) / width) # Правая граница столбца задана в единицах исходной оси X. + end = stop if column == width - 1 else bisect_left(timestamps, boundary, edge, stop) # Последний столбец включает отсчёты точно на правой границе окна. + if end > edge: # Пустые пиксели не создают искусственных измерений. + ranges.append((edge, end)) # Запоминаем исходный диапазон для выбора первого, минимального, максимального и последнего отсчётов. + edge = end # Следующий столбец продолжает ряд без потерь и повторного включения границы. + if stop < count: # Сосед справа сохраняет линию, пересекающую правую границу окна. + ranges.append((stop, stop + 1)) # Внешний сосед добавляет не более одной конечной точки к пиксельному бюджету. + has_gaps = bool(self.nodes[4][1]) # Нулевой счётчик корня доказывает отсутствие пропусков во всём ряду и исключает лишние запросы между компактными экстремумами. + previous = None # Индекс предыдущей выбранной конечной точки нужен для проверки разрыва между столбцами. + for begin, end in ranges: # Обрабатываем только экранные диапазоны и двух возможных внешних соседей. + summary = self.between(begin, end) # Получаем точные экстремумы через индекс, читая лишь неполные края блоков. + roles = summary[1:3] if extrema_only else summary[:4] # Новый экранный режим уменьшает число вершин, не изменяя исходные экстремумы или прежний публичный результат. + if extrema_only and begin == start: # Первый видимый столбец сохраняет также начало линии, чтобы она правильно пересекала левый край окна. + roles += (summary[0],) # Дополнительная роль нужна только одному столбцу, а не каждому пикселю. + if extrema_only and end == stop: # Последний видимый столбец сохраняет конец линии для правильного пересечения правого края. + roles += (summary[3],) # Два внешних конца увеличивают общий бюджет только на две конечные точки. + selected = sorted({index for index in roles if index >= 0}) # Убираем совпадающие роли и восстанавливаем исходный временной порядок выбранных экстремумов. + if not selected: # Полностью нечисловой диапазон разрывает линию один раз независимо от числа NaN внутри пикселя. + yield None # Маркер разрыва не является измерением и обрабатывается обоими движками отрисовки. + previous = None # Следующая конечная точка начинает новый путь. + continue # В пустом пикселе нет конечных экстремумов для отрисовки. + for index in selected: # На один непустой пиксель приходится не более четырёх исходных измерений. + if has_gaps and previous is not None and previous + 1 < index and (summary[4] or previous < begin) and self.between(previous + 1, index)[4]: # Проверяем разрывы только при наличии NaN в записи; соседние индексы и доказанно конечные ряды не требуют дополнительных запросов дерева. + yield None # Разрыв сохраняет пропуски между выбранными экстремумами без повторного запроса того же диапазона дерева. + yield timestamps[index], self.values[index] # Возвращаем исходные координаты и значения без усреднения или изменения амплитуды. + previous = index # Запоминаем конец текущего пути для следующей выбранной точки. diff --git a/python/set_devices/plot_processing.py b/python/set_devices/plot_processing.py index c128c39..071c9ed 100644 --- a/python/set_devices/plot_processing.py +++ b/python/set_devices/plot_processing.py @@ -10,7 +10,7 @@ are separate objects, never channels in the acquisition or measurement model. from __future__ import annotations import csv from bisect import bisect_left, bisect_right -from operator import itemgetter +from .plot_decimation import PointTimes # Используем координаты X без копирования ряда и без недоступного в Python 3.8 параметра key. from dataclasses import dataclass from datetime import datetime, timezone from .signal_reconstruction import METHODS, reconstruct @@ -28,8 +28,9 @@ class FrozenPoints(tuple): def between(self, left, right): if self.ordered: - start = bisect_left(self, left, key=itemgetter(0)) - stop = bisect_right(self, right, key=itemgetter(0)) + timestamps = PointTimes(self) # Создаём индексируемое представление X, сохраняя логарифмическую сложность поиска границ. + start = bisect_left(timestamps, left) # Начинаем с первой точки X >= left, включая все повторы левой границы. + stop = bisect_right(timestamps, right) # Заканчиваем перед первой точкой X > right, включая все повторы правой границы. if start == 0 and stop == len(self): return self result = tuple.__new__(type(self), self[start:stop]) diff --git a/python/set_devices/plot_ticks.py b/python/set_devices/plot_ticks.py new file mode 100644 index 0000000..7db48d8 --- /dev/null +++ b/python/set_devices/plot_ticks.py @@ -0,0 +1,10 @@ +"""Точность подписей шкал при приближении до небольших долей исходного диапазона.""" # Форматирование подписей отделено от расчёта координат и не требует Qt. +import math # Логарифмы определяют число значащих цифр, необходимое для различения соседних делений. + + +def tick_precision(value, step, minimum=4): # Значение и шаг задаются в одинаковых единицах; минимум сохраняет обычный вид подписей при крупном масштабе. + if not math.isfinite(value) or not math.isfinite(step) or value == 0 or step <= 0: # Для нуля и непригодного шага порядок числа не определён, поэтому используем исходную точность. + return minimum # Без вычисления логарифма сохраняем безопасное форматирование специальных значений. + value_order = math.floor(math.log10(abs(value))) # Порядок абсолютной координаты учитывает значащие цифры перед десятичной точкой и большие смещения оси. + step_order = math.floor(math.log10(step)) # Порядок положительного шага показывает, до какого десятичного разряда нужно различать деления. + return min(16, max(minimum, value_order - step_order + 1)) # Ограничение 16 цифрами соответствует полезной точности double, а разность порядков сохраняет отдельную подпись для каждого деления. diff --git a/python/set_devices/qt_ports/CONSOLE.md b/python/set_devices/qt_ports/CONSOLE.md new file mode 100644 index 0000000..7c32bbf --- /dev/null +++ b/python/set_devices/qt_ports/CONSOLE.md @@ -0,0 +1,68 @@ +# Общая консоль Qt + +`set_devices.qt_ports.console.ConsoleView` — общий порт представления для +журналов SETGUI. Он не управляет портами, опросом и отправкой команд. + +Приложение → `ConsoleView` → Qt 6 / Qt 5. Протокольные декодеры передают +готовые подписи и необязательные исходные байты; консоль не вычисляет CRC. + +| Файл | Назначение и зависимости | +|---|---| +| `set_devices/qt_ports/console.py` | Виджет и файловый экспорт; stdlib и PySide6 либо PySide2 | +| `examples/console_examples.py` | По одному примеру служебной консоли, CAN и RS485; действующие кодеки templates | +| `tests/test_console.py` | Проверки истории, паузы, фильтров, очистки и UTF-8; pytest и Qt | + +## Возможности, собранные из журналов SETGUI + +| Возможность | Источник / поведение общего компонента | +|---|---| +| Очистка | Канальные консоли платы, TX/RX, Modbus; удаляет также скрытые строки и очередь обновления | +| Пауза | Эмуляторы CAN; экран заморожен, история продолжает принимать данные до заданного предела | +| TX/RX | Диагностика и эмуляторы; служебные ошибки без направления остаются видны | +| Автопрокрутка | Мониторы CAN и RS; её можно отключить для чтения истории | +| Цвета | Консоль платы и монитор шины; сохраняются при переразборе фильтра | +| HEX/ASCII | Диагностика RS; формат применяется к явно переданному payload | +| Сохранение | Мониторы CAN и RS; экспорт фактически видимого текста в UTF-8 | +| Поиск, копирование, перенос, масштаб | Общие инструменты всех подключённых текстовых журналов | + +## Подключение + +```python +from set_devices.qt_ports.console import ConsoleView # Подключаем общий порт представления templates. +console = ConsoleView(limit=4000, payloads=True) # Храним не более 4000 строк, включая скрытые и поступившие на паузе. +layout.addWidget(console.panel, 1) # В layout вставляется контейнер с инструментами и редактором. +console.append_message("RX ответ", direction="RX", payload=b"OK") # Передаём готовую подпись и байты без повторного разбора протокола. +console.append_message("Ошибка связи", color="#ff7b7b") # Служебная ошибка остаётся видна при выключенных TX и RX. +console.userCleared.connect(clear_frame_history) # Отдельный буфер кадров очищается тем же пользовательским действием. +``` + +Старые вызовы `appendPlainText`, `appendHtml`, `setPlainText`, `clear`, +`toPlainText` и `setMaximumBlockCount` поддерживаются. `setPlainText` заменяет +снимок истории, учитывая текущую паузу. Для внешней истории кадров подключите +`userCleared`: программный `clear()` повторно этот сигнал не испускает. + +`directions=False` скрывает встроенные флажки, если приложение уже имеет свои +фильтры TX/RX. `payloads=True` показывает форматы HEX/ASCII. События должны +поступать в GUI-потоке Qt, как при работе с обычным `QPlainTextEdit`. + +При заполнении история обновляет экран пачками с интервалом 100 мс. +Количество строк на панели относится ко всей ограниченной истории. +На паузе сохранение и копирование используют замороженный видимый экран. + +## Три запускаемых примера + +Из каталога `python`, с установленными зависимостями `.[qt]`: + +```powershell +python examples/console_examples.py --kind service +python examples/console_examples.py --kind can +python examples/console_examples.py --kind rs485 +``` + +Без `--kind` открываются все три примера. Аппаратура не требуется. +В каждом примере можно проверить очистку, паузу, поиск, TX/RX, экспорт, +копирование, автопрокрутку, перенос и масштаб; в CAN и RS485 — HEX/ASCII. + +Используется в SETGUI: CAN/RS485 и служебная консоль ESP, журналы соединения +и TX/RX, эмуляторы CAN, CAN FD, Modbus, диагностика ПМ35 и ТМС2812, +спектр и логический анализатор Altera. diff --git a/python/set_devices/qt_ports/can_frame_builder.py b/python/set_devices/qt_ports/can_frame_builder.py new file mode 100644 index 0000000..0e99116 --- /dev/null +++ b/python/set_devices/qt_ports/can_frame_builder.py @@ -0,0 +1,175 @@ +"""Общие поля конструктора CAN и SETCAN для адаптеров и обоих каналов DevBoard.""" +from PySide6.QtCore import Signal # Сигнал изменений позволяет владельцу сбрасывать готовый кадр без зависимости от транспорта. +from PySide6.QtGui import QFont # Моноширинный шрифт сохраняет читаемость HEX-идентификатора и данных. +from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QComboBox, QSpinBox, QLineEdit, QLabel # Один набор виджетов определяет форму всех потребителей. +from protocan import protocan as pc # Сборка полей протокола выполняется существующими обёртками общего C-ядра. +from set_devices import can_transport as tr # Проверка CAN ID и разбор HEX используют действующий общий транспорт. + + +DESCRIPTION = "Обычный CAN: задайте ID, DLC и Data. Для сборки ID по полям протокола выберите SETCAN." # Одинаковое пояснение режимов используется во всех панелях. + + +class CanFrameFields(QWidget): # Компонент содержит только ввод кадра; подключение и отправка остаются у владельца. + changed = Signal() # Любое изменение ввода отменяет ранее собранный кадр в соответствующем канале. + + def __init__(self, settings_factory, parent=None): # Редактор SETTINGS передаётся владельцем как визуальный компонент без копирования его реализации. + super().__init__(parent) # Родитель Qt управляет временем жизни всех полей формы. + layout = QVBoxLayout(self) # Единый вертикальный порядок исключает различия между вкладками. + layout.setContentsMargins(0, 0, 0, 0) # Внешние отступы задаёт панель приложения. + self.mode = QComboBox() # Переключатель сохраняет оба набора введённых значений. + self.mode.addItem("Обычный CAN — ID / DLC / Data", "can") # Исходный режим одинаков для всех трёх конструкторов. + self.mode.addItem("SETCAN — поля протокола", "setcan") # Протокольный режим всегда создаёт расширенный идентификатор. + mode_form = QFormLayout() # Первая строка остаётся видимой в обоих режимах. + mode_form.addRow("Режим", self.mode) # Подпись поясняет назначение переключателя. + layout.addLayout(mode_form) # Выбор режима предшествует зависимым полям. + self.can_panel = QWidget() # Контейнер скрывает вместе подписи и редакторы обычного CAN. + can_form = QFormLayout(self.can_panel) # Формат, идентификатор и длина выровнены общей формой. + can_form.setContentsMargins(0, 0, 0, 0) # Поля обоих режимов начинаются на одной вертикали. + self.format = QComboBox() # IDE задаётся явно независимо от численного значения идентификатора. + self.format.addItem("Стандартный — 11 бит (STD)", False) # STD соответствует диапазону CAN ID 0..0x7FF. + self.format.addItem("Расширенный — 29 бит (EXT)", True) # EXT соответствует диапазону CAN ID 0..0x1FFFFFFF. + self.can_id = QLineEdit("123") # Исходный пример идентификатора записан в HEX. + self.can_id.setToolTip("HEX, с префиксом 0x или без него. STD: 0..7FF; EXT: 0..1FFFFFFF.") # Указываем пределы CAN ID без неявного усечения. + self.dlc = QSpinBox() # Пользователь явно задаёт длину обычного CAN-кадра. + self.dlc.setRange(0, 8) # Классический CAN допускает от нуля до восьми байтов Data. + self.dlc.setToolTip("Количество байтов Data должно точно совпадать с DLC; дополнение и обрезка не выполняются.") # Описываем строгую проверку длины. + can_form.addRow("Формат ID (IDE)", self.format) # Формат отражает фактический флаг IDE. + can_form.addRow("CAN ID (HEX)", self.can_id) # Явно обозначаем систему счисления идентификатора. + can_form.addRow("DLC (0..8 байт)", self.dlc) # Длина дана в байтах полезной нагрузки. + layout.addWidget(self.can_panel) # Обычный CAN занимает то же место, что альтернативная форма SETCAN. + self.setcan_panel = QWidget() # Общий контейнер хранит поля составного 29-битного идентификатора. + form = QFormLayout(self.setcan_panel) # Подписи протокола выравниваются с остальными формами. + form.setContentsMargins(0, 0, 0, 0) # Убираем дополнительные внутренние отступы. + self.priority = QComboBox() # Приоритет соответствует старшему полю SETCAN ID. + self.priority.addItems(["0 — критический", "1 — стандартный"]) # Подписи сохраняют существующие значения приоритета протокола. + self.priority.setCurrentIndex(1) # По умолчанию используется стандартный приоритет. + self.route = QComboBox() # Направление отличает запрос мастера от сообщения устройства. + self.route.addItems(["0 — от мастера (PM)", "1 — от устройства"]) # Сохраняем совместимые значения поля ПМ. + self.dtype = QSpinBox() # Тип устройства выбирается отдельно от номера экземпляра. + self.dtype.setRange(0, 7) # Поле Device Type занимает три бита SETCAN ID. + self.dtype.setValue(1) # Сохраняем прежний исходный тип устройства. + self.did = QSpinBox() # Номер устройства задаёт адрес внутри выбранного типа. + self.did.setRange(0, 15) # Поле Device занимает четыре бита SETCAN ID. + self.did.setValue(2) # Сохраняем прежний исходный адрес устройства. + self.mtype = QComboBox() # Тип сообщения определяет подтип и назначение Body. + self.mtype.addItems([item.name for item in pc.MsgType]) # Каталог типов берётся из общего протокольного модуля. + self.mtype.setCurrentText(pc.MsgType.ANALOG.name) # Начальный протокольный пример остаётся аналоговым сообщением. + self.sub = QComboBox() # Набор подтипов меняется вместе с MsgType. + self.arg = QLineEdit("1") # Числовой аргумент поддерживает десятичный ввод и префикс 0x. + self.settings_body = settings_factory() # Используем переданный редактор байтов Z и Y без зависимости от приложения. + self.arg_panel = QWidget() # Альтернативные редакторы аргумента занимают одну строку. + arg_layout = QHBoxLayout(self.arg_panel) # Горизонтальная компоновка сохраняет левое выравнивание SETTINGS. + arg_layout.setContentsMargins(0, 0, 0, 0) # Исключаем сдвиг аргумента относительно остальных редакторов. + arg_layout.addWidget(self.arg) # Обычный аргумент виден для всех типов кроме SETTINGS. + arg_layout.addWidget(self.settings_body) # Два байта SETTINGS заменяют единое поле аргумента. + arg_layout.addStretch(1) # Свободная ширина остаётся справа от редакторов. + self.count = QSpinBox() # RegCount используется протокольными типами Modbus. + self.count.setRange(0, 15) # Поле количества занимает четыре бита Body Modbus. + self.count.setValue(1) # Исходный запрос относится к одному регистру. + self.sub_label = QLabel("Подтип") # Подпись уточняется при выборе типа сообщения. + self.arg_label = QLabel("SensorID / адрес") # Назначение аргумента зависит от MsgType. + rows = [("Priority", self.priority), ("ПМ", self.route), ("Device Type (0..7)", self.dtype), ("Device (0..15)", self.did), ("Msg Type", self.mtype), (self.sub_label, self.sub), (self.arg_label, self.arg_panel), ("RegCount (Modbus)", self.count)] # Единый порядок полей исключает расхождение форм. + for label, control in rows: # Все протокольные строки добавляются из одного визуального описания. + form.addRow(label, control) # Подпись связана с соответствующим редактором. + layout.addWidget(self.setcan_panel) # Протокольная форма показывается только в режиме SETCAN. + self.data = QLineEdit() # Полезная нагрузка общая для обоих способов ввода идентификатора. + self.data.setPlaceholderText("01 02 03 04 05 06 07 08") # Пример показывает формат ввода HEX-байтов. + data_form = QFormLayout() # Общая строка Data остаётся видимой при смене режима. + data_form.addRow("Data (HEX, до 8 байт)", self.data) # Указываем ограничение классического CAN. + layout.addLayout(data_form) # Данные завершают форму перед кнопками владельца. + for control in (self.mode, self.data): # Длинные поля получают достаточную ширину в обоих режимах. + control.setMaximumWidth(420) # Предел 420 пикселей сохраняет компактность исходного конструктора. + self.format.setMaximumWidth(340) # Название формата целиком помещается в строке шириной до 340 пикселей. + for control in (self.priority, self.route, self.mtype, self.sub, self.arg, self.can_id): # Одинаковая ширина полей ID задаётся в общем компоненте. + control.setMaximumWidth(220) # Предел 220 пикселей соответствует прежней форме SETCAN. + for control in (self.dtype, self.did, self.count, self.dlc): # Короткие числовые поля не растягиваются по ширине панели. + control.setMaximumWidth(100) # Предел 100 пикселей достаточен для всех допустимых значений. + font = QFont("Consolas", 10) # Шрифт с фиксированной шириной знаков упрощает чтение HEX. + for control in (self.can_id, self.data): # Числовой HEX и полезная нагрузка оформляются одинаково. + control.setFont(font) # Используем один шрифт для всех владельцев компонента. + self._subtype() # Настраиваем первоначальные подписи до вычисления ширины столбца. + labels = [part.labelForField(part.itemAt(row, QFormLayout.ItemRole.FieldRole).widget()) for part in (mode_form, can_form, form, data_form) for row in range(part.rowCount())] # Собираем подписи всех форм для общего выравнивания. + width = max(label.sizeHint().width() for label in labels) # Ширина столбца рассчитывается в пикселях по текущему шрифту Qt. + for label in labels: # Поля обоих режимов должны начинаться в одной позиции. + label.setMinimumWidth(width) # Самая длинная подпись задаёт единый левый столбец. + for container in (self, self.can_panel, self.setcan_panel, self.arg_panel): # Промежуточные контейнеры наследуют фон панели без тёмных полос. + container.setObjectName("canBuilderFields") # Локальный селектор ограничивает правило контейнерами формы. + container.setStyleSheet("QWidget#canBuilderFields { background: transparent; }") # Редакторы сохраняют собственный штатный фон. + self.mode.currentIndexChanged.connect(self._mode_changed) # Переключение режима одновременно меняет видимость и отменяет готовность кадра. + self.mtype.currentIndexChanged.connect(self._subtype) # Новый MsgType обновляет подтипы и редактор Body. + for control in (self.format, self.priority, self.route, self.mtype, self.sub): # Любой выбор из списка меняет будущий кадр. + control.currentIndexChanged.connect(lambda *_: self.changed.emit()) # Отбрасываем индекс Qt, поскольку владельцу нужен только сигнал устаревания результата. + for control in (self.can_id, self.arg, self.data): # Все текстовые поля участвуют в сборке кадра. + control.textChanged.connect(lambda *_: self.changed.emit()) # Отбрасываем текст сигнала Qt и отменяем старый кадр даже при неверном промежуточном вводе. + for control in (self.dlc, self.dtype, self.did, self.count, self.settings_body.z, self.settings_body.y): # Слежение включает оба байта SETTINGS. + control.valueChanged.connect(lambda *_: self.changed.emit()) # Отбрасываем числовой аргумент Qt, сохраняя единый сигнал необходимости новой сборки. + self._mode_changed() # Начальная видимость одинакова у всех потребителей. + + def _mode_changed(self): # Режим определяет только видимость; введённые значения сохраняются. + raw = self.mode.currentData() == "can" # Полный CAN ID вводится только в обычном режиме. + self.can_panel.setVisible(raw) # Показываем формат, ID и DLC для обычного CAN. + self.setcan_panel.setVisible(not raw) # Альтернативно показываем составные поля SETCAN. + self.changed.emit() # Смена способа ввода отменяет ранее собранный кадр. + + def _subtype(self): # Общие подписи и список подтипов используются всеми экземплярами формы. + msg_type = pc.MsgType[self.mtype.currentText()] # Значение выбирается из существующего общего каталога. + settings = msg_type == pc.MsgType.SETTINGS # Только SETTINGS редактируется отдельными байтами Z и Y. + self.arg.setVisible(not settings) # Единый числовой аргумент скрывается для SETTINGS. + self.settings_body.setVisible(settings) # Двухбайтовый редактор появляется вместо числового аргумента. + table = {pc.MsgType.BROADCAST: (pc.BroadcastType, "Broadcast.Type", "Body (0..15)"), pc.MsgType.DISCRETE: (pc.DiscreteType, "Discrete.Type", "Body (0..4095)"), pc.MsgType.ANALOG: (pc.AnalogType, "Analog.Type", "SensorID (0..4095)")} # Таблица определяет визуальные подписи существующих протокольных перечислений. + current = self.sub.currentText() # Сохраняем выбранный подтип, если он допустим для нового сообщения. + self.sub.clear() # Старые варианты не должны остаться в новом типе сообщения. + self.sub.setEnabled(msg_type in table) # Отдельный подтип доступен только у трёх перечисленных типов. + if msg_type in table: # Подписи и значения перечислений берутся из одного места. + enum, sub_label, arg_label = table[msg_type] # Получаем визуальное описание выбранного MsgType. + self.sub.addItems([item.name for item in enum]) # Значения берутся из общего протокольного каталога. + if current in [item.name for item in enum]: # Совместимый выбор пользователя сохраняется. + self.sub.setCurrentText(current) # Восстанавливаем допустимый подтип после заполнения списка. + else: # Типы без отдельного подтипа используют Body по собственному назначению. + sub_label = "—" # Подпись явно показывает отсутствие подтипа. + arg_label = "Body (обычно 0)" # Для PULSE сохраняем исходное описание аргумента. + if msg_type in (pc.MsgType.MODBUS_COIL, pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # Все четыре вида Modbus задают начальный адрес. + arg_label = "StrAdr (0..4095)" # Двенадцатибитный адрес показан в прежних единицах регистров. + elif msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE: # GAS использует всё поле Body под адрес. + arg_label = "Адрес регистра (0..65535)" # Полный 16-битный диапазон указан в подписи. + elif msg_type == pc.MsgType.ERROR: # Код ошибки вводится в отдельный байт Body. + arg_label = "ErrorCode (0..255)" # Показываем допустимый однобайтовый диапазон. + elif settings: # SETTINGS редактируется двухбайтовым компонентом. + arg_label = "Body: Z | Y" # Подпись соответствует порядку байтов протокола. + self.sub_label.setText(sub_label) # Одинаковая подпись подтипа обновляется во всех вкладках. + self.arg_label.setText(arg_label) # Аргумент всегда подписан по выбранному MsgType. + + def body(self, msg_type, arg, count): # Общая диспетчеризация вызывает существующие обёртки C-ядра без второй реализации wire-кодека. + if msg_type == pc.MsgType.BROADCAST: # BROADCAST объединяет подтип и четырёхбитный аргумент. + return pc.merge_broadcast(pc.BroadcastType[self.sub.currentText()], arg & 0xF) # Маска 0xF сохраняет прежнее ограничение аргумента четырьмя битами. + if msg_type == pc.MsgType.DISCRETE: # Дискретное сообщение использует собственное перечисление подтипов. + return pc.merge_discrete(pc.DiscreteType[self.sub.currentText()], arg) # Поле собирается общим протокольным модулем. + if msg_type == pc.MsgType.ANALOG: # Аналоговое сообщение передаёт SensorID в Body. + return pc.merge_analog(pc.AnalogType[self.sub.currentText()], arg) # Существующий кодек задаёт расположение подтипа и SensorID. + if msg_type in (pc.MsgType.MODBUS_COIL, pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # У четырёх видов Modbus одинаковый формат Body. + return pc.merge_modbus(arg, count) # Адрес и количество объединяются общей функцией протокола. + if msg_type == pc.MsgType.ERROR: # Сохраняем существующую категорию ошибки с нулевым кодом источника. + return pc.merge_error(0, arg) # Размещение кода ошибки остаётся ответственностью общего ядра. + return arg & 0xFFFF # Остальные типы сохраняют прежнее ограничение Body шестнадцатью битами. + + def frame_values(self): # Возвращаем проверенные параметры CAN без упаковки конкретного транспорта. + data = tr.parse_hex(self.data.text()) # Общий разбор сохраняет поддержку пробелов, запятых и префиксов 0x. + if len(data) > 8: # Классический CAN не допускает более восьми байтов данных. + raise ValueError("данные длиннее 8 байт") # Сообщаем об ошибке до передачи в транспорт. + if self.mode.currentData() == "can": # Обычный режим использует полный идентификатор и явный DLC. + identifier = int(self.can_id.text().strip(), 16) # Поле ID всегда интерпретируется как HEX. + extended = bool(self.format.currentData()) # Малый числовой ID также может иметь выбранный EXT. + tr.validate_can_id(identifier, extended) # Проверка общего транспорта запрещает усечение ID до допустимого диапазона. + if len(data) != self.dlc.value(): # Количество введённых байтов обязано точно совпадать с DLC. + raise ValueError(f"DLC = {self.dlc.value()}, а Data содержит {len(data)} байт; количество байтов должно совпадать.") # Оператор видит обе длины и может исправить ввод. + return identifier, extended, data, None # У обычного CAN нет отдельного протокольного Body. + msg_type = pc.MsgType[self.mtype.currentText()] # SETCAN использует выбранный тип сообщения. + arg = self.settings_body.value() if msg_type == pc.MsgType.SETTINGS else int(self.arg.text().strip() or "0", 0) # SETTINGS читается из Z/Y, остальные аргументы поддерживают привычные числовые префиксы. + body = self.body(msg_type, arg, self.count.value()) # Один путь сборки Body применяется ко всем владельцам формы. + identifier = pc.ProtoCanId.build(self.priority.currentIndex(), self.route.currentIndex(), self.dtype.value(), self.did.value(), msg_type, body) # Идентификатор собирается существующей обёрткой общего C-ядра. + return identifier, True, data, body # SETCAN всегда передаётся с расширенным 29-битным идентификатором. + + def bind(self, owner, prefix): # Сохраняем публичные имена полей приложения при переходе на общий компонент. + names = ("mode", "can_panel", "setcan_panel", "format", "can_id", "dlc", "priority", "route", "dtype", "did", "mtype", "sub", "arg", "settings_body", "count", "data", "sub_label", "arg_label") # Совместимые атрибуты позволяют не менять интеграцию транспорта и внешние потребители. + for name in names: # Каждое старое имя ссылается на настоящий виджет общего компонента. + setattr(owner, prefix + name, getattr(self, name)) # Префиксы build_, builder_ и rs485_builder_ разделяют три независимых состояния. diff --git a/python/set_devices/qt_ports/can_monitor.py b/python/set_devices/qt_ports/can_monitor.py index 6c13b5c..d753419 100644 --- a/python/set_devices/qt_ports/can_monitor.py +++ b/python/set_devices/qt_ports/can_monitor.py @@ -2,33 +2,40 @@ from datetime import datetime from pathlib import Path -from PySide6.QtCore import QTimer +from PySide6.QtCore import QTimer, Signal # Таймер обновляет буфер, а общий сигнал сообщает владельцу об изменении любых настроек расшифровки. from PySide6.QtWidgets import (QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox, QComboBox, QLabel, QLineEdit, QTableWidget, QTableWidgetItem, QMessageBox, QApplication, QAbstractItemView, QFileDialog) from ..can_transport import build_frame -from ..can_monitor import CanSession, PROTOCOLS, parse_filter, format_data, decode_protocol +from ..can_monitor import CanSession, PROTOCOLS, UMP_MAPS, parse_filter, parse_gas_filter, matches_filters, format_data, decode_protocol # Общие декодер, карты и независимые фильтры обеспечивают одинаковое поведение всех CAN-мониторов. class MonitorControls(QWidget): + decoding_changed = Signal() # Владельцы обновляют онлайн и трассировку при смене формата, карты адресов или номера УМП. + def __init__(self, owner, directory, default="auto"): super().__init__(owner) self.owner = owner self.directory = directory self.session = CanSession() self._dirty = False - layout = QHBoxLayout(self) + self._pending_frames = {} # Упорядоченные ключи объединяют повторы между тактами таймера и сохраняют порядок первого поступления новых кадров. + self._history_rows = {} # Ключ уникального кадра указывает на строку и последний показанный счётчик, исключая поиск по всей таблице. + self._history_total = 0 # Сумма показанных повторов обновляется по разнице счётчиков, без перебора накопленной истории. + self._history_needs_reset = False # Частичная ошибка записи требует однократной сверки таблицы с фактически сохранённой сессией. + controls_layout = QVBoxLayout(self) # Отдельная строка параметров УМП сохраняет компактную ширину основной панели монитора. + controls_layout.setContentsMargins(0, 0, 0, 0) # Панель встраивается в существующую вкладку без дополнительных внешних отступов. + layout = QHBoxLayout() # Основные кнопки остаются в прежнем горизонтальном порядке над параметрами УМП. + controls_layout.addLayout(layout) # Общие элементы занимают первую строку вертикального контейнера. layout.setContentsMargins(0, 0, 0, 0) self.protocol = QComboBox() for key, label in PROTOCOLS: self.protocol.addItem(label, key) self.protocol.setMinimumContentsLength(28) self.protocol.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - self.protocol.setToolTip( - "Выберите формат CAN вручную. УМП / Balsam — legacy CAN; " - "карта 167/v1 — имена слов 0…127 и 0x5000…0x507F в ProtoCAN; " - "новые ID — назначенные диапазоны 5000…5127 и 6000…6127.") - self.protocol.setCurrentIndex(self.protocol.findData(default)) + self.protocol.setToolTip("Выберите формат CAN. Для УМП / ProtoCAN GAS карта адресов и устройство выбираются отдельно.") # Подсказка объясняет разделение протокола и прикладного профиля. + legacy_ump = default in ("ump1_gas167", "ump2_gas167", "ump_gas") # Старые значения исходного профиля поддерживаются без возврата дублирующихся пунктов в список. + self.protocol.setCurrentIndex(self.protocol.findData("ump_protocan" if legacy_ump else default)) # Прежние профили УМП открывают единый формат с отдельно восстановленными параметрами. layout.addWidget(QLabel("Протокол")) layout.addWidget(self.protocol) self.raw = QCheckBox("Без парса") @@ -57,15 +64,52 @@ class MonitorControls(QWidget): self.status = QLabel("Буфер: 0") layout.addWidget(self.status) layout.addStretch(1) + self.ump_options = QWidget() # Контейнер дополнительных параметров показывается только для формата УМП / ProtoCAN GAS. + ump_layout = QHBoxLayout(self.ump_options) # Карта и номер УМП расположены рядом на второй строке панели. + ump_layout.setContentsMargins(0, 0, 0, 0) # Вложенная строка выравнивается с основными элементами монитора. + ump_layout.addWidget(QLabel("Карта адресов")) # Подпись отличает нумерацию регистров от формата CAN-кадра. + self.ump_map = QComboBox() # Выбор карты определяет словарь параметров при неизменном формате ProtoCAN. + for key, label in UMP_MAPS: # Оба монитора используют единый каталог действующей и планируемой карт. + self.ump_map.addItem(label, key) # Пользователь видит статус карты, а декодер получает устойчивый ключ профиля. + self.ump_map.setToolTip("167/v1: слова 0…127 и 0x5000…0x507F. Новые десятичные ID 5000…5127 и 6000…6127 назначены, но ещё не перенесены в прошивку; устройство определяется по ID.") # Подсказка указывает диапазоны обеих карт и состояние планируемой адресации. + self.ump_map.setCurrentIndex(self.ump_map.findData("assigned" if default == "ump_gas" else "gas167")) # Прежний профиль новых ID восстанавливает сквозную карту, остальные начинают с текущей. + ump_layout.addWidget(self.ump_map) # Карта выбирается независимо от списка форматов CAN. + self.ump_node_label = QLabel("Устройство") # Номер УМП относится к устройству, а не к отдельному протоколу. + ump_layout.addWidget(self.ump_node_label) # Подпись находится перед селектором номера УМП. + self.ump_node = QComboBox() # Текущая локальная карта требует ручного назначения УМП 1 или УМП 2. + self.ump_node.addItem("УМП 1", 1) # Число 1 обозначает первый УМП и передаётся декодеру как номер устройства. + self.ump_node.addItem("УМП 2", 2) # Число 2 обозначает второй УМП; карта регистров остаётся общей для обоих приборов. + self.ump_node.setCurrentIndex(self.ump_node.findData(2 if default == "ump2_gas167" else 1)) # Старый профиль второго УМП сохраняет выбранный прибор, остальные используют первый. + self.ump_node.setToolTip("Номер УМП для карты 167/v1 задаётся вручную. В новой карте устройство определяется по GAS ID.") # Подсказка объясняет, почему ручной выбор скрывается для сквозных ID. + ump_layout.addWidget(self.ump_node) # Устройство занимает собственное поле после карты адресов. + ump_layout.addStretch(1) # Свободное место справа удерживает дополнительные поля у левого края панели. + controls_layout.addWidget(self.ump_options) # Параметры УМП добавляются под основной строкой без расширения списка протоколов. + self._update_ump_options() # Исходный формат определяет видимость дополнительной строки до первого показа вкладки. self.timer = QTimer(self) self.timer.setInterval(250) self.timer.timeout.connect(self.refresh) self.timer.start() QApplication.instance().aboutToQuit.connect(self.session.close) self.destroyed.connect(lambda: self.session.close()) - self.protocol.currentIndexChanged.connect(lambda *_: self.refilter()) + self.protocol.currentIndexChanged.connect(self._change_protocol) # Смена формата обновляет параметры УМП и все представления принятых кадров. + self.ump_map.currentIndexChanged.connect(self._change_protocol) # Смена карты перерасшифровывает буфер и обновляет необходимость ручного номера устройства. + self.ump_node.currentIndexChanged.connect(self._change_protocol) # Смена устройства применяется к уже принятым кадрам текущей локальной карты. self.raw.toggled.connect(lambda *_: self.refilter()) + def _update_ump_options(self): # Видимость дополнительных полей зависит от формата и способности карты определить устройство по адресу. + self.ump_options.setVisible(self.protocol.currentData() == "ump_protocan") # Остальные форматы обходятся без настроек карты УМП. + manual_node = self.ump_map.currentData() == "gas167" # Только действующая локальная карта требует вручную выбранного номера УМП. + self.ump_node_label.setVisible(manual_node) # Подпись устройства скрывается вместе с ненужным ручным селектором новой карты. + self.ump_node.setVisible(manual_node) # Сквозные ID сами задают УМП, поэтому ручной номер не должен противоречить адресу кадра. + + def _change_protocol(self, *_args): # Сигналы трёх селекторов используют общий путь обновления, не зависящий от индекса изменённого поля. + self._update_ump_options() # Сначала интерфейс показывает только применимые к выбранному формату параметры. + self.refilter() # Таблица уникальных кадров сразу получает расшифровку с новой картой и устройством. + self.decoding_changed.emit() # Владелец обновляет онлайн, трассировку и сведения о ранее принятых кадрах. + + def decode(self, frame): # Все таблицы монитора разбирают кадры с одним набором выбранных параметров. + return decode_protocol(frame, self.protocol.currentData(), ump_map=self.ump_map.currentData(), ump_node=self.ump_node.currentData()) # Формат, карта и номер УМП передаются независимо, исключая расхождение онлайн и буфера. + def format_data(self, data): return format_data(data, self.data_format.isChecked()) @@ -79,13 +123,28 @@ class MonitorControls(QWidget): layout = QVBoxLayout(panel) layout.setContentsMargins(0, 0, 0, 0) row = QHBoxLayout() - row.addWidget(QLabel("Фильтр ID (hex)")) + self.filter_enabled = QCheckBox("Фильтр CAN ID (hex)") # Первый флажок управляет существующим отбором по идентификатору кадра. + self.filter_enabled.setChecked(True) # Сохраняем прежнее поведение: ввод CAN ID сразу фильтрует нижнюю таблицу. + row.addWidget(self.filter_enabled) # Флажок занимает место прежней подписи фильтра. self.filter = QLineEdit() self.filter.setPlaceholderText("701 или 0x701, 201") - self.filter.setToolTip("Фильтр только нижней таблицы; сверху отображаются все ID") + self.filter.setToolTip("CAN ID в HEX. Оба включённых фильтра работают по И; фильтруется только нижняя таблица, сверху остаются все кадры.") # Поясняем совместный отбор и сохраняем независимость основных таблиц. self.filter.setClearButtonEnabled(True) self.filter.textChanged.connect(self.refilter) row.addWidget(self.filter) + self.gas_filter_enabled = QCheckBox("Фильтр GAS (dec / 0xHEX)") # Второй флажок позволяет включить адреса GAS отдельно или совместно с CAN ID. + row.addWidget(self.gas_filter_enabled) # Размещаем новый критерий в той же строке рядом с существующим фильтром. + self.gas_filter = QLineEdit() # Поле содержит список адресов слов GAS, независимо от списка идентификаторов кадров. + self.gas_filter.setPlaceholderText("5000, 5127 или 0x5000") # Примеры различают десятичные назначенные ID и шестнадцатеричное локальное окно. + self.gas_filter.setToolTip("GAS ID: DEC либо HEX с 0x, через запятую. Учитываются все слова кадра. При включённых обоих фильтрах должны совпасть и CAN ID, и GAS ID.") # Объясняем формат и поиск адреса внутри многословной посылки. + self.gas_filter.setClearButtonEnabled(True) # Очистка временно убирает GAS-условие без изменения флажка CAN ID. + self.gas_filter.setEnabled(False) # Новый фильтр включается пользователем явно и не меняет прежний начальный экран. + self.gas_filter.textChanged.connect(self.refilter) # Изменение списка сразу пересчитывает строки и счётчики сохранённого буфера. + self.filter_enabled.toggled.connect(self.filter.setEnabled) # Выключенный CAN-критерий сохраняет введённый текст для повторного включения. + self.filter_enabled.toggled.connect(self.refilter) # Снятие флажка сразу убирает ограничение CAN ID. + self.gas_filter_enabled.toggled.connect(self.gas_filter.setEnabled) # Состояние поля показывает, применяется ли GAS-условие. + self.gas_filter_enabled.toggled.connect(self.refilter) # Каждый флажок независимо пересчитывает пересечение двух критериев. + row.addWidget(self.gas_filter) # Поле GAS расположено перед общим счётчиком совпавших кадров. self.count = QLabel("Кадров: 0") row.addWidget(self.count) layout.addLayout(row) @@ -106,8 +165,10 @@ class MonitorControls(QWidget): def ingest(self, identifier, data, extended, rtr=False, source="CAN", timestamp=None): try: - self.session.append(identifier, data, extended, rtr, source, timestamp) + key = self.session.append(identifier, data, extended, rtr, source, timestamp) # Сессия возвращает точную идентичность кадра с учётом канала, STD/EXT, RTR и данных. + self._pending_frames[key] = None # Один ключ объединяет любое число повторов до следующего обновления экрана. except OSError as exc: + self._history_needs_reset = True # Ошибка могла возникнуть после изменения буфера, поэтому следующий такт заново сверит все строки. self.status.setText("Ошибка записи: " + str(exc)) self.session.stop() self.record.setText("● Запись") @@ -159,46 +220,68 @@ class MonitorControls(QWidget): if not self.owner._paused and self._dirty: self._dirty = False self.status.setText("Буфер: %d" % sum(self.session.counts.values())) - self.refilter() + self._update_history(self._history_needs_reset) # Обычный такт обрабатывает лишь новые данные; полная сверка нужна только после ошибки записи. - def refilter(self): - if not hasattr(self, "filter"): - return - try: - ids = parse_filter(self.filter.text()) - except ValueError as exc: - self.count.setText(str(exc)) - ids = set() - else: - count = sum(value for key, value in self.session.counts.items() - if ids is None or key in ids) - unique_count = sum(1 for values, _ in self.session.unique_frames.values() - if ids is None or int(values[3], 16) in ids) - self.count.setText("Кадров: %d; уникальных: %d" % (count, unique_count)) - self.history.horizontalHeaderItem(7).setText( - "Данные (DEC)" if self.data_format.isChecked() else "Данные (HEX)") - self.history.setColumnHidden(8, self.raw.isChecked()) - self.history.setVisible(ids is not None) - if ids is None: - self.history.setRowCount(0) - return - frames = [(values, count) for values, count in self.session.unique_frames.values() - if int(values[3], 16) in ids] - self.history.setRowCount(len(frames)) - for row, (values, count) in enumerate(frames): - data = bytes.fromhex(values[6]) - summary = "" - if not self.raw.isChecked(): - frame = build_frame(int(values[3], 16), data, - ide=values[2] == "EXT", rtr=bool(values[4]), - to_can=values[1] == "TX") - summary = decode_protocol(frame, self.protocol.currentData()).summary - display = values[:6] + (count, self.format_data(data), summary) - for column, value in enumerate(display): - item = self.history.item(row, column) - if item is None: - self.history.setItem(row, column, QTableWidgetItem(str(value))) - elif item.text() != str(value): - item.setText(str(value)) - if column == 8: - self.history.item(row, column).setToolTip(summary) + def refilter(self): # Изменение фильтра, протокола или формата требует однократного пересчёта существующих строк. + self._update_history(True) # Полная перестройка применяется только по явному изменению настроек либо сбросу буфера. + + def _update_history(self, rebuild): # Таймер и настройки используют один путь отбора, но разный объём входных записей. + if not hasattr(self, "filter"): # При сборке панели сигналы могут прийти до создания нижней таблицы. + return # Отложим отображение до завершения построения элементов интерфейса. + error = None # Ошибка активного фильтра заменяет счётчики понятным сообщением и очищает выборку. + try: # Разбор коротких условий выполняется одинаково для полного и добавочного обновления. + ids = parse_filter(self.filter.text()) if self.filter_enabled.isChecked() else None # Текст выключенного CAN-фильтра не влияет на выборку и не вызывает ошибок ввода. + gas_ids = parse_gas_filter(self.gas_filter.text()) if self.gas_filter_enabled.isChecked() else None # Независимо разбираем только включённое условие адресов GAS. + except ValueError as exc: # Неверный ввод не должен оставлять на экране строки от прежнего корректного фильтра. + error = str(exc) # Сохраняем объяснение для итоговой подписи после очистки строк. + ids, gas_ids = set(), None # Пустое множество CAN ID даёт пустую видимую выборку. + filtered = ids is not None or gas_ids is not None # Нижняя таблица нужна лишь при наличии хотя бы одного непустого условия. + self.history.horizontalHeaderItem(7).setText("Данные (DEC)" if self.data_format.isChecked() else "Данные (HEX)") # Заголовок соответствует выбранному представлению байтов. + self.history.setColumnHidden(8, self.raw.isChecked()) # Сырой режим скрывает расшифровку независимо от способа обновления. + self.history.setVisible(filtered) # Без ограничений сохраняем компактный вид основной таблицы. + updates = self.history.updatesEnabled() # Запоминаем исходный режим отрисовки, чтобы не включать её вопреки владельцу. + self.history.setUpdatesEnabled(False) # Пачка изменений не должна вызывать промежуточную перерисовку и перерасчёт геометрии. + blocked = self.history.blockSignals(True) # Программное заполнение не должно вызывать обработчики отдельных изменённых ячеек. + try: # Восстановление состояния Qt гарантируется также при ошибке декодирования. + if rebuild or not filtered or error is not None: # Смена условий и недопустимый ввод отменяют прежнее соответствие ключей строкам. + self.history.setRowCount(0) # Полная очистка выполняется по настройке, а не каждые 250 мс при приёме. + self._history_rows.clear() # Индексы строк больше не относятся к новой выборке. + self._history_total = 0 # Сумма повторов пересчитывается для нового набора подходящих кадров. + if filtered and error is None: # Скрытая таблица и некорректные условия не требуют фильтрации или декодирования истории. + keys = self.session.unique_frames if rebuild else self._pending_frames # Только явная перестройка перебирает всю сессию; таймер берёт изменённые ключи. + for key in keys: # Словари сохраняют порядок первого появления уникальных кадров, даже если между ними пришли повторы. + values, count = self.session.unique_frames[key] # Получаем последние время и счётчик с учётом всех повторов в текущей пачке. + previous = self._history_rows.get(key) # Уже показанный кадр прошёл неизменные фильтры и не нуждается в повторной расшифровке. + if previous is not None: # У повторов меняются только время последнего приёма и число физических кадров. + row, old_count = previous # Сохраняем прежнюю сумму, чтобы добавить только новые приёмы. + display = ((0, values[0]), (6, count)) # Колонки 0 и 6 содержат время и счётчик, остальные данные идентичны по ключу. + else: # Новый ключ необходимо проверить по обоим активным условиям. + data = bytes.fromhex(values[6]) # Данные нужны для GAS-отбора и однократной расшифровки новой строки. + if not matches_filters(int(values[3], 16), data, values[2] == "EXT", bool(values[4]), can_ids=ids, gas_ids=gas_ids): # Проверяем пересечение CAN/GAS с учётом формата и RTR. + continue # Неподходящий кадр остаётся в полной сессии для сохранения и последующей смены фильтров. + row, old_count = self.history.rowCount(), 0 # Новая уникальная посылка добавляется в конец с её полным счётчиком с начала сессии. + self.history.insertRow(row) # Существующие строки и выделение не пересоздаются при поступлении новой посылки. + summary = "" # В режиме без парса не вызываем декодер даже при первом отображении кадра. + if not self.raw.isChecked(): # Расшифровка вычисляется только для новой строки либо при явной перестройке настроек. + frame = build_frame(int(values[3], 16), data, ide=values[2] == "EXT", rtr=bool(values[4]), to_can=values[1] == "TX") # Восстанавливаем исходную метаинформацию сохранённой посылки. + summary = self.decode(frame).summary # Используем выбранные протокол, карту адресов и номер устройства. + display = enumerate(values[:6] + (count, self.format_data(data), summary)) # Новая строка заполняется целиком в порядке заголовков таблицы. + for column, value in display: # У повторов этот цикл касается двух ячеек вместо всей накопленной таблицы. + item = self.history.item(row, column) # Повторно используем существующий объект ячейки для сохранения выделения. + if item is None: # Ячейки создаются только при добавлении новой уникальной посылки. + item = QTableWidgetItem() # Пустой объект получает текст общим путём ниже. + self.history.setItem(row, column, item) # Таблица принимает владение созданной ячейкой. + if item.text() != str(value): # Не уведомляем модель Qt о фактически неизменившемся значении. + item.setText(str(value)) # Преобразование сохраняет прежнее отображение чисел и меток времени. + if column == 8: # Последний столбец содержит длинную расшифровку, которую удобно читать в подсказке. + item.setToolTip(str(value)) # Подсказка обновляется вместе с новой расшифровкой при смене настроек. + self._history_rows[key] = (row, count) # Запоминаем актуальные индекс и показанный счётчик для следующей пачки повторов. + self._history_total += count - old_count # Добавляем только новые физические приёмы без суммирования всей истории. + self._pending_frames.clear() # Все поступившие ключи учтены либо скрыты неизменными фильтрами. + self._history_needs_reset = False # Сверка после ошибки успешно завершена и больше не требует полного обхода. + total = self._history_total if filtered else sum(self.session.counts.values()) # Без фильтра подпись относится ко всей сессии, хотя сама таблица скрыта. + unique = len(self._history_rows) if filtered else len(self.session.unique_frames) # Число уникальных кадров берём из готового индекса без повторного отбора. + self.count.setText(error if error is not None else "Кадров: %d; уникальных: %d" % (total, unique)) # При ошибке оставляем причину, иначе показываем согласованные счётчики выборки. + finally: # Любой выход должен вернуть исходное поведение сигналов и перерисовки Qt. + self.history.blockSignals(blocked) # Восстанавливаем состояние, установленное владельцем до обновления. + self.history.setUpdatesEnabled(updates) # Готовая пачка отображается за одно обновление виджета. diff --git a/python/set_devices/qt_ports/candle_adapter.py b/python/set_devices/qt_ports/candle_adapter.py index 76e81b0..1681787 100644 --- a/python/set_devices/qt_ports/candle_adapter.py +++ b/python/set_devices/qt_ports/candle_adapter.py @@ -12,13 +12,15 @@ from __future__ import annotations import ctypes as ct import os -from dataclasses import dataclass +from dataclasses import dataclass, field # Имя продукта хранится рядом с адресом канала, но не меняет идентичность физического подключения. from pathlib import Path import sys import threading import re from .qt_compat import QObject, Signal +from ..can_adapter_settings import CandleOptions, CanTiming, FD_LENGTHS, calculate_timing # Общая модель проверяет флаги, DLC и аппаратные пределы тайминга. +from collections import deque # Ограниченный журнал FD сохраняет кадры даже при закрытом окне диагностики. _EXTENDED_ID = 0x80000000 @@ -36,12 +38,13 @@ class CandleError(RuntimeError): class CandleChannel: path: str channel: int + product: str = field(default="", compare=False) # Настоящая USB-строка продукта; смена подписи не создаёт другое подключение с тем же путём и каналом. @property def label(self) -> str: lower = self.path.lower() - product = "CANnectivity" if "vid_1209&pid_ca01" in lower else "candle" - return f"{product} — канал {self.channel}" + product = self.product.strip() or ("CANnectivity" if "vid_1209&pid_ca01" in lower else "candle") # Предпочитает имя из прошивки, сохраняя прежние подписи при отсутствии USB-строки или старой DLL. + return f"{product} — канал {self.channel}" # Показывает пользовательский номер в имени продукта и независимый индекс CAN-канала. @property def adapter_kind(self) -> str: @@ -58,6 +61,23 @@ class _Frame(ct.Structure): ] +class _FdFrame(ct.Structure): # gs_usb сохраняет общий заголовок Classic и FD, расширяя только поле данных. + _pack_ = 1 # USB-пакет не содержит выравнивающих отступов компилятора. + _fields_ = _Frame._fields_[:-2] + [("data", ct.c_uint8 * 64), ("timestamp_us", ct.c_uint32)] # 64 байта — максимальная длина данных CAN FD. + + +class _Capability(ct.Structure): # Поля соответствуют candle_capability_t и ответу BT_CONST. + _fields_ = [(name, ct.c_uint32) for name in ("feature", "fclk_can", "tseg1_min", "tseg1_max", "tseg2_min", "tseg2_max", "sjw_max", "brp_min", "brp_max", "brp_inc")] # Частота измеряется в герцах, сегменты — в квантах CAN. + + +class _Timing(ct.Structure): # Структура передаёт пять параметров в управляющий endpoint USB. + _fields_ = [(name, ct.c_uint32) for name in ("prop_seg", "phase_seg1", "phase_seg2", "sjw", "brp")] # Порядок совпадает с публичным C ABI. + + +def _timing(value: CanTiming) -> _Timing: # Преобразуем проверенную переносимую модель в ctypes без зависимости модели от Windows. + return _Timing(value.prop_seg, value.phase_seg1, value.phase_seg2, value.sjw, value.brp) # Передаём сегменты и делитель без округления. + + def _library_path() -> Path: explicit = os.environ.get('CANDLE_LIBRARY') if explicit: @@ -83,6 +103,8 @@ class _Api: self._fn("candle_list_length", [handle, ct.POINTER(ct.c_uint8)]) self._fn("candle_dev_get", [handle, ct.c_uint8, ct.POINTER(handle)]) self._fn("candle_dev_get_path", [handle], ct.c_wchar_p) + if hasattr(self.dll, "candle_dev_get_product"): # Поддерживает прежние версии библиотеки без функции чтения имени USB. + self._fn("candle_dev_get_product", [handle, ct.c_wchar_p, ct.c_uint32]) # Согласует выходной UTF-16-буфер и его размер в кодовых единицах с публичным C ABI. self._fn("candle_dev_open", [handle]) self._fn("candle_dev_close", [handle]) self._fn("candle_dev_free", [handle]) @@ -95,12 +117,32 @@ class _Api: self._fn("candle_frame_read", [handle, ct.POINTER(_Frame), ct.c_uint32]) self._fn("candle_frame_type", [ct.POINTER(_Frame)], ct.c_int) self._fn("candle_frame_id", [ct.POINTER(_Frame)], ct.c_uint32) + self._fn("candle_channel_get_capabilities", [handle, ct.c_uint8, ct.POINTER(_Capability)]) # Базовый API возможностей доступен и у прежней библиотеки. + self._fn("candle_channel_set_timing", [handle, ct.c_uint8, ct.POINTER(_Timing)]) # Ручной и рассчитанный тайминги используют один USB-запрос. + optional = {"candle_channel_start_configured": [handle, ct.c_uint8, ct.c_uint32], "candle_channel_get_data_capabilities": [handle, ct.c_uint8, ct.POINTER(_Capability)], "candle_channel_set_termination": [handle, ct.c_uint8, ct.c_uint32], "candle_channel_get_termination": [handle, ct.c_uint8, ct.POINTER(ct.c_uint32)], "candle_channel_get_diagnostics": [handle, ct.c_uint8, ct.POINTER(ct.c_uint32), ct.POINTER(ct.c_uint32), ct.POINTER(ct.c_uint32)], "candle_channel_bus_off_recover": [handle, ct.c_uint8], "candle_channel_set_data_timing": [handle, ct.c_uint8, ct.POINTER(_Timing)], "candle_fd_frame_send": [handle, ct.c_uint8, ct.POINTER(_FdFrame)], "candle_fd_frame_read": [handle, ct.POINTER(_FdFrame), ct.c_uint32], "candle_fd_frame_type": [ct.POINTER(_FdFrame)]} # Необязательные экспорты позволяют сообщить понятную ошибку старой DLL. + for name, arguments in optional.items(): # Регистрация выполняется один раз при загрузке библиотеки. + if hasattr(self.dll, name): # Отсутствующее расширение проверяется при его явном выборе. + self._fn(name, arguments, ct.c_int if name.endswith("frame_type") else ct.c_bool) # Тип кадра — enum, остальные функции возвращают bool. def _fn(self, name: str, args: list, result=ct.c_bool) -> None: function = getattr(self.dll, name) function.argtypes = args function.restype = result + def enter_dfu(self, path): # Открывает отдельный runtime-интерфейс выбранного адаптера через проверяемый экспорт DLL. + function = getattr(self.dll, "candle_dev_enter_dfu", None) # Старая библиотека не должна молча имитировать успешный переход. + if function is None: # Проверяет ABI до остановки действующего CAN-сеанса. + raise CandleError("Обновите candle.dll: переход в DFU недоступен") # Оставляет пользователю понятную причину отсутствующего расширения. + function.argtypes, function.restype = [ct.c_wchar_p, ct.POINTER(ct.c_uint8)], ct.c_uint32 # Передаёт точный USB-путь UTF-16, шестибайтовый статус и код Windows фиксированной ширины. + status = (ct.c_uint8 * 6)() # DFU 1.1 возвращает bStatus, три байта задержки, bState и iString. + error = function(path, status) # DLL выбирает интерфейс обновления по общему родителю с CAN-интерфейсом. + if error: # Отказ доступа, отсутствие интерфейса и потеря USB не являются подтверждением DFU. + detail = "Интерфейс обновления не найден: нужна прошивка CANable 2.5 / weCANdle и драйвер WinUSB для Firmware Update Interface" if error == 1168 else ct.FormatError(ct.c_int32(error).value).strip() # ERROR_NOT_FOUND равен 1168; знаковое представление сохраняет 32 бита кодов SetupAPI 0xE000xxxx без OverflowError в ctypes. + if error in (0xE000020B, 0xE000021C, 0xE0000225): # SetupAPI обозначает этими кодами отсутствующий узел, удалённый интерфейс или неизвестный путь USB. + detail = "Выбранный USB-адаптер больше не найден. Переподключите его и обновите список устройств." # Даёт понятный следующий шаг вместо отсутствующего системного описания SetupAPI. + raise CandleError(f"Не удалось подтвердить переход в DFU: {detail}") # Не предлагает записывать flash до обнаружения настоящего загрузчика. + return bytes(status) # Сохраняет точные поля ответа прошивки для проверки протокола вызывающим методом. + def scan(self) -> list[CandleChannel]: result: list[CandleChannel] = [] physical_devices: set[str] = set() @@ -128,8 +170,8 @@ class _Api: key = re.sub(r"&[0-9a-f]{4}(?=#\{)", "", key) if key not in physical_devices: physical_devices.add(key) - result.extend(CandleChannel(path, channel) - for channel in range(channels.value)) + product = self.product_name(device) # Читает имя один раз для всех каналов уже открытого физического USB-адаптера. + result.extend(CandleChannel(path, channel, product) for channel in range(channels.value)) # Передаёт настоящую подпись общим спискам снифера, терминала и прошивки. self.dll.candle_dev_close(device) finally: self.dll.candle_dev_free(device) @@ -137,6 +179,12 @@ class _Api: self.dll.candle_list_free(listing) return result + def product_name(self, device): # Читает отображаемое имя устройства без изменения его USB-пути и состояния CAN. + function = getattr(self.dll, "candle_dev_get_product", None) # Не требует нового экспорта от старой совместимой библиотеки. + if function is None: return "" # Отсутствие функции включает существующую резервную подпись вместо отказа сканирования. + product = ct.create_unicode_buffer(128) # USB-строка содержит максимум 126 кодовых единиц UTF-16 плюс завершающий ноль. + return product.value.strip() if function(device, product, len(product)) else "" # Не выдаёт пустой или неудачно прочитанный дескриптор за новое имя адаптера. + def acquire(self, wanted_path: str) -> ct.c_void_p: listing = ct.c_void_p() if not self.dll.candle_list_scan(ct.byref(listing)): @@ -165,6 +213,7 @@ class CandleAdapter(QObject): transmit_echo = Signal(int, bytes, bool, bool) bus_error = Signal(int, bytes, int) connection_lost = Signal(str) + fd_received = Signal(int, bytes, bool, int, int) # FD получает отдельный маршрут: ID, данные, EXT, флаги gs_usb и аппаратная метка в микросекундах. def __init__(self, parent: QObject | None = None) -> None: super().__init__(parent) @@ -175,6 +224,10 @@ class CandleAdapter(QObject): self._reader: threading.Thread | None = None self._send_lock = threading.Lock() self._listen_only = False + self.options = CandleOptions() # Настройки сеанса не меняются после запуска канала. + self.capabilities = None # Реальная маска и пределы становятся известны после открытия устройства. + self.nominal_timing, self.fd_timing = None, None # Диагностика покажет фактические сегменты и достигнутую точку выборки. + self.fd_history = deque(maxlen=500) # Последние 500 FD-кадров доступны в окне диагностики без неограниченного роста памяти. def _get_api(self) -> _Api: if self._api is None: @@ -189,18 +242,37 @@ class CandleAdapter(QObject): return self._device is not None def connect_channel(self, channel: CandleChannel, bitrate: int, - listen_only: bool = False) -> None: + listen_only: bool = False, *, options: CandleOptions | None = None) -> None: # Необязательный объект сохраняет совместимость прежних вызовов. self.disconnect_channel() + selected = options or CandleOptions() # При отсутствии расширенных настроек сохраняются обычный режим и автоматические метки. api = self._get_api() device = api.acquire(channel.path) try: if not api.dll.candle_dev_open(device): raise CandleError("Не удалось открыть candle-адаптер") - if not api.dll.candle_channel_set_bitrate(device, channel.channel, bitrate): - raise CandleError(f"Адаптер не поддерживает {bitrate} бит/с") - mode = _MODE_LISTEN_ONLY if listen_only else 0 - if not api.dll.candle_channel_start(device, channel.channel, mode): - raise CandleError("Не удалось запустить CAN-канал") + cap = _Capability() # У каждого канала могут быть собственные ограничения контроллера. + self._check(api.dll.candle_channel_get_capabilities(device, channel.channel, ct.byref(cap)), "прочитать возможности канала") # Отсутствие ответа не считается отсутствием всех возможностей. + mode = selected.flags(listen_only, cap.feature) # Неподдерживаемый явный флаг останавливает подключение до настройки шины. + nominal = selected.timing or calculate_timing(cap, bitrate, selected.sample_point) # Автоматический расчёт поддерживает частоты, отличные от 48 МГц. + nominal.validate(cap, bitrate) # Ручной тайминг также обязан совпадать с выбранной скоростью. + data = None # Отсутствие FD оставляет быструю фазу неподключённой и не показывает фиктивный тайминг. + timing = _timing(nominal) # ctypes-объект живёт до завершения синхронного USB-запроса. + self._check(api.dll.candle_channel_set_timing(device, channel.channel, ct.byref(timing)), "установить номинальный тайминг") # Скорость не округляется по старой таблице фиксированных делителей. + if selected.fd: # До запуска FD настраиваем и проверяем быструю фазу. + for name in ("candle_channel_get_data_capabilities", "candle_channel_set_data_timing", "candle_fd_frame_read", "candle_fd_frame_send", "candle_fd_frame_type"): # Полноценная работа требует и чтения, и записи FD. + self._require(name) # Устаревшая DLL выдаёт явную ошибку вместо обрезания 64-байтовых кадров. + data_cap = _Capability() # Расширенный запрос возвращает отдельные пределы фазы данных. + self._check(api.dll.candle_channel_get_data_capabilities(device, channel.channel, ct.byref(data_cap)), "прочитать пределы CAN FD") # Без пределов нельзя безопасно рассчитать быструю фазу. + data = selected.data_timing or calculate_timing(data_cap, selected.data_bitrate, selected.data_sample_point) # Быстрая фаза получает собственную скорость и точку выборки. + data.validate(data_cap, selected.data_bitrate) # Проверяем ручной тайминг по ограничениям FD, а не номинальной фазы. + data_timing = _timing(data) # Подготавливаем структуру стандартного DATA_BITTIMING. + self._check(api.dll.candle_channel_set_data_timing(device, channel.channel, ct.byref(data_timing)), "установить тайминг CAN FD") # Канал не запускается при отказе быстрой фазы. + if selected.termination is not None: # Состояние терминатора меняется только по явному выбору пользователя. + self._check(self._require("candle_channel_set_termination")(device, channel.channel, int(selected.termination)), "переключить терминатор") # Проверенная возможность исключает попытку управления внешним резистором. + starter = getattr(api.dll, "candle_channel_start_configured", None) # Новый экспорт не добавляет HW_TIMESTAMP к точной маске настроек. + if starter is None and selected.hardware_timestamp is False: # Старый start автоматически включает аппаратные метки. + raise CandleError("Для отключения аппаратных меток обновите candle.dll") # Не показываем настройку выполненной, когда старая DLL её отменяет. + self._check((starter or api.dll.candle_channel_start)(device, channel.channel, mode), "запустить CAN-канал") # Только подтверждённый запуск означает успешное подключение. except Exception: api.dll.candle_dev_close(device) api.dll.candle_dev_free(device) @@ -208,6 +280,10 @@ class CandleAdapter(QObject): self._device = device self._channel = channel.channel self._listen_only = listen_only + self.options = selected # Читатель выбирает размер структуры по реально запущенному режиму. + self.capabilities = cap # Диагностика показывает фактическую маску функций и частоту канала. + self.nominal_timing, self.fd_timing = nominal, data # Сохраняем действительно переданные сегменты, а не только желаемый процент выборки. + self.fd_history.clear() # Кадры предыдущего устройства не смешиваются с новым сеансом. self._stop.clear() self._reader = threading.Thread(target=self._read_loop, name="candle-rx", daemon=True) @@ -227,6 +303,29 @@ class CandleAdapter(QObject): self._reader = None self._listen_only = False + def enter_dfu_mode(self): # Останавливает текущий CAN-сеанс перед обращением к отдельному USB-интерфейсу загрузчика. + api = self._get_api() # Использует уже загруженную библиотеку транспорта, не создавая второго владельца CAN. + if not hasattr(api.dll, "candle_dev_enter_dfu"): # Не закрывает рабочий канал при заведомо несовместимой версии DLL. + raise CandleError("Обновите candle.dll: переход в DFU недоступен") # Объясняет необходимость обновления встроенной библиотеки SETGUI. + with self._send_lock: # Запрещает одновременную передачу кадра во время остановки и освобождения USB. + if not self.connected: # Команда должна относиться к конкретному подключённому адаптеру пользователя. + raise CandleError("Сначала подключите Candle / weCANdle-адаптер") # Не выбирает первый найденный USB-адаптер автоматически. + path = api.dll.candle_dev_get_path(self._device) # Копирует точный путь до освобождения нативного handle устройства. + if not path: # Пустой путь не позволяет надёжно выбрать физический интерфейс обновления. + raise CandleError("Не удалось определить USB-путь выбранного адаптера") # Сохраняет подключение при невозможности адресовать команду. + self.disconnect_channel() # Останавливает RX-поток, сбрасывает канал CAN и освобождает WinUSB-сеанс до DETACH. + self.connection_lost.emit("CAN-сеанс остановлен для перехода адаптера в DFU") # Обновляет владельца соединения и отменяет его пинг, обмен и отправку кадров. + status = api.enter_dfu(path) # Отдельный управляющий сеанс не использует освобождённый CAN-handle. + if len(status) != 6: # Неполный ответ не должен выглядеть как подтверждённый статус DFU. + raise CandleError("Неполный ответ DFU_GETSTATUS") # Защищает разбор полей при несовместимой обёртке DLL. + if status[0] or status[4] == 10: # bStatus ненулевой либо bState=dfuERROR по DFU 1.1 означают отказ прошивки. + raise CandleError(f"Прошивка отклонила DFU: статус {status[0]}, код {status[5]}") # iString передаёт дополнительный код ошибки CANable 2.5. + if status[4] == 1: # appDETACH означает необходимость аппаратного сброса после восстановления настройки BOOT0. + return "Для входа в DFU отключите и снова подключите USB-кабель адаптера." # Не утверждает, что устройство уже появилось в загрузчике. + if status[4] != 0: # CANable 2.5 подтверждает отложенный переход только состоянием appIDLE. + raise CandleError(f"Неожиданное состояние DFU: {status[4]}") # Не принимает неизвестное состояние за успешную команду. + return "Команда входа в DFU принята. Откройте STM32CubeProgrammer → USB и обновите список устройств." # Отделяет подтверждение команды от фактического обнаружения ROM-загрузчика. + def send(self, can_id: int, data: bytes, *, extended: bool = True) -> None: device = self._device if device is None: @@ -243,34 +342,92 @@ class CandleAdapter(QObject): frame.channel = self._channel frame.data[:len(data)] = data with self._send_lock: + if self._device is not device: # Переход в DFU мог освободить handle, пока отправитель ожидал блокировку передачи. + raise CandleError("CAN-сеанс уже остановлен") # Не передаёт сохранённый указатель в DLL после закрытия USB-адаптера. if not self._get_api().dll.candle_frame_send( device, self._channel, ct.byref(frame)): raise CandleError("Candle API не передал CAN-кадр") + def _require(self, name): # Проверяем необязательный экспорт непосредственно перед использованием расширения. + function = getattr(self._get_api().dll, name, None) # Имя берётся из внутреннего списка функций, а не от пользователя. + if function is None: # Старый бинарный файл не должен приводить к необработанному AttributeError. + raise CandleError(f"Обновите candle.dll: отсутствует {name}") # Указываем конкретное несовместимое расширение. + return function # Возвращаем функцию с уже зарегистрированной сигнатурой ctypes. + + @staticmethod # Проверка результата не зависит от состояния Qt-объекта. + def _check(result, action): # Все USB-настройки требуют подтверждённого результата bool. + if not result: # false означает, что устройство не приняло настройку или запрос завершился ошибкой. + raise CandleError(f"Candle: не удалось {action}") # Контекст этапа помогает исправить выбранную конфигурацию. + + def diagnostics(self) -> str: # Чтение выполняется только у уже открытого канала без повторного захвата устройства. + if not self.connected: # Опрос не должен неявно подключать CAN или менять выбранный режим. + raise CandleError("Сначала подключите адаптер") # Пользователь явно управляет жизненным циклом соединения. + cap = self.capabilities # Используем сохранённый при подключении ответ BT_CONST. + lines = [f"Возможности: 0x{cap.feature:08X}; частота CAN: {cap.fclk_can} Гц", f"TSEG1 {cap.tseg1_min}…{cap.tseg1_max}; TSEG2 {cap.tseg2_min}…{cap.tseg2_max}; SJW ≤ {cap.sjw_max}; BRP {cap.brp_min}…{cap.brp_max}, шаг {cap.brp_inc}"] # Единицы и пределы показываются вместе с маской. + for name, value in (("Номинальная фаза", self.nominal_timing), ("Данные FD", self.fd_timing)): # Обе фазы могут иметь разные достижимые точки выборки. + if value is not None: # Classic-сеанс не должен показывать параметры неиспользуемой быстрой фазы. + total = 1 + value.prop_seg + value.phase_seg1 + value.phase_seg2 # Полное число квантов в бите включает SYNC_SEG. + lines.append(f"{name}: {cap.fclk_can / value.brp / total:g} бит/с, выборка {(total - value.phase_seg2) / total * 100:.2f} %, PROP/PH1/PH2/SJW/BRP = {value.prop_seg}/{value.phase_seg1}/{value.phase_seg2}/{value.sjw}/{value.brp}") # Показываем фактически настроенную скорость и точку вместо обещания недостижимого точного процента. + if cap.feature & 8192: # GET_STATE объявляется битом 13 протокола gs_usb. + state, rx, tx = ct.c_uint32(), ct.c_uint32(), ct.c_uint32() # Все три значения относятся к одному ответу контроллера. + self._check(self._require("candle_channel_get_diagnostics")(self._device, self._channel, ct.byref(state), ct.byref(rx), ct.byref(tx)), "прочитать состояние") # Не подменяем отказ нулевыми счётчиками. + names = ("Error-active", "Error-warning", "Error-passive", "Bus-off", "Stopped", "Sleeping") # Стандартные состояния контроллера CAN согласно gs_usb. + lines.append(f"Состояние: {names[state.value] if state.value < len(names) else state.value}; RX errors: {rx.value}; TX errors: {tx.value}") # Показываем счётчики ошибок отдельно от числа принятых кадров. + if cap.feature & 2048: # Только аппаратно переключаемый терминатор имеет читаемое состояние. + state = ct.c_uint32() # Нулевое значение означает OFF, единица — ON. + self._check(self._require("candle_channel_get_termination")(self._device, self._channel, ct.byref(state)), "прочитать терминатор") # GET_TERMINATION не меняет сопротивление на шине. + lines.append("Терминатор: " + ("120 Ом" if state.value else "выключен")) # Указываем физический смысл переключателя. + return "\n".join(lines) # Текст пригоден для диагностики и копирования без дополнительных файлов. + + def recover_bus_off(self) -> None: # Восстановление выполняется только по явной кнопке диагностики. + if not self.connected or not self.capabilities.feature & 0x40000: # Расширение BUS_OFF_RECOVERY не является универсальной функцией gs_usb. + raise CandleError("Адаптер не объявил поддержку восстановления Bus-off") # Не отправляем неизвестный vendor-запрос старой прошивке. + self._check(self._require("candle_channel_bus_off_recover")(self._device, self._channel), "восстановить Bus-off") # Результат определяется реальным ответом устройства. + + def send_fd(self, can_id: int, data: bytes, *, extended: bool = True, brs: bool = True) -> None: # Отдельный API не меняет семантику Classic CAN send. + if not self.connected or self._listen_only or not self.options.fd: # Передача требует активного канала с настроенной быстрой фазой. + raise CandleError("Передача FD требует активного подключения CAN FD") # Пассивный режим защищён и при прямом вызове API. + if len(data) not in FD_LENGTHS or not 0 <= can_id <= (0x1FFFFFFF if extended else 0x7FF): # Стандарт FD допускает только длины из таблицы DLC. + raise CandleError("Неверный CAN ID или длина CAN FD (0…8, 12, 16, 20, 24, 32, 48, 64)") # Не дополняем незаметно пользовательский пакет. + frame = _FdFrame() # Полная структура предотвращает выход за пределы восьмибайтового буфера Classic. + frame.can_id = can_id | (_EXTENDED_ID if extended else 0) # Старший бит указывает расширенный 29-битный идентификатор. + frame.can_dlc, frame.flags = FD_LENGTHS.index(len(data)), 2 | (4 if brs else 0) # Биты 1 и 2 означают FD и переключение скорости BRS. + frame.data[:len(data)] = data # Остаток буфера обнулён конструктором ctypes. + with self._send_lock: # Classic и FD используют один USB OUT endpoint и один native event. + self._check(self._require("candle_fd_frame_send")(self._device, self._channel, ct.byref(frame)), "передать CAN FD") # Ошибка записи остаётся видимой вызывающему коду. + def _read_loop(self) -> None: device = self._device if device is None: return api = self._get_api() while not self._stop.is_set() and self._device is device: - frame = _Frame() - if not api.dll.candle_frame_read(device, ct.byref(frame), 50): + frame = _FdFrame() if self.options.fd else _Frame() # В FD-сеансе библиотека возвращает оба формата в безопасной структуре на 64 байта. + reader = api.dll.candle_fd_frame_read if self.options.fd else api.dll.candle_frame_read # Выбор функции согласован с размером выходного буфера. + if not reader(device, ct.byref(frame), 50): # 50 мс ограничивает задержку остановки фонового потока. continue if frame.channel != self._channel: continue - kind = api.dll.candle_frame_type(ct.byref(frame)) + kind = (api.dll.candle_fd_frame_type if self.options.fd else api.dll.candle_frame_type)(ct.byref(frame)) # ctypes не смешивает указатели на разные структуры. + if frame.flags & 2: # FD даже с короткими данными нельзя передавать декодерам как Classic CAN. + if frame.can_dlc > 15: # DLC имеет только четыре значащих бита согласно CAN FD. + continue # Повреждённый пакет не должен индексировать таблицу длин вне диапазона. + record = (frame.can_id & 0x1FFFFFFF, bytes(frame.data[:FD_LENGTHS[frame.can_dlc]]), bool(frame.can_id & _EXTENDED_ID), frame.flags, frame.timestamp_us) # Сохраняем полный payload и исходную метку в микросекундах. + self.fd_history.append(("TX echo" if kind == _FRAME_ECHO else "RX", record)) # Журнал явно отличает эхо от получения кадра с шины. + self.fd_received.emit(*record) # Просмотр FD использует самостоятельный маршрут и не попадает в мост RS485. + continue # Короткий FD-кадр также не маскируется под Classic. size = min(frame.can_dlc, 8) data = bytes(frame.data[:size]) if kind == _FRAME_ERROR or frame.flags & 0x01: self.bus_error.emit(frame.can_id & 0x1FFFFFFF if kind == _FRAME_ERROR else 0, data, frame.flags) if kind == _FRAME_ECHO: - self.transmit_echo.emit(api.dll.candle_frame_id(ct.byref(frame)), data, + self.transmit_echo.emit(frame.can_id & 0x1FFFFFFF, data, # Маска выделяет идентификатор без приведения FD-структуры к указателю Classic. bool(frame.can_id & 0x80000000), bool(frame.can_id & 0x40000000)) elif kind == _FRAME_RECEIVE: - self.capture_received.emit(api.dll.candle_frame_id(ct.byref(frame)), + self.capture_received.emit(frame.can_id & 0x1FFFFFFF, # Сохраняем STD/EXT ID независимо от выбранной структуры приёма. data, bool(frame.can_id & 0x80000000), bool(frame.can_id & 0x40000000)) - self.frame_received.emit(api.dll.candle_frame_id(ct.byref(frame)), + self.frame_received.emit(frame.can_id & 0x1FFFFFFF, # Совместимый сигнал получает только Classic-кадры, обработанные выше. data) def close(self) -> None: diff --git a/python/set_devices/qt_ports/console.py b/python/set_devices/qt_ports/console.py new file mode 100644 index 0000000..d223377 --- /dev/null +++ b/python/set_devices/qt_ports/console.py @@ -0,0 +1,180 @@ +"""Общая консоль Qt: ограниченная история и инструменты просмотра без управления транспортом.""" # Модуль относится к порту представления templates и не реализует протоколы устройств. +from collections import deque # Кольцевая история ограничивает память при непрерывном обмене. +from html import escape # Текст устройства не должен становиться HTML-разметкой журнала. +from pathlib import Path # Экспорт сохраняет явно выбранный пользователем файл в UTF-8. +import csv # Стандартный CSV корректно экранирует кавычки, разделители и пустые строки журнала. +import json # JSON сохраняет строки с кириллицей без потери символов и дополнительного разбора протоколов. +import re # Метки направления извлекаются только из начала строки после необязательного времени. +try: # Поддерживаем актуальный Qt и существующие установки на Python для Windows 7. + from PySide6.QtCore import QTimer, Signal # Таймер объединяет обновления заполненного журнала. + from PySide6.QtGui import QFont, QTextDocument # Документ извлекает обычный текст из уже оформленных сообщений приложения. + from PySide6.QtWidgets import QApplication, QCheckBox, QComboBox, QFileDialog, QHBoxLayout, QLabel, QLineEdit, QMessageBox, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget # Панель использует только стандартные элементы Qt. +except ImportError: # Старый порт сохраняет тот же публичный интерфейс консоли. + from PySide2.QtCore import QTimer, Signal # В Qt 5 доступны те же сигналы и таймеры. + from PySide2.QtGui import QFont, QTextDocument # Цвета и извлечение текста не зависят от версии Qt. + from PySide2.QtWidgets import QApplication, QCheckBox, QComboBox, QFileDialog, QHBoxLayout, QLabel, QLineEdit, QMessageBox, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget # Состав инструментов одинаков в обоих портах. + + +class ConsoleView(QPlainTextEdit): # Наследование сохраняет привычные appendPlainText, appendHtml и toPlainText у потребителей. + userCleared = Signal() # Владелец отдельной истории может удалить её при явном нажатии «Очистить». + + def __init__(self, parent=None, limit=4000, directions=True, payloads=False): # Предел задан в строках, включая скрытые и поступившие на паузе. + super().__init__(parent) # Владельца редактора впоследствии принимает контейнер panel. + self.records = deque(maxlen=max(1, int(limit))) # Каждая запись хранит текст, оформление, направление и необязательные байты. + self.setReadOnly(True) # Журнал показывает полученные события и не допускает ручной подмены текста. + self.setFont(QFont("Cascadia Mono", 9)) # Моноширинный шрифт выравнивает HEX, адреса и метки времени. + super().setMaximumBlockCount(self.records.maxlen) # Документ ограничен тем же количеством строк, что история. + self.timer = QTimer(self) # Таймер уничтожается вместе с редактором и не переживает закрытие вкладки. + self.timer.setSingleShot(True) # За одну пачку входящих строк достаточно одного полного обновления. + self.timer.setInterval(100) # Интервал 100 мс ограничивает перестроения десятью в секунду при полном буфере. + self.timer.timeout.connect(self.refresh) # Перестроение всегда читает последние записи и текущие фильтры. + self.panel = QWidget(parent) # Контейнер можно вставить в layout или вкладку вместо самого редактора. + layout = QVBoxLayout(self.panel) # Две компактные строки инструментов остаются над областью текста. + layout.setContentsMargins(0, 0, 0, 0) # Внешние отступы задаёт приложение-потребитель. + actions = QHBoxLayout() # Основные операции сгруппированы отдельно от фильтров просмотра. + self.clear_button = QPushButton("Очистить") # Очистка удаляет также скрытую историю и накопленное на паузе. + self.clear_button.clicked.connect(self._user_clear) # Сигнал владельцу позволяет очистить дополнительный буфер кадров. + actions.addWidget(self.clear_button) # Очистка постоянно доступна у левого края консоли. + self.pause = QCheckBox("Пауза") # Пауза замораживает экран, продолжая сохранять входящие сообщения. + actions.addWidget(self.pause) # Пауза относится только к этому экземпляру журнала. + self.follow = QCheckBox("Автопрокрутка") # Прокрутку можно отключить для чтения старых записей. + self.follow.setChecked(True) # По умолчанию новые события видны сразу. + actions.addWidget(self.follow) # Управление расположено рядом с паузой просмотра. + for title, callback in (("Копировать", self.copy_visible), ("Сохранить…", self.save_dialog), ("−", lambda: self.zoomOut(1)), ("+", lambda: self.zoomIn(1))): # Масштаб меняется на один шаг Qt без изменения данных. + button = QPushButton(title) # Кнопки используют тему и шрифт приложения. + button.clicked.connect(callback) # Обработчик вызывается только по явному действию пользователя. + actions.addWidget(button) # Одинаковый порядок действий используется всеми консолями. + actions.addStretch(1) # Свободное место не растягивает подписи инструментов. + layout.addLayout(actions) # Основная строка отделена от параметров отображения. + filters = QHBoxLayout() # Поиск и направления занимают вторую строку для умеренной минимальной ширины. + self.search = QLineEdit() # Фильтр работает по обычному тексту всех сохранённых строк. + self.search.setPlaceholderText("Поиск / фильтр текста") # Подпись показывает, что скрытые строки остаются в истории. + filters.addWidget(self.search, 1) # Поле поиска получает свободную ширину консоли. + self.show_tx, self.show_rx = QCheckBox("TX", self.panel), QCheckBox("RX", self.panel) # Родитель назначается до setVisible, чтобы фильтры направлений не появлялись отдельными окнами при сборке консоли. + for control in (self.show_tx, self.show_rx): # Оба фильтра действуют независимо и применяются к истории. + control.setChecked(True) # Первое открытие показывает весь обмен. + control.setVisible(directions) # Потребители со своими фильтрами могут скрыть дублирующие элементы. + filters.addWidget(control) # Направления расположены рядом с текстовым фильтром. + self.display = QComboBox(self.panel) # Родитель исключает отдельное окно при setVisible(payloads); формат относится только к сообщениям с явно переданными байтами. + self.display.addItems(("Как получено", "HEX", "ASCII", "HEX + ASCII")) # Обычный текст и ответы устройства не перекодируются. + self.display.setToolTip("HEX/ASCII применяется к байтам, переданным через append_message(payload=…).") # Приложение явно определяет границы полезной нагрузки. + self.display.setVisible(payloads) # Выбор байтового представления показывается только потребителю с явным payload. + filters.addWidget(self.display) # Представление можно менять без повторной передачи данных. + self.wrap = QCheckBox("Перенос") # Перенос длинных строк удобен на узких панелях. + filters.addWidget(self.wrap) # Переключатель не изменяет исходный текст при экспорте. + self.count = QLabel() # Счётчик показывает объём ограниченной истории, включая скрытые строки. + filters.addWidget(self.count) # Количество остаётся видно при включённом фильтре. + layout.addLayout(filters) # Параметры находятся непосредственно над текстом. + layout.addWidget(self, 1) # Редактор занимает оставшуюся высоту контейнера. + for control in (self.pause, self.show_tx, self.show_rx, self.follow): # Изменения параметров применяются к уже накопленным данным. + control.toggled.connect(self.refresh) # Снятие паузы показывает сохранённые во время неё события. + self.search.textChanged.connect(self.refresh) # Поиск немедленно обновляет видимую часть истории. + self.display.currentIndexChanged.connect(self.refresh) # Выбор HEX/ASCII заново форматирует сохранённый payload. + self.wrap.toggled.connect(lambda checked: self.setLineWrapMode(QPlainTextEdit.WidgetWidth if checked else QPlainTextEdit.NoWrap)) # Отключённый перенос сохраняет горизонтальную прокрутку. + self.setLineWrapMode(QPlainTextEdit.NoWrap) # Начальный режим совпадает с выключенным флажком переноса. + self.refresh() # Пустой журнал сразу получает корректный счётчик. + + def setMaximumBlockCount(self, limit): # Сохраняем совместимость с существующими настройками журналов SETGUI. + self.records = deque(self.records, maxlen=max(1, int(limit))) # Предел ограничивает и скрытую историю, а не только документ. + super().setMaximumBlockCount(self.records.maxlen) # Согласуем вместимость редактора с кольцевым буфером. + self.refresh() # Уменьшение лимита сразу удаляет вытесненные строки с экрана. + + def append_message(self, text, direction="", color=None, payload=None, _html=None, _defer=False): # Принимаем готовый текст и данные, не выполняя разбор протокола. + for line in str(text).split("\n"): # Многострочные расшифровки также подчиняются общему лимиту строк. + match = re.match(r"^(?:\[[^\]]+\]\s*|\d\d:\d\d:\d\d(?:\.\d+)?\s*)?(TX|RX|>>>)\s", line) # Направление распознаётся только у начальной метки, а не по словам внутри ошибки. + role = direction or (("TX" if match[1] == ">>>" else match[1]) if match else "") # Явная роль имеет приоритет над текстовой эвристикой. + html = _html or ('%s' % (escape(color, quote=True), escape(line)) if color else "") # Безопасное оформление сохраняет исходный текст устройства. + record = (line, html, role, bytes(payload) if payload is not None else None) # Снимок payload не зависит от последующих изменений входного bytearray. + expired = len(self.records) == self.records.maxlen # Вытеснение требует убрать старую строку даже при скрытых новых событиях. + self.records.append(record) # На паузе и под фильтрами данные продолжают сохраняться в пределах лимита. + if not self.pause.isChecked() and not _defer: # Пауза и пакетная замена замораживают документ, но не историю. + if expired or self.timer.isActive(): # Заполненный буфер обновляется пачками для устойчивого интенсивного приёма. + if not self.timer.isActive(): self.timer.start() # Следующие события не отодвигают уже запланированное обновление. + elif self._visible(record): self._append_record(record) # Обычный поток дописывает одну строку без переразбора всей истории. + self.count.setText("%d строк" % len(self.records)) # Счётчик истории обновляется даже при замороженном экране. + + def appendPlainText(self, text): # Старые потребители могут продолжать писать обычный текст. + self.append_message(text) # Ограничения, пауза и фильтры применяются через единый путь записи. + + def appendHtml(self, html): # Прежнее цветное оформление приложения остаётся доступно через API QPlainTextEdit. + document = QTextDocument() # Временный документ преобразует форматированный фрагмент в строки для поиска. + document.setHtml(html) # Разметка поступает от приложения; внешние данные оно должно экранировать. + text = document.toPlainText() # Обычный текст используется для поиска и определения направления. + self.append_message(text, _html=html if "\n" not in text else None) # Однострочное оформление сохраняется без полного обновления истории. + + def setPlainText(self, text): # Снимок внешней истории полностью заменяет данные этого представления. + self.timer.stop() # Старое отложенное обновление не должно вернуть предыдущий снимок. + self.records.clear() # Сохраняется только актуальный результат форматирования потребителя. + if text: self.append_message(text, _defer=True) # Пустой снимок не создаёт фиктивную запись. + self.refresh() # Поиск и фильтры применяются к новому снимку целиком. + + def clear(self): # Программная очистка удаляет все данные и отменяет ожидающее обновление. + self.timer.stop() # Запланированное обновление больше не требуется. + self.records.clear() # Скрытые записи и накопленное на паузе не должны вернуться. + super().clear() # Явная очистка действует сразу даже при замороженном экране. + self.count.setText("0 строк") # Счётчик согласован с удалённой историей. + + def _user_clear(self): # Только действие оператора уведомляет владельца внешней истории. + self.clear() # Сначала очищаем собственный буфер и видимый документ. + self.userCleared.emit() # Потребитель может безопасно вызвать clear повторно без рекурсивного сигнала. + + def _visible(self, record): # Единое условие применяется при добавлении и полном обновлении. + text, _html, role, _payload = record # Поиск использует исходный текст сообщения независимо от выбранного формата байтов. + return (role != "TX" or self.show_tx.isChecked()) and (role != "RX" or self.show_rx.isChecked()) and self.search.text().casefold() in text.casefold() # Служебные сообщения сохраняются при отключённых направлениях. + + def _append_record(self, record): # Добавляем одну подготовленную запись, учитывая формат и положение прокрутки. + text, html, _role, payload = record # Байты присутствуют только при явной передаче payload приложением. + bar, position = self.verticalScrollBar(), self.verticalScrollBar().value() # Запоминаем позицию до изменения размера документа. + horizontal, offset = self.horizontalScrollBar(), self.horizontalScrollBar().value() # Автопрокрутка по вертикали не должна сбрасывать просмотр длинной строки по горизонтали. + mode = self.display.currentIndex() # Нулевой режим сохраняет текст и цвета, заданные потребителем. + if payload is not None and mode: # Формат меняет только подписанную приложением полезную нагрузку. + hexadecimal = payload.hex(" ").upper() # HEX показывает каждый исходный байт двумя цифрами. + ascii_text = "".join(chr(value) if 32 <= value <= 126 else "." for value in payload) # Диапазон печатного ASCII задан стандартом; управляющие байты заменяются точками. + super().appendPlainText(text + " · " + (hexadecimal if mode == 1 else ascii_text if mode == 2 else hexadecimal + " | " + ascii_text)) # Исходная подпись не теряется при смене представления байтов. + elif html: super().appendHtml(html) # Сохраняем безопасное оформление или прежний фрагмент приложения. + else: super().appendPlainText(text) # Обычный текст не интерпретируется как HTML. + bar.setValue(bar.maximum() if self.follow.isChecked() else position) # Отключённая автопрокрутка сохраняет место чтения. + horizontal.setValue(offset) # Дописывание строки сохраняет выбранный горизонтальный участок журнала. + + def refresh(self, *_args): # Сигналы Qt могут передавать индекс, флаг или текст. + self.timer.stop() # Немедленное обновление заменяет ожидающее пакетное перестроение. + if self.pause.isChecked(): return # Изменения фильтров во время паузы применятся после её снятия. + bar, position = self.verticalScrollBar(), self.verticalScrollBar().value() # Сохраняем место чтения до очистки документа. + horizontal, offset = self.horizontalScrollBar(), self.horizontalScrollBar().value() # Фильтрация и пакетное обновление не должны возвращать длинные строки к левому краю. + super().clear() # Очищаем только документ, сохраняя ограниченную историю. + for record in self.records: # Показываем оставшиеся записи в исходном порядке. + if self._visible(record): self._append_record(record) # Скрытые строки остаются доступными для следующего выбора фильтра. + bar.setValue(bar.maximum() if self.follow.isChecked() else min(position, bar.maximum())) # При сокращении документа ограничиваем прежнюю позицию новым диапазоном. + horizontal.setValue(offset) # Qt ограничивает прежнее смещение текущей шириной документа после перестроения. + self.count.setText("%d строк" % len(self.records)) # Счётчик включает временно скрытые записи. + + def copy_visible(self): # Экспортируется фактически показанный текст, включая состояние паузы и фильтра. + QApplication.clipboard().setText(self.toPlainText()) # Копирование всей видимой консоли не требует ручного выделения. + + def save_to(self, path, file_format=None): # Явный формат используется диалогом, а прямой вызов определяет формат по расширению файла. + destination = Path(path) # Путь может поступить строкой от Qt или объектом Path от вызывающего кода. + file_format = (file_format or destination.suffix.lstrip(".") or "txt").lower() # Имена расширений нечувствительны к регистру; без расширения сохраняется прежний TXT. + if file_format not in ("csv", "json", "txt"): # Не допускаем сохранения текста под видом неподдерживаемого формата. + raise ValueError("Выберите формат CSV, JSON или TXT") # Ошибка доступна как прямому вызывающему коду, так и диалогу. + text = self.toPlainText() # Единый снимок учитывает фильтры, формат байтов и замороженный на паузе экран. + rows = [{"line": index, "text": line} for index, line in enumerate(text.split("\n"), 1)] if text else [] # Нумерация с единицы сохраняет порядок и пустые строки расшифровки. + if file_format == "csv": # Табличное представление содержит номер строки и её полный текст. + with destination.open("w", encoding="utf-8-sig", newline="") as stream: # BOM помогает Excel распознать кириллицу; newline исключает лишние пустые строки в Windows. + writer = csv.DictWriter(stream, fieldnames=("line", "text")) # Стабильные имена столбцов позволяют обрабатывать журналы скриптами. + writer.writeheader() # Даже пустой журнал получает корректную схему CSV. + writer.writerows(rows) # Стандартный писатель экранирует кавычки и запятые без изменения содержимого. + elif file_format == "json": # Массив объектов сохраняет ту же схему строк, что CSV. + destination.write_text(json.dumps(rows, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") # Читаемый UTF-8 сохраняет кириллицу и валидный пустой массив. + else: # TXT остаётся точной текстовой копией показанного журнала. + destination.write_text(text, encoding="utf-8") # Прежний контракт сохранения TXT не добавляет заголовки или номера строк. + + def save_dialog(self): # Пользователь самостоятельно выбирает назначение журнала. + filters = "CSV UTF-8 (*.csv);;JSON UTF-8 (*.json);;Текст UTF-8 (*.txt)" # Все консоли предлагают одинаковые три формата; CSV выбран первым. + path, selected_filter = QFileDialog.getSaveFileName(self, "Сохранить консоль", "console", filters) # Имя без расширения позволяет выбрать любой формат без ручной замены суффикса. + if path: # Записываем только явно выбранный файл. + file_format = Path(path).suffix.lstrip(".").lower() # Явно введённое поддерживаемое расширение имеет приоритет над фильтром диалога. + if file_format not in ("csv", "json", "txt"): # Если расширение отсутствует или неизвестно, применяем выбранный формат. + file_format = "json" if "*.json" in selected_filter else "txt" if "*.txt" in selected_filter else "csv" # При отсутствии фильтра Qt используется первый предложенный формат CSV. + path += "." + file_format # Итоговое расширение всегда соответствует фактически записанному формату. + try: self.save_to(path, file_format) # Обрабатываем отказ файловой системы без прерывания приёма данных. + except (OSError, ValueError) as error: QMessageBox.warning(self, "Сохранение консоли", str(error)) # Причина ошибки остаётся доступна оператору. diff --git a/python/set_devices/qt_ports/plot_drag.py b/python/set_devices/qt_ports/plot_drag.py index da1f936..88c8e00 100644 --- a/python/set_devices/qt_ports/plot_drag.py +++ b/python/set_devices/qt_ports/plot_drag.py @@ -14,7 +14,7 @@ except ImportError: DRAG_HINT = ('ЛКМ рядом с маркером — двигать маркер; ЛКМ на свободном поле — ' - 'перемещение по X; Ctrl + ЛКМ или Shift + ЛКМ — перемещение по Y. ' + 'перемещение по X; Ctrl + ЛКМ — перемещение по Y; Shift + ЛКМ — по Y со стороны начала жеста. ' # Для двух шкал Shift выбирает сторону в точке нажатия и сохраняет её до отпускания кнопки. 'Щелчок мимо маркеров — одиночный курсор.') @@ -34,7 +34,7 @@ def cursor_hit(plot, position, value, event, radius=8): class PlotDragInteraction: """Capture a hit marker or pan one axis, chosen at the start of the drag.""" - def _capture_y_pan(self): + def _capture_y_pan(self, event=None): # Необязательное событие нажатия позволяет владельцу двух шкал выбрать одну Y; клавиатура передаёт только исходную область. return self.viewport def _apply_y_pan(self, fraction, initial): @@ -58,7 +58,7 @@ class PlotDragInteraction: self.setFocus(Qt.MouseFocusReason) self._press = QPointF(pos) self._press_viewport = self.viewport - self._press_y_pan = self._capture_y_pan() + self._press_y_pan = self._capture_y_pan(event) # Фиксируем выбранную шкалу и её исходный диапазон при нажатии, чтобы пересечение центра не меняло цель перетаскивания. self._press_markers = self.markers self._press_bounds = self.visible_bounds self._pan_vertical = vertical_pan_requested(event) diff --git a/python/set_devices/qt_ports/plot_dual_axis.py b/python/set_devices/qt_ports/plot_dual_axis.py index f57dfc7..70f6f23 100644 --- a/python/set_devices/qt_ports/plot_dual_axis.py +++ b/python/set_devices/qt_ports/plot_dual_axis.py @@ -8,6 +8,13 @@ except ImportError: from PySide2.QtCore import QPointF, Qt from PySide2.QtGui import QColor from protocan.plot import Bounds, Viewport +from set_devices.plot_ticks import tick_precision # Обе амплитудные шкалы должны различать соседние деления даже при сильном приближении. + + +def amplitude_axis_margin(widget, bounds): # Отступ правой шкалы зависит от ширины её уточнённых подписей в текущем шрифте виджета. + step = (bounds.top - bounds.bottom) / max(100, widget.height() / 50) # Консервативная плотность делений даёт запас точности без обращения к геометрии, которая сама вычисляет этот отступ. + labels = [f'{value:.{tick_precision(value, step)}g}' for value in (bounds.bottom, bounds.top)] # Оцениваем самые длинные крайние подписи в том же формате, что используется при отрисовке шкалы. + return max(72, 14 + max(widget.fontMetrics().horizontalAdvance(label) for label in labels)) # Прежний минимум 72 пикселя и запас 14 пикселей сохраняют обычный вид и предотвращают обрезание длинных чисел. def small_amplitude(values, threshold=30): @@ -32,7 +39,8 @@ def split_amplitudes(series, threshold=30): class DualAxisPlot: """Mixin: left axis for large channels, right for small channels. - Shift-wheel selects the axis by the pointer's half of the analog pane. + Ctrl + колесо выбирает шкалу по половине аналоговой области под указателем. + Shift + ЛКМ перемещает одну Y, выбранную стороной графика при нажатии. The host supplies series_bounds/project_series rendering hooks. """ def __init__(self, *args, **kwargs): @@ -115,23 +123,28 @@ class DualAxisPlot: def plot_rect(self): rect = super().plot_rect() if self.right_axis_keys: - rect.setWidth(max(1, rect.width() - 72)) + rect.setWidth(max(1, rect.width() - self.right_axis_margin())) # Уточнённые подписи правой Y получают достаточно места без выхода за границы виджета. return rect def right_axis_margin(self): - return 72 if self.right_axis_keys else 0 + return amplitude_axis_margin(self, self.right_visible_bounds) if self.right_axis_keys else 0 # Используем фактический правый диапазон и текущий шрифт; при отсутствии правой шкалы отступ не нужен. def reset_viewport(self): self.right_viewport = Viewport() super().reset_viewport() - def _capture_y_pan(self): - return super()._capture_y_pan(), self.right_viewport + def _capture_y_pan(self, event=None): # Снимок содержит области выбранных шкал; None исключает другую шкалу из всего текущего жеста. + left, right = super()._capture_y_pan(event), self.right_viewport # Сохраняем начальные области до движения, чтобы смещение считалось от точки нажатия без накопления ошибок. + if event is not None and event.modifiers() & Qt.ShiftModifier and self.right_axis_keys and self.has_left_axis(): # Выбор стороны нужен только для Shift с двумя отдельными Y; Ctrl, стрелки и единственная Y сохраняют общий перенос. + position = event.position() if hasattr(event, 'position') else event.localPos() # Получаем локальную точку нажатия одинаково для Qt 6 и Qt 5. + return (None, right) if position.x() >= self.value_rect().center().x() else (left, None) # Центр аналоговой области разделяет стороны; на самой границе выбираем правую Y, как при Ctrl с колесом. + return left, right # Общие команды перемещения получают обе области, а график с одной Y использует свою основную область. def _apply_y_pan(self, fraction, initial): left, right = initial - super()._apply_y_pan(fraction, left) - if self.core and not self.lock_y and self.right_axis_keys and self.has_left_axis(): + if left is not None: # Отсутствующая левая область означает, что Shift выбрал только правую шкалу при нажатии. + super()._apply_y_pan(fraction, left) # Общий обработчик перемещает левую Y и учитывает её фиксацию без изменения временной оси. + if right is not None and self.core and not self.lock_y and self.right_axis_keys and self.has_left_axis(): # Правая Y сдвигается лишь при включении в снимок жеста, наличии двух шкал и снятой общей фиксации Y. self.right_viewport = right.transform(self.core, pan_y=fraction) def reset_interaction(self): @@ -139,7 +152,7 @@ class DualAxisPlot: super().reset_interaction() def wheelEvent(self, event): - if not event.modifiers() & Qt.ShiftModifier: + if not event.modifiers() & Qt.ControlModifier: # Ctrl включает масштаб Y выбранной стороны; колесо без Ctrl, включая Shift, передаётся общей навигации по X. return super().wheelEvent(event) pos = event.position() if hasattr(event, 'position') else event.posF() rect = self.value_rect() @@ -177,7 +190,7 @@ def paint_right_axis(painter, core, rect, bounds): for index in range(count): value = (first + index) * step y = rect.top() + bounds.fraction(core, value, True) * rect.height() - painter.drawText(QPointF(rect.right() + 7, y + 4), f'{value:.4g}') + painter.drawText(QPointF(rect.right() + 7, y + 4), f'{value:.{tick_precision(value, step)}g}') # Сохраняем четыре значащие цифры при обычном масштабе и добавляем разряды по шагу правой шкалы при приближении. painter.restore() @@ -189,7 +202,7 @@ class SingleAmplitudeAxis: def plot_rect(self): rect = super().plot_rect() if not self.has_left_axis(): - rect.setWidth(max(1, rect.width() - 72)) + rect.setWidth(max(1, rect.width() - amplitude_axis_margin(self, self.visible_bounds))) # Единственная правая шкала тренда или спектра получает тот же запас для длинных подписей при приближении. return rect def paint_axes(self, painter): diff --git a/python/set_devices/qt_ports/plot_navigation.py b/python/set_devices/qt_ports/plot_navigation.py index 0fbbe27..72dfe4a 100644 --- a/python/set_devices/qt_ports/plot_navigation.py +++ b/python/set_devices/qt_ports/plot_navigation.py @@ -10,7 +10,8 @@ except ImportError: from PySide2.QtCore import Qt from PySide2.QtWidgets import QScrollArea -NAVIGATION_HINT = ('Колесо и +/− — масштаб X; Ctrl + колесо и Ctrl + +/− — масштаб Y. ' +NAVIGATION_HINT = ('Колесо и +/− — масштаб X; Ctrl + колесо — масштаб Y со стороны указателя; ' # Поясняем выбор левой или правой амплитудной шкалы по положению указателя при удерживаемом Ctrl. + 'Ctrl + +/− — масштаб Y. ' # Клавиатурный масштаб Y сохраняет прежнее поведение без выбора стороны указателем. 'ЛКМ — перемещение по X; Ctrl + ЛКМ — по Y; ' '←/→ — перемещение по X; ↑/↓ — по Y; Home/End — начало/конец.') diff --git a/python/set_devices/qt_ports/plot_workers.py b/python/set_devices/qt_ports/plot_workers.py index 27d5b97..1c296b3 100644 --- a/python/set_devices/qt_ports/plot_workers.py +++ b/python/set_devices/qt_ports/plot_workers.py @@ -1,24 +1,27 @@ """Reusable background workers for dense plots and viewport measurements.""" +from collections import deque # Кольцевые очереди живого графика требуют единого снимка между проходами амплитудной статистики и частоты. try: from PySide6.QtCore import QObject, QRunnable, Signal except ImportError: from PySide2.QtCore import QObject, QRunnable, Signal -from set_devices.plot_decimation import pixel_envelope, viewport_samples +from set_devices.plot_decimation import pixel_envelope, render_envelope, viewport_samples # Рабочее задание поддерживает точный прежний формат и компактную экранную огибающую для аналогового графика. from set_devices.oscilloscope import measurements +from set_devices.background_work import WorkBudget # Даже фоновый Python-расчёт должен регулярно отдавать GIL многочисленным обработчикам интерфейса Qt. class EnvelopeSignals(QObject): ready = Signal(str, object, object) class EnvelopeJob(QRunnable): - def __init__(self, key, geometry, timestamps, values, left, right, width, signals): + def __init__(self, key, geometry, timestamps, values, left, right, width, signals, compact=False): # Необязательный режим оставляет прежний контракт внешних пользователей, а аналоговый график включает два экстремума на столбец. super().__init__() self.args = (timestamps, values, left, right, width) self.key, self.geometry, self.signals = key, geometry, signals + self.select = render_envelope if compact else pixel_envelope # Выбор алгоритма выполняется один раз при создании задания, не внутри многомиллионного обхода. def run(self): try: - points = tuple(pixel_envelope(*self.args)) + points = tuple(self.select(*self.args)) # Фоновый результат сохраняет точные пики и разрывы в согласованном с рисователем экранном бюджете. except Exception: points = None try: @@ -31,18 +34,43 @@ class NavigationSignals(QObject): ready = Signal(int, object, object) +class _NavigationSamples: # Повторяемая выборка окна позволяет измерять исходные ряды без копии миллионов пар координат. + def __init__(self, times, values, bounds, check_cancelled): # Храним источники задания; вызывающий код создаёт снимок изменяемых очередей перед численными проходами. + self.times, self.values, self.bounds, self.check_cancelled = times, values, bounds, check_cancelled # Ссылки сохраняют исходную точность и порядок без экранного сокращения. + self.count = 0 # Число отсчётов определяется при первом полном проходе и включает нечисловые амплитуды, как прежний список. + + def __iter__(self): # Статистики и частота независимо обходят то же окно, не удерживая промежуточные пары в памяти. + count = 0 # Каждый проход считает только точки внутри включительных временных границ. + for index, (x, y) in enumerate(viewport_samples(self.times, self.values, self.bounds.left, self.bounds.right)): # Индексируемый источник ищет окно двоичным поиском; потоковый сохраняет прежний порядок. + if index % 1024 == 0: # Проверяем отмену через 1024 просмотренных отсчёта, даже когда неупорядоченный ряд лежит вне окна. + self.check_cancelled() # Не продолжаем чтение старого диапазона после нового жеста навигации. + if self.bounds.left <= x <= self.bounds.right: # Включаем обе границы и все дубликаты временных меток, как исходная реализация. + count += 1 # Счётчик соответствует прежнему len(points), независимо от конечности амплитуды. + yield x, y # Пара существует только на время текущего численного прохода и не копируется в большой список. + self.count = count # Публикуем количество только после полного прохода, чтобы отменённая выборка не выдавала частичный результат. + + class NavigationJob(QRunnable): - def __init__(self, revision, series, bounds, emitter): + def __init__(self, revision, series, bounds, emitter, cancelled=None): # Необязательное событие отмены сохраняет совместимость общих графиков и останавливает устаревшие измерения. super().__init__() self.revision, self.series, self.bounds, self.emitter = revision, series, bounds, emitter + self.cancelled = cancelled # Событие принадлежит одному заданию и не сбрасывается при запуске расчёта нового окна. + self.work_budget = WorkBudget(cancelled) # Короткие добровольные паузы предотвращают многосекундное ожидание GIL главным потоком. + + def _check_cancelled(self): # Проверяем отмену на границах этапов и небольших блоков исходных отсчётов. + self.work_budget() # Одновременно прекращаем устаревшие измерения и регулярно освобождаем GIL для рисования и событий мыши. def run(self): stats = {} try: for key, times, values in self.series: - points = [(x, y) for x, y in viewport_samples(times, values, self.bounds.left, self.bounds.right) - if self.bounds.left <= x <= self.bounds.right] - stats[key] = measurements(points), len(points) + self._check_cancelled() # Не начинаем обход следующего канала после возобновления перемещения или изменения масштаба. + samples = _NavigationSamples(times, values, self.bounds, self._check_cancelled) # Повторяемый вид файлового окна устраняет копирование миллионов пар и сохраняет отмену чтения источника. + ordered = getattr(times, "ordered", isinstance(times, (list, tuple, range))) # Применяем тот же контракт упорядоченности, что и viewport_samples, включая смещённые файловые координаты. + points = tuple(samples) if isinstance(times, deque) or isinstance(values, deque) or not ordered else samples # Только живые очереди и неупорядоченный путь получают единый снимок для согласованных амплитуд и частоты. + result = measurements(points, self._check_cancelled) # Передаём отмену внутрь всех численных этапов, чтобы новый жест не ждал окончания полного среднего или СКЗ. + stats[key] = result, samples.count # Количество относится к завершённому проходу того же окна либо к первоначальному снимку живого ряда. + self._check_cancelled() # При отмене во время вычислений не продолжаем остальные каналы и не публикуем устаревшие значения. self.emitter.ready.emit(self.revision, stats, self.bounds) except Exception: try: diff --git a/python/set_devices/qt_ports/qcustomplot_renderer.py b/python/set_devices/qt_ports/qcustomplot_renderer.py index 726ad4f..111d179 100644 --- a/python/set_devices/qt_ports/qcustomplot_renderer.py +++ b/python/set_devices/qt_ports/qcustomplot_renderer.py @@ -6,6 +6,8 @@ from pathlib import Path import subprocess import tempfile from threading import Lock +import math # Кодируем разрывы кривой нечисловыми значениями Y, сохраняя упорядоченные координаты X для нативного движка. +from set_devices.plot_decimation import pixel_envelope # Передаём движку только точки, различимые при текущем масштабе изображения. try: from PySide6.QtCore import QObject, QRunnable, Signal except ImportError: @@ -44,19 +46,26 @@ class NativePlotEngine: self.process = subprocess.Popen([str(self.executable)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=env, bufsize=0, creationflags=getattr(subprocess, 'CREATE_NO_WINDOW', 0), cwd=self.executable.parent) - key = (id(times), id(values)) + key = (id(times), id(values), len(times), len(values), bounds.left, bounds.right, width) # Выборка зависит от исходного снимка, окна X и физической ширины изображения; масштаб Y её не меняет. record = self.records.get(key) if record is None: self.serial += 1 path = Path(self.directory.name) / f'{self.serial}.bin' + points = [] # Временный список ограничен экранной шириной и не содержит миллионов исходных измерений. + for point in pixel_envelope(times, values, bounds.left, bounds.right, width): # Сохраняем первый, минимальный, максимальный и последний отсчёты каждого пиксельного столбца. + if point is not None: # Конечные измерения передаются с исходными координатами и амплитудами. + points.append(point) # Экстремумы остаются видимыми даже для импульса длиной в один исходный отсчёт. + elif points and math.isfinite(points[-1][1]): # Повторные маркеры одного разрыва не должны увеличивать размер передаваемого ряда. + points.append((points[-1][0], math.nan)) # Дублированная метка времени и NaN в Y разрывают путь без нарушения порядка X. with path.open('wb') as stream: - array('d', times).tofile(stream) - array('d', values).tofile(stream) - record = (path, times, values) + array('d', (point[0] for point in points)).tofile(stream) # Записываем только экранные координаты X в прежнем формате 64-битных чисел. + array('d', (point[1] for point in points)).tofile(stream) # Массив Y соответствует сокращённому X и включает маркеры разрывов. + record = (path, times, values, len(points)) # Ссылки сохраняют идентичность исходного снимка; длина описывает только передаваемый экранный ряд. self.records[key] = record if len(self.records) > 4: - self.records.pop(next(iter(self.records))) - request = dict(file=str(record[0]), count=len(times), width=width, height=height, + expired = self.records.pop(next(iter(self.records))) # Оставляем четыре последние экранные выборки, как и в кэше нативного процесса. + expired[0].unlink(missing_ok=True) # Освобождаем устаревший временный файл, чтобы навигация не накапливала данные на диске. + request = dict(file=str(record[0]), count=record[3], width=width, height=height, # Нативному процессу сообщается фактическое число отрисовываемых точек вместо полного размера записи. left=bounds.left, right=bounds.right, bottom=bounds.bottom, top=bounds.top, color=color) self.process.stdin.write((json.dumps(request)+'\n').encode()) self.process.stdin.flush() diff --git a/python/set_devices/qt_ports/slcan_adapter.py b/python/set_devices/qt_ports/slcan_adapter.py index 1a6748a..a09787e 100644 --- a/python/set_devices/qt_ports/slcan_adapter.py +++ b/python/set_devices/qt_ports/slcan_adapter.py @@ -7,8 +7,11 @@ from __future__ import annotations from dataclasses import dataclass +from collections import deque # Храним ограниченную историю FD для отдельного просмотра диагностики. +from ..can_adapter_settings import SlcanOptions, FD_LENGTHS # Профиль прошивки определяет команды и допустимые длины CAN FD. +import re # Поиск ближайшего служебного байта за один проход сохраняет скорость при пакетном приёме большого числа CAN-кадров. -from .qt_compat import QObject, Signal +from .qt_compat import QObject, Signal, QElapsedTimer, QTimer # Таймеры ограничивают ожидание ответов и откладывают выдачу кадров до окончания настройки. from .qt_compat import QSerialPort, QSerialPortInfo @@ -33,11 +36,7 @@ class SlcanChannel: return "slcan" -_BITRATE_COMMANDS = { - 10_000: "S0", 20_000: "S1", 50_000: "S2", 100_000: "S3", - 125_000: "S4", 250_000: "S5", 500_000: "S6", 800_000: "S7", - 1_000_000: "S8", -} +_RECORD_END = re.compile(rb"[\r\n\x07]") # CR, LF и BEL имеют коды ASCII 13, 10 и 7; любой из них завершает запись протокола. def encode_frame(can_id: int, data: bytes, *, extended: bool | None = None) -> bytes: @@ -80,6 +79,7 @@ class SlcanAdapter(QObject): frame_received = Signal(int, bytes) capture_received = Signal(int, bytes, bool, bool) connection_lost = Signal(str) + fd_received = Signal(int, bytes, bool, int, int) # Отдельный маршрут FD исключает ошибочный разбор кадра как Classic CAN. def __init__(self, parent: QObject | None = None) -> None: super().__init__(parent) @@ -88,10 +88,19 @@ class SlcanAdapter(QObject): self._serial.errorOccurred.connect(self._error) self._buffer = bytearray() self._listen_only = False + self.options = SlcanOptions() # Без расширенных параметров остаётся прежний подтверждаемый протокол Lawicel. + self.fd_history = deque(maxlen=500) # Не более 500 последних FD-кадров сохраняется между открытиями окна просмотра. + self._query_prefix = None # Диагностические ответы отличаем от подтверждений настройки и CAN-кадров. + self._query_reply = None # Полная строка ответа сохраняется только во время явного диагностического запроса. + self._initializing = False # Открытие COM-порта ещё не подтверждает настройку CAN-контроллера. + self._waiting_command = False # Отличаем подтверждение текущей команды от служебных строк рабочего потока. + self._command_reply: bool | None = None # None означает ожидание, True — CR/ACK, False — BEL/отказ прошивки. + self._after_cr = False # Следующий LF после CR относится к тому же окончанию строки, даже при раздельных USB-пакетах. + self._pending_frames: list[tuple[int, bytes, bool]] = [] # Кадры при открытии CAN сохраняются до готовности подписчиков монитора. @property def connected(self) -> bool: - return self._serial.isOpen() + return self._serial.isOpen() and not self._initializing # Считаем соединение готовым только после подтверждения всех команд настройки. def scan(self) -> list[SlcanChannel]: # Windows не предоставляет надёжного признака протокола SLCAN. @@ -102,11 +111,11 @@ class SlcanAdapter(QObject): def connect_channel(self, channel: SlcanChannel, bitrate: int, host_baudrate: int = 115200, - listen_only: bool = False) -> None: + listen_only: bool = False, *, options: SlcanOptions | None = None) -> None: # Расширенные параметры передаются отдельно от прежнего контракта подключения. + selected = options or SlcanOptions() # Дефолт сохраняет C, Sn и O/L с ожиданием CR/BEL. + commands = selected.commands(bitrate, listen_only) # Проверяем весь профиль до закрытия прежнего соединения и открытия COM. self.disconnect_channel() - command = _BITRATE_COMMANDS.get(bitrate) - if command is None: - raise SlcanError(f"SLCAN не поддерживает {bitrate} бит/с") + self.options = selected # Настройка ожидания команд нужна уже во время инициализации порта. self._serial.setPortName(channel.path) if host_baudrate not in (9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600): @@ -119,23 +128,67 @@ class SlcanAdapter(QObject): if not self._serial.open(QSerialPort.OpenModeFlag.ReadWrite): raise SlcanError(f"Не удалось открыть {channel.path}: {self._serial.errorString()}") self._buffer.clear() + self.fd_history.clear() # Журнал нового подключения не содержит сообщений прежнего устройства. self._listen_only = listen_only - # Close first so reconnecting also works after an interrupted session. - open_command = "L" if listen_only else "O" - if self._serial.write(f"C\r{command}\r{open_command}\r".encode("ascii")) < 0: - message = self._serial.errorString() - self._serial.close() - self._listen_only = False - raise SlcanError(f"Не удалось настроить SLCAN: {message}") + self._initializing = True # Во время настройки не выдаём ложный статус готовности и первые кадры с прежней скоростью CAN. + try: # Любой отказ настройки должен закрыть порт и разрешить повторную попытку подключения. + self._command("C", allow_rejection=True) # Закрываем прежний канал; BEL допустим, если канал уже закрыт по правилам Lawicel. + for command in commands: # Профиль определяет порядок скорости, режима, фильтров, повторов и открытия. + self._command(command) # Любой отказ прекращает настройку без опасного возврата к активному режиму. + except SlcanError: # Отказ прошивки, неполная запись и отсутствие ответа одинаково означают неудачное подключение. + self._serial.close() # Освобождаем COM-порт, чтобы пользователь мог исправить скорость или тип адаптера. + self._buffer.clear() # Остатки неудачного обмена не должны повреждать строки следующего подключения. + self._pending_frames.clear() # Не отправляем в монитор данные сеанса, который не удалось открыть. + self._listen_only = False # Сбрасываем ограничение режима вместе с неудачным подключением. + raise # Сохраняем точную причину отказа для статусной строки вызывающей вкладки. + finally: # Признак настройки должен сбрасываться как при успехе, так и при исключении. + self._initializing = False # После возврата вызывающая вкладка сможет установить правильную скорость и статус. + QTimer.singleShot(0, self._read) # Выдаём накопленные первые кадры в следующем цикле Qt, после обновления настроек монитора. + + def _command(self, command: str, *, allow_rejection: bool = False) -> None: # Последовательный обмен сохраняет синхронный контракт подключения всех вкладок. + self._read() # Убираем ранее пришедшие ответы до начала ожидания новой команды. + self._command_reply = None # Старое подтверждение не может подтверждать следующую настройку. + self._waiting_command = True # Пустая строка CR или отдельный BEL теперь относятся к текущей команде. + packet = (command + "\r").encode("ascii") # Каждая команда Lawicel передаётся отдельной строкой с завершающим ASCII CR. + elapsed = QElapsedTimer() # Монотонное время не зависит от перевода системных часов Windows. + elapsed.start() # Общий срок ожидания включает запись команды и все фрагменты ответа. + try: # Флаг ожидания обязательно очищается при любом результате обмена. + if self._serial.write(packet) != len(packet): # Частичная локальная запись также не гарантирует передачу полной команды адаптеру. + raise SlcanError(f"SLCAN: не удалось передать {command}: {self._serial.errorString()}") # Указываем неотправленную команду и причину драйвера. + if self.options.profile in ("canable", "canable2"): # Эти прошивки не предоставляют CR/BEL для подтверждения конфигурации. + if self._serial.bytesToWrite() and not self._serial.waitForBytesWritten(self.options.command_timeout_ms): # Ждём фактическую передачу очереди Qt в драйвер, а не выдуманный ACK. + raise SlcanError(f"CANable: не удалось отправить {command}") # Ошибка локального драйвера не считается успешным подключением. + self._serial.waitForReadyRead(20) # Пауза до 20 мс даёт прошивке обработать отдельную команду USB CDC. + self._read() # Сохраняем уже пришедшие CAN-кадры, не требуя неподдерживаемого служебного ответа. + if self._command_reply is False or not self._serial.isOpen(): # Не игнорируем явный BEL и отключение даже в профиле без ACK. + raise SlcanError(f"CANable: отказ при выполнении {command}") # Пользователь получает конкретный этап неудачной настройки. + return # Статус интерфейса отдельно сообщает, что профиль не подтверждает команды. + while self._command_reply is None and self._serial.isOpen(): # CAN-кадры между служебными ответами не заменяют подтверждение команды. + remaining = self.options.command_timeout_ms - elapsed.elapsed() # Общий выбранный тайм-аут включает все фрагменты ответа команды. + if remaining <= 0: # Поток посторонних байтов не должен удерживать подключение в ожидании навсегда. + break # Далее сформируем понятную ошибку отсутствия SLCAN-ответа. + if self._serial.bytesAvailable() or self._serial.waitForReadyRead(remaining): # Используем уже поступившие байты или ждём только в пределах общего срока. + self._read() # Тот же обработчик разбирает ответы CR/BEL и сохраняет встреченные CAN-кадры. + else: # Драйвер завершил ожидание без новых данных либо порт был отключён. + break # Не запускаем повторный полный тайм-аут на ту же команду. + if not self._serial.isOpen(): # Физическое отключение во время настройки не является подтверждением команды. + raise SlcanError(f"SLCAN: порт закрыт при выполнении {command}: {self._serial.errorString()}") # Сообщаем о потере порта на конкретном этапе. + if self._command_reply is None: # Успешное открытие COM и запись в драйвер сами по себе не доказывают поддержку Lawicel. + raise SlcanError(f"SLCAN: нет ответа на {command}; проверьте тип адаптера и скорость COM") # Направляем пользователя к настройкам, влияющим на обмен ASCII-командами. + if not self._command_reply and not allow_rejection: # Только отказ повторного C при уже закрытом канале допускается протоколом настройки. + raise SlcanError(f"SLCAN: адаптер отклонил команду {command} (BEL)") # Отказ скорости или режима CAN больше не маскируется статусом подключения. + finally: # После команды подтверждения рабочего потока больше не меняют результат настройки. + self._waiting_command = False # Возвращаем обработчик приёма в обычный режим. def disconnect_channel(self) -> None: - if not self._serial.isOpen(): - return - self._serial.write(b"C\r") - self._serial.waitForBytesWritten(100) - self._serial.close() - self._buffer.clear() - self._listen_only = False + if self._serial.isOpen(): # Команда закрытия нужна только для реально открытого COM-порта. + self._serial.write(b"C\r") # Просим прошивку остановить CAN до освобождения порта. + self._serial.waitForBytesWritten(100) # Ограничиваем ожидание отправки закрытия ста миллисекундами, чтобы не задерживать выход. + self._serial.close() # Освобождаем порт независимо от доступности прошивки. + self._buffer.clear() # Частичная строка прежнего сеанса не должна приклеиваться к первому кадру нового подключения. + self._pending_frames.clear() # Отложенный обработчик Qt не должен выдавать кадры после отключения или переподключения. + self._after_cr = False # Новый сеанс начинает разбор окончаний строк без состояния предыдущего CR. + self._listen_only = False # Отключённый транспорт не сохраняет ограничение старого режима. def send(self, can_id: int, data: bytes, *, extended: bool = True) -> None: if not self.connected: @@ -149,24 +202,109 @@ class SlcanAdapter(QObject): raise SlcanError(f"SLCAN не передал CAN-кадр: {self._serial.errorString()}") def _read(self) -> None: - self._buffer.extend(bytes(self._serial.readAll())) - while b"\r" in self._buffer: - raw, _, remainder = self._buffer.partition(b"\r") - self._buffer[:] = remainder - frame = decode_frame(raw) - if frame is not None: - self.capture_received.emit(frame[0], frame[1], raw[:1] == b'T', False) - self.frame_received.emit(*frame) + if not self._serial.isOpen(): # Отложенное чтение после закрытия не должно обращаться к неоткрытому драйверу. + return # Отключение уже очистило очередь и неполную строку. + self._buffer.extend(bytes(self._serial.readAll())) # Накапливаем фрагменты USB/COM до полного кадра или служебного ответа. + while self._buffer: # За одно чтение драйвер может вернуть несколько кадров и подтверждений команд. + if self._after_cr: # CR+LF считается одним окончанием, даже если LF пришёл в следующем чтении. + self._after_cr = False # Состояние относится только к ближайшему байту после CR. + if self._buffer[0] == 10: # ASCII LF имеет код 10 и не является началом следующего SLCAN-кадра. + del self._buffer[0] # Удаляем дополнительный LF, чтобы он не мешал распознаванию t/T и не давал второй ACK. + continue # Продолжаем с первого байта следующей записи, если он уже поступил. + boundary = _RECORD_END.search(self._buffer) # Ищем первый разделитель, не сканируя весь остаток пакета отдельно для отсутствующих LF и BEL. + if boundary is None: # Неполную строку нельзя декодировать до поступления окончания. + break # Сохраняем её в буфере для следующего readyRead. + end = boundary.start() # Ближайшая граница сохраняет исходный порядок кадров и подтверждений команд. + raw = bytes(self._buffer[:end]) # Получаем строку без служебного разделителя. + separator = self._buffer[end] # Тип разделителя отличает подтверждение команды от BEL. + del self._buffer[:end + 1] # Удаляем обработанную запись, не теряя оставшуюся часть потока. + self._after_cr = separator == 13 # ASCII CR имеет код 13; следующий LF принадлежит этому же окончанию. + if separator == 7: # ASCII BEL имеет код 7 и сообщает об отклонении последней команды. + if self._waiting_command and self._command_reply is None: # Принимаем только первый ответ текущего этапа настройки. + self._command_reply = False # Сохраняем отказ для проверки в последовательном обмене командами. + continue # BEL не должен приклеиваться к следующему CAN-кадру. + if self.options.fd and raw[:1] in (b"d", b"D", b"b", b"B") and self._receive_fd(raw): # Только корректная FD-строка забирается отдельным маршрутом; версия CANable может начинаться с HEX-буквы. + continue # Даже FD с данными до восьми байтов не меняет тип при передаче подписчикам. + frame = decode_frame(raw) # Кадры STD/EXT декодируются прежним публичным кодеком. + if frame is not None: # Служебные строки и ответы прошивки не попадают в общий монитор CAN. + self._pending_frames.append((frame[0], frame[1], raw[:1] == b"T")) # Сохраняем данные и признак EXT, включая первые кадры во время открытия. + elif raw and self._query_prefix is not None and raw.startswith(self._query_prefix): # Диагностические строки распознаются только после исключения CAN-кадров. + self._query_reply = raw.decode("ascii", errors="replace") # Версия CANable не имеет префикса V, поэтому допускается пустой ожидаемый префикс. + elif not raw and self._waiting_command and self._command_reply is None: # Пустая строка CR означает ACK по Lawicel; строка с CAN-кадром не подтверждает команду. + self._command_reply = True # Разрешаем отправку следующей команды только после реального подтверждения. + if not self._initializing: # Первые кадры выдаются после возврата подключения, когда вкладка уже установила скорость CAN. + pending, self._pending_frames = self._pending_frames, [] # Отделяем очередь до вызова подписчиков, чтобы повторное чтение не дублировало кадры. + for can_id, data, extended in pending: # Выдаём все накопленные кадры в исходном порядке. + self.capture_received.emit(can_id, data, extended, False) # Полные метаданные наполняют общий CAN-монитор. + self.frame_received.emit(can_id, data) # Совместимый сигнал сохраняет работу существующих клиентов ProtoCAN. def _error(self, error: QSerialPort.SerialPortError) -> None: - if error in (QSerialPort.SerialPortError.NoError, - QSerialPort.SerialPortError.NotOpenError): - return + if error in (QSerialPort.SerialPortError.NoError, # Сигнал NoError не означает потерю соединения. + QSerialPort.SerialPortError.NotOpenError, # Обращение после закрытия не требует повторного отключения. + QSerialPort.SerialPortError.TimeoutError): # Тайм-аут синхронного ожидания проверяет сама команда; порт при этом остаётся исправным. + return # Не превращаем отсутствие ответа на команду в ошибку физического соединения. if self._serial.isOpen(): message = self._serial.errorString() self._serial.close() self._listen_only = False - self.connection_lost.emit(f"Связь с SLCAN прервана: {message}") + if not self._initializing: # При настройке исключение возвращает connect_channel, избегая повторного отключения из обработчика GUI. + self.connection_lost.emit(f"Связь с SLCAN прервана: {message}") # Во время обычного приёма уведомляем вкладку о настоящем обрыве. def close(self) -> None: self.disconnect_channel() + + def _receive_fd(self, raw: bytes) -> bool: # Результат отличает корректный FD от диагностической строки с похожей первой буквой. + extended = raw[:1] in (b"D", b"B") # Заглавная буква означает идентификатор длиной восемь HEX-цифр. + width = 8 if extended else 3 # Стандартный ID занимает три HEX-цифры в ASCII-протоколе. + try: # Сохраняем устойчивость потока при повреждённых USB/COM-строках. + identifier = int(raw[1:1 + width], 16) # Извлекаем числовой ID без префикса команды. + length = FD_LENGTHS[int(raw[1 + width:2 + width], 16)] # Четырёхбитный DLC переводится в фактическое число байтов. + payload = bytes.fromhex(raw[2 + width:].decode("ascii")) # Для CANable FD не документирован дополнительный суффикс временной метки. + except (ValueError, UnicodeError, IndexError): # Неполный ID, DLC или HEX-пара отклоняют только текущую запись. + return False # Неподходящая строка ещё может оказаться ответом версии CANable. + if len(payload) != length or not 0 <= identifier <= (0x1FFFFFFF if extended else 0x7FF): # Не обрезаем лишние байты и не принимаем отрицательный ID или идентификатор другого формата. + return False # Повреждённые данные не должны выглядеть успешным приёмом. + record = (identifier, payload, extended, 2 | (4 if raw[:1] in (b"b", b"B") else 0), 0) # CANable не предоставляет аппаратную метку; ноль явно обозначает её отсутствие. + self.fd_history.append(("RX", record)) # История ограничена размером deque и доступна после открытия диагностики. + self.fd_received.emit(*record) # В мост и прикладной декодер Classic этот кадр не поступает. + return True # Вызывающий обработчик не должен повторно трактовать этот кадр как служебный ответ. + + def send_fd(self, can_id: int, data: bytes, *, extended: bool = True, brs: bool = True) -> None: # Используем документированные команды расширения CANable 2.0. + if not self.connected or self._listen_only or not self.options.fd: # Проверка защищает передачу независимо от состояния кнопок GUI. + raise SlcanError("Передача FD требует активного подключения CAN FD") # Пассивный режим не допускает обхода через API. + if len(data) not in FD_LENGTHS or not 0 <= can_id <= (0x1FFFFFFF if extended else 0x7FF): # Разрешаем только точные длины DLC без скрытого дополнения. + raise SlcanError("Неверный CAN ID или длина CAN FD (0…8, 12, 16, 20, 24, 32, 48, 64)") # Сообщаем фактический набор допустимых размеров. + prefix = ("B" if extended else "b") if brs else ("D" if extended else "d") # BRS выбирается буквой команды, а не полем ASCII-пакета. + packet = f"{prefix}{can_id:0{8 if extended else 3}X}{FD_LENGTHS.index(len(data)):X}{data.hex().upper()}\r".encode("ascii") # ID, DLC и данные образуют одну завершённую строку SLCAN. + if self._serial.write(packet) != len(packet): # Частичная запись не гарантирует доставку последнего CR в прошивку. + raise SlcanError("SLCAN не передал CAN FD") # Причина остаётся видимой в диагностическом окне отправки. + self.fd_history.append(("TX queued", (can_id, bytes(data), extended, 2 | (4 if brs else 0), 0))) # Локальная запись не выдаётся за подтверждение передачи на CAN. + + def diagnostics(self) -> str: # Явная диагностика не меняет режим CAN и не выполняется фоновым таймером. + if not self.connected: # Чтение версии не должно захватывать ещё не выбранный COM-порт. + raise SlcanError("Сначала подключите адаптер") # Настройка и жизненный цикл подключения остаются под управлением пользователя. + lines = [] # Ответы V и N читают сведения, F дополнительно сбрасывает индикатор ошибки согласно Lawicel. + canable = self.options.profile != "lawicel" # CANable возвращает V без буквенного префикса, а регистр E иногда без завершающего CR. + if canable: # Отсутствие подтверждения настроек сообщается независимо от успешного чтения версии. + lines.append(f"Профиль {self.options.profile}: команды конфигурации без ACK/NACK; применение настроек не подтверждается прошивкой.") # Диагностика не превращает ответ V в подтверждение предыдущих M/A/Y. + for command in (("V", "E") if canable else ("V", "N", "F")): # Набор фиксирован спецификацией выбранной прошивки. + self._read() # Сначала выдаём уже накопленные CAN-кадры, не смешивая их с ответом запроса. + self._query_prefix, self._query_reply = (b"" if canable else command.encode("ascii")), None # CANable не использует префикс V в строке версии. + elapsed = QElapsedTimer() # Ограничиваем полный запрос монотонным временем, а не числом фрагментов. + elapsed.start() # Тайм-аут включает отправку и все поступившие строки CAN. + try: # Состояние запроса очищается также при ошибке записи или обрыве порта. + packet = (command + "\r").encode("ascii") # Все команды завершаются одиночным CR протокола Lawicel. + if self._serial.write(packet) != len(packet): # Локальная ошибка передачи должна быть видна вызывающему коду. + raise SlcanError(f"Не удалось отправить {command}") # Указываем конкретный отказавший диагностический запрос. + while self._query_reply is None and self.connected: # Приём CAN-кадров продолжается тем же обработчиком. + remaining = self.options.command_timeout_ms - elapsed.elapsed() # Поток кадров не должен бесконечно продлевать ожидание версии. + if remaining <= 0 or not (self._serial.bytesAvailable() or self._serial.waitForReadyRead(remaining)): # Отсутствие ответа завершает только текущий запрос. + break # Следующие строки диагностики покажут, какая команда не поддерживается. + self._read() # Ответ распознаётся по префиксу, а CAN продолжает поступать обычным подписчикам. + if command == "E" and self._buffer.startswith(b"CANable Error Register:"): # Документированная исходная прошивка может возвращать E без CR. + self._query_reply = bytes(self._buffer).decode("ascii", errors="replace") # Такой ответ принимаем только после завершения ожидания, не обрезая поток CAN. + self._buffer.clear() # Нетерминированная служебная строка не должна приклеиваться к следующему CAN-кадру. + lines.append(self._query_reply or f"{command}: нет ответа") # Отсутствие данных не заменяем выдуманными версией или нулевыми ошибками. + finally: # Следующий обычный приём не должен сохранять посторонние строки как ответ старого запроса. + self._query_prefix = None # Завершаем явную диагностическую транзакцию. + return "\n".join(lines) # Текст можно скопировать для анализа состояния устройства. diff --git a/python/set_devices/qt_ports/viewport_navigation.py b/python/set_devices/qt_ports/viewport_navigation.py index a662265..8f60e41 100644 --- a/python/set_devices/qt_ports/viewport_navigation.py +++ b/python/set_devices/qt_ports/viewport_navigation.py @@ -1,5 +1,6 @@ """Debounced viewport statistics shared by desktop charts.""" import time +from threading import Event # Сигнал отмены позволяет фоновому расчёту прекращать обработку старого окна при продолжении масштабирования. from dataclasses import replace try: from PySide6.QtCore import QObject, QTimer, QThreadPool, Qt @@ -16,6 +17,7 @@ class ViewportNavigation(QObject): self.chart = chart self._navigation_revision = 0 self._navigation_busy = False + self._navigation_cancel = Event() # Отдельное потокобезопасное событие относится к текущему фоновому расчёту измерений. self._navigation_emitter = _NavigationSignals(self) self._navigation_emitter.ready.connect(self._navigation_ready, Qt.ConnectionType.QueuedConnection) self._navigation_timer = QTimer(self) @@ -25,6 +27,7 @@ class ViewportNavigation(QObject): def _navigation_changed(self): self._navigation_revision += 1 + self._navigation_cancel.set() # Сразу отменяем статистику предыдущего окна, чтобы она не конкурировала с новой отрисовкой миллионов отсчётов. if max((len(s.values) for s in self.chart.plot._series), default=0) <= 20000: self.chart._scope_measurements() self.chart._refresh_processing() @@ -43,15 +46,16 @@ class ViewportNavigation(QObject): self._navigation_timer.start() return self._navigation_busy = True + self._navigation_cancel = Event() # После окончания перемещения создаём новый независимый сигнал отмены для актуального окна. bounds = self.chart.plot.visible_bounds panel = self.chart.processing offset = self.chart._plot_time_offset if not self.chart.fft.isChecked() else 0. # Navigation changes the next calculation's domain; retained curves keep # their original domain. Avoid preparing millions of inputs on the UI. panel._snapshot = replace(panel._snapshot, x_range=(bounds.left + offset, bounds.right + offset)) - series = [(s.key, s.timestamps, s.values) for s in self.chart.plot._series if not s.discrete] - QThreadPool.globalInstance().start(_NavigationJob(self._navigation_revision, series, bounds, - self._navigation_emitter)) + series = [(s.key, s.timestamps, s.values) for s in self.chart.plot._series if s.visible and not s.discrete] # Скрытые каналы не занимают процессор повторным расчётом статистики при перемещении графика. + QThreadPool.globalInstance().start(_NavigationJob(self._navigation_revision, series, bounds, # Фоновый расчёт использует полные исходные значения только актуального видимого окна. + self._navigation_emitter, self._navigation_cancel)) # Передаём событие отмены вместе с существующими ревизией и каналом результата. def _navigation_ready(self, revision, stats, bounds): self._navigation_busy = False diff --git a/python/set_devices/tms_terminal.py b/python/set_devices/tms_terminal.py index d51f17a..6d4ef17 100644 --- a/python/set_devices/tms_terminal.py +++ b/python/set_devices/tms_terminal.py @@ -43,9 +43,9 @@ CRC_TAIL = 3 #: Границы настройки в GUI: меньше одного поля смысла нет, больше не бывает. MIN_DIGIT_BYTES = 1 -MAX_DIGIT_BYTES = 64 +MAX_DIGIT_BYTES = 96 # Ответ 22220 содержит 70 дискретных байт; предел 96 оставляет запас в пределах буфера UART прошивки на 512 байт. MIN_ANALOG_COUNT = 1 -MAX_ANALOG_COUNT = 64 +MAX_ANALOG_COUNT = 128 # Ответ 22220 содержит 80 знаковых слов; 128 слов вместе с дискретами помещаются в 512-байтовый буфер прошивки. #: Номера команд, enum в конце RS_Functions.h. COMMAND_NAMES: Dict[int, str] = { diff --git a/python/tests/test_byte_work_panel.py b/python/tests/test_byte_work_panel.py index 3fda8c2..a488b36 100644 --- a/python/tests/test_byte_work_panel.py +++ b/python/tests/test_byte_work_panel.py @@ -120,9 +120,11 @@ def test_read_accepts_address_formats_and_displays_both_values(page, address): widget, protocol = page widget.byte_read_address.setText(address) widget.byte_read_button.click() + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert protocol.requests == [(0x1000, None, 7)] - assert not widget.byte_read_button.isEnabled() + assert widget.byte_read_button.isEnabled() # Ручная кнопка принимает новые запросы, пока текущее чтение ожидает ответ. protocol.reply(True, {"value": 0xABCD}) + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert widget.byte_read_address.text() == "$1000" assert widget.byte_read_value.text() == "ABCD" assert widget.byte_read_binary.text() == "1010 1011 1100 1101" @@ -144,6 +146,7 @@ def test_invalid_inputs_do_not_send(page, address, value, binary): widget.byte_write_value.setText(value) widget.byte_write_binary.setText(binary) widget.byte_write_button.click() + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert protocol.requests == [] assert "Проверьте" in widget.status.text() @@ -156,11 +159,14 @@ def test_write_is_verified_and_controller_is_captured_for_whole_operation(page, widget.byte_write_value.setText("0301") widget.sync_byte_value("0301", 16) widget.byte_write_button.click() + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert protocol.requests == [(0x1000, 0x0301, 13)] controller[0] = 21 protocol.reply(True, {"raw": b"ack"}) + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert protocol.requests[-1] == (0x1000, None, 13) protocol.reply(True, {"value": readback}) + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert widget.byte_read_value.text() == f"{readback:04X}" assert ("Запись проверена" in widget.status.text()) == confirmed if not confirmed: @@ -171,18 +177,23 @@ def test_write_is_verified_and_controller_is_captured_for_whole_operation(page, def test_failure_and_cancellation_restore_controls_and_ignore_late_reply(page): widget, protocol = page widget.byte_read_button.click() + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. protocol.reply(False, "CRC ответа не совпадает") + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert widget.status.text() == "CRC ответа не совпадает" assert widget.byte_read_button.isEnabled() widget.byte_read_button.click() + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. late_reply = protocol.callback widget.stop() assert protocol.cancelled == 1 widget.byte_read_button.click() + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. late_reply(True, {"value": 0x9999}) assert widget.byte_read_value.text() == "" - assert not widget.byte_read_button.isEnabled() + assert widget.byte_read_button.isEnabled() # Ручная кнопка принимает новые запросы, пока текущее чтение ожидает ответ. protocol.reply(True, {"value": 0x1234}) + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. assert widget.byte_read_value.text() == "1234" assert widget.byte_read_button.isEnabled() @@ -193,19 +204,31 @@ def test_controller_provider_is_used_by_bus_raw_memory_and_macros(app, tmp_path) widget = ByteWorkPanel(protocol, device_address=lambda: controller[0], macros_file=tmp_path / "address.json") try: - widget.raw_widget.memory_write() - widget.raw_widget.memory_read() - assert protocol.requests == [(0x2000, 0, 21), (0x2000, None, 21)] - widget.bus_widget.read_from_bus() - assert protocol.requests[-2:] == [(0x200B, 0, 21), (0x200F, None, 21)] + widget.raw_widget.memory_write() # Первая операция сохраняет контроллер до ожидания общей очереди. + widget.raw_widget.memory_read() # Второе нажатие принимается до завершения первой записи. + QTest.qWait(15) # Запись получает владение общим соединением. + protocol.reply(True, {"raw": b"ack"}) # Подтверждаем текущую запись перед следующим чтением. + QTest.qWait(15) # Следующая ручная операция начинает PEEK. + protocol.reply(True, {"value": 0x1234}) # Возвращаем слово ручного чтения памяти. + QTest.qWait(15) # Освобождаем очередь после завершения второго действия. + assert protocol.requests == [(0x2000, 0, 21), (0x2000, None, 21)] # Оба нажатия используют контроллер своего исходного снимка. + widget.bus_widget.read_from_bus() # Последовательное чтение также выполняется асинхронно через общую очередь. + QTest.qWait(15) # Отправляем подготовку SBUS. + protocol.reply(True, {"raw": b"ack"}) # Подтверждение позволяет перейти к буферу SBUS. + QTest.qWait(15) # Отправляем чтение существующего регистра результата. + protocol.reply(True, {"value": 0x1234, "raw_response": {"raw": b"reply"}}) # Возвращаем слово последовательной шины. + QTest.qWait(15) # Завершаем логическую операцию перед явным макросом. + assert protocol.requests[-2:] == [(0x200B, 0, 21), (0x200F, None, 21)] # Адреса и формат существующей SBUS остаются прежними. widget.bus_widget.execute_macro_commands([{"type": "read", "tetrad": 3, "register": 5}]) controller[0] = 22 QTest.qWait(20) assert protocol.requests[-1] == (0x200B, 0x35, 21) protocol.reply(True, {"raw": b"ack"}) + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. QTest.qWait(20) assert protocol.requests[-1] == (0x200F, None, 21) protocol.reply(True, {"value": 0x4321, "raw_response": {"raw": b"reply"}}) + QTest.qWait(15) # Доставляем назначенный шаг общей очереди через события Qt без синхронной блокировки GUI. QTest.qWait(20) assert not widget.bus_widget._macro_running assert widget.bus_widget.bus_read_value_label.text() == "0x4321 (17185)" diff --git a/python/tests/test_console.py b/python/tests/test_console.py new file mode 100644 index 0000000..1b50ff1 --- /dev/null +++ b/python/tests/test_console.py @@ -0,0 +1,77 @@ +"""Проверки общей консоли на настоящем Qt без физического устройства.""" # Проверяем сохранность истории, фильтры и очистку при асинхронном обновлении. +import os # Виртуальная платформа выбирается до импорта Qt. +os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") # Тесты не открывают окна на рабочем столе. +import pytest # Фикстура даёт каждому сценарию независимую консоль. +from set_devices.qt_ports.console import ConsoleView, QApplication # Используем реальный порт templates, а не имитацию обработчиков. + + +@pytest.fixture # Создаём отдельный журнал для проверки независимости состояний. +def console(): # Ссылка на приложение удерживается до завершения сценария. + app = QApplication.instance() or QApplication([]) # Qt требует приложение перед созданием виджетов. + view = ConsoleView(limit=3, payloads=True) # Малый предел проверяет вытеснение без большого массива данных. + yield view # Сценарий управляет настоящими сигналами флажков и кнопок. + view.panel.deleteLater() # Удаляется контейнер вместе с редактором и таймером. + app.processEvents() # Отложенное удаление доставляется до следующего сценария. + + +def test_pause_keeps_bounded_history_and_clear_cannot_resurrect(console): # Очистка на паузе должна удалять также невидимые данные. + console.appendPlainText("первая") # Первая запись сразу видна на экране. + console.pause.setChecked(True) # Замораживаем только представление. + for index in range(5): console.appendPlainText("строка %d" % index) # На паузе поступает больше данных, чем помещается в истории. + assert console.toPlainText() == "первая" and len(console.records) == 3 # Экран заморожен, память ограничена. + console.pause.setChecked(False) # Возобновление показывает последние сохранённые строки. + assert console.toPlainText().splitlines() == ["строка 2", "строка 3", "строка 4"] # Вытеснённые записи больше не появляются. + console.appendPlainText("ожидает таймер") # Полный буфер ставит пакетное обновление в очередь. + assert console.timer.isActive() # Проверяем именно очистку при ожидающем обновлении. + console.pause.setChecked(True) # Очистка должна работать и при замороженном экране. + console.clear_button.click() # Пользователь удаляет весь журнал через общую панель. + console.pause.setChecked(False) # Возобновление не должно вернуть старые данные. + assert not console.records and not console.toPlainText() and not console.timer.isActive() # Документ, история и очередь согласованы. + + +def test_filters_restore_hidden_rows_and_preserve_service_errors(console): # Фильтры направлений не должны скрывать ошибки без метки TX/RX. + console.appendPlainText("[12:00:00] TX команда") # Начальная метка после времени определяет направление. + console.appendPlainText("12:00:01.123 RX ответ") # Поддерживаем существующий формат временных меток SETGUI. + console.appendPlainText("#ERR RX timeout") # Слово RX внутри ошибки не делает её принятым пакетом. + console.show_rx.setChecked(False) # Скрываем только входящие пакеты. + console.show_tx.setChecked(False) # Оба направления можно выключить одновременно. + assert console.toPlainText() == "#ERR RX timeout" # Служебная ошибка остаётся доступной оператору. + console.search.setText("ОТВЕТ") # Регистр запроса не должен влиять на поиск. + console.show_rx.setChecked(True) # Входящие данные восстанавливаются из сохранённой истории. + assert console.toPlainText() == "12:00:01.123 RX ответ" # Поиск применяется к той же записи без повторного приёма. + console.search.clear() # Снимаем текстовый фильтр. + assert len(console.records) == 3 # Фильтры не удаляют события. + + +def test_payload_and_utf8_export_use_visible_snapshot(console, tmp_path): # Сохранение и копирование соответствуют выбранному представлению. + console.append_message("RX пакет <текст>", direction="RX", payload=b"A\x00\xff") # Payload содержит печатный, управляющий и не-ASCII байты. + console.display.setCurrentText("HEX + ASCII") # Выбираем совместное представление байтов. + assert console.toPlainText() == "RX пакет <текст> · 41 00 FF | A.." # Непечатные байты заменяются точками без потери HEX. + path = tmp_path / "журнал.txt" # Проверяем кириллицу в имени и содержимом файла. + console.save_to(path) # Экспорт выполняется без диалога, сохраняя тот же код записи. + assert path.read_text(encoding="utf-8") == console.toPlainText() # UTF-8 сохраняет фактически видимый текст. + console.copy_visible() # Кнопка копирует весь показанный журнал. + assert QApplication.clipboard().text() == console.toPlainText() # Буфер обмена совпадает с экспортом. + + +def test_multiline_html_and_snapshot_obey_limit(console): # Предел относится к строкам, а не к числу вызовов записи. + console.appendPlainText("0\n1\n2\n3\n4") # Один пакет расшифровки превышает лимит документа и истории. + console.refresh() # Применяем запланированное пакетное обновление. + assert console.toPlainText() == "2\n3\n4" # Старые строки не возвращаются при смене фильтра. + console.setPlainText("снимок") # Потребитель может передать результат повторного разбора кадров целиком. + console.appendHtml('<ошибка>') # Проверяем совместимость прежнего цветного API SETGUI. + console.search.setText("ошибка") # Поиск должен работать по тексту без тегов разметки. + assert console.toPlainText() == "<ошибка>" # Спецсимволы устройства остаются обычным текстом. + console.search.clear() # Возвращаем обе записи с исходным оформлением. + assert console.toPlainText() == "снимок\n<ошибка>" # Фильтр не теряет предыдущий снимок истории. + + +def test_clear_notifies_external_owner_once(console): # Владелец может очистить свой буфер и повторно вызвать clear без рекурсии. + external = ["старый кадр"] # Имитируем отдельную историю протокольных кадров приложения. + def clear_owner(): # Обработчик очищает внешний источник повторного форматирования. + external.clear() # Старые кадры не вернутся после смены парсера. + console.clear() # Повторный программный вызов не должен снова эмитировать пользовательский сигнал. + console.userCleared.connect(clear_owner) # Подключаем тот же контракт, что консоли платы и TX/RX SETGUI. + console.appendPlainText("строка") # До очистки журнал содержит данные. + console.clear_button.click() # Нажимаем настоящую кнопку Qt. + assert not external and not console.toPlainText() # Обе истории очищены одним действием. diff --git a/python/tests/test_plot.py b/python/tests/test_plot.py index 11f14f1..fa89240 100644 --- a/python/tests/test_plot.py +++ b/python/tests/test_plot.py @@ -64,10 +64,28 @@ class PlotTests(unittest.TestCase): self.assertEqual(view.width, moved.width) expanded = moved.transform(self.core, zoom_x=.8) self.assertGreater(expanded.width, moved.width) - limited = view.transform(self.core, zoom_x=1e10) - self.assertEqual(1e-7, limited.width) + limited = view.transform(self.core, zoom_x=1e15) # Заведомо превышаем новый предел 10^12 раз, чтобы проверить ограничение без обнуления ширины. + self.assertEqual(1e-12, limited.width) # Минимальная доля полного диапазона X должна позволять приближение в 100 000 раз сильнее прежнего. self.assertEqual(limited, limited.transform(self.core, zoom_x=2)) + def test_deep_zoom_keeps_both_axes_navigable(self): # Проверяем совместное приближение X и Y, независимое перемещение, границы и возвращение к полному диапазону. + view = Viewport() # Начинаем с полного диапазона обеих осей без фиксации. + for _ in range(160): # 160 шагов с коэффициентом 1,25 проходят оба прежних предела и достигают нового ограничения 10^12 раз. + view = view.transform(self.core, zoom_x=1.25, zoom_y=1.25, focus_x=.3, focus_y=.7) # Увеличиваем вокруг разных опорных точек, чтобы обнаружить смешение осей. + self.assertAlmostEqual(.3, view.x + .3 * view.width, places=14) # Координата опоры X должна оставаться на месте даже при минимальной ширине. + self.assertAlmostEqual(.7, view.y + .7 * view.height, places=14) # Независимая опора Y не должна дрейфовать при многократном увеличении. + self.assertEqual((1e-12, 1e-12), (view.width, view.height)) # Обе оси достигают триллионной доли полного диапазона и не превращаются в нулевой интервал. + self.assertEqual(view, view.transform(self.core, zoom_x=2, zoom_y=2)) # Дополнительное увеличение на пределе сохраняет область без накопления смещения. + moved = view.transform(self.core, pan_x=.2, pan_y=-.2) # Сдвигаем X и Y в противоположные стороны на пятую часть текущего окна. + self.assertLess(moved.x, view.x) # Положительное экранное перемещение X уменьшает смещение области. + self.assertGreater(moved.y, view.y) # Отрицательное перемещение Y увеличивает её нормированное смещение. + self.assertEqual((view.width, view.height), (moved.width, moved.height)) # Перемещение не должно самопроизвольно менять достигнутое увеличение. + for direction in (-1e15, 1e15): # Большое перемещение в обе стороны проверяет ограничение краями полного диапазона. + edge = moved.transform(self.core, pan_x=direction, pan_y=direction) # Заведомо выходим за исходные границы по каждой оси. + self.assertGreaterEqual(min(edge.x, edge.y), 0) # Начало области остаётся внутри диапазона, а не уходит в отрицательные координаты. + self.assertLessEqual(max(edge.x + edge.width, edge.y + edge.height), 1) # Конец области не выходит за исходные данные. + self.assertEqual(Viewport(), moved.transform(self.core, zoom_x=1e-15, zoom_y=1e-15)) # Уменьшение с большим запасом возвращает полный диапазон и нулевые смещения. + def test_invalid_numeric_inputs_do_not_escape_to_painter(self): for value in (math.nan, math.inf, -math.inf): self.assertEqual(Viewport(), Viewport().transform(self.core, zoom_x=value)) diff --git a/tools/dsview/PLATES_BUSES.md b/tools/dsview/PLATES_BUSES.md new file mode 100644 index 0000000..691a0e1 --- /dev/null +++ b/tools/dsview/PLATES_BUSES.md @@ -0,0 +1,123 @@ +# Декодеры DSView для шин 96-контактного интерфейса + +Два независимых декодера: **Plates PBus** и **Plates SBus**. Показывают +адрес устройства, регистр, сырые 16-битные данные, результат проверок +и итог каждого обращения. Повторные одинаковые обращения выводятся отдельно. + +Декодеры устанавливаются в DSView и разбирают цифровой захват шин, +используемых с SETGUI. Формат взят из `ParallelBusSlave_ver_2_0.vhd` +и `SerialBusSlave_ver_2_0.vhd` из `ip_repo` репозитория PlatesSim. Зависимости +от установленного SETGUI или PlatesConf нет. Число 96 относится +к разъёму; ширина данных PBus составляет 16 бит. + +## Установка + +1. Закрыть DSView. +2. Скопировать обе папки `plates_pbus` и `plates_sbus` из `decoders` + в каталог `decoders` используемой установки DSView. Внутри каждой + папки должны непосредственно лежать `__init__.py` и `pd.py`. +3. Открыть DSView, загрузить захват или получить новый. +4. В списке декодеров выбрать **Plates PBus** либо **Plates SBus** + и назначить соответствующие каналы анализатора. При одновременном + захвате обеих шин добавить оба декодера. + +Используется sigrok API 3 и синтаксис Python 3.6+. Формат декодеров +сверён со штатными пакетами установленного DSView и +[исходниками DSView](https://github.com/DreamSourceLab/DSView/tree/master/libsigrokdecode4DSL/decoders). +Общие сведения о пользовательских декодерах — в +[инструкции производителя](https://dreamsourcelab.cn/logic-analyzer/protocol_decoder_howto/). + +## Каналы PBus + +| Сигнал декодера | Подключение | Назначение | +| --- | --- | --- | +| PBCE | `pbce` | Низкий уровень разрешает транзакцию | +| PBACK | `pback` | Подтверждения адреса, данных и инверсии | +| D0…D15 | `pbdata[0]`…`pbdata[15]` | Все 16 разрядов общей двунаправленной шины | +| PBCLK | `pbclk`, необязательно | Проверка уровня тактовой линии в фазах ответа | + +Для полного декодирования PBus требуется **18 каналов**, с PBCLK — 19. +Анализатор на 16 каналов не захватит полный набор одновременно. +Назначать D0…D15 по номерам разрядов шины, а номера контактов +96-контактного разъёма брать из схемы конкретной платы. + +Операция начинается со спада PBCE. Первый спад PBACK подтверждает адрес: +`PBDATA[15:8] = dev*16 + reg`, `PBDATA[7:0] = ~PBDATA[15:8]`. +Следующий подъём PBACK подтверждает 16-битные данные; следующий спад — +их 16-битную инверсию. При назначенном PBCLK данные должны подтверждаться +при CLK=0, инверсия — при CLK=1. Выборка слов выполняется по ACK. + +Неверная инверсия адреса, неверная инверсия ответа, нарушение фазы CLK +и незавершённое ожидание ACK выводятся отдельными предупреждениями. +Снятие CE до завершения или конец захвата сохраняют частичную операцию +с признаком `complete=False`. Начальный фрагмент захвата с уже низким CE +пропускается до следующего полного начала транзакции. + +## Каналы SBus + +| Сигнал декодера | Подключение | Направление | +| --- | --- | --- | +| SBCLK | `sbclk` | Тактовая линия мастера | +| SBDATAIN | `sbdatain` | ТМС → платы | +| SBDATAOUT | `sbdataout` | Платы → ТМС | + +Для SBus достаточно **трёх каналов**. Имена IN/OUT соответствуют +входу и выходу ведомого блока в HDL. + +Кадр содержит 29 бит старшим вперёд: направление (0 — чтение, +1 — запись), устройство (4), регистр (4), данные (16), CRC (4). +Декодер выбирает биты по нарастающим фронтам SBCLK. Заголовок и данные +записи идут по SBDATAIN; данные чтения и CRC ответа — по SBDATAOUT. +CRC учитывает все 25 бит направления, адреса и данных, а затем +четыре завершающие единицы по алгоритму HDL. Это собственный алгоритм, +его нельзя заменять произвольным штатным CRC-4. + +| Параметр | По умолчанию | Смысл | +| --- | --- | --- | +| Frame gap (us) | 3,6 мкс | Минимальное время неподвижного CLK для синхронизации нового кадра | +| Write ACK sampling delay (us) | 0,5 мкс | Задержка выборки SBDATAOUT после последнего бита CRC записи | + +Пауза учитывается при обоих уровнях CLK. Значение 3,6 мкс взято +из текущих COUNT_RESET=180 и частоты блока SBus 50 МГц. +Задержка ACK 0,5 мкс — настраиваемая точка наблюдения после проверки CRC +и до сброса по паузе. Для другого ведомого или других времён обмена +параметры нужно согласовать с захватом. Межкадровая пауза должна превышать +длительность обычного неподвижного участка CLK внутри кадра; +задержка ACK должна быть положительной и меньше межкадровой паузы. + +Низкий SBDATAOUT в точке выборки подтверждает запись. Высокий уровень +помечается `ACK HIGH (NACK / no response)`: по одному уровню нельзя +отличить отказ от отсутствия платы. CRC и ACK показываются независимо. +ACK frontend PlatesSim подтверждает CRC, но не доказывает помещение +команды в FIFO или её применение CPU1. + +Если файл закончился до выборки ACK, полная запись сохраняется с `ack=None`. +Частичный кадр отмечается числом полученных битов; следующий кадр +синхронизируется после паузы. В начале захвата SBus ожидает наблюдаемую +паузу, чтобы фрагмент уже идущего обмена не стал ложным заголовком. +При записи включать в захват паузу перед первым кадром и время после CRC. + +## Проверки и границы подтверждённого + +Из корня репозитория: + +```powershell +python -m unittest discover -s tools/dsview/tests -p test_plates_buses.py -v # Проверка декодеров на цифровых трассах без запуска DSView. +``` + +21 тест проверяет оба направления SBus, CRC, отдельную выборку ACK, +повторы, паузы обоих уровней, восстановление синхронизации, края диапазонов +PBus, обе инверсные проверки, фазы ACK, отсутствие каналов и обрывы захвата. +Среда тестов исполняет рабочие методы `decode()` и `end()` через подмену +API ожидания событий; сигналы формируются независимо от автоматов декодеров. +Дополнительно проверены синтаксис Python 3.6 и UTF-8 исходников. + +Загрузка новых пакетов в интерфейсе DSView и захват физического обмена +с SETGUI пока не проверены. Номера контактов разъёма и соответствие каналам +анализатора задаются по фактическому подключению. Модели отдельных линий +TK/PWM/ACK в эти декодеры не входят. + +Python-выход каждого декодера содержит `['FRAME', словарь]`. Общие поля: +`bus`, `operation`, `dev`, `reg`, `value`. У SBus отдельно доступны `crc`, +`crc_expected`, `crc_ok`, `ack`; у PBus — `address_word`, `address_ok`, +`inverse`, `inverse_ok`, `errors`, `complete`, `ok`. diff --git a/tools/dsview/README.md b/tools/dsview/README.md index 2417921..e096361 100644 --- a/tools/dsview/README.md +++ b/tools/dsview/README.md @@ -103,6 +103,41 @@ segmentation, timing-profile and sigrok API boundary tests. SETGUI's decoder dialogs, single/all removal with Yes/No, stacking and child lifetime. The check saves decoder dialog screenshots alongside the report. +## Application protocols from templates + +SET CAN includes the current shared parsers and dictionaries. Select +`Protocol / протокол` in the decoder settings: + +- `protocan` / `devboard`: ProtoCAN/SETCAN, GAS, Settings, boot services, + discrete and analog messages, device names and assigned GAS IDs. +- `balsam`: Balsam 167, including the actual rotating wire-word order and + separate operator-panel IDs. +- `ump-protocan`: UMP 1/2 with the explicitly selected `gas167` local map or + `assigned` global IDs. Assigned IDs do not imply firmware support. +- `deif`: DEIF XDi-192 / CANopen with STD CAN frames and physical values. +- `legacy`: explicitly select a project from the shared catalog: + Буксир, СЭДБМ, Ледокол, Бальзам, 23550, 23550.X, 23550.2, Янтарь, 23550 БСУ. +- `set-v2`: segmented SET v2, with CRC, sequence and timeout checks. +- `auto`: Balsam IDs, the SET v2 transport prefix, otherwise ProtoCAN. + Project-specific legacy formats and UMP maps always require explicit selection. + +Frames, Fields, Registers, Payload and Errors are separate annotation rows. +SET UART can apply the same non-segmented CAN profiles inside the AA55 bridge; +its Bridge settings select the profile, project and UMP map/node. + +TMS UART stacks on UART and reads `TMS_TO_TERMINAL` using the shared terminal +parser. Choose a preset layout or `custom` with discrete-byte/analog-word +counts, plus MODBUS or CCITT-FALSE CRC. For a 22220 reply, select `custom`, +70 discrete bytes and 80 analog words. RX/TX buffers are independent; +UART errors and configured gaps discard incomplete data. Only frames with +valid CRC are emitted. This decoder covers terminal telemetry layouts; +variable-length TMS bootloader/memory exchanges are not terminal telemetry. + +`protocol-files.json` is the single payload manifest for the embedded builder +and the standalone installer. Canonical Python modules and JSON maps are +copied unchanged into the private decoder runtime; no GUI imports or external +Python packages are required. Restart DSView after updating the decoders. + ## Annotation search The patch searches every enabled result column of the selected decoder and @@ -171,3 +206,22 @@ The decoder selector starts with **Пользовательские**: IGBT 1SP/ Transistor pair, SET UART, SET CAN and PM35 UART. **Стандартные** contains the remaining decoders. Search matches names and IDs in both sections and hides empty section headings. The changes are packaged in `decoder-panel.patch`. + + +## Шины 96-контактного интерфейса: Plates PBus / Plates SBus + +В общую ведомость поставки включены `plates_pbus` и `plates_sbus`. +Они устанавливаются вместе с остальными анализаторами, включаются в +будущую сборку embedded DSView и работают непосредственно с logic-каналами. +Назначение сигналов, формат обмена, параметры CRC/ACK и ограничения захвата +описаны в [PLATES_BUSES.md](PLATES_BUSES.md). + +В checkout SETGUI запуск `buildb_bat/INSTALL_DSVIEW_DECODERS.bat` без +параметров выбирает `dist/dsview`; при отсутствии полного компонента там +проверяется `src/gui_desktop/native/dsview`. Выбранный путь печатается до +копирования. Для отдельной установки передать `-DsViewPath` с её каталогом. +Для записи в защищённый Program Files требуются права администратора; +обновление декодеров не требует записи в сам `DSView.exe`. +Перед установкой закрыть целевой DSView, затем открыть его снова. +Добавление пакетов обновляет Python-декодеры без пересборки EXE; +изменение раздела «Пользовательские» применяется при следующей нативной сборке. diff --git a/tools/dsview/build.py b/tools/dsview/build.py index 9e1b36c..c2872db 100644 --- a/tools/dsview/build.py +++ b/tools/dsview/build.py @@ -15,13 +15,21 @@ import subprocess REVISION = '2e9e2c8e' +def protocol_payload(): # Одна ведомость управляет упаковкой переносимых декодеров и их зависимостей. + recipe = Path(__file__).resolve().parent # Рецепт находится в tools/dsview относительно закреплённого templates. + python = recipe.parents[1] / 'python' # Исходники прикладных протоколов берутся из того же checkout, что адаптеры. + manifest = json.loads((recipe / 'protocol-files.json').read_text(encoding='utf-8')) # JSON также читает установщик standalone DSView. + files = [(recipe / 'decoders' / name / leaf, Path(name) / leaf) for name in manifest['adapters'] for leaf in ('__init__.py', 'pd.py')] # Каждый адаптер имеет стандартную точку входа и реализацию sigrok. + files += [(python / 'logic_analyzer/decoders' / (name + '.py'), Path('common/setgui_decoders') / (name + '.py')) for name in manifest['cores']] # Ядра устанавливаются с прежним пространством имён common.setgui_decoders. + files += [(python / name, Path('common/setgui_decoders/templates') / name) for name in manifest['template_files']] # Переносимые библиотеки и карты копируются без изменения исходных файлов. + return files # Пары исходник/назначение используются и для контрольной суммы, и для копирования. + + def recipe_digest(): """Identify the patch, packaging recipe, adapters and their shared cores.""" recipe = Path(__file__).resolve().parent - core = recipe.parents[1] / 'python/logic_analyzer/decoders' - inputs = [recipe / 'build.py', recipe / 'setgui-host.patch', recipe / 'gate-pair-checkbox.patch', recipe / 'decoder-panel.patch', recipe / 'driver-summary.patch', recipe / 'windows-usb-events.patch', recipe / 'native/gate_summary.h'] - inputs += sorted((recipe / 'decoders').rglob('*.py')) - inputs += [core / (name + '.py') for name in ('gate_timing', 'transistor_pair', 'set_uart', 'set_can', 'pm35_uart')] + inputs = [recipe / 'build.py', recipe / 'protocol-files.json', recipe / 'setgui-host.patch', recipe / 'gate-pair-checkbox.patch', recipe / 'decoder-panel.patch', recipe / 'driver-summary.patch', recipe / 'windows-usb-events.patch', recipe / 'native/gate_summary.h'] # Ведомость и нативные патчи входят в версию рецепта. + inputs += [source for source, _ in protocol_payload()] # Изменение парсера, адаптера или JSON-карты делает установленный компонент устаревшим. digest = hashlib.sha256() for item in inputs: digest.update(item.relative_to(recipe.parents[1]).as_posix().encode('utf-8') + b'\0') @@ -46,12 +54,10 @@ def package_decoders(output): decoders = Path(output) / 'decoders' shutil.copytree(recipe / 'decoders', decoders, dirs_exist_ok=True, ignore=shutil.ignore_patterns('__pycache__')) - common = decoders / 'common/setgui_decoders' - common.mkdir(parents=True, exist_ok=True) - (common / '__init__.py').write_text('', encoding='utf-8') - core = recipe.parents[1] / 'python/logic_analyzer/decoders' - for name in ('gate_timing', 'transistor_pair', 'set_uart', 'set_can', 'pm35_uart'): - shutil.copy2(core / (name + '.py'), common / (name + '.py')) + for source, relative in protocol_payload(): # Декодеры, ядра и карты устанавливаются по единой ведомости. + destination = decoders / relative # Все файлы остаются внутри выбранного каталога декодеров. + destination.parent.mkdir(parents=True, exist_ok=True) # Новые переносимые пакеты получают собственные подкаталоги. + shutil.copy2(source, destination) # Канонические реализации templates копируются побайтно без отдельного форка протокола. def main(): diff --git a/tools/dsview/decoder-panel.patch b/tools/dsview/decoder-panel.patch index 5947bed..6d62171 100644 --- a/tools/dsview/decoder-panel.patch +++ b/tools/dsview/decoder-panel.patch @@ -93,14 +93,14 @@ - { - srd_decoder *dec = (srd_decoder *)(info->_data_handle); - panel->AddDataItem(QString(dec->id), QString(dec->name), info); -+ const QStringList customIds = {"gate_driver_timing", "transistor_pair", "set_uart", "set_can", "pm35_uart"}; ++ const QStringList customIds = {"gate_driver_timing", "transistor_pair", "set_uart", "set_can", "pm35_uart", "tms_uart", "plates_pbus", "plates_sbus"}; // При сборке пользовательский раздел включает анализаторы обеих шин 96-контактного интерфейса. + for (bool custom : {true, false}) { + for (auto info : _decoderInfoList) { + srd_decoder *dec = (srd_decoder *)(info->_data_handle); + if (customIds.contains(QString(dec->id)) != custom) + continue; + panel->AddDataItem(QString(dec->id), QString(dec->name), info, -+ custom ? QString::fromUtf8("Пользовательские") : QString::fromUtf8("Стандартные")); ++ custom ? QStringLiteral("Пользовательские") : QStringLiteral("Стандартные")); // Unicode-заголовок выбирается по принадлежности декодера; QStringLiteral сохраняет кириллицу без преобразования через системную кодировку Windows. + } } diff --git a/tools/dsview/decoders/plates_pbus/__init__.py b/tools/dsview/decoders/plates_pbus/__init__.py new file mode 100644 index 0000000..31672d3 --- /dev/null +++ b/tools/dsview/decoders/plates_pbus/__init__.py @@ -0,0 +1,2 @@ +"""Декодер параллельной шины 96-контактного интерфейса.""" # Описание пакета доступно загрузчику декодеров DSView. +from .pd import Decoder # Экспорт класса нужен штатному загрузчику libsigrokdecode. diff --git a/tools/dsview/decoders/plates_pbus/pd.py b/tools/dsview/decoders/plates_pbus/pd.py new file mode 100644 index 0000000..0dd6b3d --- /dev/null +++ b/tools/dsview/decoders/plates_pbus/pd.py @@ -0,0 +1,140 @@ +"""PBus по ParallelBusSlave_ver_2_0.vhd; Python 3.6+, sigrok API 3.""" # Времена выборки определяются ACK аппаратного ведомого. +import sigrokdecode as srd # DSView предоставляет цифровые отсчёты и выходные аннотации. + + +# CE ограничивает транзакцию, три перехода ACK подтверждают адрес, данные и их инверсию. +class Decoder(srd.Decoder): # Протокол работает непосредственно с захватом логических уровней. + api_version = 3 # API ожидания событий поддерживается libsigrokdecode4DSL. + id = 'plates_pbus' # Имя пакета не пересекается со штатным parallel. + name = 'Plates PBus' # Название в списке протоколов DSView. + longname = 'Plates 96-pin PBus' # Название связывает декодер с интерфейсом плат. + desc = 'PBus reads with address complement, ACK and inverted data checks.' # Текущий HDL реализует внешнее чтение PBus. + license = 'gplv3+' # Допустимый идентификатор лицензии libsigrokdecode. + inputs = ['logic'] # Входные данные — цифровые каналы анализатора. + outputs = ['plates_pbus'] # Структурированные результаты доступны следующему уровню. + tags = ['Embedded/industrial'] # Категория промышленного обмена. + channels = ( # Обязательные сигналы не подменяются нулём при отсутствии захвата. + {'id': 'ce', 'name': 'PBCE', 'desc': 'Active-low transaction enable'}, # Индекс 0: CE=0 разрешает обмен согласно HDL. + {'id': 'ack', 'name': 'PBACK', 'desc': 'Address / data / inverse acknowledge'}, # Индекс 1: переходы 0,1,0 задают три фазы. + ) + tuple({'id': 'd%d' % i, 'name': 'D%d' % i, 'desc': 'PBDATA bit %d' % i} for i in range(16)) # Индексы 2…17 соответствуют физическим разрядам D0…D15. + optional_channels = ( # Для выборки достаточно ACK, поэтому тактовая линия необязательна. + {'id': 'clk', 'name': 'PBCLK', 'desc': 'Optional phase validation clock'}, # Индекс 18: данные ожидаются при CLK=0, инверсия — при CLK=1. + ) # При наличии CLK проверяется согласованность фаз с текущим HDL. + annotations = ( # Числовые типы совместимы с форматом аннотаций DSView. + ('1', 'device', 'Device'), # Индекс 0: старшая тетрада восьмибитного адреса. + ('2', 'register', 'Register'), # Индекс 1: младшая тетрада адреса. + ('3', 'data', 'Data'), # Индекс 2: прочитанное 16-битное значение. + ('4', 'check', 'Checks'), # Индекс 3: инверсная защита адреса и ответа. + ('5', 'frame', 'Transaction'), # Индекс 4: итог полного или оборванного обращения. + ('1000', 'warning', 'Warnings'), # Индекс 5: ошибки адреса, ответа, фаз и отсутствующих ACK. + ) # Индекс класса в put() отличается от числового типа в первом поле. + annotation_rows = ( # Раздельные строки сохраняют читаемость при перекрытии полей. + ('device', 'Device', (0,)), # Устройство и регистр передаются одновременно. + ('register', 'Register', (1,)), # Поэтому регистр располагается на своей строке. + ('data', 'Data', (2,)), # Данные видны рядом с проверкой инверсной копии. + ('checks', 'Checks', (3,)), # Результаты проверок не теряются за итогом кадра. + ('frames', 'Transactions', (4,)), # Итог содержит адрес, значение и состояние обмена. + ('warnings', 'Warnings', (5,)), # Ошибки выделяются штатным типом DSView. + ) # Все поля выводятся без зависимости от карт регистров PlatesConf. + + # Экземпляр декодера начинает без активной транзакции. + def __init__(self): # Вызывается загрузчиком протоколов. + self.reset() # Повторный проход использует такой же сброс. + + # Незавершённое состояние предыдущего захвата не переносится в следующий. + def reset(self): # Сбрасывает только внутренний автомат. + self.packet = None # Словарь операции появляется на спаде CE. + self.phase = None # Ожидаемая фаза: address, data, inverse или done. + self.ss = 0 # Начало транзакции задаётся в отсчётах захвата. + self.phase_start = 0 # Начало текущего ожидания нужно для границ аннотаций. + + # Аннотации и структурированные кадры регистрируются до обработки сигналов. + def start(self): # Вызывается средой DSView при запуске декодирования. + self.out_ann = self.register(srd.OUTPUT_ANN) # Текстовые поля отображаются над захватом. + self.out_python = self.register(srd.OUTPUT_PYTHON) # Пакеты сохраняют сырые значения и результаты проверок. + + # Каждая аннотация привязана к фактическим границам текущей фазы. + def annotate(self, start, end, kind, text): # kind — индекс annotations, а не числовой тип DSView. + self.put(start, max(start, end), self.out_ann, [kind, [text]]) # Одноточечные переходы также допустимы. + + # Порядок назначения каналов DSView задаёт значение разрядов без перестановки байтов. + def word(self, pins): # На входе полный набор сигналов текущего отсчёта. + return sum(pins[2 + i] << i for i in range(16)) # D0 имеет вес 1, D15 — 32768; результат беззнаковый. + + # Ошибка добавляется и в выходной пакет, и в видимую строку предупреждений. + def warning(self, text, end): # end обозначает отсчёт обнаружения ошибки. + self.packet['errors'].append(text) # Причины остаются доступны потребителю Python-выхода. + self.annotate(self.phase_start, end, 5, text) # Предупреждение относится к текущей фазе обмена. + + # Адрес находится в старшем байте; младший должен быть его инверсией согласно HDL. + def address(self, word, end): # Выборка выполняется на первом низком ACK либо при закрытии запроса без ACK. + address = word >> 8 # Ровно восемь бит делятся на два четырёхбитных адреса. + self.packet.update(dev=address >> 4, reg=address & 15, address_word=word, address_ok=((word & 255) == (address ^ 255))) # Маска 255 ограничивает инверсию одним байтом. + self.annotate(self.ss, end, 0, 'DEV 0x%X' % self.packet['dev']) # Старшая тетрада определяет устройство 0…15. + self.annotate(self.ss, end, 1, 'REG 0x%X' % self.packet['reg']) # Младшая тетрада определяет регистр 0…15. + self.annotate(self.ss, end, 3, 'ADDR 0x%04X %s' % (word, 'OK' if self.packet['address_ok'] else 'BAD')) # Видна и исходная инверсная копия адреса. + if not self.packet['address_ok']: # Несогласованность байтов не маскируется правильными данными ответа. + self.warning('Address complement mismatch', end) # На исправном ведомом такой адрес не должен получать ACK. + + # Итог формируется даже при обрыве, но неполная операция никогда не считается успешной. + def emit_frame(self, end, complete): # complete означает получение всех трёх фаз ACK. + self.packet['complete'] = complete # Полнота отделена от результата проверок содержимого. + self.packet['ok'] = complete and not self.packet['errors'] # Любая ошибка проверки остаётся явной. + value = self.packet['value'] # При отсутствии фазы данных значение остаётся None. + text = 'READ %X:%X = %s %s' % (self.packet['dev'], self.packet['reg'], '?' if value is None else '0x%04X' % value, 'OK' if self.packet['ok'] else 'BAD / incomplete') # Формат не выдаёт предположение за данные шины. + self.annotate(self.ss, end, 4, text) # Итог покрывает весь интервал обращения. + self.put(self.ss, end, self.out_python, ['FRAME', self.packet]) # Даже повторное чтение того же значения остаётся отдельной операцией. + + # Возврат CE либо конец захвата закрывает незаконченное ожидание ACK. + def close(self, end): # Завершённая операция уже выведена на ACK инверсии и не дублируется. + if self.packet is not None and self.phase != 'done': # Пустой захват или уже завершённый кадр не создают ошибок. + if self.phase == 'address': # При отсутствии первого ACK сохраняем хотя бы запрос на спаде CE. + self.address(self.packet['address_word'], end) # Это наблюдавшийся адрес, а не восстановление по ответу. + self.warning('Incomplete PBus: missing %s ACK' % self.phase, end) # Сообщение различает отсутствие адресного ответа, данных и инверсии. + self.emit_frame(end, False) # Частичные данные доступны с complete=False. + self.packet = None # После закрытия CE предыдущая операция больше не активна. + self.phase = None # Новая операция должна начаться новым спадом CE. + + # Последний незакрытый запрос виден и при обрыве самого файла захвата. + def end(self): # Метод вызывается DSView после последнего блока данных. + self.close(getattr(self, 'last_samplenum', getattr(self, 'samplenum', 0))) # Используем последнюю известную границу захвата. + + # Состояния автомата соответствуют аппаратной последовательности ACK 0 -> 1 -> 0. + def decode(self): # Ожидание событий завершается самой средой декодирования. + if not all(self.has_channel(i) for i in range(18)): # Для полного слова обязательны CE, ACK и все 16 разрядов данных. + raise ValueError('PBus requires PBCE, PBACK and all D0..D15 channels') # Отсутствующий разряд не заменяется ложным нулём. + have_clock = self.has_channel(18) # PBCLK улучшает диагностику, но не нужен для выборки по ACK. + previous = self.wait({}) # Начало посреди активного CE игнорируется до следующей полной операции. + while True: # Изменения самих данных не вызывают лишние пробуждения декодера. + pins = self.wait([{0: 'e'}, {1: 'e'}]) # Фазы ограничиваются только CE и ACK, а данные читаются в точке подтверждения. + now = self.samplenum # Все границы аннотаций задаются в отсчётах. + if pins[0]: # CE=1 завершает текущий обмен независимо от уровня ACK. + self.close(now) # Незаконченная фаза становится явной ошибкой. + else: # Только низкий CE разрешает принимать ACK ведомого. + if previous[0]: # Спад CE начинает новую операцию даже при одновременном переходе ACK. + self.ss = self.phase_start = now # Начало фазы адреса совпадает с разрешением обмена. + self.packet = {'bus': 'PBus', 'operation': 'read', 'dev': None, 'reg': None, 'address_word': self.word(pins), 'address_ok': None, 'value': None, 'inverse': None, 'inverse_ok': None, 'errors': []} # Пропущенные фазы имеют явное значение None. + self.phase = 'address' # Первым ожидается низкий адресный ACK. + falling = previous[1] == 1 and pins[1] == 0 # ACK=0 подтверждает адрес или инверсную копию в зависимости от фазы. + rising = previous[1] == 0 and pins[1] == 1 # ACK=1 подтверждает прямые данные ответа. + if self.packet is not None and self.phase == 'address' and falling: # Первый спад ACK фиксирует защищённый адрес. + self.address(self.word(pins), now) # Адрес читается после готовности приёмника, а не по произвольному фронту CLK. + self.phase, self.phase_start = 'data', now # Следующий ACK должен стать высоким при готовности данных. + elif self.packet is not None and self.phase == 'data' and rising: # Высокий ACK отмечает прямое слово ответа. + self.packet['value'] = self.word(pins) # Сохраняется всё 16-битное значение PBus. + self.annotate(self.phase_start, now, 2, 'DATA 0x%04X' % self.packet['value']) # Число показывается в шестнадцатеричном виде с ведущими нулями. + if have_clock and pins[18] != 0: # В HDL TransmitData выдаёт ACK только при низком PBCLK. + self.warning('Data ACK while PBCLK is not low', now) # Ошибка фазы помогает выявить неверное подключение либо нарушение обмена. + self.phase, self.phase_start = 'inverse', now # Далее ожидается низкий ACK инверсного слова. + elif self.packet is not None and self.phase == 'inverse' and falling: # Последний спад ACK завершает проверяемый обмен. + inverse = self.word(pins) # Инверсия выбирается отдельно от прямых данных. + valid = inverse == (self.packet['value'] ^ 65535) # Маска 65535 ограничивает инверсию ровно 16 разрядами HDL. + self.packet.update(inverse=inverse, inverse_ok=valid) # Сохраняем и сырое слово, и результат проверки. + self.annotate(self.phase_start, now, 3, 'INVERSE 0x%04X %s' % (inverse, 'OK' if valid else 'BAD')) # Проверяем содержимое, а не только наличие третьего ACK. + if not valid: # Повреждённый ответ не становится успешным из-за полного числа фаз. + self.warning('Data complement mismatch', now) # Ошибка относится к данным ответа. + if have_clock and pins[18] != 1: # В HDL TransmitCheck выдаёт ACK при высоком PBCLK. + self.warning('Inverse ACK while PBCLK is not high', now) # Проверка включается только при назначении необязательного канала. + self.emit_frame(now, True) # Итог доступен сразу после третьего подтверждения. + self.phase = 'done' # Возврат CE в единицу не должен дублировать кадр. + previous = pins # Следующий переход сравнивается с фактическими последними уровнями CE и ACK. diff --git a/tools/dsview/decoders/plates_sbus/__init__.py b/tools/dsview/decoders/plates_sbus/__init__.py new file mode 100644 index 0000000..93cc378 --- /dev/null +++ b/tools/dsview/decoders/plates_sbus/__init__.py @@ -0,0 +1,2 @@ +"""Декодер последовательной шины 96-контактного интерфейса.""" # Описание пакета доступно загрузчику декодеров DSView. +from .pd import Decoder # Экспорт класса нужен штатному загрузчику libsigrokdecode. diff --git a/tools/dsview/decoders/plates_sbus/pd.py b/tools/dsview/decoders/plates_sbus/pd.py new file mode 100644 index 0000000..af16d5e --- /dev/null +++ b/tools/dsview/decoders/plates_sbus/pd.py @@ -0,0 +1,172 @@ +"""SBus по SerialBusSlave_ver_2_0.vhd; Python 3.6+, sigrok API 3.""" # Формат берётся из HDL, без зависимости от приложения SETGUI. +import math # Округление длительностей вверх исключает преждевременное срабатывание таймеров. +import sigrokdecode as srd # Среда DSView предоставляет входные отсчёты и выходные аннотации. + + +# CRC повторяет параллельные присваивания HDL, включая четыре завершающие единицы. +def frame_crc(direction, address, value): # В расчёт входят направление, восьмибитный адрес и 16 бит данных. + word = (direction << 24) | (address << 16) | value # Поля образуют 25 бит в порядке передачи от старшего к младшему. + crc = 0 # Начальное состояние регистра CRC равно x"0" в SerialBusSlave_ver_2_0.vhd. + for bit in [((word >> shift) & 1) for shift in range(24, -1, -1)] + [1] * 4: # После 25 бит HDL подаёт четыре единицы. + c3, c2, c1, c0 = [(crc >> shift) & 1 for shift in (3, 2, 1, 0)] # Все новые разряды используют прежнее состояние CRC. + crc = ((c2 ^ c3) << 3) | ((c1 ^ c0) << 2) | (c0 << 1) | (bit ^ c1) # Это точная обратная связь HDL, а не стандартный CRC-4. + return crc # На провод передаются четыре бита результата, начиная с бита 3. + + +# Декодер разделяет кадры по паузе любого уровня CLK и выбирает линию данных по направлению. +class Decoder(srd.Decoder): # Базовый класс реализован встроенным модулем DSView. + api_version = 3 # API 3 позволяет ждать фронтов и временных интервалов без перебора всех отсчётов. + id = 'plates_sbus' # Уникальное имя не пересекается со штатными декодерами. + name = 'Plates SBus' # Короткое название отображается при выборе протокола. + longname = 'Plates 96-pin SBus' # Уточнение отличает шину от других последовательных протоколов. + desc = 'SBus: direction, device, register, data, CRC and write ACK.' # Краткое описание доступно в диалоге DSView. + license = 'gplv3+' # Это допустимый идентификатор лицензии для libsigrokdecode. + inputs = ['logic'] # Декодер получает цифровые сигналы анализатора. + outputs = ['plates_sbus'] # Python-пакеты можно использовать в следующем уровне декодирования. + tags = ['Embedded/industrial'] # Категория соответствует промышленной шине плат. + channels = ( # Направления линий указаны относительно мастера ТМС. + {'id': 'clk', 'name': 'SBCLK', 'desc': 'Serial clock'}, # CLK задаёт границы битов и паузы между кадрами. + {'id': 'tx', 'name': 'SBDATAIN', 'desc': 'TMS -> plates'}, # На этой линии находятся запрос и данные записи. + {'id': 'rx', 'name': 'SBDATAOUT', 'desc': 'Plates -> TMS'}, # На этой линии находятся данные чтения и активный низкий ACK записи. + ) # Все три линии обязательны для проверки обоих направлений. + options = ( # Времена задаются в микросекундах и пересчитываются по частоте захвата. + {'id': 'idle_us', 'desc': 'Frame gap (us)', 'default': 3.6}, # В текущем HDL COUNT_RESET=180 при 50 МГц: 180/50=3,6 мкс. + {'id': 'ack_us', 'desc': 'Write ACK sampling delay (us)', 'default': 0.5}, # Полмикросекунды после CRC оставляют запас для логики проверки до сброса по паузе. + ) # Параметры можно изменить для реального захвата другой аппаратуры. + annotations = ( # Первое поле задаёт числовой тип DSView; индекс кортежа используется в put(). + ('1', 'direction', 'Direction'), # Индекс 0: чтение или запись со стороны ТМС. + ('2', 'device', 'Device'), # Индекс 1: адрес устройства 0…15. + ('3', 'register', 'Register'), # Индекс 2: адрес регистра 0…15. + ('4', 'data', 'Data'), # Индекс 3: сырое 16-битное значение без выдуманных единиц. + ('5', 'crc', 'CRC'), # Индекс 4: принятая и рассчитанная контрольные суммы. + ('6', 'ack', 'Write ACK'), # Индекс 5: подтверждение записи, отдельное от проверки CRC. + ('7', 'frame', 'Transaction'), # Индекс 6: итог операции целиком. + ('1000', 'warning', 'Warnings'), # Индекс 7: CRC, отказ и незавершённые кадры. + ) # Числовой тип 1000 соответствует предупреждениям в DSView. + annotation_rows = ( # Параллельные строки позволяют видеть поля и итог кадра одновременно. + ('fields', 'Fields', (0, 1, 2, 3)), # Неперекрывающиеся поля запроса и данных. + ('checks', 'CRC / ACK', (4, 5)), # Независимые проверки целостности и ответа платы. + ('frames', 'Transactions', (6,)), # Сводная строка удобна для поиска обращений. + ('warnings', 'Warnings', (7,)), # Ошибки видны независимо от масштаба остальных строк. + ) # Индексы соответствуют annotations выше. + + # Новый экземпляр должен начинаться без синхронизации с границей кадра. + def __init__(self): # Загрузчик создаёт экземпляр при добавлении декодера. + self.reset() # Единый сброс используется также при повторном декодировании. + + # Сбрасываем только состояние захвата, не значения обязательных входных каналов. + def reset(self): # Вызывается средой при начале нового прохода. + self.samplerate = None # Частота захвата будет передана через metadata(). + self.bits = [] # Элементы содержат номер отсчёта и значение бита текущего кадра. + self.pending = None # Завершённая запись ждёт отдельного момента выборки ACK. + self.ack_at = None # Номер отсчёта выборки ACK существует только при pending. + + # Выходы регистрируются после сброса до обработки первых отсчётов. + def start(self): # API DSView вызывает этот метод перед decode(). + self.out_ann = self.register(srd.OUTPUT_ANN) # Текстовые поля и предупреждения рисуются над захватом. + self.out_python = self.register(srd.OUTPUT_PYTHON) # Структурированные кадры сохраняют независимые CRC и ACK. + + # Частота нужна для отделения кадров по реальному времени, а не количеству битов. + def metadata(self, key, value): # Среда передаёт метаданные захвата независимо от фронтов. + if key == srd.SRD_CONF_SAMPLERATE: # Другие метаданные не влияют на разбор шины. + self.samplerate = value # Единица измерения — отсчёты в секунду. + + # Обёртка сохраняет допустимый порядок границ даже для одноточечной аннотации. + def annotate(self, start, end, kind, text): # kind — индекс annotations, text — содержимое над сигналом. + self.put(start, max(start, end), self.out_ann, [kind, [text]]) # Одноточечные поля направления допустимы API. + + # Поля передаются старшим битом вперёд; срез не включает правую границу. + def field(self, start, end): # Параметры задают позиции битов внутри 29-битного кадра. + value = 0 # Аккумулятор формируется заново для каждого поля. + for _, bit in self.bits[start:end]: # Номер отсчёта не влияет на числовое значение. + value = (value << 1) | bit # Следующий бит занимает младший разряд после сдвига. + return value # Значение сохраняется без знакового преобразования. + + # Итог записи отделяет хороший CRC от ACK; ACK не доказывает применение команды CPU1. + def emit_frame(self, packet, end): # packet уже содержит все поля и результаты доступных проверок. + ack = packet['ack'] # Для чтения и необследованного ответа записи значение остаётся None. + suffix = '' if packet['operation'] == 'read' else ' ACK ' + ('?' if ack is None else ('OK' if ack else 'HIGH')) # Высокий уровень не различает NACK и отсутствие платы. + status = 'OK' if packet['crc_ok'] else 'BAD' # Целостность CRC показывается независимо от подтверждения. + text = '%s %X:%X = 0x%04X CRC %s%s' % (packet['operation'].upper(), packet['dev'], packet['reg'], packet['value'], status, suffix) # Адреса и данные удобны для сверки с регистрами проекта. + self.annotate(self.bits[0][0], end, 6, text) # Сводная аннотация покрывает весь кадр и ожидание ACK. + self.put(self.bits[0][0], end, self.out_python, ['FRAME', packet]) # Структурированный выход не теряет повторные одинаковые команды. + + # Бит принимается только по нарастающему фронту, когда ответ ведомого уже установлен после спада. + def receive_bit(self, pins): # pins имеет порядок CLK, запрос ТМС, ответ платы. + index = len(self.bits) # Первый бит — направление, следующие восемь — адрес. + if index >= 29: # Кадр содержит 1+8+16+4 бита; лишние такты до паузы не становятся новым запросом. + return # Синхронизация нового кадра требует паузы на CLK. + source = 1 if index < 9 or self.bits[0][1] else 2 # Заголовок и запись идут от ТМС; данные чтения и CRC — от платы. + self.bits.append((self.samplenum, pins[source])) # Сохраняем точное положение каждого принятого бита. + count = len(self.bits) # Поле выводится сразу после последнего составляющего бита. + if count == 1: # Направление 0 означает чтение, 1 означает запись в HDL. + self.annotate(self.samplenum, self.samplenum, 0, 'WRITE' if self.bits[0][1] else 'READ') # Операция указана относительно ТМС. + for size, begin, kind, label, width in ((5, 1, 1, 'DEV', 1), (9, 5, 2, 'REG', 1), (25, 9, 3, 'DATA', 4)): # Границы определены ширинами адреса и данных HDL. + if count == size: # Одно поле выводится только один раз за кадр. + self.annotate(self.bits[begin][0], self.samplenum, kind, '%s 0x%0*X' % (label, width, self.field(begin, size))) # Нулевые старшие разряды данных сохраняются. + if count != 29: # Проверка CRC возможна только при полном кадре. + return # Неполные кадры будут отмечены по паузе или концу захвата. + direction, address, value = self.field(0, 1), self.field(1, 9), self.field(9, 25) # Восьмибитный адрес делится на устройство и регистр. + actual, expected = self.field(25, 29), frame_crc(direction, address, value) # CRC рассчитывается над теми же данными, которые видны на проводе. + packet = {'bus': 'SBus', 'operation': 'write' if direction else 'read', 'dev': address >> 4, 'reg': address & 15, 'value': value, 'crc': actual, 'crc_expected': expected, 'crc_ok': actual == expected, 'ack': None} # Неизвестное подтверждение не подменяется успешным. + self.annotate(self.bits[25][0], self.samplenum, 4, 'CRC %X / %X %s' % (actual, expected, 'OK' if actual == expected else 'BAD')) # Оба значения помогают диагностировать ошибку захвата. + if actual != expected: # Ошибка видна и в отдельной строке предупреждений. + self.annotate(self.bits[25][0], self.samplenum, 7, 'CRC mismatch') # Повреждённый кадр всё равно выводится для диагностики. + if direction: # Запись подтверждается после проверки CRC ведомым. + self.pending = packet # Выход кадра откладывается до выборки ACK. + self.ack_at = self.samplenum + self.ack_samples # Задержка отсчитывается от последнего бита CRC. + else: # У чтения после CRC нет отдельного подтверждения ведомого. + self.emit_frame(packet, self.samplenum) # Полное чтение доступно без ожидания межкадровой паузы. + + # Частичный заголовок не выдаётся за достоверную операцию. + def close_partial(self, end): # Вызывается на паузе и при завершении захвата. + if self.pending is not None: # Захват может закончиться до заданного времени выборки ACK. + self.annotate(self.bits[-1][0], end, 7, 'Write ACK not sampled: capture ended') # Наблюдений недостаточно для вывода о подтверждении. + self.emit_frame(self.pending, end) # Полные данные сохраняются с ack=None. + self.pending = None # Повторный end() не должен дублировать кадр. + if 0 < len(self.bits) < 29: # Полный кадр уже выведен и не считается обрывом. + self.annotate(self.bits[0][0], end, 7, 'Incomplete SBus frame: %d/29 bits' % len(self.bits)) # Число бит помогает найти место потери синхронизации. + self.bits = [] # Следующая операция начинает собственный независимый буфер. + + # end() поддерживает диагностику обрыва даже без следующего фронта или полной паузы. + def end(self): # DSView передаёт last_samplenum после последнего блока захвата. + self.close_partial(getattr(self, 'last_samplenum', getattr(self, 'samplenum', 0))) # Резервная граница полезна в средах без last_samplenum. + + # Ожидаем фронты и ближайший таймер; тихий участок захвата не требует перебора отсчётов. + def decode(self): # Бесконечное ожидание завершается самой средой libsigrokdecode. + if not self.samplerate or not all(self.has_channel(i) for i in range(3)): # Для времени и обоих направлений нужны частота захвата и три сигнала. + raise ValueError('SBus requires samplerate, SBCLK, SBDATAIN and SBDATAOUT') # Ошибка настройки отличается от повреждённого кадра. + idle_us, ack_us = self.options['idle_us'], self.options['ack_us'] # Настройки относятся к временной шкале захвата. + if not math.isfinite(idle_us) or not math.isfinite(ack_us) or not 0 < ack_us < idle_us: # ACK должен наблюдаться раньше сброса при паузе. + raise ValueError('Require finite 0 < ACK delay < frame gap') # Неверные интервалы не должны создавать ложную диагностику. + gap = max(1, int(math.ceil(self.samplerate * idle_us / 1000000.0))) # Миллион переводит микросекунды в секунды. + self.ack_samples = max(1, int(math.ceil(self.samplerate * ack_us / 1000000.0))) # Округление вверх обеспечивает минимум один отсчёт ожидания. + if self.ack_samples >= gap: # При грубой дискретизации разные времена могут попасть в один отсчёт. + raise ValueError('Samplerate too low to separate ACK sampling and frame gap') # Такой захват не позволяет выполнить заданную временную проверку. + pins = self.wait({}) # Первый отсчёт задаёт уровень CLK без выдуманного фронта. + previous, last_edge, armed = pins[0], self.samplenum, False # Начало посреди кадра игнорируется до наблюдаемой паузы. + while True: # Каждый проход обрабатывает фронт или один ближайший таймер. + deadlines = [] if armed else [last_edge + gap] # После подтверждённой паузы достаточно дождаться следующего фронта. + if self.pending is not None: # Отдельный таймер ACK не зависит от дальнейших тактов CLK. + deadlines.append(self.ack_at) # Последний CRC может быть последним тактом в захвате. + conditions = [{0: 'e'}] # Учитываются оба фронта, поскольку сброс HDL отсчитывается от любого изменения CLK. + if deadlines: # Таймер задаётся относительно текущего положения декодера. + conditions.append({'skip': max(1, min(deadlines) - self.samplenum)}) # Минимум один отсчёт исключает ожидание в той же точке. + pins = self.wait(conditions) # Значения линий доступны и при срабатывании временного условия. + now = self.samplenum # Номер отсчёта общий для фронтов и таймеров. + if self.pending is not None and now >= self.ack_at: # ACK измеряется после CRC, а не на его последнем фронте. + self.pending['ack'] = pins[2] == 0 # В HDL низкий SBDATAOUT подтверждает запись; высокий означает отказ либо отсутствие ответа. + self.annotate(self.bits[-1][0], now, 5, 'ACK' if self.pending['ack'] else 'ACK HIGH (NACK / no response)') # Уровень ответа не скрывается даже при плохом CRC. + if not self.pending['ack']: # Отсутствие низкого ACK является отдельной проблемой обмена. + self.annotate(self.bits[-1][0], now, 7, 'No low write ACK') # Это не доказательство конкретной причины отказа. + self.emit_frame(self.pending, now) # Повторные записи выводятся отдельными кадрами. + self.pending = None # Таймер подтверждения больше не нужен. + if not armed and now - last_edge >= gap: # Пауза допустима как при высоком, так и при низком CLK. + self.close_partial(now) # Незавершённый предыдущий кадр отмечается до повторной синхронизации. + armed = True # Первый следующий нарастающий фронт начинает заголовок. + if pins[0] != previous: # Срабатывание одного таймера не должно создавать фиктивный бит. + if pins[0] and (armed or self.bits): # После паузы начинаем кадр; внутри кадра продолжаем сбор. + armed = False # До следующей длинной паузы новый заголовок запрещён. + self.receive_bit(pins) # Бит выбирается с нужной линии с учётом направления. + last_edge = now # Любой фронт перезапускает измерение неподвижного CLK. + previous = pins[0] # Следующий таймер сравнивается с последним реальным уровнем. diff --git a/tools/dsview/decoders/set_can/pd.py b/tools/dsview/decoders/set_can/pd.py index 40b84b6..bb1a2b1 100644 --- a/tools/dsview/decoders/set_can/pd.py +++ b/tools/dsview/decoders/set_can/pd.py @@ -1,71 +1,70 @@ -# Сегментация SET v2 и интерпретация CAN-данных зависят от выбранного слоя. Адрес и номер -# сегмента должны проверяться до объединения данных; classic CAN-пакет ограничен восемью -# байтами. Этот адаптер переводит события libsigrokdecode в аннотации DSView; координаты -# выборок пересчитываются с учётом частоты захвата. +import sigrokdecode as srd # API sigrok передаёт кадры базового CAN-декодера и принимает аннотации. +from common.setgui_decoders.set_can import Reassembler # Существующий сборщик проверяет сегментацию и тайм-аут SET v2. +from common.setgui_decoders.template_protocols import CAN_PROFILES, LEGACY_PROJECTS, decode_can # Профили и каталоги определяются общими библиотеками templates. -import sigrokdecode as srd -from common.setgui_decoders.set_can import Reassembler, legacy +class Decoder(srd.Decoder): # Стековый анализатор добавляет прикладные дорожки к физическому CAN. + api_version = 3 # Версия интерфейса соответствует поставляемому libsigrokdecode4DSL. + id = 'set_can' # Стабильный ID сохраняет совместимость записей и меню SETGUI. + name = 'SET CAN' # Короткое имя используется в дорожках и диалоге выбора. + longname = 'SET CAN / ProtoCAN / Balsam / UMP / DEIF / legacy' # Подпись перечисляет подключённые семейства протоколов. + desc = 'Templates protocols, application fields, registers and SET v2 reassembly.' # Описывает результат прикладного разбора. + license = 'gplv2+' # Лицензия адаптера соответствует остальным декодерам SET. + inputs = ['can'] # Источник — базовый декодер CAN, а не сырые логические уровни. + outputs = ['set'] # Тип структурированного выхода сохранён для совместимости стека. + tags = ['Embedded/industrial'] # Категория для штатного каталога DSView. + options = ( # Несовместимые карты адресов выбираются явно. + {'id': 'protocol', 'desc': 'Protocol / протокол', 'default': 'protocan', 'values': CAN_PROFILES}, # Прежнее значение по умолчанию сохраняет настройки существующих записей. + {'id': 'project', 'desc': 'Legacy CAN project / проект', 'default': LEGACY_PROJECTS[0], 'values': LEGACY_PROJECTS}, # Проект применяется в режиме legacy. + {'id': 'ump_map', 'desc': 'UMP map / карта УМП', 'default': 'gas167', 'values': ('gas167', 'assigned')}, # Локальная карта отделена от назначенных глобальных GAS ID. + {'id': 'ump_node', 'desc': 'UMP node / номер УМП', 'default': 1, 'values': (1, 2)}, # Локальные адреса 167/v1 не содержат номер УМП. + ) # Неприменимые к профилю настройки игнорируются. + annotations = (('frame', 'Frame'), ('payload', 'Payload'), ('error', 'Error'), ('field', 'Field'), ('register', 'Register')) # Первые три индекса сохраняют прежние дорожки. + annotation_rows = (('frames', 'Frames', (0,)), ('payload', 'Payload', (1,)), ('errors', 'Errors', (2,)), ('fields', 'Fields', (3,)), ('registers', 'Registers', (4,))) # Поля и регистры получают самостоятельные строки. + def __init__(self): # Каждый экземпляр имеет независимое состояние разбора. + self.reset() # Незавершённые сегменты не переходят между записями. -class Decoder(srd.Decoder): - api_version = 3 - id = 'set_can' - name = 'SET CAN' - longname = 'SET v2 CAN / ProtoCAN / Balsam' - desc = 'Application fields and segmented SET packets over classic CAN.' - license = 'gplv2+' - inputs = ['can'] - outputs = ['set'] - tags = ['Embedded/industrial'] - options = ({'id': 'protocol', 'desc': 'CAN protocol (select explicitly)', - 'default': 'protocan', 'values': ('protocan', 'set-v2', 'balsam')},) - annotations = (('frame', 'Frame'), ('payload', 'Payload'), ('error', 'Error')) - annotation_rows = (('frames', 'Frames', (0,)), ('payload', 'Payload', (1,)), ('errors', 'Errors', (2,))) + def reset(self): # Перезапуск освобождает память сборщика. + self.reassembler = Reassembler() # Машина ограничивает число параллельных пакетов и проверяет порядок сегментов. + self.samplerate = None # Частота поступает событием metadata. - def __init__(self): - self.reset() + def metadata(self, key, value): # Метаданные задают шкалу времени сборки пакетов. + if key == srd.SRD_CONF_SAMPLERATE: # Прочие метаданные не влияют на тайм-ауты. + self.samplerate = value # Частота выражена в отсчётах в секунду. - # Состояние принадлежит одному запуску декодера. Сброс не должен - # переносить незавершённый кадр или частоту из предыдущей записи. - def reset(self): - self.reassembler = Reassembler() - self.samplerate = None + def start(self): # Выходы регистрируются в штатной фазе запуска sigrok. + self.out_ann = self.register(srd.OUTPUT_ANN) # Аннотации предназначены для дорожек и поиска DSView. + self.out_python = self.register(srd.OUTPUT_PYTHON) # Словарь полей доступен последующим слоям стека. - # DSView передаёт время в номерах отсчётов. Частота нужна общему ядру - # для перевода тайм-аутов и измерений в физические единицы. - def metadata(self, key, value): - if key == srd.SRD_CONF_SAMPLERATE: - self.samplerate = value - - # Выходы регистрируются в жизненном цикле sigrok, а не в конструкторе. - # Аннотации предназначены для дорожек, структурированные события — для стека. - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.out_python = self.register(srd.OUTPUT_PYTHON) - - def decode(self, ss, es, data): - frame_type, ident, rtr, dlc, payload = data - if frame_type != 'extended' or rtr == 'remote': - return - mode = self.options['protocol'] - if not 0 <= dlc <= 8 or len(payload) != dlc: - events = [(ss, es, None, 'Invalid classic CAN DLC')] - # Сегментированный SET v2 требует времени для тайм-аута сборки. - # Идентификатор, порядок сегментов и CRC проверяет общее ядро. - elif mode == 'set-v2': - if not self.samplerate: - raise ValueError('SET CAN requires samplerate for reassembly timeout') - events = self.reassembler.feed(ident, payload, ss, es, es * 1000.0 / self.samplerate) - else: - try: - result = legacy(ident, payload, mode) - events = [(ss, es, result, None)] if result else [] - except ValueError as exc: - events = [(ss, es, None, str(exc))] - for start, end, result, error in events: - self.put(start, end, self.out_ann, [2 if error else 0, [error or result['summary']]]) - if result: - result['can_id'] = ident - self.put(start, end, self.out_python, ['FRAME', result]) - if events and payload: - self.put(ss, es, self.out_ann, [1, [' '.join('%02X' % b for b in payload)]]) + def decode(self, ss, es, data): # Границы входного CAN-кадра выражены в отсчётах. + frame_type, ident, rtr, dlc, payload = data # Кортеж соответствует выходу штатного CAN-декодера. + mode = self.options['protocol'] # Профиль определяет формат ID и полезной нагрузки. + if frame_type not in ('extended', 'standard') or rtr == 'remote': # RTR не содержит прикладных данных. + return # Такие кадры остаются в базовых дорожках CAN. + if frame_type == 'standard' and mode != 'deif': # DEIF использует STD CANopen, остальные подключённые протоколы — EXT. + return # Предотвращает интерпретацию 11-битного ID как адреса ProtoCAN. + if not 0 <= dlc <= 8 or len(payload) != dlc: # Classic CAN ограничивает нагрузку восемью байтами и требует совпадения длины с DLC. + events = [(ss, es, None, 'Invalid classic CAN DLC')] # Повреждённый кадр показывается как ошибка. + elif mode == 'set-v2' or mode == 'auto' and ident >> 24 == 0x12: # Авто распознаёт зарезервированный префикс SET v2 без угадывания проекта. + if not self.samplerate: # Частота нужна для корректного тайм-аута сборки. + raise ValueError('SET CAN requires samplerate for reassembly timeout') # Движок получает явную ошибку конфигурации. + events = self.reassembler.feed(ident, payload, ss, es, es * 1000.0 / self.samplerate) # Перевод отсчётов в миллисекунды соответствует контракту сборщика. + else: # Несегментированные протоколы обрабатывают каждый кадр независимо. + try: # Ошибка одного кадра не должна прекращать разбор записи. + result = decode_can(ident, payload, mode, extended=frame_type == 'extended', ump_map=self.options['ump_map'], ump_node=self.options['ump_node'], project=self.options['project']) # Подключает текущий парсер templates и выбранную карту. + events = [(ss, es, result, None)] if result else [] # Чужой ID не создаёт ложных событий выбранного проекта. + except ValueError as exc: # Проверки DLC, диапазонов и форматов возвращают диагностический текст. + events = [(ss, es, None, str(exc))] # Следующий кадр продолжит обрабатываться. + for start, end, result, error in events: # Сборщик может выдать несколько событий за один кадр. + self.put(start, end, self.out_ann, [2 if error else 0, [error or result['summary']]]) # Сводка попадает на дорожку Frames либо Errors. + if result: # Подробности выдаются для распознанного сообщения. + for title, value in result.get('fields', []): # Названия и единицы определены общим парсером. + self.put(start, end, self.out_ann, [3, ['%s: %s' % (title, value)]]) # Поля доступны для просмотра и поиска. + for address, value in result.get('registers') or []: # Отсутствующая регистровая нагрузка отличается от пустого запроса. + self.put(start, end, self.out_ann, [4, ['R%04X = %04X (%d)' % (address, value, value)]]) # Адрес и слово показаны в HEX, значение также в десятичной системе. + for warning in result.get('warnings', []): # Замечания общего парсера сохраняются вместе с корректными полями. + self.put(start, end, self.out_ann, [2, [warning]]) # Предупреждения видны в строке ошибок. + result['can_id'] = ident # ID остаётся доступным последующим слоям. + self.put(start, end, self.out_python, ['FRAME', result]) # Передаёт полную модель события. + if events and payload: # Сырые байты позволяют сопоставить расшифровку с исходным CAN. + self.put(ss, es, self.out_ann, [1, [' '.join('%02X' % byte for byte in payload)]]) # Порядок байтов совпадает с захватом. diff --git a/tools/dsview/decoders/set_uart/pd.py b/tools/dsview/decoders/set_uart/pd.py index 4401c19..8ab027a 100644 --- a/tools/dsview/decoders/set_uart/pd.py +++ b/tools/dsview/decoders/set_uart/pd.py @@ -5,6 +5,7 @@ import sigrokdecode as srd from common.setgui_decoders.set_uart import StreamParser +from common.setgui_decoders.template_protocols import LEGACY_PROJECTS # Проекты CAN внутри моста выбираются из того же каталога templates. class Decoder(srd.Decoder): @@ -21,9 +22,13 @@ class Decoder(srd.Decoder): {'id': 'protocol', 'desc': 'Protocol', 'default': 'auto', 'values': ('auto', 'v2', 'v1', 'bridge')}, {'id': 'gap_ms', 'desc': 'Reset incomplete frame after gap (ms, 0 disables)', 'default': 100}, + {'id': 'can_protocol', 'desc': 'Bridge CAN protocol', 'default': 'protocan', 'values': ('protocan', 'auto', 'devboard', 'balsam', 'ump-protocan', 'deif', 'legacy')}, # Профиль применяется к прикладным кадрам, переданным транспортом AA55. + {'id': 'project', 'desc': 'Bridge legacy CAN project', 'default': LEGACY_PROJECTS[0], 'values': LEGACY_PROJECTS}, # Исторический проект выбирается явно, поскольку его ID могут пересекаться с другими форматами. + {'id': 'ump_map', 'desc': 'Bridge UMP map', 'default': 'gas167', 'values': ('gas167', 'assigned')}, # Разделяет текущую локальную карту и назначенные глобальные GAS ID. + {'id': 'ump_node', 'desc': 'Bridge UMP node', 'default': 1, 'values': (1, 2)}, # Номер УМП задаётся отдельно от локального адреса регистра. ) - annotations = (('frame', 'Frame'), ('payload', 'Payload'), ('error', 'Error')) - annotation_rows = (('frames', 'Frames', (0,)), ('payload', 'Payload', (1,)), ('errors', 'Errors', (2,))) + annotations = (('frame', 'Frame'), ('payload', 'Payload'), ('error', 'Error'), ('field', 'Field')) # Индексы прежних аннотаций сохранены, подробные поля добавлены в конец. + annotation_rows = (('frames', 'Frames', (0,)), ('payload', 'Payload', (1,)), ('errors', 'Errors', (2,)), ('fields', 'Fields', (3,))) # Поля прикладного парсера видны на отдельной дорожке. def __init__(self): self.reset() @@ -52,27 +57,37 @@ class Decoder(srd.Decoder): prefix = ('RX', 'TX')[direction] + ' ' self.put(ss, es, self.out_ann, [2 if error else 0, [prefix + (error or frame['summary'])]]) if frame: - if frame['protocol'] == 'ProtoCAN bridge' and frame['flags'] & 1 and not frame['flags'] & 10: + if frame['protocol'] == 'ProtoCAN bridge' and not frame['flags'] & 10: # Флаги RTR и ERR исключают прикладные данные; STD допускается для профиля DEIF. # Imported only at decode time: both packages are installed together. - from common.setgui_decoders.set_can import legacy + from common.setgui_decoders.template_protocols import decode_can # Мост использует те же прикладные парсеры, что анализатор SET CAN. try: - application = legacy(frame['can_id'], frame['payload']) + application = decode_can(frame['can_id'], frame['payload'], self.options['can_protocol'], extended=bool(frame['flags'] & 1), project=self.options['project'], ump_map=self.options['ump_map'], ump_node=self.options['ump_node']) # Флаг IDE и выбранные настройки передаются общему парсеру без изменения wire-данных. frame['application'] = application - self.put(ss, es, self.out_ann, [0, [application['summary']]]) + if application: # Выбранный профиль может не распознать чужой CAN ID. + self.put(ss, es, self.out_ann, [0, [application['summary']]]) # Прикладная сводка дополняет сведения о транспортном кадре моста. + for title, value in application.get('fields', []): # Детали CAN внутри UART берутся из того же результата templates. + self.put(ss, es, self.out_ann, [3, ['%s: %s' % (title, value)]]) # Поля доступны без отдельного импорта записи в CAN-монитор. except ValueError as exc: self.put(ss, es, self.out_ann, [2, [str(exc)]]) + for title, value in frame.get('fields', []): # Стековые UART-профили могут возвращать готовые прикладные поля. + self.put(ss, es, self.out_ann, [3, [prefix + '%s: %s' % (title, value)]]) # Префикс RX/TX сохраняет направление каждого значения. frame['direction'] = direction self.put(ss, es, self.out_python, ['FRAME', frame]) if frame['payload']: self.put(ss, es, self.out_ann, [1, [prefix + ' '.join('%02X' % b for b in frame['payload'])]]) + def make_parser(self): # Фабрика позволяет использовать ту же UART-границу с другим переносимым потоковым парсером. + return StreamParser(self.options['protocol']) # Каждый экземпляр хранит байты только одного направления. + def decode(self, ss, es, data): kind, direction, payload = data if direction not in (0, 1): return # RX и TX имеют независимые парсеры: перемежающиеся байты двух направлений # нельзя объединять в один прикладной кадр. - parser = self.parsers.setdefault(direction, StreamParser(self.options['protocol'])) + if direction not in self.parsers: # В отличие от setdefault, проверка не создаёт и не отбрасывает парсер на каждом UART-событии. + self.parsers[direction] = self.make_parser() # Парсер создаётся один раз на направление и сохраняет незавершённый кадр. + parser = self.parsers[direction] # RX и TX продолжают использовать независимые буферы. if kind in ('INVALID STOPBIT', 'INVALID STARTBIT', 'PARITY ERROR', 'BREAK'): self.emit(parser.flush(), direction) self.put(ss, es, self.out_ann, [2, [kind]]) diff --git a/tools/dsview/decoders/tms_uart/__init__.py b/tools/dsview/decoders/tms_uart/__init__.py new file mode 100644 index 0000000..5947668 --- /dev/null +++ b/tools/dsview/decoders/tms_uart/__init__.py @@ -0,0 +1 @@ +from .pd import Decoder # Экспортирует стандартную точку входа анализатора libsigrokdecode. diff --git a/tools/dsview/decoders/tms_uart/pd.py b/tools/dsview/decoders/tms_uart/pd.py new file mode 100644 index 0000000..2f2309c --- /dev/null +++ b/tools/dsview/decoders/tms_uart/pd.py @@ -0,0 +1,18 @@ +from set_uart.pd import Decoder as SetUartDecoder # Общий адаптер уже разделяет RX/TX, учитывает паузы и отклоняет ошибки UART. +from common.setgui_decoders.tms_uart import LAYOUTS, TmsStreamParser, tms # Подключает существующий парсер и каталог раскладок templates. + +class Decoder(SetUartDecoder): # Использует проверенную UART-границу вместо второй реализации обработки байтов sigrok. + id = 'tms_uart' # Отдельный ID позволяет одновременно анализировать SET и исторический терминальный обмен. + name = 'TMS UART' # Короткое имя отображается в меню и дорожках. + longname = 'TMS terminal / TMS_TO_TERMINAL' # Полное имя соответствует структуре действующего протокола терминала. + desc = 'Templates TMS terminal frames, analog values, discrete bits and CRC.' # Подсказка перечисляет доступные поля расшифровки. + options = ( # Параметры раскладки повторяют возможности общего парсера терминала. + {'id': 'layout', 'desc': 'Layout / раскладка', 'default': tms.DEFAULT_PRESET, 'values': LAYOUTS}, # Готовые раскладки поступают из единого каталога templates. + {'id': 'digit_bytes', 'desc': 'Custom discrete bytes / байт дискретов', 'default': 38}, # В custom задаётся длина дискретной части в байтах. + {'id': 'analog_count', 'desc': 'Custom analog words / слов аналогов', 'default': 34}, # В custom задаётся число знаковых 16-битных аналоговых слов. + {'id': 'crc', 'desc': 'CRC variant', 'default': tms.DEFAULT_CRC, 'values': tuple(tms.CRC_VARIANTS)}, # Неподтверждённые CRC кадры общий парсер не выдаёт. + {'id': 'gap_ms', 'desc': 'Reset after gap (ms, 0 disables)', 'default': 100}, # Пауза 100 мс по умолчанию отделяет незавершённые посылки. + ) # Опции протокола SET здесь не требуются. + + def make_parser(self): # Базовый адаптер создаёт отдельный парсер для каждого направления UART. + return TmsStreamParser(self.options['layout'], self.options['digit_bytes'], self.options['analog_count'], self.options['crc']) # Общая модель проверяет диапазоны и рассчитывает длину кадра. diff --git a/tools/dsview/install_decoders.ps1 b/tools/dsview/install_decoders.ps1 index 8ea6321..79ca608 100644 --- a/tools/dsview/install_decoders.ps1 +++ b/tools/dsview/install_decoders.ps1 @@ -63,7 +63,8 @@ if (-not (Test-Path -LiteralPath (Join-Path $decoderRoot 'common') -PathType Con # An explicit allowlist excludes tests, bytecode and unrelated modules. # The private common/setgui_decoders layout matches the embedded build. $files = @() -foreach ($name in @('gate_driver_timing', 'transistor_pair', 'set_uart', 'set_can', 'pm35_uart')) { +$manifest = Get-Content -LiteralPath (Join-Path $PSScriptRoot 'protocol-files.json') -Encoding UTF8 -Raw | ConvertFrom-Json # Общая ведомость совпадает с рецептом встроенного DSView. +foreach ($name in $manifest.adapters) { # Список включает все поставляемые анализаторы без отдельного перечня в установщике. foreach ($leaf in @('__init__.py', 'pd.py')) { $files += [pscustomobject]@{ Source = Join-Path $PSScriptRoot "decoders/$name/$leaf" @@ -71,12 +72,18 @@ foreach ($name in @('gate_driver_timing', 'transistor_pair', 'set_uart', 'set_ca } } } -foreach ($name in @('__init__', 'gate_timing', 'transistor_pair', 'set_uart', 'set_can', 'pm35_uart')) { +foreach ($name in $manifest.cores) { # Общие ядра и адаптеры устанавливаются из одной закреплённой версии templates. $files += [pscustomobject]@{ Source = Join-Path $templateRoot "python/logic_analyzer/decoders/$name.py" Relative = "common/setgui_decoders/$name.py" } } +foreach ($name in $manifest.template_files) { # Подключённым парсерам нужны исходные модули и JSON-словари протоколов. + $files += [pscustomobject]@{ # Новые зависимости проходят те же проверки, резервное копирование и откат, что существующие ядра. + Source = Join-Path $templateRoot "python/$name" # Источник всегда находится в общем templates, независимо от текущего каталога. + Relative = "common/setgui_decoders/templates/$name" # Закрытый каталог не создаёт лишних анализаторов в списке sigrok. + } # Исходные пакеты сохраняют собственные относительные импорты и не требуют внешнего Python. +} # Все зависимости включены в транзакцию до первого изменения установленного декодера. # Validate the entire payload and destination before changing any decoder. foreach ($file in $files) { if (-not (Test-Path -LiteralPath $file.Source -PathType Leaf)) { @@ -97,13 +104,31 @@ if ($CheckOnly) { Write-Output "Validated $($files.Count) files for $targetRoot. No files changed." return } -# A mapped/running Windows EXE cannot be opened for writing. Never terminate DSView. -try { - $handle = [IO.File]::Open($exe, [IO.FileMode]::Open, [IO.FileAccess]::ReadWrite, [IO.FileShare]::Read) - $handle.Dispose() -} catch { - throw "Close DSView and check write permissions for '$targetRoot'. For Program Files, run PowerShell as administrator. $($_.Exception.Message)" -} +# Проверяем запущенный процесс отдельно: установка декодеров не требует права записи в DSView.exe. +foreach ($process in @(Get-Process -Name 'DSView' -ErrorAction SilentlyContinue)) { # Другие экземпляры DSView не мешают обновлению выбранного каталога. + try { # Доступ к пути процесса может быть ограничен правами владельца. + $processPath = $process.MainModule.FileName # Путь определяет принадлежность процесса конкретной установке. + } catch { # Без пути нельзя достоверно исключить работу целевого компонента. + throw 'Cannot inspect a running DSView process. Close DSView before installing decoders.' # Установщик не завершает процесс и не прерывает захват. + } # Ошибка просмотра процесса отделена от отсутствия права копировать файлы. + if ($processPath -and [string]::Equals([IO.Path]::GetFullPath($processPath), $exe, [StringComparison]::OrdinalIgnoreCase)) { # Регистр Windows-пути не влияет на совпадение. + throw "Close DSView before updating decoders in '$targetRoot'." # После закрытия требуется повторный запуск того же установщика. + } # Работа другой установки DSView допускается. +} # Проверка выполняется только при настоящем копировании, после CheckOnly. + +# Пробные файлы проверяют реальные каталоги назначения и резервных копий, не затрагивая EXE. +foreach ($directory in @($targetRoot, $decoderRoot)) { # Резервные копии создаются рядом с EXE, а новые модули — внутри decoders. + $probe = Join-Path $directory ('.set-decoder-write-' + [guid]::NewGuid().ToString('N') + '.tmp') # Уникальное имя исключает перезапись пользовательского файла. + $handle = $null # Дескриптор освобождается и при неудачном создании файла. + try { # Права записи проверяются до резервного копирования и замены первого декодера. + $handle = [IO.File]::Open($probe, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None) # Пробный файл проверяет создание в выбранном каталоге. + } catch { # Защищённый Program Files требует повышения прав либо выбора доступной установки. + throw "No write access to '$directory'. Select a writable DSView directory or run PowerShell as administrator for Program Files. $($_.Exception.Message)" # Сообщение называет каталог, а не ошибочно запущенный EXE. + } finally { # Временные проверки не должны оставлять файлы после успешного или неуспешного запуска. + if ($null -ne $handle) { $handle.Dispose() } # Закрываем только дескриптор созданного нами файла. + if ([IO.File]::Exists($probe)) { [IO.File]::Delete($probe) } # Удаляется только уникальный файл текущей проверки, без обхода каталогов. + } # Исходные декодеры на этом этапе ещё не изменены. +} # Дальнейшая транзакция сохраняет существующую политику резервного копирования и отката. # Keep each previous version outside decoder discovery directories. # Retain backups after success for manual recovery, not only after errors. @@ -150,6 +175,6 @@ try { } throw $failure } -Write-Output "Installed: IGBT 1SP/1SD, SET UART, SET CAN, PM35 UART in $decoderRoot" +Write-Output "Installed: $($manifest.adapters -join ', ') in $decoderRoot" # Список формируется по общей ведомости, включая Plates PBus и Plates SBus. if (Test-Path -LiteralPath $backup) { Write-Output "Previous files retained in: $backup" } -Write-Output 'Restart DSView. Add UART/CAN first, then stack the corresponding SET decoder. No external Python is required.' +Write-Output 'Restart DSView. Plates PBus/SBus use logic channels directly; SET UART/CAN decoders stack over UART/CAN. No external Python is required.' # Подключение шинных анализаторов отличается от надстроек над UART/CAN. diff --git a/tools/dsview/protocol-files.json b/tools/dsview/protocol-files.json new file mode 100644 index 0000000..975df95 --- /dev/null +++ b/tools/dsview/protocol-files.json @@ -0,0 +1,17 @@ +{ + "adapters": ["gate_driver_timing", "transistor_pair", "set_uart", "set_can", "pm35_uart", "tms_uart", "plates_pbus", "plates_sbus"], + "cores": ["__init__", "gate_timing", "transistor_pair", "set_uart", "set_can", "pm35_uart", "template_protocols", "tms_uart"], + "template_files": [ + "protocan/__init__.py", + "protocan/native.py", + "protocan/protocan.py", + "protocan/balsam.py", + "protocan/legacycan.py", + "protocan/gas_167.py", + "protocan/gas_167_registers.json", + "set_devices/__init__.py", + "set_devices/deif_xdi.py", + "set_devices/ump_can.py", + "set_devices/tms_terminal.py" + ] +} diff --git a/tools/dsview/setgui-host.patch b/tools/dsview/setgui-host.patch index 8470419..91e5dd8 100644 --- a/tools/dsview/setgui-host.patch +++ b/tools/dsview/setgui-host.patch @@ -597,8 +597,8 @@ index 648eb5b8..1a023707 100644 + const auto after = _protocol_lay_items.size(); + ok = phase % 2 == 0 ? after == before : after == (phase == 1 ? before - 1 : 0); + } -+ } else if (phase < 8) { -+ const QString id = QStringList({"gate_driver_timing", "set_uart", "set_can", "pm35_uart"})[phase - 4]; ++ } else if (phase < 9) { // Проверяем также новый парсер терминальных UART-посылок ТМС. ++ const QString id = QStringList({"gate_driver_timing", "set_uart", "set_can", "pm35_uart", "tms_uart"})[phase - 4]; // Индекс отсчитывается после четырёх проверок удаления анализаторов. + if (get_protocol_index_by_id(id) < 0) ok = false; + else { + QTimer::singleShot(80, this, [report, id]() { @@ -618,7 +618,7 @@ index 648eb5b8..1a023707 100644 + ok = QString(trace->decoder()->stack().back()->decoder()->id) == id; + } + } -+ } else if (phase == 8) { ++ } else if (phase == 9) { // После пяти прикладных анализаторов проверяем удаление всего набора дорожек. + answer(QMessageBox::Yes); + on_del_all_protocol(); + ok = _protocol_lay_items.empty() && _session->get_decode_signals().empty(); diff --git a/tools/dsview/tests/test_decoders.py b/tools/dsview/tests/test_decoders.py index eae67b4..abcff6f 100644 --- a/tools/dsview/tests/test_decoders.py +++ b/tools/dsview/tests/test_decoders.py @@ -58,6 +58,9 @@ try: gate = importlib.import_module('gate_driver_timing.pd') pair_decoder = importlib.import_module('transistor_pair.pd') pmcore = importlib.import_module('common.setgui_decoders.pm35_uart') + templates_core = importlib.import_module('common.setgui_decoders.template_protocols') # Новый прикладной слой импортируется из изолированного runtime. + tms_decoder = importlib.import_module('tms_uart.pd') # Проверяет контракт точки входа нового UART-анализатора. + tms_core = importlib.import_module('common.setgui_decoders.tms_uart') # Потоковый адаптер использует поставленные общие раскладки терминала. finally: sys.path.pop(0) if previous is None: @@ -225,7 +228,7 @@ class CanTests(unittest.TestCase): cancore.legacy(0x1b530010, b'\x00') def test_balsam_mask_and_endianness(self): - result = cancore.legacy(0xba0010, bytes.fromhex('a01012340000ffff'), 'balsam') + result = cancore.legacy(0xba0010, bytes.fromhex('0000ffffa0101234'), 'balsam') # Реальная прошивка передаёт value2, value3, header, value1; отмечены первое и третье слова. self.assertEqual(result['registers'], [(16, 0x1234), (18, 0xffff)]) self.assertIsNone(cancore.legacy(0xba000f, bytes(8), 'balsam')) @@ -241,6 +244,83 @@ class CanTests(unittest.TestCase): self.assertIn('status=0', cancore.legacy(0x1b5c0702, bytes.fromhex('00ff000000000000'))['summary']) +class TemplateProtocolTests(unittest.TestCase): # Сверяет прикладные события DSView с действующими парсерами templates. + def test_every_legacy_project_uses_its_wire_layout(self): # Все проекты проверяются настоящими кодировщиками обоих исторических форматов. + for project in templates_core.legacycan.PROJECTS: # Каталог включает Буксир, СЭДБМ, Ледокол, Бальзам, 23550, Янтарь и варианты формата. + with self.subTest(project=project.name): # Ошибка сообщает конкретный несовместимый профиль. + node = project.nodes[0] # Достаточно одного узла для проверки раскладки выбранного проекта. + packet = templates_core.legacycan.encode_write(project.format, node.rx_id, 16, (0x1234, 0xffff)) # Различающиеся байты выявляют ошибку порядка слов и байтов. + result = templates_core.decode_can(packet.can_id, packet.data, 'legacy', project=project.name) # Разбор выполняется тем же путём, что у адаптера sigrok. + self.assertEqual(result['registers'], [(16, 0x1234), (17, 0xffff)]) # Оба wire-формата должны восстанавливать одинаковые адреса и значения. + self.assertIn(node.name, result['summary']) # Вывод включает имя устройства из актуального каталога проекта. + + def test_balsam_real_wire_order_and_pult(self): # Регрессия неправильного положения адресного слова в прежнем адаптере. + for ident in (0xba0004, 0xba0014, 0x745009, 0x745019): # Проверяются УМП в обоих направлениях и отдельная пара ID пульта. + result = templates_core.decode_can(ident, bytes.fromhex('11223344e07f8000'), 'balsam') # Маска 111 в header=E07F отмечает три слова начиная с командного регистра 127. + self.assertEqual(result['registers'], [(127, 0x8000), (128, 0x1122), (129, 0x3344)]) # В wire сначала идут второе и третье слова, а первое находится в конце. + self.assertIsNone(templates_core.decode_can(0xba000f, bytes(8), 'balsam')) # Отсутствующий узел не выдаётся за сообщение Balsam. + + def test_ump_maps_keep_nodes_and_assigned_ids_separate(self): # Локальная карта 167/v1 и новые глобальные ID не должны смешиваться. + local = templates_core.decode_can(0x1b53007f, b'\x80\x00', 'ump-protocan', ump_node=2) # Бит 7 командного регистра означает пуск УМП в локальной карте. + self.assertIn('УМП 2', local['summary']) # Локальный адрес не теряет выбранный вручную номер устройства. + self.assertIn('cUMPstart', local['summary']) # Имена команд берутся из действующей карты, а не остаются сырым HEX. + assigned = templates_core.decode_can(0x1b530000 | 6000, b'\x01\x00', 'ump-protocan', ump_map='assigned') # Десятичный GAS ID 6000 относится к назначенной карте второго УМП. + self.assertIn('sens_error[0]', assigned['summary']) # Параметр получает имя из JSON-словаря templates. + + def test_deif_standard_can_and_physical_value(self): # DEIF должен получать STD-кадры, которые прежний SET CAN отбрасывал. + decoder = instance(can, protocol='deif') # Выбор DEIF явно разрешает стандартный CANopen ID. + raw = bytes.fromhex('010130027b000000') # Объект 0x3001:02 содержит RAW=123, соответствующий углу 12.3 градуса. + decoder.decode(10, 90, ('standard', 0x201, 'data', len(raw), raw)) # Вектор проходит реальную границу адаптера sigrok. + result = frames(decoder)[0] # Результат доступен и в Python-выходе, и в аннотациях. + self.assertIn('12.3', result['summary']) # Масштаб задаёт существующий DEIF-парсер. + self.assertTrue(any(item[2] == 0 and item[3][0] == 3 for item in decoder.emitted)) # Проверяет фактическое появление подробных полей на новой дорожке. + + def test_can_auto_routes_set_v2_and_balsam(self): # Авто ограничено проверяемыми сигнатурами и не угадывает исторические проекты. + decoder = instance(can, protocol='auto') # Профиль использует прежний сборщик SET v2 и общий парсер Balsam. + for index, payload in enumerate(CanTests().segments()): # Документированный SET PING разбивается штатным тестовым транспортом. + decoder.decode(index * 1000, index * 1000 + 900, ('extended', 0x122a0000, 'data', len(payload), payload)) # Номер отсчёта обеспечивает проверяемый тайм-аут сборки. + self.assertEqual(frames(decoder)[-1]['raw'], PING) # Авто должен вернуть исходный CRC-подтверждённый SET v2 пакет. + raw = bytes.fromhex('0000000080101234') # Заголовок отмечает первое слово по адресу 16, находящееся в конце CAN-данных. + decoder.decode(4000, 4900, ('extended', 0xba0014, 'data', 8, raw)) # ID относится к ответу первого УМП Balsam 167. + self.assertEqual(frames(decoder)[-1]['registers'], [(16, 0x1234)]) # Авто не интерпретирует Balsam как Boot Data ProtoCAN. + + def test_uart_bridge_uses_selected_can_profile(self): # Проверяет перенос общего CAN-разбора через UART-транспорт AA55. + for profile, ident, flags, payload in (('balsam', 0xba0014, 1, bytes.fromhex('0000000080101234')), ('deif', 0x201, 0, bytes.fromhex('010130027b000000'))): # Векторы охватывают EXT Balsam и STD DEIF с разным значением IDE. + decoder = instance(uart, can_protocol=profile) # Выбор профиля моста не меняет основной потоковый формат SET UART. + body = bytes([6 + len(payload), 1, flags]) + struct.pack('= origin + edge # Таймер может совпасть с фронтом в той же точке. + else: # Цифровой канал имеет уровень 0 или 1. + before, after = self.samples[sample - 1][channel], self.samples[sample][channel] # Сравниваются соседние отсчёты, а не соседние пробуждения. + valid = valid and before != after and (edge == 'e' or (edge == 'r' and after == 1) or (edge == 'f' and after == 0)) # Разрешены оба фронта или отдельное направление. + if valid: # Несколько альтернатив могут совпасть одновременно. + matched |= 1 << index # DSView представляет matched целочисленной маской. + if matched: # Возвращаем ближайшее подходящее событие, не пропуская таймеры. + self.samplenum, self.matched = sample, matched # Атрибуты обновляются до возврата уровней. + return self.samples[sample] # Декодер видит уровни именно в точке события. + raise EndOfCapture() # Отсутствие событий до конца захвата завершает поток. + + +# Импорт не должен оставлять ложный sigrokdecode в окружении остальных тестов проекта. +def load_decoders(): # Возвращает модули для доступа к классам и проверяемому CRC. + root = Path(__file__).resolve().parents[1] / 'decoders' # Оба независимых пакета лежат в соседней папке decoders. + stub = types.ModuleType('sigrokdecode') # Создаём подмену только для импорта зависимых классов. + stub.Decoder, stub.OUTPUT_ANN, stub.OUTPUT_PYTHON, stub.SRD_CONF_SAMPLERATE = Runtime, 0, 1, 2 # Значения констант согласованы с Runtime. + original = sys.modules.get('sigrokdecode') # Ранее импортированный настоящий модуль нужно сохранить. + sys.modules['sigrokdecode'] = stub # Классы декодеров получают тестовую реализацию базового API. + sys.path.insert(0, str(root)) # Пакеты импортируются без копирования исходников. + try: # Восстановление окружения обязательно и при ошибке импорта. + return importlib.import_module('plates_sbus.pd'), importlib.import_module('plates_pbus.pd') # Проверяется и экспорт из __init__.py. + finally: # Другие тесты не должны зависеть от нашей подмены. + sys.path.remove(str(root)) # Убираем только путь, добавленный этим импортом. + if original is None: # При отсутствии настоящего модуля восстанавливаем его отсутствие. + del sys.modules['sigrokdecode'] # Ссылки внутри декодеров уже удерживают тестовую среду. + else: # В окружении с sigrokdecode возвращаем исходный объект. + sys.modules['sigrokdecode'] = original # Чужие импорты продолжают работать штатно. + + +SBUS, PBUS = load_decoders() # Все проверки исполняют рабочие файлы, а не копии алгоритмов. + + +# Трасса хранит уровни на каждом отсчёте, поэтому среда независимо обнаруживает реальные фронты. +class Trace: # Частота тестовых трасс SBus равна 100 МГц: один отсчёт — 10 нс. + def __init__(self, levels): # Начальные уровни задаются до первого сохранённого отсчёта. + self.levels, self.samples = list(levels), [] # Текущие уровни отделены от уже записанного захвата. + + def hold(self, count, updates=None): # Удерживаем сигналы count отсчётов после применения изменений. + for channel, level in (updates or {}).items(): # Незаданные сигналы сохраняют прежнее состояние. + self.levels[channel] = level # Канал индексируется в порядке объявления декодера. + self.samples.extend([tuple(self.levels)] * count) # Кортежи исключают случайное изменение истории при следующем фронте. + + +# Кадры задаются фиксированными полями и CRC, без обращения к реализации расчёта в декодере. +def serial_frame(trace, direction=1, address=0x32, value=0x1234, crc=1, ack=0, limit=29, tail=1000, tail_clock=0): # Полный формат содержит 29 нарастающих фронтов. + frame = (direction << 28) | (address << 20) | (value << 4) | crc # Временная разметка независима от внутреннего буфера декодера. + for index, shift in enumerate(range(28, 28 - limit, -1)): # limit позволяет оборвать кадр на любом поле. + bit = (frame >> shift) & 1 # Каждый бит передаётся старшим вперёд. + tx, rx = (bit, 1) if index < 9 or direction else (1, bit) # При чтении TX заполнен единицами, чтобы обнаружить выбор неверной линии. + trace.hold(14, {0: 0, 1: tx, 2: rx}) # Ведомое устанавливает ответ на спаде CLK за 140 нс до выборки. + trace.hold(14, {0: 1}) # Полупериод 140 нс совпадает с существующим HDL-тестом. + if tail: # Отсутствие хвоста моделирует конец файла непосредственно после последнего бита. + trace.hold(tail, {0: tail_clock, 2: ack if direction else trace.levels[2]}) # ACK появляется после последнего CRC, а затем CLK может оставаться неподвижным. + + +# Формирование PBus не использует состояния декодера: задаётся только последовательность физических уровней. +def parallel_frame(trace, address=0x32, value=0x1234, inverse=None, bad_address=False, phases=3, clock_ok=True, simultaneous=False): # phases ограничивает число полученных подтверждений. + word = (address << 8) | ((address ^ 255) ^ int(bad_address)) # Адрес защищён побитовой инверсией младшего байта. + data = {2 + bit: (word >> bit) & 1 for bit in range(16)} # D0…D15 записываются на отдельные физические каналы. + trace.hold(10, data) # Адрес устанавливается до разрешения CE. + trace.hold(10, {0: 0, 1: 0 if simultaneous and phases else 1, 18: 1}) # Возможен одновременный спад CE и адресного ACK в одном отсчёте. + if phases: # Адресный ACK опускается только при наличии ответа. + trace.hold(10, {1: 0}) # Первый низкий ACK подтверждает приём адреса. + if phases >= 2: # Прямые данные передаются только после адресного подтверждения. + trace.hold(10, {2 + bit: (value >> bit) & 1 for bit in range(16)}) # Данные становятся стабильны заранее. + trace.hold(10, {1: 1, 18: 0 if clock_ok else 1}) # Высокий ACK подтверждает прямые данные при низком CLK. + if phases >= 3: # Полное чтение должно получить независимое инверсное слово. + inverse = (value ^ 65535) if inverse is None else inverse # Аргумент позволяет повредить контрольную копию. + trace.hold(10, {2 + bit: (inverse >> bit) & 1 for bit in range(16)}) # Инверсия устанавливается до своего ACK. + trace.hold(10, {1: 0, 18: 1 if clock_ok else 0}) # Последний низкий ACK отмечает готовность контрольного слова. + trace.hold(10, {0: 1, 1: 1}) # CE возвращается в неактивное состояние, ведомое отпускает ACK. + + +# Настройка окружения одинакова для всех трасс и не зависит от алгоритма протокола. +def run_decoder(module, trace, options=None, connected=None, samplerate=100000000): # Временная шкала по умолчанию соответствует 10 нс на отсчёт. + decoder = module.Decoder() # Исполняется штатный конструктор и reset(). + decoder.samples, decoder.result, decoder.samplenum = trace.samples, [], 0 # Состояние тестовой среды хранится отдельно от автомата шины. + decoder.connected = set(range(len(trace.levels))) if connected is None else set(connected) # При необходимости можно отключать отдельные входы. + decoder.options = {item['id']: item['default'] for item in getattr(decoder, 'options', ())} # Среда применяет объявленные значения по умолчанию. + decoder.options.update(options or {}) # Тест может изменить интервалы выборки. + decoder.start() # Выходы должны быть зарегистрированы до первой аннотации. + if samplerate is not None and hasattr(decoder, 'metadata'): # PBus не требует частоту для выборки по ACK. + decoder.metadata(2, samplerate) # Константа 2 соответствует SRD_CONF_SAMPLERATE заглушки. + try: # Только штатный конец захвата перехватывается как успешное завершение. + decoder.decode() # Проверяется настоящий цикл wait(), а не отдельно вызванные внутренние методы. + except EndOfCapture: # Любое другое исключение делает тест ошибочным. + decoder.last_samplenum = len(trace.samples) - 1 # Последний отсчёт нужен для корректного end(). + decoder.end() # Незавершённые операции должны быть выведены при конце файла. + packets = [data[1] for _, _, output, data in decoder.result if output == 1] # Извлекаем структурированные FRAME-пакеты. + warnings = [data[1][0] for _, _, output, data in decoder.result if output == 0 and data[0] == len(decoder.annotations) - 1] # Последний класс обоих декодеров содержит предупреждения. + return packets, warnings # Проверяем одновременно данные операций и явную диагностику. + + +# Набор проверяет содержимое кадров, повторную синхронизацию, границы и настройку каналов. +class DecoderTests(unittest.TestCase): # unittest позволяет запускать тесты без GUI и библиотек DSView. + def serial(self): # Готовим заведомо достаточную паузу перед первым запросом. + trace = Trace((0, 1, 1)) # Мастер держит низкий CLK, обе линии данных отпущены в единицу. + trace.hold(1000) # Десять микросекунд превышают 3,6 мкс reset в HDL. + return trace # Дальнейшие фронты добавляются конкретным тестом. + + def parallel(self): # PBus стартует в неактивной фазе CE. + trace = Trace((1, 1) + (0,) * 16 + (1,)) # CE и ACK высокие, D0…D15 нулевые, CLK высокий. + trace.hold(10) # Первый wait() увидит исходные уровни до спада CE. + return trace # Физический запрос добавляется независимо от декодера. + + def test_write_and_delayed_ack_without_more_clocks(self): # Проверяем отдельный таймер ACK после последнего такта. + trace = self.serial() # Начальная пауза обеспечивает синхронизацию. + serial_frame(trace, tail_clock=1) # После CRC CLK остаётся высоким без новых фронтов. + packets, warnings = run_decoder(SBUS, trace) # Декодируется весь цифровой поток. + self.assertEqual((packets[0]['dev'], packets[0]['reg'], packets[0]['value']), (3, 2, 0x1234)) # Поля должны совпасть с запросом. + self.assertTrue(packets[0]['crc_ok'] and packets[0]['ack']) # Хороший CRC и низкий ACK проверяются независимо. + self.assertEqual(warnings, []) # Полный корректный кадр не содержит предупреждений. + + def test_read_uses_response_line(self): # TX после заголовка специально не содержит полезных данных чтения. + trace = self.serial() # Пауза позволяет принять первый бит направления. + serial_frame(trace, direction=0, value=0xCAFE, crc=7) # Контрольный вектор ответа отличается от всех единиц на TX. + packets, warnings = run_decoder(SBUS, trace) # Читаем по нарастающим фронтам после установки RX на спаде. + self.assertEqual((packets[0]['operation'], packets[0]['value'], packets[0]['ack']), ('read', 0xCAFE, None)) # У чтения нет ACK записи. + self.assertTrue(packets[0]['crc_ok']) # Контрольная сумма включает заголовок с TX и данные с RX. + self.assertEqual(warnings, []) # Правильное переключение линий не создаёт ошибок. + + def test_repeated_writes_and_both_idle_levels(self): # Повтор одинакового значения остаётся отдельной командой. + trace = self.serial() # Первый кадр начинается после начальной паузы. + serial_frame(trace, tail_clock=1) # Первая межкадровая пауза держит CLK высоким. + serial_frame(trace, tail_clock=0) # Вторая пауза держит CLK низким. + packets, warnings = run_decoder(SBUS, trace) # Оба уровня паузы должны разрешать синхронизацию. + self.assertEqual([packet['value'] for packet in packets], [0x1234, 0x1234]) # Никакой дедупликации по значению быть не должно. + self.assertEqual(warnings, []) # Повторная команда и высокий idle являются допустимыми. + + def test_crc_error_does_not_hide_ack(self): # ACK не заменяет проверку целостности принятого кадра. + trace = self.serial() # Создаём синхронизированный поток. + serial_frame(trace, crc=0, ack=0) # Один бит CRC повреждён, но ответ линии низкий. + packets, warnings = run_decoder(SBUS, trace) # Кадр должен остаться доступным для диагностики. + self.assertFalse(packets[0]['crc_ok']) # Расчёт CRC обнаруживает повреждение. + self.assertTrue(packets[0]['ack']) # Наблюдавшийся ACK сохраняется независимо от CRC. + self.assertIn('CRC mismatch', warnings) # Ошибка присутствует в отдельной строке. + + def test_high_ack_is_not_success(self): # Высокий RX может означать отказ или отсутствие ведомого. + trace = self.serial() # Подготавливаем запрос с правильным CRC. + serial_frame(trace, ack=1) # Плата не подтверждает запись низким уровнем. + packets, warnings = run_decoder(SBUS, trace) # Разбор не должен путать CRC и успешность ответа. + self.assertTrue(packets[0]['crc_ok']) # Данные на запросе не повреждены. + self.assertFalse(packets[0]['ack']) # Высокий ответ не считается подтверждением. + self.assertIn('No low write ACK', warnings) # Причина обмена отмечается явно без предположений о плате. + + def test_partial_frame_resynchronizes_after_gap(self): # Потерянные биты не должны сдвигать все последующие кадры. + trace = self.serial() # Создаём начало корректно синхронизированного кадра. + serial_frame(trace, limit=12) # Обрываем кадр после заголовка и части данных. + serial_frame(trace) # Следующий кадр начинается после достаточной паузы. + packets, warnings = run_decoder(SBUS, trace) # Автомат должен восстановиться независимо от остатка первого запроса. + self.assertEqual(len(packets), 1) # Частичный кадр не выдаётся за полную команду. + self.assertEqual(packets[0]['value'], 0x1234) # Следующий кадр читается без смещения. + self.assertTrue(any('12/29' in text for text in warnings)) # Обрыв первого кадра остаётся виден. + + def test_capture_starting_mid_frame_waits_for_gap(self): # В начале файла может отсутствовать заголовок. + trace = Trace((0, 1, 1)) # Предварительной паузы здесь намеренно нет. + trace.hold(1) # Захват начинается непосредственно перед неизвестным тактом. + serial_frame(trace, limit=15) # Эти биты нельзя надёжно считать первым заголовком. + serial_frame(trace) # После паузы можно декодировать полную операцию. + packets, warnings = run_decoder(SBUS, trace) # Начальный фрагмент игнорируется до синхронизации. + self.assertEqual(len(packets), 1) # Ложный первый кадр не создаётся. + self.assertEqual(warnings, []) # Непроверяемый начальный фрагмент не объявляется ошибкой протокола. + + def test_capture_ends_in_data(self): # end() должен диагностировать обрыв без следующего события. + trace = self.serial() # Первый кадр начнётся после паузы. + serial_frame(trace, limit=20, tail=0) # Захват заканчивается внутри 16-битных данных. + packets, warnings = run_decoder(SBUS, trace) # Единственный способ закрыть фрагмент — end(). + self.assertEqual(packets, []) # Частичное значение не публикуется как полное. + self.assertTrue(any('20/29' in text for text in warnings)) # Сообщение содержит фактическое количество наблюдавшихся битов. + + def test_capture_ends_before_ack_sampling(self): # Нельзя считать неизвестный ACK ни положительным, ни отрицательным. + trace = self.serial() # Кадр полностью помещается после паузы. + serial_frame(trace, tail=0) # Конец захвата наступает раньше таймера ACK. + packets, warnings = run_decoder(SBUS, trace) # end() сохраняет полный запрос. + self.assertIsNone(packets[0]['ack']) # Подтверждение осталось ненаблюдавшимся. + self.assertIn('Write ACK not sampled: capture ended', warnings) # Причина неизвестности указана явно. + + def test_serial_bad_configuration(self): # Ошибки настройки должны выявляться до разбора потока. + for options in ({'ack_us': 0}, {'ack_us': 4}, {'idle_us': float('nan')}): # Проверяем нулевой, чрезмерный и нечисловой интервалы. + with self.subTest(options=options), self.assertRaises(ValueError): # Каждый неверный набор обязан быть отвергнут. + run_decoder(SBUS, self.serial(), options=options) # Не требуется наличие команды на входе. + with self.assertRaises(ValueError): # Отсутствие RX нельзя подменять единицей либо нулём. + run_decoder(SBUS, self.serial(), connected=(0, 1)) # Чтение и ACK требуют физического ответного канала. + with self.assertRaises(ValueError): # Без частоты захвата микросекунды не переводятся в отсчёты. + run_decoder(SBUS, self.serial(), samplerate=None) # Произвольные предполагаемые частоты недопустимы. + with self.assertRaises(ValueError): # Слишком редкие отсчёты сливают ACK и межкадровую паузу. + run_decoder(SBUS, self.serial(), samplerate=100000) # При 100 кГц один отсчёт равен 10 мкс. + + def test_crc_fixed_vectors(self): # Дополнительные контрольные значения охватывают направления и крайние адреса. + for direction, address, value, expected in ((1, 0, 0, 1), (0, 0, 0, 12), (1, 255, 65535, 1), (0, 255, 65535, 12), (0, 0x32, 0xCAFE, 7), (1, 0x57, 0, 7)): # Векторы фиксированы и не вычисляются генератором трассы. + with self.subTest(direction=direction, address=address, value=value): # Ошибка укажет конкретный вектор. + self.assertEqual(SBUS.frame_crc(direction, address, value), expected) # Проверяем в том числе четыре завершающие единицы HDL. + + def test_parallel_full_words_and_optional_clock(self): # Проверяем края диапазонов и сохранение старшего разряда данных. + for address, value in ((0, 0), (255, 65535), (0x32, 0x1234), (0x8F, 0x8001)): # Адрес и данные не должны превращаться в знаковые числа. + for connected in (range(18), range(19)): # PBCLK может отсутствовать либо участвовать в проверке фаз. + with self.subTest(address=address, value=value, clock=len(connected) == 19): # Каждый вариант проверяется независимо. + trace = self.parallel() # Готовим неактивные исходные уровни. + parallel_frame(trace, address=address, value=value) # На провод подаётся полная последовательность ACK. + packets, warnings = run_decoder(PBUS, trace, connected=connected) # Выборка идёт по реальным переходам ACK. + self.assertEqual((packets[0]['dev'], packets[0]['reg'], packets[0]['value']), (address >> 4, address & 15, value)) # Разделение адреса должно сохранять все биты. + self.assertTrue(packets[0]['ok'] and packets[0]['complete']) # Успешность требует полноты и правильной защиты. + self.assertEqual(warnings, []) # Корректный обмен не должен вызывать ложные ошибки. + + def test_parallel_bad_address_with_and_without_ack(self): # Повреждение адреса видно и при молчании ведомого. + for phases in (0, 3): # Проверяем отсутствие ответа и ошибочно подтверждённый адрес. + trace = self.parallel() # Начинаем отдельный захват для каждого случая. + parallel_frame(trace, bad_address=True, phases=phases) # Инвертируем один бит защитной копии адреса. + packets, warnings = run_decoder(PBUS, trace) # Декодер сохраняет наблюдавшийся запрос. + self.assertFalse(packets[0]['address_ok'] or packets[0]['ok']) # Хорошие данные ответа не исправляют неверный запрос. + self.assertIn('Address complement mismatch', warnings) # Ошибка защиты адреса должна остаться явной. + + def test_parallel_bad_inverse(self): # Последний ACK сам по себе не доказывает целостности данных. + trace = self.parallel() # Подготавливаем обычный адрес и прямые данные. + parallel_frame(trace, inverse=0) # Контрольное слово намеренно не равно инверсии 0x1234. + packets, warnings = run_decoder(PBUS, trace) # Все фазы обмена всё же присутствуют. + self.assertTrue(packets[0]['complete']) # Полнота и правильность являются разными свойствами. + self.assertFalse(packets[0]['inverse_ok'] or packets[0]['ok']) # Повреждённая копия делает обмен ошибочным. + self.assertIn('Data complement mismatch', warnings) # Есть понятная причина ошибки. + + def test_parallel_missing_each_ack(self): # Место обрыва различается по ожидаемой фазе. + for phases, missing in ((0, 'address'), (1, 'data'), (2, 'inverse')): # Проверяем все три точки ожидания. + with self.subTest(phases=phases): # Диагностика должна назвать нужную фазу. + trace = self.parallel() # Каждый запрос имеет свой неактивный префикс. + parallel_frame(trace, phases=phases) # CE снимается до завершения операции. + packets, warnings = run_decoder(PBUS, trace) # Закрытие по CE обязано выдать частичный результат. + self.assertFalse(packets[0]['complete'] or packets[0]['ok']) # Неполная операция никогда не успешна. + self.assertIn('Incomplete PBus: missing %s ACK' % missing, warnings) # Указана конкретная отсутствующая фаза. + + def test_parallel_capture_ends_before_inverse(self): # Отсутствие возврата CE не должно терять частичный запрос. + trace = self.parallel() # Создаём начало запроса и два подтверждения. + parallel_frame(trace, phases=2) # Генератор завершает CE, но ниже этот хвост удаляется. + trace.samples = trace.samples[:-10] # Обрываем файл при ещё активном CE. + packets, warnings = run_decoder(PBUS, trace) # end() должен закрыть ожидаемую инверсию. + self.assertEqual(packets[0]['value'], 0x1234) # Наблюдавшиеся прямые данные сохраняются. + self.assertIn('Incomplete PBus: missing inverse ACK', warnings) # Отсутствие последнего подтверждения остаётся явным. + + def test_parallel_phase_checks_only_with_clock(self): # Необязательный CLK усиливает диагностику, не меняя данные. + trace = self.parallel() # Одинаковые уровни используются в двух конфигурациях каналов. + parallel_frame(trace, clock_ok=False) # ACK данных и инверсии приходят при неверных уровнях CLK. + packets, warnings = run_decoder(PBUS, trace) # Подключённый CLK должен выявить обе ошибки. + self.assertFalse(packets[0]['ok']) # Данные правильные, но протокол фаз нарушен. + self.assertEqual(len(warnings), 2) # Ошибки прямой и инверсной фазы независимы. + packets, warnings = run_decoder(PBUS, trace, connected=range(18)) # Без захвата CLK его уровень не интерпретируется. + self.assertTrue(packets[0]['ok']) # Доступные проверки CE, ACK и содержимого проходят. + self.assertEqual(warnings, []) # Нельзя жаловаться на незахваченный сигнал. + + def test_parallel_repeats_and_simultaneous_enable_ack(self): # Фронты CE и ACK могут попасть в один отсчёт анализатора. + trace = self.parallel() # До первого запроса видны исходные высокие CE и ACK. + parallel_frame(trace, simultaneous=True) # Адресный ACK совпадает со спадом CE. + parallel_frame(trace) # Повтор того же чтения обязан оставаться отдельной операцией. + packets, warnings = run_decoder(PBUS, trace) # Оба способа начала проходят один автомат. + self.assertEqual(len(packets), 2) # Ни один запрос не теряется и не дублируется. + self.assertTrue(all(packet['ok'] for packet in packets)) # Оба кадра содержат полные корректные проверки. + self.assertEqual(warnings, []) # Совпадение фронтов само по себе не ошибка. + + def test_parallel_start_in_active_transaction(self): # Начальная активная CE не доказывает наличие полного адреса. + trace = self.parallel() # Сначала строим полный физический обмен. + parallel_frame(trace) # Часть начала будет удалена из файла захвата. + trace.samples = trace.samples[45:] # Первый видимый отсчёт находится внутри активной операции. + parallel_frame(trace) # Следующий полный запрос должен декодироваться нормально. + packets, warnings = run_decoder(PBUS, trace) # Начальный фрагмент игнорируется до следующего спада CE. + self.assertEqual(len(packets), 1) # Частичное начало не порождает ложной операции. + self.assertEqual(warnings, []) # Нельзя диагностировать отсутствующий в файле адрес. + + def test_parallel_requires_every_data_bit(self): # Один незахваченный разряд делает 16-битное слово недостоверным. + with self.assertRaises(ValueError): # Декодер обязан отвергнуть неполное назначение каналов. + run_decoder(PBUS, self.parallel(), connected=range(17)) # Здесь отсутствует обязательный D15. + + def test_python36_syntax_and_line_comments(self): # Стиль проекта требует комментарий к каждой строке нового кода. + for path in Path(__file__).resolve().parents[1].glob('decoders/plates_*/*.py'): # Проверяются устанавливаемые Python-файлы обеих шин, без чужих декодеров при переносе в SETGUI. + source = path.read_text(encoding='utf-8') # Некорректная кодировка должна сразу приводить к ошибке. + ast.parse(source, filename=str(path), feature_version=(3, 6)) # DSView использует Python 3.6, поэтому более новый синтаксис запрещён. + for number, line in enumerate(source.splitlines(), 1): # Номер строки помогает исправить нарушение стиля. + if line.strip() and not line.lstrip().startswith('#'): # Пустые строки и отдельные комментарии не содержат исполняемый код. + self.assertIn('#', line, '%s:%d' % (path, number)) # Каждая строка кода сопровождается пояснением. + + +if __name__ == '__main__': # Разрешаем запуск как файла и через unittest discovery. + unittest.main() # Стандартный запуск выдаёт количество проверок и подробности ошибок. diff --git a/tools/dsview/tests/test_runtime.py b/tools/dsview/tests/test_runtime.py index 6cc908a..f5c0221 100644 --- a/tools/dsview/tests/test_runtime.py +++ b/tools/dsview/tests/test_runtime.py @@ -43,14 +43,13 @@ class RuntimeTests(unittest.TestCase): with tempfile.TemporaryDirectory() as temporary: root = Path(temporary) recipe = root / 'tools/dsview' - core = root / 'python/logic_analyzer/decoders' - core.mkdir(parents=True) - (recipe / 'decoders/gate_driver_timing').mkdir(parents=True) - (recipe / 'native').mkdir() + recipe.mkdir(parents=True) # Временный рецепт воспроизводит относительную структуру закреплённого templates. + (recipe / 'protocol-files.json').write_bytes(RECIPE.with_name('protocol-files.json').read_bytes()) # Реальная ведомость гарантирует включение новых зависимостей и карт. files = [recipe / 'build.py', recipe / 'setgui-host.patch', recipe / 'gate-pair-checkbox.patch', recipe / 'decoder-panel.patch', recipe / 'driver-summary.patch', recipe / 'windows-usb-events.patch', recipe / 'native/gate_summary.h', recipe / 'decoders/gate_driver_timing/pd.py'] - files += [core / (name + '.py') for name in ('gate_timing', 'transistor_pair', 'set_uart', 'set_can', 'pm35_uart')] + files += [root / item.relative_to(RECIPE.parents[2]) for item, _ in BUILD.protocol_payload()] # Проверка охватывает все канонические модули и JSON-карты, перечисленные в поставке. for item in files: + item.parent.mkdir(parents=True, exist_ok=True) # Для каждого переносимого пакета создаются вложенные каталоги. item.write_text('initial') with patch.object(BUILD, '__file__', str(recipe / 'build.py')): initial = BUILD.recipe_digest() @@ -60,3 +59,6 @@ class RuntimeTests(unittest.TestCase): self.assertNotEqual(initial, BUILD.recipe_digest()) item.write_text('initial') self.assertEqual(initial, BUILD.recipe_digest()) + with (recipe / 'protocol-files.json').open('a', encoding='utf-8') as output: # Пробел меняет хеш, сохраняя корректность JSON-ведомости. + output.write('\n') # Изменение самого состава поставки также должно требовать обновления runtime. + self.assertNotEqual(initial, BUILD.recipe_digest()) # Устаревшая ведомость не допускается к упаковке незаметно. From 41e24629ce04c73525ae0e86116a16e13e03db58 Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 24 Oct 2026 15:40:51 +0300 Subject: [PATCH 07/12] =?UTF-8?q?=D0=A0=D0=B0=D1=81=D1=88=D0=B8=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20DEIF,=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83?= =?UTF-8?q?=D0=B7=D0=BA=D1=83=20CAN=20=D0=B8=20=D0=BE=D0=B1=D1=89=D1=83?= =?UTF-8?q?=D1=8E=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D1=83?= =?UTF-8?q?=20=D1=81=D0=B8=D0=B3=D0=BD=D0=B0=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt. Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor. Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов. Обновить справочники устройств, проекты CCS и регрессионные проверки. --- c/firmware-info/tools/identity.py | 43 +- c/protocan-boot/.gitignore | 8 + c/protocan-boot/CMakeLists.txt | 17 +- c/protocan-boot/README.md | 8 +- c/protocan-boot/include/pcan_boot.h | 7 +- c/protocan-boot/ports/tms320f2812/README.md | 15 + c/protocan-boot/ports/tms320f2812/boot2812.h | 24 + .../ports/tms320f2812/boot_store.c | 105 + c/protocan-boot/ports/tms320f2812/nor_flash.c | 69 + c/protocan-boot/ports/tms320f28335/README.md | 100 +- .../ports/tms320f28335/f28335_boot_platform.h | 1 + .../tms320f28335/f28335_can_application.c | 10 + .../ports/tms320f28335/f28335_can_boot.c | 98 +- .../ports/tms320f28335/f28335_can_boot.h | 6 +- .../ports/tms320f28335/f28335_flash_app.c | 26 + .../ports/tms320f28335/f28335_flash_app.h | 11 + .../ports/tms320f28335/f28335_flash_update.c | 86 + .../ports/tms320f28335/f28335_flash_update.h | 20 + c/protocan-boot/projects/README.md | 156 + c/protocan-boot/projects/build.py | 86 + .../projects/ccs/f2812/.ccsproject | 20 + c/protocan-boot/projects/ccs/f2812/.cproject | 306 + c/protocan-boot/projects/ccs/f2812/.project | 106 + .../projects/ccs/f2812/F2812_CAN_NOR.cmd | 28 + c/protocan-boot/projects/ccs/f2812/board.c | 30 + .../projects/ccs/f2812/boot_store.c | 1 + .../projects/ccs/f2812/codestart.asm | 12 + c/protocan-boot/projects/ccs/f2812/main.c | 114 + .../projects/ccs/f2812/nor_flash.c | 1 + .../projects/ccs/f2812/shared_boot.c | 1 + .../ccs/f2812/targetConfigs/TMS320F2812.ccxml | 12 + .../projects/ccs/f28335/.ccsproject | 20 + c/protocan-boot/projects/ccs/f28335/.cproject | 326 + c/protocan-boot/projects/ccs/f28335/.project | 115 + .../projects/ccs/f28335/F28335_CAN_AB.cmd | 32 + .../projects/ccs/f28335/codestart.asm | 12 + .../projects/ccs/f28335/flash_update.c | 33 + c/protocan-boot/projects/ccs/f28335/main.c | 127 + .../projects/ccs/f28335/shared_boot.c | 5 + .../f28335/targetConfigs/TMS320F28335.ccxml | 54 + c/protocan-boot/src/pcan_boot.c | 20 +- .../tests/f28335_stubs/DSP2833x_Device.h | 2 +- c/protocan-boot/tests/run_tests.py | 4 +- c/protocan-boot/tests/test_f2812_nor.c | 83 + c/protocan-boot/tests/test_f28335_can_boot.c | 46 +- c/protocan-boot/tests/test_pcan_busy.c | 22 + c/protocan-boot/vendor/ti/README.md | 20 + .../ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd | 102 + .../f2812/common/include/DSP281x_DefaultIsr.h | 123 + .../f2812/common/include/DSP281x_Examples.h | 88 + .../common/include/DSP281x_GlobalPrototypes.h | 87 + .../include/DSP281x_SWPrioritizedIsrLevels.h | 5881 +++++++++ .../vendor/ti/f2812/include/DSP281x_Adc.h | 224 + .../ti/f2812/include/DSP281x_CpuTimers.h | 184 + .../ti/f2812/include/DSP281x_DefaultIsr.h | 123 + .../vendor/ti/f2812/include/DSP281x_DevEmu.h | 103 + .../vendor/ti/f2812/include/DSP281x_Device.h | 144 + .../vendor/ti/f2812/include/DSP281x_ECan.h | 1163 ++ .../vendor/ti/f2812/include/DSP281x_Ev.h | 654 + .../vendor/ti/f2812/include/DSP281x_Gpio.h | 1034 ++ .../vendor/ti/f2812/include/DSP281x_Mcbsp.h | 777 ++ .../vendor/ti/f2812/include/DSP281x_PieCtrl.h | 153 + .../vendor/ti/f2812/include/DSP281x_PieVect.h | 210 + .../vendor/ti/f2812/include/DSP281x_Sci.h | 233 + .../vendor/ti/f2812/include/DSP281x_Spi.h | 183 + .../vendor/ti/f2812/include/DSP281x_SysCtrl.h | 325 + .../ti/f2812/include/DSP281x_XIntrupt.h | 78 + .../vendor/ti/f2812/include/DSP281x_Xintf.h | 111 + .../ti/f2812/source/DSP281x_CpuTimers.c | 109 + .../f2812/source/DSP281x_GlobalVariableDefs.c | 265 + .../vendor/ti/f2812/source/DSP281x_PieCtrl.c | 84 + .../vendor/ti/f2812/source/DSP281x_SysCtrl.c | 295 + .../ti/f2812/source/DSP281x_usDelay.asm | 71 + .../f28335/cmd/DSP2833x_Headers_nonBIOS.cmd | 240 + .../common/include/DSP2833x_DefaultIsr.h | 236 + .../common/include/DSP2833x_Dma_defines.h | 125 + .../common/include/DSP2833x_EPwm_defines.h | 253 + .../f28335/common/include/DSP2833x_Examples.h | 176 + .../include/DSP2833x_GlobalPrototypes.h | 363 + .../common/include/DSP2833x_I2c_defines.h | 176 + .../include/DSP2833x_SWPrioritizedIsrLevels.h | 10803 ++++++++++++++++ .../ti/f28335/common/include/DSP28x_Project.h | 28 + .../vendor/ti/f28335/include/DSP2833x_Adc.h | 465 + .../ti/f28335/include/DSP2833x_CpuTimers.h | 283 + .../vendor/ti/f28335/include/DSP2833x_DMA.h | 437 + .../ti/f28335/include/DSP2833x_DevEmu.h | 154 + .../ti/f28335/include/DSP2833x_Device.h | 655 + .../vendor/ti/f28335/include/DSP2833x_ECan.h | 2109 +++ .../vendor/ti/f28335/include/DSP2833x_ECap.h | 245 + .../vendor/ti/f28335/include/DSP2833x_EPwm.h | 720 + .../vendor/ti/f28335/include/DSP2833x_EQep.h | 407 + .../vendor/ti/f28335/include/DSP2833x_Gpio.h | 711 + .../vendor/ti/f28335/include/DSP2833x_I2c.h | 319 + .../vendor/ti/f28335/include/DSP2833x_Mcbsp.h | 1299 ++ .../ti/f28335/include/DSP2833x_PieCtrl.h | 260 + .../ti/f28335/include/DSP2833x_PieVect.h | 349 + .../vendor/ti/f28335/include/DSP2833x_Sci.h | 377 + .../vendor/ti/f28335/include/DSP2833x_Spi.h | 292 + .../ti/f28335/include/DSP2833x_SysCtrl.h | 642 + .../ti/f28335/include/DSP2833x_XIntrupt.h | 127 + .../vendor/ti/f28335/include/DSP2833x_Xintf.h | 197 + .../ti/f28335/source/DSP2833x_ADC_cal.asm | 51 + .../ti/f28335/source/DSP2833x_CpuTimers.c | 161 + .../source/DSP2833x_GlobalVariableDefs.c | 746 ++ .../ti/f28335/source/DSP2833x_PieCtrl.c | 121 + .../ti/f28335/source/DSP2833x_SysCtrl.c | 604 + .../ti/f28335/source/DSP2833x_usDelay.asm | 84 + c/set-protocol/CMakeLists.txt | 4 + c/set-protocol/docs/DEIF_XDI.md | 104 + c/set-protocol/docs/EMULATOR_SERVICES.md | 26 + c/set-protocol/include/deif_xdi.h | 41 + c/set-protocol/include/set_signal.h | 9 + c/set-protocol/ports/android/Android.mk | 1 + .../ru/setcorp/setprotocol/deif/DeifXdi.kt | 60 + c/set-protocol/ports/android/set_deif_jni.c | 32 + .../setcorp/setprotocol/deif/DeifXdiTest.kt | 34 + c/set-protocol/src/deif_xdi.c | 185 + c/set-protocol/src/set_signal.c | 16 +- c/set-protocol/tests/fixtures/deif-xdi-v1.tsv | 15 + c/set-protocol/tests/test_deif_xdi.c | 26 + c/set-protocol/tools/build_host.py | 7 +- c/st7789/st7789_disabled.h | 6 + cpp/signal-eigen/README.md | 50 + cpp/signal-eigen/build.py | 63 + cpp/signal-eigen/signal_eigen.cpp | 40 + cpp/signal-eigen/vendor/eigen-3.4.0.tar.gz | Bin 0 -> 2705005 bytes doc/setcan/DEVICE_REGISTRY.md | 15 +- doc/setcan/Протокол CAN и ОАП.md | 17 +- doc/setcan/Протокол CAN и ОАП.xlsx | Bin 87602 -> 477367 bytes docs/reference-comparison.md | 210 + python/README.md | 7 + python/protocan/can_boot.py | 44 +- python/protocan/f28335_flash.py | 99 + python/protocan/protocan.py | 11 + python/protocan/stm_invertor.py | 28 + python/set_devices/deif_controls.py | 52 + python/set_devices/deif_display.py | 129 + python/set_devices/deif_emulator.py | 36 + python/set_devices/deif_native.py | 75 + python/set_devices/deif_slave.py | 56 + python/set_devices/deif_xdi.py | 238 +- python/set_devices/emulator_protocol.py | 140 + python/set_devices/firmware_identity.py | 26 +- python/set_devices/generator_data.py | 20 +- python/set_devices/mcu_profiles.py | 46 + python/set_devices/plot_processing.py | 15 +- .../qt_ports/circuit_parameters.py | 33 + python/set_devices/qt_ports/deif_emulator.py | 120 + .../qt_ports/deif_emulator_panel.py | 189 + .../set_devices/qt_ports/emulator_serial.py | 181 + .../qt_ports/emulator_workspace.py | 36 + python/set_devices/qt_ports/igbt_client.py | 138 + python/set_devices/qt_ports/plot_dual_axis.py | 16 +- .../set_devices/qt_ports/plot_processing.py | 26 +- .../qt_ports/reference_comparison.py | 375 + .../set_devices/qt_ports/reference_overlay.py | 299 + .../set_devices/qt_ports/reference_results.py | 155 + python/set_devices/qt_ports/stm_settings.py | 9 +- .../qt_ports/viewport_navigation.py | 7 +- python/set_devices/signal_diagnostics.py | 131 + python/set_devices/signal_eigen.py | 18 + python/set_devices/signal_fault_models.py | 396 + python/set_devices/signal_joint_models.py | 79 + python/set_devices/signal_reconstruction.py | 24 +- python/set_devices/signal_reference.py | 168 + python/set_devices/waveform.py | 12 +- python/tests/test_can_boot_services.py | 16 + python/tests/test_deif_shared.py | 19 + python/tests/test_firmware_clients.py | 5 +- .../tests/test_reference_comparison_port.py | 141 + 170 files changed, 43762 insertions(+), 281 deletions(-) create mode 100644 c/protocan-boot/.gitignore create mode 100644 c/protocan-boot/ports/tms320f2812/README.md create mode 100644 c/protocan-boot/ports/tms320f2812/boot2812.h create mode 100644 c/protocan-boot/ports/tms320f2812/boot_store.c create mode 100644 c/protocan-boot/ports/tms320f2812/nor_flash.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_can_application.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_flash_app.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_flash_app.h create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_flash_update.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_flash_update.h create mode 100644 c/protocan-boot/projects/README.md create mode 100644 c/protocan-boot/projects/build.py create mode 100644 c/protocan-boot/projects/ccs/f2812/.ccsproject create mode 100644 c/protocan-boot/projects/ccs/f2812/.cproject create mode 100644 c/protocan-boot/projects/ccs/f2812/.project create mode 100644 c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd create mode 100644 c/protocan-boot/projects/ccs/f2812/board.c create mode 100644 c/protocan-boot/projects/ccs/f2812/boot_store.c create mode 100644 c/protocan-boot/projects/ccs/f2812/codestart.asm create mode 100644 c/protocan-boot/projects/ccs/f2812/main.c create mode 100644 c/protocan-boot/projects/ccs/f2812/nor_flash.c create mode 100644 c/protocan-boot/projects/ccs/f2812/shared_boot.c create mode 100644 c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml create mode 100644 c/protocan-boot/projects/ccs/f28335/.ccsproject create mode 100644 c/protocan-boot/projects/ccs/f28335/.cproject create mode 100644 c/protocan-boot/projects/ccs/f28335/.project create mode 100644 c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd create mode 100644 c/protocan-boot/projects/ccs/f28335/codestart.asm create mode 100644 c/protocan-boot/projects/ccs/f28335/flash_update.c create mode 100644 c/protocan-boot/projects/ccs/f28335/main.c create mode 100644 c/protocan-boot/projects/ccs/f28335/shared_boot.c create mode 100644 c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml create mode 100644 c/protocan-boot/tests/test_f2812_nor.c create mode 100644 c/protocan-boot/tests/test_pcan_busy.c create mode 100644 c/protocan-boot/vendor/ti/README.md create mode 100644 c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm create mode 100644 c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm create mode 100644 c/set-protocol/docs/DEIF_XDI.md create mode 100644 c/set-protocol/include/deif_xdi.h create mode 100644 c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/deif/DeifXdi.kt create mode 100644 c/set-protocol/ports/android/set_deif_jni.c create mode 100644 c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/deif/DeifXdiTest.kt create mode 100644 c/set-protocol/src/deif_xdi.c create mode 100644 c/set-protocol/tests/fixtures/deif-xdi-v1.tsv create mode 100644 c/set-protocol/tests/test_deif_xdi.c create mode 100644 c/st7789/st7789_disabled.h create mode 100644 cpp/signal-eigen/README.md create mode 100644 cpp/signal-eigen/build.py create mode 100644 cpp/signal-eigen/signal_eigen.cpp create mode 100644 cpp/signal-eigen/vendor/eigen-3.4.0.tar.gz create mode 100644 docs/reference-comparison.md create mode 100644 python/protocan/f28335_flash.py create mode 100644 python/protocan/stm_invertor.py create mode 100644 python/set_devices/deif_controls.py create mode 100644 python/set_devices/deif_display.py create mode 100644 python/set_devices/deif_emulator.py create mode 100644 python/set_devices/deif_native.py create mode 100644 python/set_devices/deif_slave.py create mode 100644 python/set_devices/emulator_protocol.py create mode 100644 python/set_devices/mcu_profiles.py create mode 100644 python/set_devices/qt_ports/circuit_parameters.py create mode 100644 python/set_devices/qt_ports/deif_emulator.py create mode 100644 python/set_devices/qt_ports/deif_emulator_panel.py create mode 100644 python/set_devices/qt_ports/emulator_serial.py create mode 100644 python/set_devices/qt_ports/emulator_workspace.py create mode 100644 python/set_devices/qt_ports/igbt_client.py create mode 100644 python/set_devices/qt_ports/reference_comparison.py create mode 100644 python/set_devices/qt_ports/reference_overlay.py create mode 100644 python/set_devices/qt_ports/reference_results.py create mode 100644 python/set_devices/signal_diagnostics.py create mode 100644 python/set_devices/signal_eigen.py create mode 100644 python/set_devices/signal_fault_models.py create mode 100644 python/set_devices/signal_joint_models.py create mode 100644 python/set_devices/signal_reference.py create mode 100644 python/tests/test_deif_shared.py create mode 100644 python/tests/test_reference_comparison_port.py diff --git a/c/firmware-info/tools/identity.py b/c/firmware-info/tools/identity.py index 5d7fd0c..fd01f92 100644 --- a/c/firmware-info/tools/identity.py +++ b/c/firmware-info/tools/identity.py @@ -13,6 +13,7 @@ import json import os from pathlib import Path import subprocess +import tempfile # Резервирует номер сборки через временный файл на том же диске, как общий итератор ветки 166. def git_state(repository: Path) -> dict: @@ -36,20 +37,46 @@ def git_state(repository: Path) -> dict: def write_atomic(path: Path, text: str): path.parent.mkdir(parents=True, exist_ok=True) temporary = path.with_name(path.name + ".tmp") - temporary.write_text(text, encoding="utf-8", newline="\n") + with open(temporary, "w", encoding="utf-8", newline="\n") as stream: # Сохраняет UTF-8 и LF также на Python 3.8, где Path.write_text ещё не принимает newline. + stream.write(text) # Полностью записывает заголовок или паспорт перед атомарной заменой целевого файла. temporary.replace(path) -def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict: - settings = json.loads(config.read_text(encoding="utf-8")) - version = settings["version"] - if (len(version) != 3 or any(type(v) is not int for v in version) - or not all(0 <= v <= limit for v, limit in zip(version, (255, 255, 999)))): - raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]") +def next_version(version): # Повторяет общий итератор 166 и переносит переполнение младшего разряда в старший. + result = list(version) # Не изменяет исходный номер до проверки полного переполнения. + for index, limit in ((2, 999), (1, 255), (0, 255)): # Контракт firmware-info v1 допускает patch 0..999 и major/minor 0..255. + if result[index] < limit: # Выбирает младший разряд, который ещё допускает увеличение. + result[index] += 1 # Занимает следующий номер попытки сборки ровно один раз. + return result # Возвращает новый номер с сохранёнными старшими и обнулёнными переполненными младшими разрядами. + result[index] = 0 # Переносит единицу к следующему разряду при достижении предела текущего. + raise ValueError("Firmware version exhausted at 255.255.999") # Не допускает повторного использования версии после полного переполнения контракта. + + +def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict: # Формирует один паспорт текущей попытки после сохранения номера автоматической сборки. + settings = json.loads(config.read_text(encoding="utf-8-sig")) # Принимает исходный JSON в UTF-8, включая старые файлы Windows с BOM. + version = settings["version"] # Начальный номер берётся из единственного сохраняемого источника проекта. + if not isinstance(version, list) or len(version) != 3 or any(type(value) is not int or not 0 <= value <= limit for value, limit in zip(version, (255, 255, 999))): # Проверяет три целых разряда и пределы протокола до изменения JSON. + raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]") # Останавливает prebuild при неверном формате счётчика. + if type(settings.get("increment_version", False)) is not bool: # Старые проекты сохраняют ручной режим; автоматический требует настоящего логического true. + raise ValueError("increment_version must be true or false") # Не принимает строки и числа вместо явной настройки счётчика. for field in ("product", "target"): if not isinstance(settings.get(field), str) or not settings[field].strip(): raise ValueError(f"missing {field}") - source, dependency = git_state(repository), git_state(templates) + if settings.get("increment_version", False): # Увеличение выполняется только при подготовке основного проекта, а не при упаковке RAM, CAN и Flash. + version = settings["version"] = next_version(version) # Один вычисленный номер используется исходным JSON, генерируемым заголовком и паспортом. + with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", newline="\n", dir=config.parent, prefix=".firmware-version-", delete=False) as stream: # Временный файл рядом с JSON позволяет атомарную замену счётчика на том же диске. + temporary = Path(stream.name) # Запоминает только собственный файл для очистки при отказе сохранения. + try: # Ошибка записи должна сохранить исходный JSON и удалить незавершённый временный файл. + stream.write(json.dumps(settings, ensure_ascii=False, indent=2) + "\n") # Сохраняет новый номер и все дополнительные настройки проекта в UTF-8. + except BaseException: # Освобождает собственный файл также при прерывании процесса записи. + stream.close() # Windows разрешает удалить временный файл после закрытия его дескриптора. + temporary.unlink() # Удаляет только незавершённый файл этой попытки резервирования номера. + raise # Возвращает исходную ошибку вместо продолжения сборки с несохранённой версией. + try: # Номер должен быть надёжно занят до генерации выходов и начала компиляции. + temporary.replace(config) # Атомарно фиксирует счётчик, чтобы следующая попытка не повторила номер при последующей ошибке сборки. + finally: # При неудачной замене исходный JSON остаётся прежним, а собственный временный файл очищается. + temporary.unlink(missing_ok=True) # После успешного переименования файла уже нет; Python 3.8 поддерживает missing_ok. + source, dependency = git_state(repository), git_state(templates) # Отмечает изменённый счётчик в происхождении текущего выпуска после резервирования номера. # A clean application built with a modified templates checkout is dirty too. known = source["commit"] is not None and dependency["commit"] is not None dirty = bool(source["dirty"] or dependency["dirty"]) diff --git a/c/protocan-boot/.gitignore b/c/protocan-boot/.gitignore new file mode 100644 index 0000000..01b5059 --- /dev/null +++ b/c/protocan-boot/.gitignore @@ -0,0 +1,8 @@ +# Результаты отдельных конфигураций CCS воспроизводятся установленным TI compiler. +/projects/ccs/*/Debug/ +/projects/ccs/*/Release/ +# Служебные локальные настройки IDE и launch не входят в переносимый проект. +/projects/ccs/*/.settings/ +/projects/ccs/*/.launches/ +# Python cache не является исходником общего модуля или проекта. +**/__pycache__/ diff --git a/c/protocan-boot/CMakeLists.txt b/c/protocan-boot/CMakeLists.txt index 2548300..523ad00 100644 --- a/c/protocan-boot/CMakeLists.txt +++ b/c/protocan-boot/CMakeLists.txt @@ -1,6 +1,6 @@ -# РЎР±РѕСЂРєР° библиотеки protocan_boot. Состав РёСЃС…РѕРґРЅРёРєРѕРІ Рё публичные include-пути задают -# подключение Рє проекту потребителя. Файл также собирает Рё регистрирует хостовые проверки; -# запускать РёС… следует через CTest РёР· каталога СЃР±РѕСЂРєРё. +# Общая C99-библиотека ProtoCAN Boot и аппаратно независимые host-тесты. +# Каждый контроллер сохраняет собственное состояние и отдельный аппаратный порт. +# Дополнительные проекты CCS находятся в projects/ccs и не требуют CMake для TI-сборки. cmake_minimum_required(VERSION 3.13) project(protocan_boot C) @@ -17,7 +17,7 @@ else() target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic) endif() -option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN boot" ON) +option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN Boot" ON) # Не включает host-модели в код MCU. if(PCAN_BOOT_BUILD_TESTS) enable_testing() add_executable(test_pcan_boot tests/test_pcan_boot.c) @@ -45,3 +45,12 @@ if(PCAN_BOOT_BUILD_TESTS) add_test(NAME f28335_store_${width} COMMAND test_f28335_store_${width}) endforeach() endif() + +if(PCAN_BOOT_BUILD_TESTS) # Подключает настоящий аппаратно независимый драйвер NOR F2812 и регрессию длительного BUSY. + add_executable(test_f2812_nor tests/test_f2812_nor.c src/pcan_boot.c ports/tms320f2812/nor_flash.c ports/tms320f2812/boot_store.c) # Компилирует production-код вместе с x16 моделью чипа. + target_compile_definitions(test_f2812_nor PRIVATE PCAN_BOOT_WIDE_BYTES BOOT2812_HOST) # Октеты C28x широкие; подменяется только физическая шина памяти. + add_test(NAME f2812_nor COMMAND test_f2812_nor) # Регистрирует проверки CRC, SCI8, границ, manifest и отказов NOR. + add_executable(test_pcan_busy tests/test_pcan_busy.c src/pcan_boot.c) # Использует тот же codec, который обслуживает длинные аппаратные операции. + target_compile_definitions(test_pcan_busy PRIVATE PCAN_BOOT_WIDE_BYTES) # Проверяет wire-статус при 16-битном представлении октета C28x. + add_test(NAME pcan_busy COMMAND test_pcan_busy) # Регистрирует проверку продления session при живом прогрессе erase. +endif() # Включение библиотек без тестов не добавляет host-модель в прошивку. diff --git a/c/protocan-boot/README.md b/c/protocan-boot/README.md index b1bb5c7..9aa74e8 100644 --- a/c/protocan-boot/README.md +++ b/c/protocan-boot/README.md @@ -180,8 +180,14 @@ ctest --test-dir build --output-on-failure ## F28335 / большая EEPROM -[Порт M95M02](ports/tms320f28335/README.md) подключён в `tms_periph/periph_167`. +[Порт M95M02](ports/tms320f28335/README.md) подключён в `28335_periph`, ветка 167. Использует отдельный Flash-загрузчик и два слота EEPROM по 130560 байт. Реализованы readback/CRC, проверка SCI8, журнал метаданных, пробный запуск, CONFIRM/откат, PING/discovery и сервисный паспорт. Первичная установка Flash- загрузчика и выбор Flash boot описаны в README порта. + +## Самостоятельные проекты CCS + +Готовые проекты **F28335_CAN_AB** (M95M02) и **F2812_CAN_NOR** (AM29LV800BT), +включая необходимые файлы поддержки TI, находятся в `projects/ccs`. +[Импорт, сборка, карты памяти и установка](projects/README.md). diff --git a/c/protocan-boot/include/pcan_boot.h b/c/protocan-boot/include/pcan_boot.h index cf9f7a9..8fc830e 100644 --- a/c/protocan-boot/include/pcan_boot.h +++ b/c/protocan-boot/include/pcan_boot.h @@ -52,7 +52,8 @@ typedef enum { PCAN_BOOT_CMD_PING = 0x0CU, PCAN_BOOT_CMD_CAPABILITIES = 0x0DU, PCAN_BOOT_CMD_DEVICE_NAME = 0x0EU, - PCAN_BOOT_CMD_MEMORY_INFO = 0x0FU + PCAN_BOOT_CMD_MEMORY_INFO = 0x0FU, /* Сохраняет существующий номер постраничного паспорта памяти. */ + PCAN_BOOT_CMD_SELECT_MEMORY = 0x10U /* Выбирает 0=штатное хранилище, 1=внутренняя Flash до передачи метаданных. */ } pcan_boot_command_t; typedef enum { @@ -127,6 +128,7 @@ typedef struct { /** Optional precise result, replacing legacy boolean verify_image. */ pcan_boot_status_t (*verify_status)(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest); + pcan_boot_status_t (*select_memory)(void *user, pcan_boot_byte_t memory, pcan_boot_config_t *config); /* Необязательный порт явно переключает назначение образа до ERASE; старые порты возвращают INVALID_COMMAND. */ } pcan_boot_port_t; typedef struct { @@ -164,6 +166,9 @@ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, /** Call regularly with a wrapping monotonic millisecond clock. */ void pcan_boot_poll(pcan_boot_t *boot, uint32_t now_ms); +uint32_t pcan_boot_crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length); /* Общий потоковый CRC32 для readback аппаратных хранилищ; начальное состояние равно нулю. */ +bool pcan_boot_report_busy(pcan_boot_t *boot, pcan_boot_byte_t command, uint32_t now_ms); /* Долгие аппаратные операции сообщают BUSY тем же codec и той же session, что обычный ответ. */ + /** Переносимые операции с 29-битным ProtoCAN ID. */ uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route, pcan_boot_byte_t device_type, pcan_boot_byte_t device_id, diff --git a/c/protocan-boot/ports/tms320f2812/README.md b/c/protocan-boot/ports/tms320f2812/README.md new file mode 100644 index 0000000..5f59dc9 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/README.md @@ -0,0 +1,15 @@ +# F2812 / AM29LV800BT + +Самостоятельный проект, карта NOR, параметры CAN, установка и ограничения +описаны в [общей инструкции CCS](../../projects/README.md). + +- `boot2812.h` — физические CPU word-адреса и отдельная совместимость F2812; +- `nor_flash.c` — x16 AMD driver с ID, ограниченными program/sector erase, + DQ7/DQ5 polling, readback и BUSY; +- `boot_store.c` — упаковка октетов, проверка всей SCI8-таблицы, CRC32, + публикация manifest последними magic-словами, проверенная загрузка RAM; +- `projects/ccs/f2812/board.c` — подтверждённые линии CPLD и XINTF ПМ67; +- `projects/ccs/f2812/main.c` — независимые eCAN/IRQ/очередь/main F2812. + +Протокол и CRC повторно используются из `src/pcan_boot.c`. EEPROM отсутствует; +код F28335 и его A/B-журнал не подключаются к этому проекту. diff --git a/c/protocan-boot/ports/tms320f2812/boot2812.h b/c/protocan-boot/ports/tms320f2812/boot2812.h new file mode 100644 index 0000000..5025d04 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/boot2812.h @@ -0,0 +1,24 @@ +#ifndef BOOT2812_H /* Исключает повторное объявление профиля NOR-загрузчика F2812. */ +#define BOOT2812_H /* Отделяет основной контроллер ПМ67 от периферийного F28335. */ +#include "../../include/pcan_boot.h" /* Использует существующий ProtoCAN codec и представление октетов C28x. */ +#define BOOT2812_NOR_BASE 0x100000UL /* CPU word-адрес AM29LV800BT взят из START_ADR_FLASH действующего flash_tools.h платы. */ +#define BOOT2812_IMAGE_WORD 0x160000UL /* Новый CAN-образ занимает три полных верхних обычных сектора, выше старого образа и данных FPGA. */ +#define BOOT2812_IMAGE_BYTES 0x30000UL /* Три сектора по 0x8000 слов дают 196608 октетов полезного SCI8. */ +#define BOOT2812_META_WORD 0x17E000UL /* Последний top-boot сектор начинается после областей 16K/4K/4K слов и содержит 8192 слова. */ +#define BOOT2812_PRODUCT 0x2812U /* Отдельный Product Type запрещает запись образа F28335 в основной контроллер F2812. */ +#define BOOT2812_DEVICE_TYPE 3U /* Тип загрузчика остаётся в том же адресном классе ProtoCAN, что F28335. */ +#define BOOT2812_DEVICE_ID 6U /* Отдельный ID 6 исключает совпадение с существующим F28335 на адресе 3/7. */ +#define BOOT2812_RECOVERY_MS 3000UL /* После reset загрузчик три секунды принимает ENTER_BOOT до автоматического запуска сохранённого образа. */ +unsigned long Boot2812_Now(void); /* Возвращает монотонные миллисекунды Timer1 для CAN и ограниченных ожиданий NOR. */ +void Boot2812_Busy(void); /* Во время долгого стирания сообщает BUSY через общий codec и обслуживает аппаратный TX ACK. */ +void Boot2812_BoardInit(void); /* Настраивает действующие линии CPLD и XINTF платы ПМ67. */ +bool Boot2812_NorIdentify(void); /* До первого erase требует AMD manufacturer 0001 и top-boot device 22DA. */ +unsigned int Boot2812_NorRead(unsigned long word); /* Читает одно 16-битное слово по CPU-адресу внешней NOR. */ +bool Boot2812_NorProgram(unsigned long word, unsigned int value); /* Программирует только зарезервированные CAN-области и проверяет прочитанный результат. */ +bool Boot2812_NorErase(unsigned long word); /* Принимает только начала трёх секторов образа и одного сектора метаданных. */ +bool Boot2812_Erase(void *user, pcan_boot_byte_t slot); /* Удаляет публикацию до стирания единственного CAN-слота. */ +bool Boot2812_Write(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length); /* Сохраняет октеты ProtoCAN в x16 NOR младшим байтом вперёд. */ +pcan_boot_status_t Boot2812_Verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image); /* Проверяет CRC прочитанной NOR и все CPU-адреса SCI8 до COMMIT. */ +bool Boot2812_Commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image); /* Публикует manifest только после повторной проверки всей внешней Flash. */ +bool Boot2812_Load(uint32_t *entry); /* Читает действующий manifest, проверяет образ и переносит только разрешённую RAM. */ +#endif /* Завершает интерфейс самостоятельного NOR-порта F2812. */ diff --git a/c/protocan-boot/ports/tms320f2812/boot_store.c b/c/protocan-boot/ports/tms320f2812/boot_store.c new file mode 100644 index 0000000..8d9f701 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/boot_store.c @@ -0,0 +1,105 @@ +#include "boot2812.h" /* Использует отдельные адреса и совместимость внешней NOR F2812. */ +static unsigned int octet(uint32_t offset) /* Читает октет файла SCI8 из x16 NOR, где младший октет хранится первым. */ +{ /* Поток CAN остаётся независимым от sizeof(char) на C28x. */ + unsigned int word = Boot2812_NorRead(BOOT2812_IMAGE_WORD + offset / 2UL); /* Преобразует смещение в октетах в CPU word-адрес слота. */ + return (offset & 1UL) ? word >> 8 : word & 255U; /* Передаёт младшие восемь бит октета без знакового расширения. */ +} /* Все дальнейшие поля таблицы собираются из того же порядка октетов. */ +static unsigned int u16(uint32_t offset) /* Восстанавливает слово TI boot table в little endian. */ +{ /* Вызывается только после проверки достаточной длины соответствующего поля. */ + return octet(offset) | (octet(offset + 1UL) << 8); /* Два октета соответствуют одному слову C28x. */ +} /* Завершает чтение длины секции или данных программы. */ +static uint32_t address_at(uint32_t offset) /* Адрес TI SCI8 содержит старшее 16-битное слово перед младшим. */ +{ /* Этот порядок отличается от обычного u32 little endian метаданных ProtoCAN. */ + return ((uint32_t)u16(offset) << 16) | u16(offset + 2UL); /* Внутри каждого слова по-прежнему сохраняется little endian. */ +} /* Возвращает CPU-адрес, измеряемый в словах. */ +static bool allowed(uint32_t first, uint32_t end) /* Разрешает только реальную RAM приложения и исключает RAM работающего загрузчика. */ +{ /* Новое приложение не должно загружать инициализированные секции в L1 или RAM InitFlash до перехода в runtime. */ + return end > first && ((first >= 0x8000UL && end <= 0x8F00UL) || (first >= 0x3F8000UL && end <= 0x3FA000UL) || (first >= 0x80000UL && end <= 0x100000UL)); /* L0 до ramfuncs, полный H0 и внешняя SRAM зоны 2; периферия, NOR, стек и внутренние Flash запрещены. */ +} /* Проверки входа и всех секций выполняются до первой записи приложения в RAM. */ +static bool table(uint32_t size, bool copy, uint32_t *entry) /* Проверяет целиком SCI8 и при повторном проходе переносит данные в RAM. */ +{ /* Устойчивость загрузчика не зависит от адресов, заявленных принимаемым файлом. */ + uint32_t starts[64], ends[64], offset = 22UL, address, end; /* Лимит 64 секции ограничивает стек и число сравнений перекрытий. */ + unsigned int sections = 0U, count, i; bool entry_loaded = false; /* Требует, чтобы точка входа реально находилась среди загружаемых слов. */ + if (size < 24UL || (size & 1UL) || u16(0UL) != 0x08AAU) return false; /* Ключ SCI8 AA08, чётный размер и терминатор обязательны. */ + *entry = address_at(18UL); /* После ключа и восьми резервных слов находится CPU word-адрес C runtime. */ + while (offset + 2UL <= size) { /* Поле count читается только при наличии обоих октетов. */ + count = u16(offset); offset += 2UL; /* Размер секции выражен в 16-битных словах, а не октетах файла. */ + if (!count) return offset == size && entry_loaded; /* Запрещает хвост, незавершённую таблицу и entry вне payload. */ + if (sections == 64U || size - offset < 4UL) return false; /* Не допускает переполнения ограниченных массивов или усечённого адреса. */ + address = address_at(offset); offset += 4UL; end = address + count; /* Восстанавливает исключающую верхнюю границу CPU-диапазона секции. */ + if (!allowed(address, end) || (uint32_t)count * 2UL > size - offset) return false; /* Проверяет адреса и полный payload до обращения к RAM назначения. */ + for (i = 0; i < sections; ++i) if (address < ends[i] && starts[i] < end) return false; /* Даже правильно переданная CRC не разрешает две секции поверх одного слова. */ + starts[sections] = address; ends[sections++] = end; /* Сохраняет уже проверенный диапазон для следующих секций. */ + if (*entry >= address && *entry < end) entry_loaded = true; /* Подтверждает наличие исполняемого слова по адресу входа. */ + if (copy) { /* Этот проход выполняется только после полной read-only проверки всего образа. */ + for (i = 0; i < count; ++i) { /* Переносит ровно заявленные и предварительно проверенные слова секции. */ +#if defined(BOOT2812_HOST) /* Аппаратная модель проверяет тот же диапазон без записи по адресам процесса ПК. */ + extern void NorModel_LoadWord(uint32_t target, unsigned int value); /* Модель сохраняет каждое слово переноса для независимой проверки. */ + NorModel_LoadWord(address + i, u16(offset + (uint32_t)i * 2UL)); /* Подменяет только шину RAM назначения. */ +#else /* На F2812 CPU-адреса уже выражены в 16-битных словах. */ + *(volatile unsigned int *)(address + i) = u16(offset + (uint32_t)i * 2UL); /* Записывает секцию только в разрешённую RAM приложения. */ +#endif /* Завершает аппаратную запись либо её host-модель. */ + } /* Завершает перенос текущей секции. */ + } /* После проверочного прохода RAM остаётся нетронутой. */ + offset += (uint32_t)count * 2UL; /* Пропускает полезные октеты до следующего count. */ + } /* Исчерпание файла без терминатора означает неполный образ. */ + return false; /* Не запускает незавершённую таблицу. */ +} /* Образ с ошибкой не публикуется как запускаемый. */ +bool Boot2812_Erase(void *user, pcan_boot_byte_t slot) /* Реализует single-slot подготовку внешней NOR. */ +{ /* Существующие legacy-образы и FPGA ниже 160000 не входят в новый CAN-раздел. */ + unsigned long sector; (void)user; /* Перебирает только три полных обычных сектора нового образа. */ + if (slot || !Boot2812_NorIdentify() || !Boot2812_NorErase(BOOT2812_META_WORD)) return false; /* Сначала удаляет marker старого CAN-образа; при обрыве стирания сохраняется recovery. */ + for (sector = BOOT2812_IMAGE_WORD; sector < BOOT2812_IMAGE_WORD + BOOT2812_IMAGE_BYTES / 2UL; sector += 0x8000UL) if (!Boot2812_NorErase(sector)) return false; /* Геометрия x16 допускает erase только по границам обычных секторов 32K слов. */ + return true; /* Ядро ProtoCAN разрешает DATA только после полного успешного стирания слота. */ +} /* EEPROM-операции и несуществующий второй слот отсутствуют. */ +bool Boot2812_Write(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Упаковывает поступившие октеты в x16 слова NOR. */ +{ /* В одном вызове записывается не более одного classic CAN кадра. */ + unsigned int i, word; (void)user; /* Счётчик относится к октетам кадра, адрес NOR отдельно делится на два. */ + if (slot || !length || length > 8U || (offset & 1UL) || offset > BOOT2812_IMAGE_BYTES || length > BOOT2812_IMAGE_BYTES - offset) return false; /* Не допускает выхода из слота либо продолжения слова с неверного октета. */ + for (i = 0; i < length; i += 2U) { /* Последовательные 8-октетные блоки начинаются на границе x16 слова. */ + word = (data[i] & 255U) | ((i + 1U < length ? data[i + 1U] & 255U : 255U) << 8); /* Неполное последнее слово сохраняет FF в незанятом старшем октете. */ + if (!Boot2812_NorProgram(BOOT2812_IMAGE_WORD + (offset + i) / 2UL, word)) return false; /* Аппаратный драйвер проверяет и допустимый адрес, и результат записи каждого слова. */ + } /* Завершает сохранение текущего CAN-блока. */ + return true; /* ACK означает проверенную запись, а не только получение кадра. */ +} /* CRC ядра продвигается только после успешного возврата этого callback. */ +pcan_boot_status_t Boot2812_Verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image) /* Перепроверяет CRC непосредственно из сохранённой NOR. */ +{ /* Потоковая CRC при приёме не заменяет аппаратный readback полного файла. */ + uint32_t offset, crc = 0UL, entry; pcan_boot_byte_t bytes[32]; unsigned int count, i; (void)user; /* Небольшой буфер не требует размещать весь образ во внутренней RAM F2812. */ + if (slot || image->image_size < 24UL || image->image_size > BOOT2812_IMAGE_BYTES || (image->image_size & 1UL)) return PCAN_BOOT_STATUS_INVALID_SIZE; /* SCI8 должен целиком помещаться в выделенных трёх секторах и содержать целые слова. */ + if (image->product_type != BOOT2812_PRODUCT || image->hardware_revision_min > 1U || image->hardware_revision_max < 1U) return PCAN_BOOT_STATUS_WRONG_DEVICE; /* Образ F28335 или несовместимого изделия не становится загрузочным. */ + for (offset = 0; offset < image->image_size; offset += count) { /* Проверяет каждый фактически сохранённый октет ровно один раз. */ + count = image->image_size - offset < 32UL ? (unsigned int)(image->image_size - offset) : 32U; /* Последний буфер ограничен реальной длиной без FF-дополнения CAN. */ + for (i = 0; i < count; ++i) bytes[i] = octet(offset + i); /* Читает данные из NOR, а не из приёмной очереди CAN. */ + crc = pcan_boot_crc32_update(crc, bytes, count); /* Использует общий CRC32 ProtoCAN без дублирования полинома в аппаратном порту. */ + Boot2812_Busy(); /* Большой файл сохраняет ответы клиента при длинной проверке на реальном CPU. */ + } /* Завершает вычисление CRC readback. */ + if (crc != image->image_crc32) return PCAN_BOOT_STATUS_CRC_ERROR; /* Различает повреждение памяти и ошибку структуры SCI8. */ + return table(image->image_size, false, &entry) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_INVALID_STATE; /* Все адреса, перекрытия, терминатор и entry проверяются до COMMIT. */ +} /* До успеха verifier никакие слова приложения не переносятся в RAM. */ +bool Boot2812_Commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image) /* Публикует загрузочный manifest последней операцией после readback. */ +{ /* Формат из 12 слов фиксирован и не зависит от sizeof C-структуры. */ + unsigned int words[12], i; /* Два magic-слова, версия формата, размер, CRC, версия FW и контроль manifest. */ + pcan_boot_byte_t bytes[20]; uint32_t crc; /* CRC первых десяти слов защищает размер и контрольную сумму самого образа. */ + if (Boot2812_Verify(user, slot, image) != PCAN_BOOT_STATUS_OK) return false; /* Не публикует файл, испорченный после предыдущего VERIFY. */ + words[0] = 0x2812U; words[1] = 0xCA7EU; words[2] = 1U; words[3] = 0U; /* Magic 2812/CA7E и версия 1 отличают новый CAN manifest от прежних данных платы. */ + words[4] = (unsigned int)(image->image_size & 0xFFFFUL); words[5] = (unsigned int)(image->image_size >> 16); /* Длина выражена октетами и хранится младшим словом первой. */ + words[6] = (unsigned int)(image->image_crc32 & 0xFFFFUL); words[7] = (unsigned int)(image->image_crc32 >> 16); /* Сохраняет точную CRC всего полученного файла. */ + words[8] = (unsigned int)(image->firmware_version & 0xFFFFUL); words[9] = (unsigned int)(image->firmware_version >> 16); /* Версия кандидата не подменяется версией постоянного загрузчика. */ + for (i = 0; i < 10U; ++i) { bytes[2U * i] = words[i] & 255U; bytes[2U * i + 1U] = words[i] >> 8; } /* Wire-представление manifest использует октеты независимо от ширины C28x char. */ + crc = pcan_boot_crc32_update(0UL, bytes, 20U); words[10] = (unsigned int)(crc & 0xFFFFUL); words[11] = (unsigned int)(crc >> 16); /* CRC manifest не позволяет принять частично записанные поля размера и CRC образа. */ + for (i = 2U; i < 12U; ++i) if (!Boot2812_NorProgram(BOOT2812_META_WORD + i, words[i])) return false; /* Сначала записывает все поля, пока оба magic-слова ещё равны FF. */ + if (!Boot2812_NorProgram(BOOT2812_META_WORD + 1UL, words[1])) return false; /* Второе magic-слово фиксируется после полного тела manifest. */ + return Boot2812_NorProgram(BOOT2812_META_WORD, words[0]); /* Первое magic записывается последним: потеря питания раньше оставляет recovery. */ +} /* Повтор COMMIT обрабатывает идемпотентный автомат общего ядра. */ +bool Boot2812_Load(uint32_t *entry) /* Проверяет опубликованный образ после reset перед переносом в RAM приложения. */ +{ /* Пустой или повреждённый manifest оставляет прибор в постоянном CAN recovery. */ + unsigned int words[12], i; pcan_boot_byte_t bytes[20]; uint32_t crc; pcan_boot_manifest_t image; /* Сериализованные поля читаются явно, без memcpy по ABI структуры. */ + for (i = 0; i < 12U; ++i) words[i] = Boot2812_NorRead(BOOT2812_META_WORD + i); /* Читает только фиксированные 24 октета manifest. */ + if (words[0] != 0x2812U || words[1] != 0xCA7EU || words[2] != 1U || words[3]) return false; /* Не интерпретирует старые данные Flash либо неполный commit как запускаемый файл. */ + for (i = 0; i < 10U; ++i) { bytes[2U * i] = words[i] & 255U; bytes[2U * i + 1U] = words[i] >> 8; } /* Восстанавливает то же октетное представление, что защищалось при COMMIT. */ + crc = pcan_boot_crc32_update(0UL, bytes, 20U); /* Проверяет метаданные до использования объявленной ими длины. */ + if (crc != ((uint32_t)words[10] | ((uint32_t)words[11] << 16))) return false; /* Повреждённый размер не может вывести чтение за пределы CAN-слота. */ + image.image_size = (uint32_t)words[4] | ((uint32_t)words[5] << 16); image.image_crc32 = (uint32_t)words[6] | ((uint32_t)words[7] << 16); /* Размер и CRC файла восстанавливаются только после успешной CRC manifest. */ + image.firmware_version = (uint32_t)words[8] | ((uint32_t)words[9] << 16); image.product_type = BOOT2812_PRODUCT; image.hardware_revision_min = image.hardware_revision_max = 1U; /* Профиль образа был проверен до публикации manifest. */ + return Boot2812_Verify(0, 0U, &image) == PCAN_BOOT_STATUS_OK && table(image.image_size, true, entry); /* Сначала полный read-only проход, затем перенос и только после успеха разрешение вызова entry. */ +} /* Не загружает старые flat BIN автоматически: новый проект использует проверяемую SCI8-таблицу. */ diff --git a/c/protocan-boot/ports/tms320f2812/nor_flash.c b/c/protocan-boot/ports/tms320f2812/nor_flash.c new file mode 100644 index 0000000..0b5ff51 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/nor_flash.c @@ -0,0 +1,69 @@ +#include "boot2812.h" /* Ограничивает аппаратный драйвер разделами обновления конкретного профиля ПМ67. */ +#if defined(BOOT2812_HOST) /* Host-модель воспроизводит команды NOR без обращения к физическим CPU-адресам. */ +extern unsigned int NorModel_Read(unsigned long word); /* Модель отдаёт данные, ID и аппаратные биты готовности чипа. */ +extern void NorModel_Write(unsigned long word, unsigned int value); /* Модель принимает настоящую последовательность unlock/program/erase драйвера. */ +#define NOR_READ(word) NorModel_Read(word) /* Подменяет только чтение шины, сохраняя алгоритм драйвера. */ +#define NOR_WRITE(word, value) NorModel_Write(word, value) /* Подменяет физическую запись при проверке границ и отказов. */ +#else /* Production использует 16-битную параллельную XINTF-шину. */ +#define NOR_READ(word) (*(volatile unsigned int *)(word)) /* Один CPU-адрес C28x соответствует одному x16 слову AM29LV800BT. */ +#define NOR_WRITE(word, value) (*(volatile unsigned int *)(word) = (value)) /* Volatile сохраняет каждый командный цикл AMD в исходном порядке. */ +#endif /* Завершает выбор физической шины либо модели. */ +static void reset_read(void) /* Выводит чип из autoselect либо неудачной операции в обычный режим чтения. */ +{ /* Reset не стирает слова памяти и допустим по любому адресу чипа. */ + NOR_WRITE(BOOT2812_NOR_BASE, 0x00F0U); /* F0 — Read/Reset из таблицы команд AMD Am29LV800B. */ +} /* Все ошибки возвращают NOR в состояние, пригодное для следующей recovery-сессии. */ +static void unlock(unsigned int command) /* Выполняет общий префикс x16-команд согласно datasheet AMD. */ +{ /* Адреса ниже являются смещениями в словах, а не октетными AAA/555 режима x8. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, 0x00AAU); /* Первый unlock-цикл AA по смещению 555h в режиме x16. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x2AAUL, 0x0055U); /* Второй unlock-цикл 55 по смещению 2AAh. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, command); /* Третий цикл выбирает autoselect, программирование либо начало стирания. */ +} /* Последующий цикл данных или адрес сектора выполняет вызывающая операция. */ +unsigned int Boot2812_NorRead(unsigned long word) /* Читает только физический диапазон установленной NOR ёмкостью 1 МиБ. */ +{ /* Верхняя исключающая граница равна BASE + 512K слов. */ + return word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL ? NOR_READ(word) : 0xFFFFU; /* Вне чипа не создаёт шинного чтения по неизвестному адресу. */ +} /* Возвращает полное x16 слово без перестановки октетов. */ +bool Boot2812_NorIdentify(void) /* Идентификация обязательна перед разрешением изменяющих операций. */ +{ /* Не подменяет top-boot геометрию похожим bottom-boot или NAND-чипом. */ + unsigned int maker, device; /* Хранит два слова autoselect, прежде чем вернуть чип к чтению. */ + reset_read(); unlock(0x0090U); /* 90h включает чтение manufacturer/device ID после обычного unlock. */ + maker = NOR_READ(BOOT2812_NOR_BASE); device = NOR_READ(BOOT2812_NOR_BASE + 1UL); /* AMD: offset 0 содержит 0001, offset 1 — 22DA для Am29LV800BT x16. */ + reset_read(); /* Обычные чтения образа после проверки не должны видеть таблицу autoselect. */ + return maker == 0x0001U && device == 0x22DAU; /* Отличающийся чип получает отказ до первого sector erase. */ +} /* Не выполняет разрушительных пробных записей для определения типа памяти. */ +static bool wait_word(unsigned long word, unsigned int expected, unsigned long timeout) /* Ограничивает DQ7/DQ5 polling временем и числом проходов. */ +{ /* DQ7 отражает готовность программируемого старшего бита; DQ5 требует завершающего повторного чтения. */ + unsigned long started = Boot2812_Now(), budget = 50000000UL; /* Итерационный предел обеспечивает выход даже при остановленном Timer1. */ + unsigned int value; /* Снимок status считывается один раз на основной проход. */ + do { /* Не вызывает никаких функций из программируемой внешней NOR: код загрузчика находится во внутренней Flash. */ + value = NOR_READ(word); /* Читает именно адрес программирования либо начало стираемого сектора. */ + if ((value & 0x0080U) == (expected & 0x0080U)) return NOR_READ(word) == expected; /* После совпадения DQ7 подтверждает все 16 бит результата. */ + if (value & 0x0020U) { /* DQ5 сообщает превышение внутреннего времени алгоритма AMD. */ + if ((NOR_READ(word) & 0x0080U) == (expected & 0x0080U)) return NOR_READ(word) == expected; /* Повтор исключает нормальное завершение операции одновременно с чтением DQ5. */ + break; /* После подтверждённой ошибки больше не ждёт неопределённое время. */ + } /* Завершает трактовку аппаратного статуса текущего прохода. */ + Boot2812_Busy(); /* Долгое стирание продолжает давать клиенту живой ответ и не блокирует CAN ISR. */ + } while (--budget && Boot2812_Now() - started < timeout); /* Беззнаковое вычитание сохраняет корректность при переполнении миллисекунд. */ + reset_read(); /* Отказ возвращает чип в режим чтения перед следующей recovery-попыткой. */ + return false; /* Не сообщает успех по одному окончанию тайм-аута. */ +} /* Завершает ограниченное ожидание аппаратной операции. */ +bool Boot2812_NorProgram(unsigned long word, unsigned int value) /* Программирует только выделенный CAN-образ либо manifest. */ +{ /* Старые данные приложения, FPGA и остальные сектора чипа не входят в разрешённые диапазоны. */ + unsigned int before; /* Предварительное чтение исключает попытку перевода NOR-бита из нуля в единицу. */ + if (!((word >= BOOT2812_IMAGE_WORD && word < BOOT2812_IMAGE_WORD + BOOT2812_IMAGE_BYTES / 2UL) || (word >= BOOT2812_META_WORD && word < BOOT2812_META_WORD + 0x2000UL))) return false; /* Проверяет word-адрес до любого unlock или командного цикла. */ + before = NOR_READ(word); /* Проверяет текущее содержимое перед началом операции. */ + if (before == value) return true; /* Повтор одинакового блока не выполняет лишнее программирование. */ + if ((before & value) != value) return false; /* Бит 0→1 требует отдельного sector erase и не должен маскироваться чтением старого слова. */ + unlock(0x00A0U); NOR_WRITE(word, value); /* A0 запускает word program; следующий цикл содержит адрес и полные 16 бит данных. */ + return wait_word(word, value, 100UL); /* Сто миллисекунд дают ограниченный запас для программирования одного слова. */ +} /* Каждый успех означает фактическое совпадение прочитанного слова. */ +bool Boot2812_NorErase(unsigned long word) /* Не принимает произвольный адрес или команду полного стирания чипа. */ +{ /* Обновление ограничено секторами 12/13/14 и последним top-boot сектором 18. */ + unsigned long i, count = word == BOOT2812_META_WORD ? 0x2000UL : 0x8000UL; /* AM29LV800BT: обычный сектор 32K слов, последний boot-сектор 8K слов. */ + if (!(word == BOOT2812_IMAGE_WORD || word == BOOT2812_IMAGE_WORD + 0x8000UL || word == BOOT2812_IMAGE_WORD + 0x10000UL || word == BOOT2812_META_WORD)) return false; /* Только точные разрешённые начала секторов исключают округление в соседнюю область. */ + unlock(0x0080U); /* 80h начинает шеститактовую последовательность Sector Erase AMD. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, 0x00AAU); NOR_WRITE(BOOT2812_NOR_BASE + 0x2AAUL, 0x0055U); /* Повторяет вторую unlock-пару перед выбором сектора. */ + NOR_WRITE(word, 0x0030U); /* 30h по sector address выбирает один сектор; команда Chip Erase 10h отсутствует. */ + if (!wait_word(word, 0xFFFFU, 20000UL)) return false; /* Ограничивает ожидание двадцатью секундами с периодическими BUSY-ответами. */ + for (i = 0; i < count; ++i) if (NOR_READ(word + i) != 0xFFFFU) return false; /* Проверяет всю стёртую область, а не только её первое слово. */ + return true; /* Разрешает запись лишь после полного аппаратного readback сектора. */ +} /* При сбое сохранённый manifest уже недействителен, загрузчик остаётся в recovery. */ diff --git a/c/protocan-boot/ports/tms320f28335/README.md b/c/protocan-boot/ports/tms320f28335/README.md index 3d45984..952f98c 100644 --- a/c/protocan-boot/ports/tms320f28335/README.md +++ b/c/protocan-boot/ports/tms320f28335/README.md @@ -1,18 +1,55 @@ # F28335 + M95M02: CAN, отдельный загрузчик и A/B -Реализация состоит из Flash-загрузчика `periph_167/Bootloader`, переносимого +Реализация состоит из Flash-загрузчика `projects/ccs/f28335`, переносимого `f28335_boot_store.c`, аппаратного `f28335_boot_hw.c` и адаптера -`f28335_can_boot.c`. Приложение подключает их через `Source/Internal/can_boot.c`. +`f28335_can_boot.c`. Приложение подключает общий `f28335_can_application.c` +прямой ссылкой linked resource из templates в CCS Debug/Release. В сборке `EEPROM_M95M02=0` CAN Boot отключён. Для установленной M95M02 — значение 1. ## Адрес и формат -Device Type **3**, Device ID **7**, имя **F28335-M95M02**, Product **0x2833**, HW **1**. +Адрес определяется физическим номером **PERIPH 0–31** по новой Excel-таблице: +Type = 1 + PERIPH / 16 (целая часть), Device ID = PERIPH mod 16. +**УМП1 — 1/5, УМП2 — 1/6, задатчик — 1/8**. Product **0x2833**, HW **1** +описывают существующую аппаратную совместимость F28335 и не являются CAN-адресом. +Имена паспорта для назначенных плат — `UMP1`, `UMP2`, `Zadatchik`. +Приложение передаёт Mode в `F28335CanBoot_Init(Mode)`. Загрузчик независимо +читает те же активные низким уровнем GPIO21/20/22/51 с весами 1/2/4/8 и базой 1. +Поэтому существующие перемычки ПМ35 задают номера 1–16; номера 0 и 17–31 +поддерживаются адресным контрактом, но требуют другого источника физического номера. +Общий адрес 3/7 больше не принимается. Чужие адреса отбрасываются аппаратным +mailbox, ISR и ядром до записи EEPROM, включая данные A/B и управляющие команды. В приложении FW берётся из `firmware_version.h`, формат `major<<24 | minor<<16 | patch`; для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT. CAN **250000 бит/с**, Extended ID, окно **16 блоков по 8 октетов**. -ENTER_BOOT для session=1: `0x13790102`, STATUS: `0x1B7C0102`. +Для задатчика и session=1: ENTER_BOOT `0x11890102`, STATUS `0x198C0102`. + +## Общий запуск Flash и резервной EEPROM + +Сектор A и аппаратный boot `0x33FFF6` принадлежат постоянному загрузчику. +Flash-приложение использует `[0x300000,0x338000)`: первые 16 слов — описание +FAB1, остальные — собственные LOAD-секции. `f28335_flash_app.c` проверяет +magic/version, entry, границы, инверсию entry, маркеры и CRC32 IEEE всего +диапазона после заголовка, включая промежутки, заполненные `0xFFFF`. +Python-контракт `python/protocan/f28335_flash.py` заполняет зарезервированные +32 октета COFF по смещению, подтверждённому TI OFD, после линковки. + +Загрузчик даёт трёхсекундное окно CAN, затем запускает исправную внутреннюю +Flash в приоритете. Отсутствующая/повреждённая Flash ведёт к прежнему выбору +EEPROM A/B с trial/CONFIRM/rollback. ENTER_BOOT удерживает CAN recovery. +Handoff running=`0xFE` обозначает проверенную внутреннюю Flash; 0/1 — EEPROM +A/B, `0xFF` — отсутствие запущенного приложения. Flash-приложение обслуживает +PING и ENTER_BOOT, но не подменяет подтверждение EEPROM-кандидата. +Обновление EEPROM по CAN не меняет приоритет исправной Flash после reset. + +RS Flash должен стирать только B–H, публиковать FAB1 после проверки остальных +данных и запрещать любые адреса сектора A. В SETGUI соответствующие JTAG +маски задаются явными TI `FlashSectorA..H`: A для установки boot, B–H для +приложения. Полное стирание чипа внешним программатором не ограничивается linker. +Старая самостоятельная Flash-сборка с codestart `0x33FFF6` несовместима с этим +размещением и не должна передаваться как обновление приложения. + Образ — SCI8 BIN (`AA 08`), чётная длина от 24 до **130560 байт** включительно. Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное @@ -106,7 +143,7 @@ Python API: `protocan.can_boot.CanBootServices` — запросы и разбо ## Аппаратная интеграция MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery. -MBOX0..2 сохраняют legacy/UMP, MBOX5 остаётся heartbeat. ISR помещает сообщения +MBOX0..2 сохраняют legacy/UMP, MBOX5 загрузчик не использует. ISR помещает сообщения в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди. При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново. SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес, @@ -118,7 +155,31 @@ SPI-драйвер загрузчика имеет ограничение ожи Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует 0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации, 0xE000..0xFFFF для .ebss после перехода в C runtime. Linker резервирует -NOINIT handoff в обоих проектах. CAN не содержит операций записи внутренней Flash. +NOINIT handoff в обоих проектах. TI Flash API временно использует RAM +`0x8000..0x97FF` до запуска приложения. В обновлённом постоянном загрузчике +CAN также записывает внутреннюю Flash приложения B–H; сектор A защищён. + +## Внутренняя Flash по CAN + +После ENTER_BOOT клиент явно отправляет SELECT_MEMORY (`0x10`, DLC=1, +DATA[0]=1) до BEGIN_IMAGE/BEGIN_COMPAT. Новая сессия по умолчанию использует +EEPROM A/B, поэтому старые клиенты сохраняют прежнее поведение. Выбор памяти +после метаданных запрещён; старый boot отвечает INVALID_COMMAND до ERASE. +CAPABILITIES bit 12 обозначает поддержку записи внутренней Flash. + +Flash SCI8 с FAB1 передаётся в неактивный EEPROM-слот как staging. VERIFY +проверяет CRC32 EEPROM, таблицу, непересекающиеся адреса только B–H и FAB1/CRC +будущей Flash. COMMIT повторяет проверку staging, вызывает официальный TI API +со стиранием `0x00FE`, пишет и проверяет данные порциями до 128 слов, публикует +FAB1 последним и проверяет CRC физической Flash. ACK COMMIT приходит после +записи; клиент даёт до 180 секунд и затем отправляет отдельный REBOOT. +EEPROM active и параметры сохраняются; прежний неактивный образ заменяется staging. + +В SETGUI: «Прошивка → CAN / ProtoCAN Boot → ProtoCAN: память прошивки → +Внутренняя Flash F28335», файл `*_flash_rs.bin` существующего выпуска. +Сначала требуется обновить постоянный `F28335_CAN_AB.out` через JTAG с маской +только сектора A. В Debug/Release подключён установленный TI Flash API v2.10; +его код и таблицы копируются в RAM перед занятостью общего банка Flash A–H. ## Первичная установка @@ -126,10 +187,13 @@ NOINIT handoff в обоих проектах. CAN не содержит опе Старые BIN/OUT автоматически не заменены. Приложение должно содержать интеграцию READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом. 2. Собрать отдельный загрузчик TI C2000 COFF compiler: - `Bootloader/build.ps1 -CompilerRoot <путь-к-ti-cgt-c2000>`. - Результат — `Bootloader/build/F28335_CAN_AB.out` и MAP. -3. Один раз установить этот OUT через JTAG и выбрать аппаратный Flash boot - согласно схеме платы. Не загружать поверх него старый application OUT с + `python c/protocan-boot/projects/build.py --device f28335 --compiler <путь-к-ti-cgt-c2000>`. + Результат — `projects/ccs/f28335/Debug/F28335_CAN_AB.out` и MAP. +3. Установить обновлённый OUT через JTAG и выбрать аппаратный Flash boot + согласно схеме платы. При переходе с общего адреса 3/7 обновить и приложение, + и загрузчик: старый загрузчик не перейдёт на новый адрес после reset сам. + В SETCAN выбрать «Прошивка → CAN / ProtoCAN Boot → Устройство PERIPH» + и нужное назначение. Не загружать поверх загрузчика старый application OUT с секцией codestart во Flash. 4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery. Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и @@ -145,8 +209,10 @@ NOINIT handoff в обоих проектах. CAN не содержит опе ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти. Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B. -Проверка синтаксиса использует настоящие DSP2833x headers. Сборка TI/CCS, -раскладка итогового MAP и физические CAN/SPI/reset на плате ещё не подтверждены. +Проверка синтаксиса использует настоящие DSP2833x headers. Импорт и сборка TI/CCS, +раскладка MAP и реальные COFF LOAD-адреса проверены; физические CAN/SPI/reset +на плате требуют стендовой проверки. Отдельные проекты и команды сборки описаны +в [инструкции CCS](../../projects/README.md). CRC32 защищает от повреждения, криптографической подписи и anti-rollback по версии в этом порту нет. Удалённый CONFIRM подтверждает готовность приложения, @@ -154,3 +220,13 @@ CRC32 защищает от повреждения, криптографичес Аппаратный формат SPI boot описан в [TI Boot ROM Reference Guide](https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/2742.Boot-ROM.pdf). В A/B-схеме ROM выбирает Flash, а разбор EEPROM выполняет этот загрузчик. + +Проект предоставляет `f28335_can_application_config.h` в include paths. +Он задаёт `F28335_CAN_BOOT_APPLICATION_ENABLED` (0/1) и при включённом модуле +`F28335_CAN_BOOT_FIRMWARE_VERSION` из версии приложения. В 167 это ручной +`firmware_version.h`; профиль включён только при M95M02 без `FLASH_BOOT`. +Локальный `Source/Internal/can_boot.c` содержит только `F28335Boot_Quiesce` +со штатной остановкой нагрузки. Общие `.c` повторно включать в него не нужно: +они компилируются единственным linked resource общей библиотеки. +Постоянный Flash-загрузчик по-прежнему собирается отдельным проектом +`projects/ccs/f28335` и не линкуется в RAM-приложение. diff --git a/c/protocan-boot/ports/tms320f28335/f28335_boot_platform.h b/c/protocan-boot/ports/tms320f28335/f28335_boot_platform.h index facd3b3..e0d7bc9 100644 --- a/c/protocan-boot/ports/tms320f28335/f28335_boot_platform.h +++ b/c/protocan-boot/ports/tms320f28335/f28335_boot_platform.h @@ -1,6 +1,7 @@ #ifndef F28335_BOOT_PLATFORM_H #define F28335_BOOT_PLATFORM_H #include "f28335_boot_store.h" +#include "f28335_flash_app.h" /* Общий handoff различает EEPROM A/B, защищённое Flash-приложение и неизвестный запуск. */ #ifndef F28335_BOOT_LOADER #define F28335_BOOT_LOADER 0 #endif diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_application.c b/c/protocan-boot/ports/tms320f28335/f28335_can_application.c new file mode 100644 index 0000000..f7fe30b --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_application.c @@ -0,0 +1,10 @@ +#include "f28335_can_application_config.h" /* Получает от проекта разрешение CAN A/B и версию приложения; этот конфигурационный заголовок должен находиться в include paths CCS. */ +#ifndef F28335_CAN_BOOT_APPLICATION_ENABLED /* Отсутствующее аппаратное решение нельзя трактовать как разрешение записи служебных областей EEPROM. */ +#error "Define F28335_CAN_BOOT_APPLICATION_ENABLED in f28335_can_application_config.h" /* Останавливает сборку до появления приложения с неполной интеграцией загрузчика. */ +#endif /* Завершает проверку обязательного конфигурационного признака проекта. */ +#if F28335_CAN_BOOT_APPLICATION_ENABLED /* Самостоятельный Flash-образ и платы без M95M02 исключают весь CAN A/B-код на этапе компиляции. */ +#include "../../src/pcan_boot.c" /* Компилирует единственный автомат команд ProtoCAN Boot с его штатными сессиями, CRC32 и проверкой последовательности пакетов. */ +#include "f28335_boot_store.c" /* Подключает общий A/B-журнал, readback, проверку SCI8 и выбор подтверждённого слота той же версии templates. */ +#include "f28335_boot_hw.c" /* Предоставляет SPI EEPROM, watchdog и согласованный handoff между приложением и постоянным Flash-загрузчиком. */ +#include "f28335_can_boot.c" /* В режиме приложения обслуживает вход в boot и READY/CONFIRM, сохраняя служебные mailbox 3/4/6 отдельно от технологического CAN. */ +#endif /* Постоянный загрузчик собирается отдельным CCS-проектом templates с F28335_BOOT_LOADER=1, а не этим прикладным модулем. */ diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c index 5cbd7a4..4f1b80f 100644 --- a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c @@ -8,6 +8,21 @@ * Сброс сессии не удаляет active/pending из EEPROM. */ static pcan_boot_t boot; static f28335_boot_store_t store; +static unsigned int healthy; /* Результат открытия EEPROM-журнала известен также функции выбора назначения Flash. */ +#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Flash API доступен только постоянному загрузчику с явной поддержкой обновления B–H. */ +#include "f28335_flash_update.h" /* Подключает проверку Flash SCI8 и аппаратный writer с сохранением сектора A. */ +#include "f28335_flash_update.c" /* Общий алгоритм компилируется с тем же pcan_boot и разметкой, что этот порт. */ +static f28335_flash_update_t flash_update; /* Индекс и кеш занимают ограниченную внутреннюю RAM без загрузки приложения поверх boot. */ +static unsigned int flash_selected, flash_staging; /* Явная цель Flash использует только неактивный EEPROM-слот как временное хранилище. */ +static pcan_boot_status_t select_memory(void *u, pcan_boot_byte_t memory, pcan_boot_config_t *cfg) /* Выбирает назначение до BEGIN_IMAGE, сохраняя прежний EEPROM-путь по умолчанию. */ +{ /* Изменения конфигурации разрешены только при исправном EEPROM-журнале. */ + (void)u; if (!healthy) return PCAN_BOOT_STATUS_FLASH_ERROR; /* Ошибка чтения журнала запрещает выбор staging поверх неизвестного active. */ + if (memory > 1U) return PCAN_BOOT_STATUS_INVALID_COMMAND; /* Единственные определённые цели: 0=EEPROM A/B и 1=внутренняя Flash. */ + flash_selected = memory; flash_update.valid = false; /* Новая цель отменяет прежнее разрешение программирования. */ + cfg->slot_count = memory ? 1U : 2U; cfg->active_slot = memory ? 0U : store.active; /* CAN Flash использует один логический слот A, EEPROM сохраняет выбор неактивного A/B. */ + return PCAN_BOOT_STATUS_OK; /* Физический staging будет инвалидирован лишь при последующей команде ERASE. */ +} /* Никакие данные Flash или EEPROM при выборе цели не изменяются. */ +#endif /* Приложение и старые host-модели не подключают Flash API. */ /* Кольцевая очередь: ISR производит кадры, main потребляет. Из 32 элементов * используется 31, чтобы head==tail однозначно означало пустую очередь. * Долгие операции SPI запрещены внутри обработчика CAN. */ @@ -16,9 +31,10 @@ static struct { uint32_t id; unsigned int dlc; pcan_boot_byte_t data[8]; } queue /* reset_requested только планирует reset; Service ждёт завершения TX. * ready сообщает об окончании старта приложения, confirmed — о сохранённом * подтверждении слота. healthy отражает результат открытия журнала при Init. */ -static unsigned int reset_requested,reset_session,ready,healthy,confirmed; +static unsigned int reset_requested,reset_session,ready,confirmed; /* Состояние перехода и подтверждения приложения отделено от доступности EEPROM. */ static uint32_t sent_at,ready_at; static unsigned int main_passes; +static unsigned int addressed; /* Разрешает обслуживание только после проверки номера PERIPH и установки согласованных фильтров CAN. */ static int tx_busy,tx_canceling; /* Один исходящий mailbox исключает перезапись ещё передаваемого ответа. * MDL содержит первые четыре октета, MDH — следующие четыре, младшим вперёд. @@ -48,9 +64,19 @@ static bool transmit(void *u, uint32_t id, const pcan_boot_byte_t *d, pcan_boot_ * эти callbacks возвращают отказ, даже если им удастся передать команду записи. * ERASE для EEPROM означает инвалидирование manifest выбранного слота. */ static bool erase(void *u,pcan_boot_byte_t slot) -{ (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_prepare(&store,slot); } +{ /* ERASE подготавливает staging; внутренняя Flash остаётся неизменной до VERIFY и COMMIT. */ +#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Новая цель не меняет прежний формат EEPROM A/B. */ + if (flash_selected) { flash_update.valid = false; flash_staging = store.active == 0U ? 1U : 0U; return healthy && f28335_boot_prepare(&store, flash_staging); } /* Инвалидирует только неактивный слот, сохраняя подтверждённый резерв и параметры. */ +#endif /* В остальных сборках остаётся штатная подготовка EEPROM-слота. */ + (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_prepare(&store,slot); /* Обычный CAN-клиент сохраняет прежний путь обновления RAM-приложения. */ +} /* Подготовка не вызывает TI Flash_Erase. */ static bool write_block(void *u,pcan_boot_byte_t slot,uint32_t offset,const pcan_boot_byte_t *d,pcan_boot_byte_t n) -{ (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_write(&store,slot,offset,d,n); } +{ /* CAN ISR только ставит данные в очередь; запись staging выполняет main. */ +#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Запись Flash-файла использует тот же проверенный EEPROM writer. */ + if (flash_selected) return healthy && f28335_boot_write(&store, flash_staging, offset, d, n); /* Логический DATA_A направляется в выбранный неактивный физический слот. */ +#endif /* Обычные A/B-данные сохраняют исходную адресацию. */ + (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_write(&store,slot,offset,d,n); /* Не допускает записи из прикладной сборки. */ +} /* Внутренняя Flash ещё не затронута. */ /* Проверка включает CRC EEPROM и структуру SCI8. Сейчас отказ этого слоя * кодируется CRC_ERROR как общий отказ проверки образа; причины внутри * парсера SCI8 отдельными статусами протокола не различаются. */ @@ -58,10 +84,21 @@ static pcan_boot_status_t verify(void *u,pcan_boot_byte_t slot,const pcan_boot_m { (void)u; if(!F28335_BOOT_LOADER || !healthy) return PCAN_BOOT_STATUS_INVALID_STATE; +#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Для внутренней Flash нужен собственный допустимый диапазон SCI8 и обязательный FAB1. */ + if (flash_selected) return f28335_flash_update_validate(&flash_update, &store.io, flash_staging ? F28335_AB_SLOT_B : F28335_AB_SLOT_A, m) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_CRC_ERROR; /* Повторно читает EEPROM и проверяет транспортную CRC, таблицу и CRC будущей Flash до erase. */ +#endif /* RAM SCI8 проходит прежнюю проверку приложения EEPROM. */ return f28335_boot_verify(&store,slot,m,0)?PCAN_BOOT_STATUS_OK:PCAN_BOOT_STATUS_CRC_ERROR; } static bool commit(void *u,pcan_boot_byte_t slot,const pcan_boot_manifest_t *m) -{ (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_commit(&store,slot,m); } +{ /* COMMIT выполняет фактическую запись только после подтверждённой проверки образа. */ +#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Постоянный boot остаётся вне обновляемых секторов B–H. */ + if (flash_selected) { /* Синхронный TI API может работать дольше обычного интервала CAN, не создавая pending EEPROM. */ + bool result = healthy && F28335Boot_FlashProgram(&flash_update); /* Итог зависит от erase, каждой порции readback и полной CRC физической Flash. */ + boot.now_ms = F28335Boot_Now(); boot.last_activity_ms = boot.now_ms; return result; /* Обновляет срок сессии после аппаратной операции, чтобы штатный REBOOT не был отклонён из-за времени записи. */ + } /* Ошибка записи оставляет постоянный boot доступным для нового сеанса. */ +#endif /* Обычное обновление EEPROM сохраняет trial/CONFIRM. */ + (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_commit(&store,slot,m); /* Публикует только RAM-образ в исходном журнале A/B. */ +} /* Итоговый статус и отдельный REBOOT отправляет существующее ядро ProtoCAN. */ /* Подтверждение принадлежит приложению после READY. Загрузчик не может * подтвердить кандидата сам: иначе исчезнет смысл проверки пробного запуска. * Разрешение кормления watchdog из ISR открываем только после записи журнала. */ @@ -82,9 +119,14 @@ static unsigned int enter(void *u,pcan_boot_byte_t session) { (void)u; if(!healthy) return 2; - if(F28335_BOOT_LOADER) return 0; + if(F28335_BOOT_LOADER) { /* Постоянный загрузчик открывает сессию без дополнительного reset. */ +#if F28335_CAN_FLASH_UPDATE /* Каждая новая сессия должна начинаться со штатного EEPROM-назначения. */ + if (boot.state == PCAN_BOOT_STATE_IDLE) (void)select_memory(0, 0U, &boot.config); /* Повторный ENTER текущей сессии не меняет уже выбранную Flash. */ +#endif /* Старые сборки не используют переключение назначения. */ + return 0; /* Ядро отправит адресный ACK готовности. */ + } /* Прикладной handoff проверяется ниже. */ /* No destructive fallback on boards still starting through the SPI ROM. */ - if(F28335Boot_RunningSlot()>1 || !confirmed) return 2; + if((F28335Boot_RunningSlot()>1 && F28335Boot_RunningSlot()!=F28335_BOOT_FLASH_SLOT) || !confirmed) return 2; /* Только handoff общего загрузчика разрешает переход из EEPROM либо защищённой внутренней Flash; старый SPI-ROM старт остаётся запрещён. */ reset_session=session; reset_requested=1; return 1; } static void info32(pcan_boot_byte_t *p,uint32_t v) @@ -95,18 +137,21 @@ static void info32(pcan_boot_byte_t *p,uint32_t v) * 2 — active/pending/attempted/healthy/тайм-аут, 3 — область параметров. */ static bool info(void *u,pcan_boot_byte_t command,pcan_boot_byte_t page,pcan_boot_byte_t *out) { - static const char name[]=F28335_CAN_BOOT_DEVICE_NAME; - unsigned int i,index; (void)u; + const char *name=boot.config.device_type==1U && boot.config.device_id==8U?"Zadatchik":boot.config.device_type==1U && boot.config.device_id==5U?"UMP1":boot.config.device_type==1U && boot.config.device_id==6U?"UMP2":F28335_CAN_BOOT_DEVICE_NAME; /* Паспорт различает три назначенных Excel устройства; резервные номера сохраняют аппаратное имя. */ + unsigned int i,index,name_size=(unsigned int)strlen(name)+1U; (void)u; /* Длина включает завершающий NUL, чтобы последняя страница имени однозначно завершала чтение. */ if(command==PCAN_BOOT_CMD_CAPABILITIES && page==0) { /* bits: ping, discovery, identity, name, memory, A/B, confirm, rollback, * separate loader, session timeout, readback, SCI8 validation. */ - info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2)?0xFFFUL:0x1FUL); - info32(out+4,F28335_AB_SLOT_BYTES); return true; + info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2 || F28335Boot_RunningSlot()==F28335_BOOT_FLASH_SLOT)?0xFFFUL:0x1FUL); /* Flash-приложение с достоверным handoff поддерживает вход в постоянный CAN Boot так же, как подтверждённый EEPROM-образ. */ +#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Дополнительный бит сообщает клиенту поддержку явной внутренней Flash. */ + out[1] |= 0x10U; /* Бит 12 общего little-endian capability word означает SELECT_MEMORY и запись B–H. */ +#endif /* Старые приложения продолжают сообщать прежние возможности. */ + info32(out+4,F28335_AB_SLOT_BYTES); return true; /* Максимальная длина одинакова для staging Flash и EEPROM A/B. */ } if(command==PCAN_BOOT_CMD_DEVICE_NAME) { - if((unsigned int)page*8U>=sizeof(name)) return false; + if((unsigned int)page*8U>=name_size) return false; /* Страница после конца выбранного имени не является допустимой частью паспорта. */ for(i=0;i<8;++i) { index=(unsigned int)page*8U+i; - out[i]=index=F28335_CAN_BOOT_PERIPH_COUNT) return; /* Номер вне Excel-диапазона 0–31 не подменяется общим адресом и не открывает запись другой платы. */ memset(&cfg,0,sizeof(cfg)); memset(&port,0,sizeof(port)); io.read=F28335Boot_Read; io.write=F28335Boot_Write; io.user=0; healthy=f28335_boot_open(&store,&io); - cfg.device_type=F28335_CAN_BOOT_DEVICE_TYPE; cfg.device_id=F28335_CAN_BOOT_DEVICE_ID; + cfg.device_type=1U+periph_id/16U; cfg.device_id=periph_id%16U; /* Excel: PERIPH 0–15 → Type 1, 16–31 → Type 2; младшие четыре бита задают Device ID. */ cfg.product_type=F28335_CAN_BOOT_PRODUCT; cfg.hardware_revision=1; #if F28335_BOOT_LOADER cfg.firmware_version=store.active<2?store.image[store.active].firmware_version:0; @@ -139,15 +186,20 @@ void F28335CanBoot_Init(void) cfg.firmware_version=F28335_CAN_BOOT_FIRMWARE_VERSION; #endif head=tail=overflow=reset_requested=reset_session=ready=main_passes=0; tx_busy=tx_canceling=0; - confirmed=healthy && running<2 && store.active==running && store.pending==F28335_AB_NONE; + confirmed=running==F28335_BOOT_FLASH_SLOT || (healthy && running<2 && store.active==running && store.pending==F28335_AB_NONE); /* Flash уже проверена CRC постоянным boot; пробное подтверждение требуется только EEPROM-кандидату. */ cfg.active_slot=store.active; cfg.slot_count=2; cfg.max_image_size=F28335_AB_SLOT_BYTES; cfg.ack_window=16; cfg.session_timeout_ms=30000UL; +#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* После reset никакое случайное содержимое RAM не выбирает внутреннюю Flash. */ + flash_selected = 0U; flash_staging = F28335_AB_NONE; flash_update.valid = false; /* Возвращает исходную цель и отменяет разрешение записи предыдущей сессии. */ + port.select_memory = select_memory; /* Новая команда доступна только сборке с реально подключённым TI API. */ +#endif /* Приложение отвечает только через постоянный загрузчик после handoff. */ port.send=transmit; port.erase_slot=erase; port.write_slot=write_block; port.verify_status=verify; port.set_pending_slot=commit; port.reboot=reboot; port.confirm_running_slot=confirm; port.enter_boot=enter; port.can_reboot=can_reboot; port.service_info=info; if(!pcan_boot_init(&boot,&cfg,&port,0)) return; + addressed=1U; /* Дальнейшие ISR, основной цикл и handoff используют только успешно созданную адресную конфигурацию. */ EALLOW; /* Меняем только MBOX3/4/6: маска 88=8+16+64. MBOX0..2 — старый обмен, * MBOX5 — heartbeat. Приём broadcast выделен в отдельный точный mailbox, @@ -181,8 +233,8 @@ static void receive_box(volatile struct MBOX *box,uint32_t mask) type=pcan_boot_id_msg_type(id); if(!(box->MSGID.all&0x80000000UL) || pcan_boot_id_route(id)!=0 || (type!=9 && type!=10 && type!=11 && type!=13) || - !((pcan_boot_id_device_type(id)==F28335_CAN_BOOT_DEVICE_TYPE && - pcan_boot_id_device_id(id)==F28335_CAN_BOOT_DEVICE_ID) || + !((pcan_boot_id_device_type(id)==boot.config.device_type && /* Сравнивает тип именно этой платы, а не прежнюю общую константу 3. */ + pcan_boot_id_device_id(id)==boot.config.device_id) || /* Отбрасывает команды соседних PERIPH ещё до очереди и любых операций EEPROM. */ (type==13 && pcan_boot_id_device_type(id)==7 && pcan_boot_id_device_id(id)==15 && pcan_boot_id_msg_body(id)==0))) { ECanaRegs.CANRMP.all=mask; return; } if(next==tail) overflow=1; @@ -199,6 +251,7 @@ static void receive_box(volatile struct MBOX *box,uint32_t mask) void F28335CanBoot_RxISR(void) { + if(!addressed) return; /* Неверный или ещё не настроенный номер PERIPH не должен принимать даже оставшиеся флаги RX. */ receive_box(&ECanaMboxes.MBOX3,8UL); receive_box(&ECanaMboxes.MBOX6,64UL); } @@ -214,9 +267,11 @@ unsigned int F28335CanBoot_WatchdogAllowed(void) /* Неблокирующий диспетчер относительно ожидания CAN: вызывать в каждом проходе main. * Сами callbacks проверки/записи EEPROM синхронные. Порядок здесь важен: * проба приложения -> завершение TX -> reset -> poll -> ошибки RX -> один кадр. */ +unsigned int F28335CanBoot_Active(void) { return addressed && (boot.state!=PCAN_BOOT_STATE_IDLE || reset_requested); } /* Открытый ENTER_BOOT удерживает recovery; диагностический PING не меняет приоритет Flash и EEPROM. */ void F28335CanBoot_Service(void) { uint32_t now=F28335Boot_Now(); + if(!addressed) return; /* Не обслуживает старую RAM-сессию после отказа повторной инициализации адреса. */ if(!F28335_BOOT_LOADER && ready && !confirmed && healthy && F28335Boot_RunningSlot()<2) { /* A trial must keep executing main, not merely a timer ISR. */ /* После 100 проходов main и 5 секунд пробуем сохранить CONFIRM. @@ -261,15 +316,16 @@ void F28335CanBoot_Service(void) * или CRC незавершённой передачи: данные сессии через reset не сохраняются. */ void F28335CanBoot_Resume(unsigned int session) { - if(F28335_BOOT_LOADER && session && session<256) - (void)pcan_boot_process(&boot,pcan_boot_make_id(1,0, - F28335_CAN_BOOT_DEVICE_TYPE,F28335_CAN_BOOT_DEVICE_ID,9,(session<<8)|2),0,0); + if(addressed && F28335_BOOT_LOADER && session && session<256) /* Восстанавливает только допустимую сессию адресованного загрузчика после reset. */ + (void)pcan_boot_process(&boot,pcan_boot_make_id(1,0, /* ACK относится к тому же физическому PERIPH, который принимал ENTER_BOOT в приложении. */ + boot.config.device_type,boot.config.device_id,9,(session<<8)|2),0,0); /* MsgType 9, команда 2 и исходный SessionID сохраняют протокол handoff. */ } #else void F28335CanBoot_EarlyInit(void) {} -void F28335CanBoot_Init(void) {} +void F28335CanBoot_Init(unsigned int periph_id) { (void)periph_id; } /* Сборка без M95M02 не занимает CAN-адрес и не открывает сервис записи. */ void F28335CanBoot_RxISR(void) {} void F28335CanBoot_Service(void) {} +unsigned int F28335CanBoot_Active(void) { return 0U; } /* Профиль без M95M02 не создаёт CAN-сеанс и не удерживает старт общего загрузчика. */ void F28335CanBoot_Ready(void) {} unsigned int F28335CanBoot_WatchdogAllowed(void) { return 1; } void F28335CanBoot_Resume(unsigned int session) { (void)session; } diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h index 17b44db..59476e8 100644 --- a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h @@ -9,8 +9,7 @@ #endif /* Адрес ProtoCAN состоит из Device Type (3 бита) и Device ID (4 бита). * ProductType — отдельный код совместимости прошивки; это не CAN ID и не RS-адрес. */ -#define F28335_CAN_BOOT_DEVICE_TYPE 3U -#define F28335_CAN_BOOT_DEVICE_ID 7U +#define F28335_CAN_BOOT_PERIPH_COUNT 32U /* Лист «Интерфейс протокола», строки 45–76: PERIPH 0–31 занимают два типа по 16 экземпляров. */ #define F28335_CAN_BOOT_PRODUCT 0x2833U #define F28335_CAN_BOOT_DEVICE_NAME "F28335-M95M02" /* Порядок интеграции приложения: @@ -18,10 +17,11 @@ * таймера и EEPROM; Ready после старта прикладных подсистем; Service в main. * RxISR вызывается из CAN ISR, WatchdogAllowed проверяется перед кормлением * watchdog таймерным ISR. Resume применяется только отдельным загрузчиком. */ -void F28335CanBoot_Init(void); +void F28335CanBoot_Init(unsigned int periph_id); /* Принимает физический номер PERIPH: 5 — УМП1, 6 — УМП2, 8 — задатчик; общий адрес для всех плат исключён. */ void F28335CanBoot_EarlyInit(void); void F28335CanBoot_RxISR(void); void F28335CanBoot_Service(void); +unsigned int F28335CanBoot_Active(void); /* Удерживает загрузчик в CAN recovery после ENTER_BOOT, не запуская приложение по окончании стартового окна. */ void F28335CanBoot_Ready(void); void F28335CanBoot_Resume(unsigned int session); unsigned int F28335CanBoot_WatchdogAllowed(void); diff --git a/c/protocan-boot/ports/tms320f28335/f28335_flash_app.c b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.c new file mode 100644 index 0000000..ac5dbd5 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.c @@ -0,0 +1,26 @@ +#include "f28335_flash_app.h" /* Использует ту же границу сектора A и формат описания, что сборщик и RS-программатор. */ +bool f28335_flash_app_validate(f28335_flash_read_word_t read_word, void *user, uint32_t *entry) /* Не обращается к EEPROM и подходит для постоянного загрузчика и проверки staging RAM. */ +{ /* Никакие адреса из непроверенного заголовка не используются для чтения до проверки границ. */ + uint16_t header[F28335_FLASH_APP_HEADER_WORDS], word, octet, bit, i; /* Малый локальный буфер хранит 16 слов описания FAB1. */ + uint32_t address, start, end, expected, crc = 0xFFFFFFFFUL, target, inverse; /* CRC32 IEEE начинается со всех единиц и инвертируется после последнего октета. */ + if (!read_word || !entry) return false; /* Отсутствующий источник или выходной указатель не должен вызывать обращение к памяти. */ + for (i = 0; i < F28335_FLASH_APP_HEADER_WORDS; ++i) header[i] = read_word(user, F28335_FLASH_APP_START + i); /* Читает только фиксированное описание в секторе H. */ + if (header[0] != 0x4146U || header[1] != 0x3142U || header[2] != 1U || header[3] != F28335_FLASH_APP_HEADER_WORDS || header[14] != 0x5AA5U || header[15] != 0xA55AU) return false; /* Физические октеты ASCII FAB1, версия 1, размер и два маркера отличают завершённый образ от стёртого либо старого Flash. */ + target = (uint32_t)header[4] | ((uint32_t)header[5] << 16); /* Точка входа хранится младшим 16-битным словом вперёд внутри описания. */ + start = (uint32_t)header[6] | ((uint32_t)header[7] << 16); /* Нижняя граница защищённого CRC диапазона должна начинаться сразу после описания. */ + end = (uint32_t)header[8] | ((uint32_t)header[9] << 16); /* Верхняя граница является исключённым адресом слова, а не длиной в байтах. */ + expected = (uint32_t)header[10] | ((uint32_t)header[11] << 16); /* Сохранённая CRC32 рассчитана по физическим октетам всех слов диапазона. */ + inverse = (uint32_t)header[12] | ((uint32_t)header[13] << 16); /* Инверсия адреса выявляет частичную публикацию управляющих полей. */ + if (start != F28335_FLASH_APP_DATA || end <= start || end > F28335_FLASH_APP_STOP || target < start || target >= end || inverse != ~target) return false; /* Запрещает RAM, сектор загрузчика, пустой код и случайные адреса из повреждённого описания. */ + for (address = start; address < end; ++address) { /* Проверяет также стёртые промежутки между LOAD-секциями, чтобы JTAG и RS давали одинаковое содержимое. */ + word = read_word(user, address); /* Получает одно 16-битное слово из Flash либо из модели staging SCI8. */ + for (i = 0; i < 2U; ++i) { /* Каждый адрес C28x содержит два физических октета: сначала младший, затем старший. */ + octet = (word >> (8U * i)) & 255U; /* Маска отделяет октет независимо от 16-битного char TI. */ + crc ^= octet; /* Добавляет очередной октет в отражённое состояние CRC32 IEEE. */ + for (bit = 0; bit < 8U; ++bit) crc = (crc & 1UL) ? ((crc >> 1) ^ 0xEDB88320UL) : (crc >> 1); /* 0xEDB88320 — отражённый полином IEEE 802.3, совпадающий с zlib.crc32. */ + } /* Завершает обработку обоих октетов текущего слова. */ + } /* Завершает чтение только внутри области приложения ниже сектора A. */ + if ((crc ^ 0xFFFFFFFFUL) != expected) return false; /* Повреждённое или частично записанное приложение остаётся недоступным для запуска. */ + *entry = target; /* Публикует точку старта только после подтверждения всех адресов и данных. */ + return true; /* Разрешает загрузчику запустить именно проверенную Flash-программу. */ +} /* Ошибка никогда не меняет EEPROM, Flash или сохранённый выходной адрес. */ diff --git a/c/protocan-boot/ports/tms320f28335/f28335_flash_app.h b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.h new file mode 100644 index 0000000..94741e3 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.h @@ -0,0 +1,11 @@ +#ifndef F28335_FLASH_APP_H /* Защищает общий контракт Flash-приложения от повторного объявления. */ +#define F28335_FLASH_APP_H /* Один заголовок используется загрузчиком, RS-проверкой и host-тестами. */ +#include "../../include/pcan_boot.h" /* Получает переносимые 16- и 32-битные типы и bool для C28x и ПК. */ +#define F28335_FLASH_APP_START 0x300000UL /* Первые 16 слов сектора H содержат описание FAB1, а не аппаратный boot. */ +#define F28335_FLASH_APP_HEADER_WORDS 16U /* Размер описания равен 32 октетам при 16-битном адресуемом слове C28x. */ +#define F28335_FLASH_APP_DATA 0x300010UL /* Код и Flash LOAD-секции следуют после служебного описания. */ +#define F28335_FLASH_APP_STOP 0x338000UL /* Начало сектора A является исключённой границей приложения. */ +#define F28335_BOOT_FLASH_SLOT 0xFEU /* Отдельный handoff отличает внутреннюю Flash от EEPROM A/B и неизвестного SPI-ROM запуска. */ +typedef uint16_t (*f28335_flash_read_word_t)(void *user, uint32_t address); /* Callback читает одно физическое слово без предположения о памяти host-тестов. */ +bool f28335_flash_app_validate(f28335_flash_read_word_t read_word, void *user, uint32_t *entry); /* Проверяет описание, границы и CRC32 до передачи управления приложению. */ +#endif /* Завершает единый контракт защищённой области Flash-приложения. */ diff --git a/c/protocan-boot/ports/tms320f28335/f28335_flash_update.c b/c/protocan-boot/ports/tms320f28335/f28335_flash_update.c new file mode 100644 index 0000000..ed4182b --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_flash_update.c @@ -0,0 +1,86 @@ +#include "f28335_flash_update.h" /* Разделяет проверяемый алгоритм и аппаратные вызовы TI Flash API. */ +#include /* Явно очищает состояние источника перед разбором нового SCI8. */ +static unsigned int octet(f28335_flash_update_t *s, uint32_t offset) /* Читает октет через страничный кеш, исключая SPI-транзакцию на каждый байт CRC. */ +{ /* Все смещения ограничены фактической длиной принятого файла. */ + if (offset >= s->length) { s->fault = true; return 0U; } /* Обрезанное поле не превращается в данные за концом staging. */ + if (!s->cache_size || offset < s->cache_at || offset - s->cache_at >= s->cache_size) { /* Загружает новую страницу только при выходе за текущую. */ + s->cache_at = offset & ~255UL; /* Выравнивает смещение на страницу из 256 физических октетов. */ + s->cache_size = s->length - s->cache_at > 256UL ? 256U : (unsigned int)(s->length - s->cache_at); /* Последнее чтение не включает паддинг CAN за концом образа. */ + if (!s->io.read(s->io.user, s->base + s->cache_at, s->cache, s->cache_size)) { s->fault = true; s->cache_size = 0U; return 0U; } /* Любой неполный аппаратный обмен запрещает erase. */ + } /* После заполнения кеша извлечение октета не обращается к SPI. */ + return s->cache[offset - s->cache_at] & 255U; /* Маска сохраняет восьмибитный wire-формат на C28x. */ +} /* Завершает ограниченное чтение октета. */ +static uint16_t word(f28335_flash_update_t *s, uint32_t offset) /* SCI8 передаёт младший октет каждого 16-битного слова первым. */ +{ /* Объединяет два октета только через проверяемый источник. */ + unsigned int low = octet(s, offset); /* Явный порядок вызовов не зависит от порядка вычисления операндов компилятором. */ + return (uint16_t)(low | (octet(s, offset + 1UL) << 8)); /* Восстанавливает одно слово CPU из двух октетов SCI8. */ +} /* Завершает декодирование слова. */ +static uint32_t address_at(f28335_flash_update_t *s, uint32_t offset) /* Адрес таблицы TI содержит старшее слово перед младшим. */ +{ /* Порядок слов адреса отличается от порядка октетов внутри слова. */ + uint32_t high = word(s, offset); /* Читает старшие 16 бит адреса раньше младших. */ + return (high << 16) | word(s, offset + 2UL); /* Получает CPU word-address без перевода в байты. */ +} /* Завершает восстановление адреса SCI8. */ +static uint16_t image_word(void *user, uint32_t address) /* Предоставляет общему валидатору будущий вид Flash, включая стёртые промежутки. */ +{ /* Отсортированный индекс позволяет проверять весь CRC-диапазон последовательно. */ + f28335_flash_update_t *s = user; f28335_flash_section_t *p; /* Контекст содержит только предварительно проверенные секции. */ + if (s->cursor >= s->count || address < s->section[s->cursor].address) s->cursor = 0U; /* Возврат от заголовка к началу диапазона корректно перематывает индекс. */ + while (s->cursor < s->count) { /* Пропускает только секции, целиком лежащие перед запрошенным словом. */ + p = &s->section[s->cursor]; /* Обращается к существующему элементу проверенного индекса. */ + if (address < p->address) return 0xFFFFU; /* Flash_Erase оставляет незагружаемый промежуток заполненным единицами. */ + if (address - p->address < p->words) return word(s, p->offset + 2UL * (address - p->address)); /* Переводит смещение слов секции в октеты SCI8. */ + ++s->cursor; /* Следующий запрос не должен повторно сканировать уже пройденную секцию. */ + } /* После последней секции остаётся только стёртая Flash. */ + return 0xFFFFU; /* CRC учитывает также завершающий промежуток диапазона FAB1. */ +} /* Сам этот callback никогда не читает аппаратную Flash. */ +bool f28335_flash_update_validate(f28335_flash_update_t *s, const f28335_boot_io_t *io, uint32_t base, const pcan_boot_manifest_t *m) /* Проверяет транспорт, таблицу, допустимые адреса и FAB1 перед erase. */ +{ /* Любая ошибка оставляет объект непригодным для программирования. */ + uint32_t offset = 22UL, crc = 0UL, entry, checked_entry, bytes; unsigned int i, j, headers = 0U, have_entry = 0U; /* Заголовок SCI8 занимает 11 слов, то есть 22 октета. */ + f28335_flash_section_t p; bool ended = false; /* Временная секция нужна для вставки в отсортированный индекс. */ + if (!s || !io || !io->read || !m) return false; /* Не разыменовывает отсутствующие callbacks и manifest. */ + memset(s, 0, sizeof(*s)); s->io = *io; s->base = base; s->length = m->image_size; s->crc = m->image_crc32; /* Отбрасывает кеш и разрешение записи предыдущего образа. */ + if (s->length < 24UL || (s->length & 1UL) || s->length > F28335_AB_SLOT_BYTES || word(s, 0UL) != 0x08AAU) return false; /* Принимает только полный чётный SCI8 в пределах staging-слота. */ + for (offset = 0UL; offset < s->length; offset += bytes) { /* Независимо проверяет фактически записанную EEPROM, а не только принятые CAN-кадры. */ + bytes = s->length - offset > 256UL ? 256UL : s->length - offset; /* Делит чтение на ограниченные страницы без выхода за файл. */ + if (!s->io.read(s->io.user, base + offset, s->cache, (unsigned int)bytes)) return false; /* Аппаратная ошибка запрещает последующий erase. */ + crc = pcan_boot_crc32_update(crc, s->cache, (size_t)bytes); /* Использует общий CRC32 IEEE, совпадающий с клиентом SETGUI. */ + } /* Все октеты staging включены в транспортную CRC32. */ + s->cache_size = 0U; if (crc != s->crc) return false; /* Сбрасывает кеш после прямого чтения и отклоняет повреждённую EEPROM. */ + entry = address_at(s, 18UL); offset = 22UL; /* Точка входа следует после ключа и восьми резервных слов SCI8. */ + if (entry < F28335_FLASH_APP_DATA || entry >= F28335_FLASH_APP_STOP) return false; /* Запуск разрешён только из приложения ниже постоянного сектора A. */ + while (offset + 2UL <= s->length) { /* Для каждой секции сначала проверяет наличие поля длины. */ + p.words = word(s, offset); offset += 2UL; /* Длина секции выражена адресуемыми словами C28x. */ + if (!p.words) { ended = offset == s->length; break; } /* Нулевой терминатор обязан завершать файл без лишнего хвоста. */ + if (s->count == F28335_AB_MAX_SECTIONS || offset + 4UL > s->length) return false; /* Не допускает переполнение индекса либо обрезанный адрес секции. */ + p.address = address_at(s, offset); offset += 4UL; p.offset = offset; bytes = 2UL * p.words; /* Хранит CPU-адрес и байтовое смещение полезных данных отдельно. */ + if (bytes > s->length - offset || p.address < F28335_FLASH_APP_START || p.address >= F28335_FLASH_APP_STOP || p.words > F28335_FLASH_APP_STOP - p.address) return false; /* Исключает RAM, сектор A, CSM, OTP и выход за конец staging. */ + if (p.address == F28335_FLASH_APP_START) { if (p.words < F28335_FLASH_APP_HEADER_WORDS) return false; ++headers; } /* Полные 16 слов FAB1 должны публиковаться одной заключительной операцией. */ + if (entry >= p.address && entry - p.address < p.words) have_entry = 1U; /* Код entry обязан присутствовать именно в принятой таблице. */ + for (i = 0U; i < s->count; ++i) if (p.address < s->section[i].address + s->section[i].words && s->section[i].address < p.address + p.words) return false; /* Повторное программирование пересекающихся диапазонов запрещено. */ + for (j = s->count; j && s->section[j - 1U].address > p.address; --j) s->section[j] = s->section[j - 1U]; /* Сортирует индекс по адресу независимо от порядка секций в SCI8. */ + s->section[j] = p; ++s->count; offset += bytes; /* Запоминает непересекающуюся секцию и переходит к следующему заголовку. */ + } /* Структура файла полностью разобрана без записи Flash. */ + if (!ended || headers != 1U || !have_entry || s->fault) return false; /* Требует терминатор, единственный FAB1 и фактический исполняемый entry. */ + s->cursor = 0U; if (!f28335_flash_app_validate(image_word, s, &checked_entry) || s->fault || checked_entry != entry) return false; /* Общий валидатор проверяет magic, границы, инверсию entry и CRC будущей Flash. */ + s->entry = entry; s->valid = true; return true; /* Разрешает программирование только после всех независимых проверок. */ +} /* Ошибка проверки не меняет текущую Flash и журнал активной EEPROM. */ +bool f28335_flash_update_program(f28335_flash_update_t *s, const f28335_flash_ops_t *ops) /* Выполняет запись B–H только из полностью проверенного staging. */ +{ /* Заголовок FAB1 фиксируется после успешной проверки каждой порции данных. */ + uint16_t buffer[128]; unsigned int i, j, n; uint32_t at, left, entry; pcan_boot_manifest_t m; f28335_boot_io_t io; /* Одна порция содержит не более 128 слов, то есть 256 физических октетов. */ + if (!s || !s->valid || !ops || !ops->erase || !ops->program || !ops->read) return false; /* Неполный аппаратный контракт не должен начать стирание. */ + memset(&m, 0, sizeof(m)); m.image_size = s->length; m.image_crc32 = s->crc; io = s->io; at = s->base; /* Сохраняет исходные параметры перед полной повторной проверкой EEPROM. */ + if (!f28335_flash_update_validate(s, &io, at, &m)) return false; /* Изменение staging между VERIFY и COMMIT обнаруживается до первого erase. */ + s->valid = false; if (!ops->erase(ops->user)) return false; /* Одно разрешение записи расходуется до изменения Flash; повтор после отказа требует нового VERIFY. */ + for (i = 0U; i < s->count; ++i) { /* Программирует обычные данные каждой непересекающейся секции. */ + at = s->section[i].address; left = s->section[i].words; /* CPU-курсор и остаток выражены словами. */ + if (at == F28335_FLASH_APP_START) { at += F28335_FLASH_APP_HEADER_WORDS; left -= F28335_FLASH_APP_HEADER_WORDS; } /* Пропускает FAB1 до подтверждения всех остальных данных. */ + while (left) { /* Большие секции разбивает на порции рабочего буфера. */ + n = left > 128UL ? 128U : (unsigned int)left; /* Последняя порция может быть короче 128 слов. */ + for (j = 0U; j < n; ++j) buffer[j] = word(s, s->section[i].offset + 2UL * (at + j - s->section[i].address)); /* Распаковывает слова непосредственно из staging EEPROM. */ + if (s->fault || !ops->program(ops->user, at, buffer, n)) return false; /* Ошибка чтения, записи или readback оставляет FAB1 неопубликованным. */ + at += n; left -= n; /* Продвигает курсоры только после подтверждённой порции. */ + } /* Завершает запись данных секции. */ + } /* Все обычные слова уже записаны и проверены аппаратным портом. */ + for (i = 0U; i < F28335_FLASH_APP_HEADER_WORDS; ++i) buffer[i] = image_word(s, F28335_FLASH_APP_START + i); /* Собирает единственное проверенное описание FAB1 для заключительной записи. */ + if (s->fault || !ops->program(ops->user, F28335_FLASH_APP_START, buffer, F28335_FLASH_APP_HEADER_WORDS)) return false; /* Публикует описание только после успешной записи остальных секций. */ + return f28335_flash_app_validate(ops->read, ops->user, &entry) && entry == s->entry; /* Итоговый успех требует общей CRC уже физической Flash, а не только поблочного сравнения. */ +} /* Решение о CAN-подтверждении и перезапуске остаётся существующему протоколу. */ diff --git a/c/protocan-boot/ports/tms320f28335/f28335_flash_update.h b/c/protocan-boot/ports/tms320f28335/f28335_flash_update.h new file mode 100644 index 0000000..3fa5c66 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_flash_update.h @@ -0,0 +1,20 @@ +#ifndef F28335_FLASH_UPDATE_H /* Один контракт объединяет проверку CAN-образа и аппаратную запись внутренней Flash. */ +#define F28335_FLASH_UPDATE_H /* Исключает повторное объявление структур при подключении аппаратного порта. */ +#include "f28335_boot_store.h" /* Использует существующий побайтовый доступ к staging-слоту EEPROM и manifest ProtoCAN. */ +#include "f28335_flash_app.h" /* Получает границы приложения B–H и проверку завершающего описания FAB1. */ +typedef struct { uint32_t address, offset; uint16_t words; } f28335_flash_section_t; /* Адрес CPU считается словами, смещение SCI8 — октетами, длина секции — словами. */ +typedef struct { /* Хранит проверенный индекс SCI8, не размещая целый образ во внутренней RAM загрузчика. */ + f28335_boot_io_t io; uint32_t base, length, crc, entry; /* Источник EEPROM, начало staging, точная длина, транспортная CRC32 и подтверждённый entry. */ + f28335_flash_section_t section[F28335_AB_MAX_SECTIONS]; /* Лимит 64 совпадает с ограничением выпуска SCI8 и ограничивает расход RAM. */ + unsigned int count, cursor, cache_size; bool fault, valid; /* Курсор ускоряет последовательную CRC; fault запрещает принятие неполного чтения EEPROM. */ + uint32_t cache_at; pcan_boot_byte_t cache[256]; /* Одна страница M95M02 содержит 256 физических октетов, даже при 16-битном char C28x. */ +} f28335_flash_update_t; /* Объект принадлежит только main постоянного загрузчика, а не CAN ISR. */ +typedef struct { /* Аппаратные операции отделены от формата SCI8 для испытаний обрыва и ошибок TI API. */ + bool (*erase)(void *user); /* Стирает только секторы B–H, сохраняя сектор A с постоянным загрузчиком. */ + bool (*program)(void *user, uint32_t address, uint16_t *data, unsigned int words); /* Записывает и проверяет одну порцию слов по допустимому CPU-адресу. */ + f28335_flash_read_word_t read; void *user; /* Чтение физической Flash подтверждает общий FAB1/CRC после последней записи. */ +} f28335_flash_ops_t; /* Никаких неявных операций reset или изменения EEPROM-журнала здесь нет. */ +bool f28335_flash_update_validate(f28335_flash_update_t *s, const f28335_boot_io_t *io, uint32_t base, const pcan_boot_manifest_t *m); /* Полностью проверяет staging до первого стирания Flash. */ +bool f28335_flash_update_program(f28335_flash_update_t *s, const f28335_flash_ops_t *ops); /* Повторяет проверку, пишет данные и публикует FAB1 последним. */ +bool F28335Boot_FlashProgram(f28335_flash_update_t *s); /* Аппаратная реализация подключает официальный TI Flash API только в постоянном загрузчике. */ +#endif /* Завершает защиту интерфейса CAN-обновления внутренней Flash. */ diff --git a/c/protocan-boot/projects/README.md b/c/protocan-boot/projects/README.md new file mode 100644 index 0000000..5558558 --- /dev/null +++ b/c/protocan-boot/projects/README.md @@ -0,0 +1,156 @@ +# Отдельные проекты CCS: F28335 и F2812 + +Весь комплект находится внутри `templates/c/protocan-boot`: проекты CCS, +исходники загрузчиков, аппаратные порты, linker command files, необходимая +поддержка TI, CLI-сборка, тесты и документация. Зависимости от исходников +`28335_periph` и `BALZAM_167` при сборке отсутствуют. Требуется установленный +TI C2000 compiler с поддержкой **COFF ABI**; проверена версия **22.6.0.LTS**. + +| Проект CCS | Контроллер | Обновляемая память | Схема | +| --- | --- | --- | --- | +| `ccs/f28335` — `F28335_CAN_AB` | TMS320F28335 | M95M02, 256 КиБ | A/B, trial, CONFIRM, rollback | +| `ccs/f2812` — `F2812_CAN_NOR` | TMS320F2812 / ПМ67 | AM29LV800BT-70EI, 1 МиБ, x16 | Один выделенный NOR-слот, проверяемый manifest, CAN recovery | + +F2812 не использует EEPROM. Его карта, GPIO, частота CAN, допустимые адреса +приложения и состояние протокола отделены от F28335. + +## Открытие в Code Composer Studio + +1. **Project → Import CCS Projects**, каталог поиска — `c/protocan-boot/projects/ccs`. +2. Выбрать `F28335_CAN_AB` и `F2812_CAN_NOR`. Оставить проекты в исходном + расположении: **не включать Copy projects into workspace**, поскольку + переносимые ссылки `PCAN_ROOT` ведут к общей библиотеке выше проектов. +3. Выбрать **Debug** либо **Release**, затем **Build Project**. Оба проекта + содержат собственные `.project`, `.cproject`, `.ccsproject`. +4. OUT/MAP появятся в `ccs/<контроллер>//`. + +В `targetConfigs` сохранены существующие конфигурации Sauris SAU510: +F28335 — Iso Plus v.2, F2812 — Iso Plus. Для другого адаптера выбрать свой +Connection в Target Configuration. Компиляция и импорт не подключаются к JTAG +и не программируют плату. + +Для отдельных workspace с ограниченными правами CCS допускает переменную +`TI_APPDATA_DIR` с доступным для записи каталогом. Это служебный cache IDE, +он не относится к исходникам загрузчиков. + +## Сборка без запуска IDE + +Из корня **templates**: + +```powershell +python c/protocan-boot/projects/build.py --device f28335 +python c/protocan-boot/projects/build.py --device f2812 +python c/protocan-boot/projects/build.py --device f28335 --configuration Release +python c/protocan-boot/projects/build.py --device f2812 --configuration Release +``` + +Можно передать `--compiler <каталог-ti-cgt-c2000>` и `--output <каталог>`. +Скрипт читает состав исходников и настройки из этих же CCS-проектов, полностью +пересобирает их и проверяет реальные COFF LOAD-адреса официальным `ofd2000`. +Проверка отклоняет загружаемый RAM-код без Flash LOAD, пересечения, отсутствующие +boot branch/C entry, запись CSM/OTP и посторонних внутренних секторов. +Рядом с OUT сохраняются MAP, `build.log` и manifest с SHA-256. + +Результаты: + +- `ccs/f28335/Debug/F28335_CAN_AB.out`; +- `ccs/f2812/Debug/F2812_CAN_NOR.out`. + +OUT — постоянный загрузчик для первоначальной установки через JTAG во +**внутреннюю Flash** соответствующего TMS. Образ самого приложения передаётся +по CAN в его внешнюю память. Для автоматического запуска должен быть выбран +внутренний Flash boot; у ПМ67 необходимо также учитывать штатную логику CPLD +выбора источника reset/boot из `big_dsp_module` платы. + +## F28335 / M95M02 + +Проект использует существующий порт и формат журнала без изменения адресов: +**PERIPH 0–31: Type = 1 + PERIPH / 16, Device ID = PERIPH mod 16**. +УМП1 — **1/5**, УМП2 — **1/6**, задатчик — **1/8**. +Product **0x2833**, HW **1**, CAN **250000 бит/с**. Приложение и загрузчик +используют один аппаратный номер платы; прежний общий адрес **3/7** отменён. +Код загрузчика — внутренний сектор A `0x338000..0x33FF7F`, boot — `0x33FFF6`. +Слоты M95M02 имеют по **130560 октетов**, параметры — прежние 258 октетов +по адресу `0x3FEFC`. Приложение загружается в RAM ниже CPU word-адреса `0xE000`. + +После установки постоянного загрузчика новое приложение 167 передаётся +существующим клиентом SETGUI **CAN / ProtoCAN Boot**. Оно обязано содержать +hooks READY/CONFIRM и watchdog: пример интеграции реализован в ветке 167. +Без CONFIRM следующий reset возвращает подтверждённый active. +Полная последовательность — [документация порта F28335](../ports/tms320f28335/README.md). + +## F2812 / AM29LV800BT + +Профиль: **Device Type 3, Device ID 6, Product 0x2812, HW 1, +CAN 250000 бит/с, SYSCLKOUT 150 МГц**. CAN находится на **GPIOF6 TX / GPIOF7 RX**. +F2812 использует программную арифметику `rts2800_ml.lib`; F28335 — FPU32 +и `rts2800_fpu32.lib`. + +Внутренний сектор A загрузчика: `0x3F6000..0x3F7F7F`, boot — `0x3F7FF6`. +Внешняя NOR подключена по **CPU word-адресу `0x100000`**. Новый CAN-раздел +задан явно в `ports/tms320f2812/boot2812.h`: + +| Область | CPU word-адреса включительно | Размер | +| --- | --- | ---: | +| Существующая нижняя область: прежние образы/параметры/FPGA | `0x100000..0x15FFFF` | 768 КиБ | +| Новый SCI8 CAN-образ: обычные сектора 12/13/14 | `0x160000..0x177FFF` | **192 КиБ** | +| Неизменяемые этим загрузчиком top-boot сектора 15/16/17 | `0x178000..0x17DFFF` | 48 КиБ | +| Новый manifest: последний top-boot сектор 18 | `0x17E000..0x17FFFF` | 16 КиБ | + +Это **новое явное размещение CAN-образа**, а не автоматическое определение +свободного места в уже заполненном чипе. Перед первоначальной установкой +согласовать эти два выделенных участка с фактической картой NOR конкретной +платы. В известном исходнике FPGA начинается с `0x130000`, а новый CAN-слот +находится выше; драйвер не изменяет ничего ниже `0x160000` и в секторах 15–17. + +После reset доступно **3 секунды** для ENTER_BOOT. Открытая сессия удерживает +загрузчик; пустой/повреждённый manifest оставляет CAN recovery постоянно. +Для обновления уже работающего приложения нужно войти в это окно после reset; +приложение F2812 само по себе пока не получает обработчик ENTER_BOOT от добавления +отдельного проекта загрузчика. + +Перед записью требуется AMD manufacturer **`0x0001`**, device **`0x22DA`**. +Сначала стирается сектор manifest, затем три сектора образа. Запись проверяет +каждое слово. VERIFY повторно читает NOR, проверяет CRC32, SCI8, entry, +перекрытия и запрещённые назначения. COMMIT повторяет проверку, сохраняет +manifest с собственной CRC, два magic-слова публикуются последними. +Стирание сообщает BUSY каждые 250 мс, продлевая живую сессию. + +Это single-slot схема: при обрыве обновления последнего CAN-образа остаётся +recovery, автоматический A/B rollback для F2812 не заявляется. Полное стирание +NOR, запись внутренней Flash по CAN и программирование FPGA отсутствуют. + +Образ приложения — **TI SCI8 `AA 08`**, максимум **196608 октетов**. Старый +flat BIN основного контроллера автоматически не мигрируется. Допустимый payload: + +- L0 `0x8000..0x8EFF`; +- H0 `0x3F8000..0x3F9FFF`; +- внешняя SRAM zone2 `0x80000..0xFFFFF`. + +Стек M1, L1 `0x9000..0x9FFF`, RAM InitFlash `0x8F00..0x8FFF`, периферия, +внутренняя Flash и NOR не допускаются как назначения SCI8. `.ebss` приложения +может занять L1 после перехода в его C runtime; инициализированный payload +работающую RAM загрузчика перезаписывать не должен. Настройка приложения +F2812/его linker — отдельная от импорта загрузчика операция. + +Геометрия x16, ID и команды AA/55/A0/80/30/F0 взяты из +[оригинального datasheet AMD Am29LV800B](https://cms.nacsemi.com/content/AuthDatasheets/FASLS02690-1.pdf). +Аппаратные GPIO/CPLD и XINTF-тайминги перенесены из действующих +`big_dsp_module.c` / `flash_tools.c` ПМ67, без зависимости от этих файлов при сборке. + +## Проверки + +```powershell +$env:CC = 'C:/msys64/ucrt64/bin/gcc.exe' +python c/protocan-boot/tests/run_tests.py +``` + +Проверяются протокол, CRC, сессии/BUSY, A/B F28335 с trial/rollback/CONFIRM, +NOR F2812 с настоящими AMD command cycles, ID, readback, запрещёнными секторами, +обрывами COMMIT, повреждением CRC/SCI8 и тайм-аутом DQ7. +Вариант с CMake/CTest также поддерживается. + +Подтверждены реальные import/build обоих проектов в CCS 12.3, CLI-сборки +Debug/Release TI 22.6 COFF и проверки секций OUT. Физические JTAG/CAN/XINTF, +режим boot и поведение конкретной платы при отключении питания требуют стенда; +физическое программирование этим комплектом автоматически не выполнялось. diff --git a/c/protocan-boot/projects/build.py b/c/protocan-boot/projects/build.py new file mode 100644 index 0000000..0cd3b0a --- /dev/null +++ b/c/protocan-boot/projects/build.py @@ -0,0 +1,86 @@ +"""Сборка отдельных CCS-проектов ProtoCAN для F28335/M95M02 и F2812/AM29LV800BT.""" # Требует только Python и установленный TI C2000 COFF compiler. +import argparse # Разбирает выбранный контроллер, конфигурацию и пути toolchain. +import base64 # Читает настоящие программируемые данные COFF из официального OFD XML. +import hashlib # Связывает собранный OUT с контрольной суммой в локальном build manifest. +import json # Сохраняет точные команды, происхождение исходников и результаты проверки. +from pathlib import Path # Разрешает все зависимости внутри templates относительно расположения проекта. +import subprocess # Вызывает установленный TI compiler без shell-интерполяции аргументов. +import xml.etree.ElementTree as ET # Использует действующие .project/.cproject как источник состава и опций сборки. + +ROOT = Path(__file__).resolve().parents[1] # Корень protocan-boot содержит codec, порты, проекты и vendored TI support. +DEFAULT_COMPILER = Path("C:/ti/ccs1230/ccs/tools/compiler/ti-cgt-c2000_22.6.0.LTS") # Сохраняет проверенную версию установленного C2000 COFF compiler. + + +def settings(device, configuration, compiler): # Читает те же исходники и пути, которые получает импортированный проект CCS. + project = ROOT / "projects/ccs" / device # Каждое семейство контроллера имеет собственный Eclipse projectDescription. + config = next(item for item in ET.parse(project / ".cproject").findall(".//configuration") if item.get("name") == configuration) # Не подменяет Debug настройками Release или другого устройства. + options = {item.get("superClass", "").rsplit(".", 1)[-1]: item for item in config.findall("folderInfo/toolChain/tool/option")} # Собирает только параметры общего folderInfo без переопределений отдельных файлов. + macros = {"${PROJECT_ROOT}": str(project), "${PROJECT_LOC}": str(project), "${CG_TOOL_ROOT}": str(compiler)} # Разрешает только известные пути, не выполняя shell-подстановки. + def values(name): # Возвращает listOptionValue после подстановки локальных макросов CCS. + result = [] # Порядок include paths и библиотек остаётся тем же, что в проекте. + for item in options[name].findall("listOptionValue"): # Обрабатывает каждое явное значение текущей конфигурации. + value = item.get("value", "") # Отсутствующее значение не превращается в имя неизвестного каталога. + for macro, replacement in macros.items(): value = value.replace(macro, replacement) # Ограничивает подстановки определёнными выше путями. + if "${" in value: raise ValueError("Unresolved CCS macro: " + value) # Останавливает сборку вместо поиска случайной зависимости на машине. + result.append(value) # Добавляет параметр в исходном порядке конфигурации CCS. + return result # Возвращает обычные аргументы без скрытых изменений окружения. + sources = sorted(project.glob("*.c")) + sorted(project.glob("*.asm")) # Локальные production-исходники проекта компилируются вместе с аппаратным портом. + commands = sorted(project.glob("*.cmd")) # Каждый проект имеет собственную разметку памяти соответствующего F28xx. + for link in ET.parse(project / ".project").findall(".//linkedResources/link"): # Добавляет только explicit linkedResources из templates. + uri = link.findtext("locationURI", "") # Все общие исходники привязаны к переменной PCAN_ROOT. + if not uri.startswith("PCAN_ROOT/"): raise ValueError("Unsupported linked resource: " + uri) # Не допускает зависимость от старого firmware checkout или абсолютного чужого пути. + path = ROOT / uri.removeprefix("PCAN_ROOT/") # Разрешает vendor и общие исходники внутри переносимого protocan-boot. + if path.suffix.lower() in (".c", ".asm"): sources.append(path) # Заголовки не компилируются самостоятельными единицами трансляции. + elif path.suffix.lower() == ".cmd": commands.append(path) # Подключает оригинальное TI размещение регистров выбранного контроллера. + flags = ["-v28", "-ml", "-mt", "--abi=coffabi", "-O" + options["OPT_LEVEL"].get("value").rsplit(".", 1)[-1], "--opt_for_speed=" + options["OPT_FOR_SPEED"].get("value").rsplit(".", 1)[-1], "--gen_func_subsections=on"] # Повторяет архитектуру COFF, большие адреса, оптимизацию и сборку отдельных функций проекта CCS. + if device == "f28335": flags.append("--float_support=fpu32") # Только F28335 имеет используемый аппаратный FPU32. + flags += ["--include_path=" + value for value in values("INCLUDE_PATH")] + ["--define=" + value for value in values("DEFINE")] # Передаёт конкретные аппаратные заголовки и profile defines без потери различий между контроллерами. + if configuration == "Debug": flags.append("-g") # Debug OUT сохраняет символы для пошагового JTAG-анализа загрузчика. + return project, config.get("artifactName"), flags, sources, commands, values("LIBRARY"), values("SEARCH_PATH") # Возвращает полный воспроизводимый набор исходников и linker inputs. + + +def verify(device, image, compiler): # Проверяет реальные секции OUT после линковки, а не только текст соседнего MAP. + xml = ET.fromstring(subprocess.check_output([str(compiler / "bin/ofd2000.exe"), "-x", str(image)])) # Официальный декодер TI читает COFF текущей завершившейся сборки. + coff = xml.find(".//ti_coff") # Загружать через JTAG разрешено именно executable C2000 COFF. + if coff is None or coff.findtext("file_header/exec") != "true" or coff.findtext("file_header/target_id") != "0x9d": raise ValueError("Expected executable C2000 COFF") # Не подписывает чужой объект, ELF либо незалинкованный файл. + first, end, boot = (0x338000, 0x33FF80, 0x33FFF6) if device == "f28335" else (0x3F6000, 0x3F7F80, 0x3F7FF6) # Адреса внутренних секторов A и аппаратных boot-переходов различаются между F28335/F2812. + loaded = set() # Повторная загрузка одного физического слова из двух секций запрещена. + for section in coff.findall("section"): # Рассматривает только реальные данные секций после линковки. + address = int(section.findtext("virtual_addr", "0"), 0); raw = section.findtext("raw_data") # COFF virtual_addr обозначает LOAD, physical_addr — RUN копируемых ramfuncs. + if raw is None or section.findtext("copy") == "true" or section.findtext("name") == ".adc_cal": continue # Исключает только явные COPY/отладочные секции, BSS без raw_data и заводскую ADC-калибровку; загружаемый RAM-код обязан иметь Flash LOAD. + data = base64.b64decode(raw) # Читает точные октеты программируемого содержимого из COFF, а не считает по объявленному размеру. + if len(data) % 2 or not (first <= address < address + len(data) // 2 <= end or address == boot and len(data) == 4): raise ValueError("Loaded section outside bootloader Flash: " + str(section.findtext("name"))) # Защищает OTP, CSM, внешнюю NOR/EEPROM и остальные внутренние секторы. + for word in range(address, address + len(data) // 2): # Контролирует физические 16-битные слова всех программируемых секций. + if word in loaded: raise ValueError("Overlapping load sections") # Даже совпадающие данные не разрешают неоднозначную разметку OUT. + loaded.add(word) # Фиксирует фактически загружаемый диапазон текущего результата. + entry = int(coff.findtext("optional_file_header/entry_point", "0"), 0) # Извлекает реальную точку входа C runtime из заголовка файла. + if entry not in loaded or boot not in loaded or boot + 1 not in loaded: raise ValueError("Missing loaded C entry or codestart") # JTAG OUT обязан одновременно содержать C startup и аппаратный Flash boot переход. + return {"entry_word": entry, "boot_word": boot, "loaded_words": len(loaded)} # Эти проверенные значения входят в build manifest рядом с SHA-256. + + +def build(device, configuration, compiler, output=None): # Полностью собирает один из двух самостоятельных проектов без установки на плату. + compiler = compiler.resolve(); project, name, flags, sources, commands, libraries, searches = settings(device, configuration, compiler) # Использует абсолютный toolchain и актуальную конфигурацию CCS. + output = (output or project / configuration).resolve(); output.mkdir(parents=True, exist_ok=True) # Генерирует результаты только в каталоге выбранной сборки. + objects = [] # В линковку входят только успешно пересобранные исходники текущего вызова. + with (output / "build.log").open("w", encoding="utf-8") as log: # Журнал содержит полный набор команд и диагностику TI. + def run(command): # Не продолжает сборку после ошибки компилятора или linker. + log.write(json.dumps([str(arg) for arg in command], ensure_ascii=False) + "\n"); log.flush() # Сохраняет команду до запуска процесса без исполнения как shell-кода. + subprocess.run([str(arg) for arg in command], cwd=project, stdout=log, stderr=subprocess.STDOUT, check=True) # Ненулевой статус исключает публикацию ложного успешного результата. + for source in sources: # Все локальные и linked TI-файлы пересобираются для выбранного контроллера. + obj = output / (source.stem + ".obj"); run([compiler / "bin/cl2000.exe", *flags, "-c", "--output_file=" + str(obj), source]); objects.append(obj) # Объекты F2812 soft-float и F28335 FPU32 не смешиваются. + image = output / (name + ".out") # Имя результата совпадает с artifactName импортированного CCS-проекта. + link = [compiler / "bin/cl2000.exe", "-v28", "--abi=coffabi"] + (["--float_support=fpu32"] if device == "f28335" else []) # Linker ABI и FPU точно соответствуют скомпилированным объектам. + run([*link, "-z", "--rom_model", "--entry_point=_c_int00", "--stack_size=0x3f0", "--warn_sections", "--reread_libs", "-m" + str(image.with_suffix(".map")), "-o", image, *["--search_path=" + value for value in searches], *commands, *objects, *["-l" + value for value in libraries]]) # Подключает только собственный linker и оригинальные peripheral sections выбранного MCU. + checked = verify(device, image, compiler) # Физические LOAD-адреса, boot branch и C entry проверяются после каждой CLI-сборки. + manifest = {"device": device, "configuration": configuration, "sha256": hashlib.sha256(image.read_bytes()).hexdigest(), "sources": {str(path.relative_to(ROOT)): hashlib.sha256(path.read_bytes()).hexdigest() for path in sources}, **checked} # Связывает OUT с конкретными исходниками и результатом проверки карты. + image.with_suffix(".out.manifest.json").write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") # Не изменяет версии приложения или данные физической памяти. + return image # Вызывающий явно решает, когда устанавливать OUT через JTAG. + + +if __name__ == "__main__": # Импорт для проверки проектов не запускает compiler автоматически. + parser = argparse.ArgumentParser(description=__doc__) # Описывает два самостоятельных проекта и отсутствие программирования платы. + parser.add_argument("--device", choices=("f2812", "f28335"), required=True) # Не допускает случайной сборки для другого контроллера. + parser.add_argument("--configuration", choices=("Debug", "Release"), default="Debug") # Повторяет имена управляемых конфигураций CCS. + parser.add_argument("--compiler", type=Path, default=DEFAULT_COMPILER) # Поддерживает другую установленную версию TI с COFF ABI. + parser.add_argument("--output", type=Path) # Разрешает изолированную проверочную сборку без загрязнения импортированного CCS-проекта. + args = parser.parse_args(); print(build(args.device, args.configuration, args.compiler, args.output)) # Сообщает конкретный успешно проверенный OUT, не инициируя JTAG. diff --git a/c/protocan-boot/projects/ccs/f2812/.ccsproject b/c/protocan-boot/projects/ccs/f2812/.ccsproject new file mode 100644 index 0000000..335c4fd --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/.ccsproject @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f2812/.cproject b/c/protocan-boot/projects/ccs/f2812/.cproject new file mode 100644 index 0000000..412be58 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/.cproject @@ -0,0 +1,306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f2812/.project b/c/protocan-boot/projects/ccs/f2812/.project new file mode 100644 index 0000000..49210b8 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/.project @@ -0,0 +1,106 @@ + + + + F2812_CAN_NOR + + Отдельный постоянный загрузчик ProtoCAN для F2812 + + + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + + + + + + + + com.ti.ccstudio.core.ccsNature + + org.eclipse.cdt.core.cnature + + org.eclipse.cdt.core.ccnature + + org.eclipse.cdt.managedbuilder.core.managedBuildNature + + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + + + + ti/DSP281x_CpuTimers.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_CpuTimers.c + + + + + ti/DSP281x_GlobalVariableDefs.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c + + + + + ti/DSP281x_PieCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_PieCtrl.c + + + + + ti/DSP281x_SysCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_SysCtrl.c + + + + + ti/DSP281x_usDelay.asm + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_usDelay.asm + + + + + DSP281x_Headers_nonBIOS.cmd + + 1 + + PCAN_ROOT/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd + + + + + + + + PCAN_ROOT + + $%7BPARENT-3-PROJECT_LOC%7D + + + diff --git a/c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd b/c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd new file mode 100644 index 0000000..d47c8ac --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd @@ -0,0 +1,28 @@ +MEMORY /* Постоянный загрузчик F2812 хранится во внутренней Flash, обновляемые данные — во внешней AM29LV800BT. */ +{ /* Адреса указаны в 16-битных словах C28x, независимо от размера файлов CAN. */ +PAGE 0: /* Исполняемый код и его копируемая RAM-часть. */ + FLASHA : origin = 0x3F6000, length = 0x001F80 /* Сектор A исключает зарезервированные слова CSM в верхних 128 словах. */ + BEGIN : origin = 0x3F7FF6, length = 0x000002 /* Аппаратный Flash boot F2812 начинает длинный переход из двух слов. */ + RAMFUNCS : origin = 0x008F00, length = 0x000100 /* Последние 256 слов L0 содержат InitFlash и исключены из SCI8 payload приложения. */ + RESET : origin = 0x3FFFC0, length = 0x000002 /* ROM reset не программируется при установке загрузчика. */ +PAGE 1: /* Рабочая RAM постоянно работающего загрузчика не должна входить в загружаемый файл. */ + RAMM0 : origin = 0x000050, length = 0x0003B0 /* Исключает первые 80 слов Boot ROM scratch. */ + RAMM1 : origin = 0x000400, length = 0x000400 /* Отдельный стек на 1024 слова совпадает с аппаратным банком M1. */ + RAMDATA : origin = 0x009000, length = 0x001000 /* Банк L1 хранит очередь CAN и состояния загрузчика до перехода в приложение. */ +} /* Верхний H0 и внешняя SRAM остаются доступны payload приложения. */ +SECTIONS /* Ни одна загружаемая секция OUT не записывается во внешнюю NOR автоматически. */ +{ /* Все команды программирования NOR исполняются из внутреннего сектора A. */ + codestart : > BEGIN, PAGE = 0 /* Направляет аппаратный boot в watchdog-safe C startup. */ + .text : > FLASHA, PAGE = 0 /* Размещает общий ProtoCAN, driver NOR и проверку SCI8 в постоянной Flash. */ + .fast_run : > FLASHA, PAGE = 0 /* Штатный DSP281x_usDelay вызывается ещё из InitSysCtrl до копирования ramfuncs, поэтому его LOAD/RUN должны сразу находиться во Flash. */ + .cinit : > FLASHA, PAGE = 0 /* Таблицы ROM-модели инициализируют состояние до main. */ + .pinit : > FLASHA, PAGE = 0 /* Сохраняет стандартный startup для возможных статических конструкторов. */ + .econst : > FLASHA, PAGE = 0 /* Константы не расходуют ограниченную RAM L1. */ + .switch : > FLASHA, PAGE = 0 /* Таблицы switch остаются доступны во время erase внешнего чипа. */ + ramfuncs : LOAD = FLASHA, RUN = RAMFUNCS, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0 /* InitFlash копируется в внутреннюю RAM до изменения таймингов Flash. */ + .stack : > RAMM1, PAGE = 1 /* Стек не пересекает RAM назначения проверяемого образа. */ + .ebss : > RAMDATA, PAGE = 1 /* Состояния очереди и текущей сессии исключены из разрешённых SCI8 адресов. */ + .esysmem : > RAMDATA, PAGE = 1 /* Поддерживает стандартную секцию runtime, хотя алгоритм не требует heap. */ + .fast_vars1 : > RAMDATA, PAGE = 1 /* Подключает штатный HSPCLK выбранного TI SDK без размещения случайной orphan-секции. */ + .reset : > RESET, PAGE = 0, TYPE = DSECT /* Не выдаёт ROM reset за программируемую часть OUT. */ +} /* Не создаёт секции OTP или паролей CSM. */ diff --git a/c/protocan-boot/projects/ccs/f2812/board.c b/c/protocan-boot/projects/ccs/f2812/board.c new file mode 100644 index 0000000..e19e090 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/board.c @@ -0,0 +1,30 @@ +#include "DSP281x_Device.h" /* Использует оригинальные TI определения GPIO и XINTF F2812. */ +#include "../../../ports/tms320f2812/boot2812.h" /* Получает отдельный аппаратный профиль внешней NOR ПМ67. */ +static void operation(unsigned int a, unsigned int b, unsigned int c, unsigned int d) /* Повторяет управляющую защёлку CPLD из big_dsp_module.c штатной платы. */ +{ /* GPIOA13/A14/A15 и GPIOB13 задают код, GPIOB15 формирует строб. */ + EALLOW; /* Разрешает запись системных GPIO платы. */ + GpioDataRegs.GPADAT.bit.GPIOA13 = a; GpioDataRegs.GPADAT.bit.GPIOA14 = b; /* Первые два бита аппаратной команды соответствуют oper_mode1/2. */ + GpioDataRegs.GPADAT.bit.GPIOA15 = c; GpioDataRegs.GPBDAT.bit.GPIOB13 = d; /* Третий и четвёртый биты повторяют штатный write_oper. */ + asm(" NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 0; /* Снимает строб после установки всех четырёх битов команды. */ + asm(" RPT #2 || NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 1; /* Даёт защёлке время установления и формирует активный фронт. */ + asm(" RPT #2 || NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 0; /* Возвращает строб в исходное состояние с выдержкой как в рабочем драйвере. */ + asm(" RPT #2 || NOP"); EDIS; /* Завершает длительность импульса до следующей команды CPLD. */ +} /* Команда не изменяет выбранные аппаратные boot-перемычки контроллера. */ +void Boot2812_BoardInit(void) /* Настраивает подтверждённую схему ПМ67 с AM29LV800BT на XINTF zone6. */ +{ /* Значения линий взяты из setup_oper_line/init_flash/xintf_zone6and7_timing действующего проекта BALZAM_167. */ + EALLOW; /* GPIO mux/direction и XINTF изменяются в разрешённом защищённом контексте. */ + GpioMuxRegs.GPAMUX.bit.C1TRIP_GPIOA13 = 0; GpioMuxRegs.GPAMUX.bit.C2TRIP_GPIOA14 = 0; GpioMuxRegs.GPAMUX.bit.C3TRIP_GPIOA15 = 0; /* Выбирает GPIO для трёх командных линий CPLD вместо функций event manager. */ + GpioMuxRegs.GPBMUX.bit.C4TRIP_GPIOB13 = 0; GpioMuxRegs.GPBMUX.bit.C6TRIP_GPIOB15 = 0; /* Освобождает четвёртый бит команды и строб CPLD. */ + GpioMuxRegs.GPADIR.bit.GPIOA13 = 1; GpioMuxRegs.GPADIR.bit.GPIOA14 = 1; GpioMuxRegs.GPADIR.bit.GPIOA15 = 1; /* Переводит командные линии A в выходы, как рабочий драйвер платы. */ + GpioMuxRegs.GPBDIR.bit.GPIOB13 = 1; GpioMuxRegs.GPBDIR.bit.GPIOB15 = 1; /* Разрешает выдачу четвёртого бита и импульса защёлки. */ + XintfRegs.XINTCNF2.bit.XTIMCLK = 1; XintfRegs.XINTCNF2.bit.WRBUFF = 0; /* XTIMCLK=SYSCLKOUT/2; отключённая буферизация сохраняет порядок unlock-циклов AMD. */ + XintfRegs.XINTCNF2.bit.CLKOFF = 0; XintfRegs.XINTCNF2.bit.CLKMODE = 0; XintfRegs.XINTCNF2.bit.MPNMC = 0; /* Повторяет штатный режим XCLKOUT и микроконтроллерный boot платы. */ + XintfRegs.XTIMING6.bit.XWRLEAD = 3; XintfRegs.XTIMING6.bit.XWRACTIVE = 7; XintfRegs.XTIMING6.bit.XWRTRAIL = 3; /* Времена записи NOR повторяют проверенный flash_tools/init_flash платы в единицах XTIMCLK. */ + XintfRegs.XTIMING6.bit.XRDLEAD = 3; XintfRegs.XTIMING6.bit.XRDACTIVE = 3; XintfRegs.XTIMING6.bit.XRDTRAIL = 3; /* Времена чтения соответствуют штатному профилю AM29LV800BT-70EI. */ + XintfRegs.XTIMING6.bit.X2TIMING = 0; XintfRegs.XTIMING6.bit.USEREADY = 0; XintfRegs.XTIMING6.bit.READYMODE = 0; XintfRegs.XTIMING6.bit.XSIZE = 3; /* Выбирает 16-битную зону без внешнего READY и без дополнительного удвоения тактов. */ + XintfRegs.XTIMING2.bit.XWRLEAD = 3; XintfRegs.XTIMING2.bit.XWRACTIVE = 7; XintfRegs.XTIMING2.bit.XWRTRAIL = 3; /* Консервативный x16 режим внешней SRAM позволяет загружать приложение в zone2. */ + XintfRegs.XTIMING2.bit.XRDLEAD = 3; XintfRegs.XTIMING2.bit.XRDACTIVE = 7; XintfRegs.XTIMING2.bit.XRDTRAIL = 3; /* Удлинённое чтение SRAM не зависит от коротких прикладных таймингов. */ + XintfRegs.XTIMING2.bit.X2TIMING = 0; XintfRegs.XTIMING2.bit.USEREADY = 0; XintfRegs.XTIMING2.bit.READYMODE = 0; XintfRegs.XTIMING2.bit.XSIZE = 3; /* Не включает неподтверждённую линию READY платы. */ + asm(" RPT #7 || NOP"); EDIS; /* Сбрасывает pipeline после изменения XINTF до первого внешнего чтения. */ + operation(1U, 1U, 1U, 1U); operation(1U, 0U, 1U, 0U); operation(0U, 0U, 0U, 0U); /* Штатные select_nothing, select_strob_67_for_flash, select_work_with_flash выбирают CPU-доступ к NOR. */ +} /* Изменение схемы CPLD требует отдельного профиля платы, а не другого размера EEPROM. */ diff --git a/c/protocan-boot/projects/ccs/f2812/boot_store.c b/c/protocan-boot/projects/ccs/f2812/boot_store.c new file mode 100644 index 0000000..e825b09 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/boot_store.c @@ -0,0 +1 @@ +#include "../../../ports/tms320f2812/boot_store.c" /* Подключает проверку SCI8 и публикацию NOR manifest без копирования кода в проект CCS. */ diff --git a/c/protocan-boot/projects/ccs/f2812/codestart.asm b/c/protocan-boot/projects/ccs/f2812/codestart.asm new file mode 100644 index 0000000..b69fe2f --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/codestart.asm @@ -0,0 +1,12 @@ + .ref _c_int00 ; Стандартный COFF startup применяет .cinit и вызывает main после отключения раннего watchdog. + .sect "codestart" ; Boot ROM передаёт управление двухсловному переходу по аппаратному адресу слова 0x33FFF6. + LB flash_boot_start ; Переходит к короткой подготовке C28x во Flash, сохраняя точный размер аппаратного входа два слова. + .text ; Последовательность взята из штатного TI DSP2833x_CodeStartBranch.asm и размещается в секторе основного кода. +flash_boot_start: ; Отключает watchdog до возможной длительной обработки таблиц инициализации C, а не только после входа в main. + SETC OBJMODE ; Выбирает C28x object mode, требуемый стандартным COFF startup процессора F28335. + EALLOW ; Разрешает запись защищённого регистра WDCR перед запуском C runtime. + MOVZ DP, #7029h>>6 ; Адрес слова WDCR=0x7029 из карты F28335; DP выбирает соответствующую страницу по 64 слова. + MOV @7029h, #0068h ; Значение 0x0068 содержит контрольные биты WDCHK=101 и WDDIS=1, как официальный TI startup. + EDIS ; Возвращает защиту системных регистров перед переходом в библиотечную инициализацию. + LB _c_int00 ; Применяет штатную ROM-модель инициализации и затем запускает текущий main 167. + .end ; Завершает модуль, не добавляя произвольных данных рядом с CSM-паролями сектора A. diff --git a/c/protocan-boot/projects/ccs/f2812/main.c b/c/protocan-boot/projects/ccs/f2812/main.c new file mode 100644 index 0000000..880a3f0 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/main.c @@ -0,0 +1,114 @@ +#include "DSP281x_Device.h" /* Использует оригинальные регистры F2812, не подменяя их заголовками F28335. */ +#include "DSP281x_Examples.h" /* Подключает штатные PLL, watchdog, PIE и CpuTimers выбранного TI SDK. */ +#include "../../../ports/tms320f2812/boot2812.h" /* Выбирает отдельные NOR, Product Type и ProtoCAN-адрес F2812. */ +#include /* Инициализирует все состояния независимо от прежнего содержимого .ebss. */ +static pcan_boot_t boot; /* Этот экземпляр относится только к ПМ67/F2812 и не делит состояние с F28335. */ +static volatile unsigned int head, tail, overflow; /* ISR публикует готовые элементы очереди только после заполнения всех полей. */ +static struct { uint32_t id; unsigned int dlc; pcan_boot_byte_t data[8]; } queue[32]; /* Очередь на 31 кадр принимает окно из 16 блоков во время NOR-операций main. */ +static unsigned int tx_busy, reset_requested, operation_active, current_command; /* Отделяет физическое TX ACK, запрос reset и текущую долгую команду. */ +static uint32_t sent_at, busy_at; /* Миллисекундные отметки ограничивают TX и частоту BUSY-ответов. */ +unsigned long Boot2812_Now(void) /* Все тайм-ауты порта работают от одного Timer1. */ +{ /* Прямой счётчик C28x имеет ту же ширину, что uint32_t. */ + return CpuTimer1.InterruptCount; /* Период Timer1 ниже установлен в одну миллисекунду. */ +} /* Беззнаковые разности сохраняют корректность через переполнение. */ +interrupt void boot_tick(void) /* Прямое прерывание Timer1 не обращается к коду приложения. */ +{ /* Долгие erase/verify не должны замораживать часы либо приём CAN. */ + CpuTimer1.InterruptCount++; KickDog(); /* Миллисекундный tick и штатное обслуживание watchdog загрузчика выполняются даже во время polling NOR. */ +} /* Поведение watchdog загружаемого приложения задаёт его собственный startup. */ +static void receive(volatile struct MBOX *box, uint32_t mask) /* Копирует один Extended кадр выделенного mailbox в очередь. */ +{ /* Wire-парсер и запись памяти выполняются позднее общим ядром в main. */ + unsigned int next = (head + 1U) & 31U, i, type; uint32_t id, low, high; /* Индексы кольца ограничены 32 элементами независимо от содержимого CAN. */ + if (!(ECanaRegs.CANRMP.all & mask)) return; /* Не читает старое содержимое mailbox без нового RX-флага. */ + id = box->MSGID.all & 0x1FFFFFFFUL; type = pcan_boot_id_msg_type(id); /* Получает 29-битный ID и тип через общий codec. */ + if ((box->MSGID.all & 0x80000000UL) && !box->MSGCTRL.bit.RTR && pcan_boot_id_route(id) == 0U && (type == 9U || type == 10U || type == 13U) && ((pcan_boot_id_device_type(id) == BOOT2812_DEVICE_TYPE && pcan_boot_id_device_id(id) == BOOT2812_DEVICE_ID) || (type == 13U && pcan_boot_id_device_type(id) == 7U && pcan_boot_id_device_id(id) == 15U && !pcan_boot_id_msg_body(id)))) { /* Допускает только адресный Boot и точное discovery; чужие приборы и RTR не занимают очередь. */ + if (next == tail) overflow = 1U; /* Потеря кадра отменит сессию, а не разрешит незаметно неполный файл. */ + else { /* Сначала формирует весь элемент, затем публикует новый head. */ + queue[head].id = id; queue[head].dlc = box->MSGCTRL.bit.DLC; /* Сохраняет фактические ID и длину для проверок общего ядра. */ + low = box->MDL.all; high = box->MDH.all; /* Два 32-битных снимка не смешивают октеты разных чтений регистров. */ + for (i = 0; i < 4U; ++i) { queue[head].data[i] = (low >> (i * 8U)) & 255U; queue[head].data[i + 4U] = (high >> (i * 8U)) & 255U; } /* DBO=0 передаёт младшие октеты MDL/MDH первыми. */ + head = next; /* Публикация после копирования исключает чтение main частично заполненного элемента. */ + } /* Завершает формирование очередного элемента кольца. */ + } /* Остальные кадры не изменяют никакие состояния протокола. */ + ECanaRegs.CANRMP.all = mask; /* Подтверждает только собственный прочитанный mailbox. */ +} /* В ISR отсутствуют erase, write, CRC и загрузка приложения. */ +interrupt void boot_can_rx(void) /* Использует отдельный аппаратный CAN F2812 на GPIOF6/F7. */ +{ /* Оба служебных RX mailbox относятся к одной линии ECAN0INTA. */ + receive(&ECanaMboxes.MBOX3, 8UL); receive(&ECanaMboxes.MBOX6, 64UL); /* Mailbox 3 принимает адресные кадры, 6 — broadcast discovery. */ + PieCtrlRegs.PIEACK.all = 0x0100U; /* ACK9 открывает группу PIE9 для следующего CAN IRQ. */ +} /* Возвращает управление прерванному main без обращения к прикладным каналам ПМ67. */ +static void tx_poll(void) /* Подтверждает физическую передачу, прежде чем разрешить следующий ответ или reset. */ +{ /* Ошибка шины ограничена четвертью секунды и не приводит к бесконечному ожиданию. */ + if (!tx_busy) return; /* Свободный mailbox не требует чтения старых ACK. */ + if (ECanaRegs.CANTA.all & 16UL) { ECanaRegs.CANTA.all = 16UL; tx_busy = 0U; } /* Снимает только фактический ACK ответа mailbox 4. */ + else if (Boot2812_Now() - sent_at >= 250UL) { /* Истёкшее ожидание не разрешает выполнить ранее заказанный reset. */ + ECanaRegs.CANTRR.all = 16UL; reset_requested = 0U; /* Запрашивает отмену и сохраняет управление recovery-загрузчику. */ + if (ECanaRegs.CANAA.all & 16UL) { ECanaRegs.CANAA.all = 16UL; tx_busy = 0U; } /* Не перезаписывает mailbox до подтверждённого завершения отмены. */ + } /* Поздний ACK после запроса отмены также не восстанавливает сброшенный reset_requested. */ +} /* Состояние передачи не зависит от относительного порядка BUSY и окончательного ответа. */ +static bool transmit(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) /* Реализует физический ответ без дублирования формата ProtoCAN. */ +{ /* Вызывается только из main или синхронного NOR callback, никогда из RX ISR. */ + unsigned int i; uint32_t low = 0UL, high = 0UL, started = Boot2812_Now(), budget = 1000000UL; (void)user; /* Ограничение проходов сохраняет выход при остановленном Timer1. */ + while (tx_busy && --budget && Boot2812_Now() - started < 250UL) tx_poll(); /* Даёт предыдущему BUSY физически уйти, прежде чем отправить окончательный OK. */ + if (tx_busy || dlc > 8U) return false; /* Не теряет неподтверждённый ответ перезаписью регистров. */ + for (i = 0; i < dlc; ++i) { if (i < 4U) low |= (uint32_t)(data[i] & 255U) << (8U * i); else high |= (uint32_t)(data[i] & 255U) << (8U * (i - 4U)); } /* Упаковывает октеты C28x в MDL/MDH при DBO=0. */ + EALLOW; ECanaRegs.CANME.all &= ~16UL; /* Идентификатор TX изменяется только при отключённом mailbox. */ + ECanaMboxes.MBOX4.MSGID.all = 0x80000000UL | id; ECanaMboxes.MBOX4.MSGCTRL.all = dlc; /* IDE=1 включает Extended формат, длина сохраняется из codec. */ + ECanaMboxes.MBOX4.MDL.all = low; ECanaMboxes.MBOX4.MDH.all = high; /* Фиксирует все данные до подачи запроса передачи. */ + ECanaRegs.CANTA.all = 16UL; ECanaRegs.CANAA.all = 16UL; ECanaRegs.CANME.all |= 16UL; ECanaRegs.CANTRS.all = 16UL; EDIS; /* Удаляет старые ACK и запускает один новый аппаратный ответ. */ + sent_at = Boot2812_Now(); tx_busy = 1U; /* Следующий ответ и REBOOT ждут фактический CAN ACK. */ + return true; /* Ядро считает кадр принятым аппаратным передатчиком. */ +} /* Wire-содержимое сформировано только общим ProtoCAN codec. */ +void Boot2812_Busy(void) /* Долгие erase и проверки продолжают сообщать состояние текущей команды. */ +{ /* Функция не извлекает новые команды из очереди и не допускает вложенный процессинг сессии. */ + uint32_t now = Boot2812_Now(); tx_poll(); /* Подтверждает ранее отправленный BUSY по фактическому TX ACK. */ + if (operation_active && !tx_busy && now - busy_at >= 250UL) { busy_at = now; (void)pcan_boot_report_busy(&boot, current_command, now); } /* Ответ каждые 250 мс удерживает клиент живым при секундном стирании NOR. */ +} /* Финальный статус после callback отправит обычное ядро. */ +static void request_reset(void *user) /* Команда REBOOT не сбрасывает аппарат до передачи её статусного ответа. */ +{ /* Аппаратный reset выполнит main после освобождения TX mailbox. */ + (void)user; reset_requested = 1U; /* Не вызывает watchdog непосредственно из callback codec. */ +} /* Потеря TX ACK отменяет этот запрос в tx_poll. */ +static void can_init(void) /* Отдельные clock/GPIO F2812 не используют настройки F28335. */ +{ /* SYSCLKOUT=150 МГц при штатных XCLKIN=30 МГц и PLLCR=10 в включённом TI SDK. */ + EALLOW; GpioMuxRegs.GPFMUX.bit.CANTXA_GPIOF6 = 1; GpioMuxRegs.GPFMUX.bit.CANRXA_GPIOF7 = 1; /* Назначение CAN берётся из оригинального DSP281x_ECan.c. */ + ECanaRegs.CANTIOC.all = 8UL; ECanaRegs.CANRIOC.all = 8UL; ECanaRegs.CANME.all = 0UL; /* Включает CAN-функции и отключает mailbox до полной настройки. */ + ECanaRegs.CANMC.all = 0x3080UL; /* SCB/CCR/ABO выбирают eCAN, режим настройки и автоматическое восстановление шины. */ + while (!ECanaRegs.CANES.bit.CCE) {} /* Ожидает разрешения аппаратуры менять CANBTC. */ + ECanaRegs.CANBTC.all = (29UL << 16) | 0x017AUL; /* F2812: 150 МГц/(BRP+1=30)/(1+16+3 tq)=250000 бит/с, SJW=2 tq. */ + ECanaRegs.CANMC.all &= ~0x1000UL; while (ECanaRegs.CANES.bit.CCE) {} /* Выходит из режима настройки перед включением приёма. */ + ECanaMboxes.MBOX3.MSGID.all = 0xC0000000UL | pcan_boot_make_id(0U, 0U, BOOT2812_DEVICE_TYPE, BOOT2812_DEVICE_ID, 0U, 0U); /* AME/IDE и адресный фильтр отделяют выбранный прибор от остальных узлов CAN. */ + ECanaLAMRegs.LAM3.all = 0x100FFFFFUL; ECanaMboxes.MBOX3.MSGCTRL.all = 8UL; /* Игнорирует priority/type/body при аппаратном отборе; точные типы проверяет ISR/codec. */ + ECanaMboxes.MBOX6.MSGID.all = 0xC0000000UL | pcan_boot_make_id(0U, 0U, 7U, 15U, 13U, 0U); /* Broadcast разрешён только для discovery, а не для стирания/программирования. */ + ECanaLAMRegs.LAM6.all = 0x10000000UL; ECanaMboxes.MBOX6.MSGCTRL.all = 0UL; ECanaMboxes.MBOX4.MSGCTRL.all = 0UL; /* Фильтр discovery игнорирует только priority; зарезервированные биты MSGCTRL очищены. */ + ECanaRegs.CANMD.all = 72UL; ECanaRegs.CANMIL.all = 0UL; ECanaRegs.CANMIM.all = 72UL; /* RX 3/6 и TX4 работают на линии ECAN0INTA; остальных mailbox нет. */ + ECanaRegs.CANRMP.all = 0xFFFFFFFFUL; ECanaRegs.CANRML.all = 0xFFFFFFFFUL; ECanaRegs.CANTA.all = 0xFFFFFFFFUL; /* Удаляет старые флаги перед первым разрешением IRQ. */ + ECanaRegs.CANGIF0.all = 0xFFFFFFFFUL; ECanaRegs.CANGIM.all = 1UL; ECanaRegs.CANME.all = 88UL; /* Включает только три настроенных mailbox и прерывание линии 0. */ + PieVectTable.ECAN0INTA = &boot_can_rx; PieCtrlRegs.PIEIER9.bit.INTx5 = 1; EDIS; IER |= M_INT9; /* Подключает короткий постоянный RX ISR группы PIE9. */ +} /* Конфигурация и состояние ПМ35/F28335 остаются независимыми. */ +void main(void) /* Запускается аппаратным внутренним Flash boot F2812 через 3F7FF6. */ +{ /* Прежний внешний flat-образ не переписывается автоматически и не заменяет проверенную SCI8-таблицу. */ + pcan_boot_config_t config; pcan_boot_port_t port; uint32_t started, entry; unsigned int tried = 0U; /* Небольшие настройки и адрес входа помещаются в постоянный стек M1. */ + InitSysCtrl(); DINT; IER = 0U; IFR = 0U; /* Настраивает PLL=150 МГц и исключает старые IRQ до создания собственных векторов. */ + memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, &RamfuncsLoadEnd - &RamfuncsLoadStart); InitFlash(); /* Штатная InitFlash выполняется из RAM, пока весь остальной код хранится во внутренней Flash A. */ + InitPieCtrl(); InitCpuTimers(); Boot2812_BoardInit(); /* Подготавливает PIE/Timer1 и доступ к подтверждённой AM29LV800BT через CPLD. */ + head = tail = overflow = tx_busy = reset_requested = operation_active = current_command = 0U; sent_at = busy_at = 0UL; /* Явно очищает COFF .ebss и очередь до включения CAN IRQ. */ + memset(&config, 0, sizeof(config)); memset(&port, 0, sizeof(port)); /* Не оставляет неопределённые callbacks нового публичного API. */ + config.device_type = BOOT2812_DEVICE_TYPE; config.device_id = BOOT2812_DEVICE_ID; config.product_type = BOOT2812_PRODUCT; config.hardware_revision = 1U; /* Отдельный адрес 3/6 и Product 2812 отличают основной контроллер от F28335. */ + config.active_slot = 0U; config.slot_count = 1U; config.max_image_size = BOOT2812_IMAGE_BYTES; config.ack_window = 16U; config.session_timeout_ms = 30000UL; /* Single-slot отражает NOR-раздел без ложного обещания A/B-отката. */ + port.send = transmit; port.erase_slot = Boot2812_Erase; port.write_slot = Boot2812_Write; port.verify_status = Boot2812_Verify; port.set_pending_slot = Boot2812_Commit; port.reboot = request_reset; /* Алгоритм ProtoCAN вызывает только аппаратные операции внешней NOR. */ + if (!pcan_boot_init(&boot, &config, &port, 0)) for (;;) {} /* Ошибка конфигурации не разрешает произвольную запись памяти. */ + ConfigCpuTimer(&CpuTimer1, 150.0F, 1000.0F); EALLOW; PieVectTable.XINT13 = &boot_tick; EDIS; /* PLL выбранного TI SDK даёт 150 МГц; 1000 мкс соответствуют миллисекундным тайм-аутам протокола. */ + CpuTimer1Regs.TCR.all = 0x4020U; IER |= M_INT13; can_init(); PieCtrlRegs.PIECRTL.bit.ENPIE = 1; EINT; started = Boot2812_Now(); /* Начинает трёхсекундное окно recovery только после готовности физического CAN. */ + for (;;) { /* Постоянный main обслуживает запись и автоматически запускает только подтверждённый manifest. */ + tx_poll(); pcan_boot_poll(&boot, Boot2812_Now()); KickDog(); /* Тайм-ауты сессии, discovery и watchdog не зависят от очередного окна данных. */ + if (!tx_busy && reset_requested) { DINT; EALLOW; SysCtrlRegs.WDCR = 0x0028U; EDIS; for (;;) {} } /* После физического ACK REBOOT запускает аппаратный watchdog reset без старых ISR. */ + if (overflow || (ECanaRegs.CANRML.all & 72UL)) { overflow = 0U; ECanaRegs.CANRML.all = 72UL; tail = head; pcan_boot_abort(&boot); } /* Потеря mailbox/очереди отменяет сессию и требует передачи заново. */ + if (!tx_busy && tail != head) { /* Обрабатывает один целиком сформированный ISR элемент за проход. */ + current_command = pcan_boot_id_msg_type(queue[tail].id) == 9U ? pcan_boot_id_msg_body(queue[tail].id) & 255U : 0U; operation_active = 1U; /* BUSY содержит именно команду, которая выполняется сейчас. */ + (void)pcan_boot_process(&boot, queue[tail].id, queue[tail].data, queue[tail].dlc); operation_active = 0U; tail = (tail + 1U) & 31U; /* Производственный codec проверяет session/порядок/CRC и вызывает NOR callbacks только в main. */ + } /* Пока TX занят, очередь сохраняет все следующие кадры окна. */ + if (!tried && !tx_busy && boot.state == PCAN_BOOT_STATE_IDLE && Boot2812_Now() - started >= BOOT2812_RECOVERY_MS) { /* ENTER_BOOT удерживает загрузчик; без сессии допускается автоматический запуск сохранённого CAN-образа. */ + tried = 1U; /* Пустой или испорченный manifest не должен проверяться заново на каждом такте main. */ + if (Boot2812_NorIdentify() && Boot2812_Load(&entry)) { DINT; IER = 0U; IFR = 0U; CpuTimer1Regs.TCR.bit.TSS = 1; ECanaRegs.CANMIM.all = 0UL; ((void (*)(void))entry)(); for (;;) {} } /* Запускает только полностью проверенную RAM-таблицу; приложение само создаст свои ISR и C runtime. */ + } /* При отказе остаётся доступен CAN recovery без EEPROM. */ + } /* Ни один путь не исполняет код из стираемой внешней NOR. */ +} /* Завершение загрузчика выполняется только аппаратным reset либо проверенным переходом в приложение. */ diff --git a/c/protocan-boot/projects/ccs/f2812/nor_flash.c b/c/protocan-boot/projects/ccs/f2812/nor_flash.c new file mode 100644 index 0000000..dde47de --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/nor_flash.c @@ -0,0 +1 @@ +#include "../../../ports/tms320f2812/nor_flash.c" /* Собирает канонический драйвер AM29LV800BT из templates, сохраняя hardware callbacks отдельно от протокола. */ diff --git a/c/protocan-boot/projects/ccs/f2812/shared_boot.c b/c/protocan-boot/projects/ccs/f2812/shared_boot.c new file mode 100644 index 0000000..7c877f4 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/shared_boot.c @@ -0,0 +1 @@ +#include "../../../src/pcan_boot.c" /* Подключает общий ProtoCAN codec, сессии и CRC32 без второй реализации протокола. */ diff --git a/c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml b/c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml new file mode 100644 index 0000000..4b062df --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f28335/.ccsproject b/c/protocan-boot/projects/ccs/f28335/.ccsproject new file mode 100644 index 0000000..44f2f89 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/.ccsproject @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f28335/.cproject b/c/protocan-boot/projects/ccs/f28335/.cproject new file mode 100644 index 0000000..f49a6c4 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/.cproject @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f28335/.project b/c/protocan-boot/projects/ccs/f28335/.project new file mode 100644 index 0000000..c1b7273 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/.project @@ -0,0 +1,115 @@ + + + + F28335_CAN_AB + + Отдельный постоянный загрузчик ProtoCAN для F28335 + + + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + + + + + + + + com.ti.ccstudio.core.ccsNature + + org.eclipse.cdt.core.cnature + + org.eclipse.cdt.core.ccnature + + org.eclipse.cdt.managedbuilder.core.managedBuildNature + + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + + + + ti/DSP2833x_ADC_cal.asm + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm + + + + + ti/DSP2833x_CpuTimers.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_CpuTimers.c + + + + + ti/DSP2833x_GlobalVariableDefs.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c + + + + + ti/DSP2833x_PieCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_PieCtrl.c + + + + + ti/DSP2833x_SysCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_SysCtrl.c + + + + + ti/DSP2833x_usDelay.asm + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_usDelay.asm + + + + + DSP2833x_Headers_nonBIOS.cmd + + 1 + + PCAN_ROOT/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd + + + + + + + + PCAN_ROOT + + $%7BPARENT-3-PROJECT_LOC%7D + + + diff --git a/c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd b/c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd new file mode 100644 index 0000000..b6ba0a7 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd @@ -0,0 +1,32 @@ +MEMORY /* Отделяет постоянный загрузчик от адресов RAM payload приложения 167. */ +{ /* Все адреса и длины указаны в 16-битных словах CPU C28x. */ +PAGE 0: /* Исполняемые секции и их Flash LOAD-адреса. */ + FLASHA : origin = 0x338000, length = 0x007F80 /* Сектор A до зарезервированной CSM-области содержит постоянный загрузчик. */ + BEGIN : origin = 0x33FFF6, length = 0x000002 /* Два слова аппаратного Flash boot перехода; пароли CSM не выделяются. */ + RAMFUNCS : origin = 0x00F800, length = 0x000800 /* Верхние 2048 слов RAM загрузчика нужны InitFlash и не входят в SCI8 payload приложения. */ + RAMAPI : origin = 0x008000, length = 0x001800 /* 6144 слова временно принадлежат TI Flash API; приложение использует эту RAM только после выхода загрузчика. */ + ADC_CAL : origin = 0x380080, length = 0x000009 /* Заводская калибровка TI используется без записи/стирания. */ + RESET : origin = 0x3FFFC0, length = 0x000002 /* Аппаратный reset находится в ROM и не программируется. */ +PAGE 1: /* Рабочие данные не пересекают код RAM-приложения ниже E000. */ + BOOT_SHARED : origin = 0x000050, length = 0x000008 /* Общие с приложением восемь слов NOINIT handoff после ROM scratch 0..4F. */ + RAMM0 : origin = 0x000058, length = 0x0003A8 /* Малый банк доступен служебным неинициализированным данным. */ + RAMM1 : origin = 0x000400, length = 0x000400 /* Стек на 1024 слова не меняет расположение при переходе в приложение. */ + RAMDATA : origin = 0x00E000, length = 0x001800 /* 6144 слова store/очереди; приложение использует их только после перехода в C startup. */ +} /* Завершает физическую карту постоянного загрузчика. */ +SECTIONS /* Не выделяет ни одного загружаемого слова в RAM приложения. */ +{ /* Инициализированные Flash-секции остаются в секторе A. */ + codestart : > BEGIN, PAGE = 0 /* Аппаратный переход передаёт управление watchdog-safe C startup. */ + flash_api : { -lFlash28335_API_V210.lib(.text) -lFlash28335_API_V210.lib(.econst) } LOAD = FLASHA, RUN = RAMAPI, LOAD_START(_FlashApiLoadStart), LOAD_END(_FlashApiLoadEnd), RUN_START(_FlashApiRunStart), PAGE = 0 /* Код и таблицы TI API выполняются из RAM, пока общий банк Flash занят изменением B–H. */ + .text : > FLASHA, PAGE = 0 /* Весь постоянный алгоритм и библиотеки исполняются из Flash A. */ + .cinit : > FLASHA, PAGE = 0 /* Таблицы ROM-модели подготавливают данные загрузчика до main. */ + .pinit : > FLASHA, PAGE = 0 /* Сохраняет стандартный порядок C runtime, если компилятор создаст эту секцию. */ + .econst : > FLASHA, PAGE = 0 /* Константы протокола и имена сервиса не расходуют рабочую RAM. */ + .switch : > FLASHA, PAGE = 0 /* Таблицы переходов находятся в постоянной области загрузчика. */ + ramfuncs : LOAD = FLASHA, RUN = RAMFUNCS, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0 /* InitFlash копируется до изменения настроек самой Flash. */ + .boot_shared : > BOOT_SHARED, PAGE = 1, TYPE = NOINIT /* Не обнуляет session/slot, полученные через watchdog reset. */ + .stack : > RAMM1, PAGE = 1 /* Стек не пересекает ни handoff, ни загружаемые секции SCI8. */ + .ebss : > RAMDATA, PAGE = 1 /* Размещает очередь, журнал и структуры драйвера вне RAM payload. */ + .esysmem : > RAMDATA, PAGE = 1 /* Поддерживает стандартную секцию runtime без использования heap в алгоритме. */ + .reset : > RESET, PAGE = 0, TYPE = DSECT /* Reset-вектор ROM описывается, но не попадает в программируемый OUT. */ + .adc_cal : > ADC_CAL, PAGE = 0, TYPE = NOLOAD /* Сохраняет заводские данные ADC TI при установке загрузчика. */ +} /* Не создаёт секций CSM, OTP или паролей. */ diff --git a/c/protocan-boot/projects/ccs/f28335/codestart.asm b/c/protocan-boot/projects/ccs/f28335/codestart.asm new file mode 100644 index 0000000..b69fe2f --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/codestart.asm @@ -0,0 +1,12 @@ + .ref _c_int00 ; Стандартный COFF startup применяет .cinit и вызывает main после отключения раннего watchdog. + .sect "codestart" ; Boot ROM передаёт управление двухсловному переходу по аппаратному адресу слова 0x33FFF6. + LB flash_boot_start ; Переходит к короткой подготовке C28x во Flash, сохраняя точный размер аппаратного входа два слова. + .text ; Последовательность взята из штатного TI DSP2833x_CodeStartBranch.asm и размещается в секторе основного кода. +flash_boot_start: ; Отключает watchdog до возможной длительной обработки таблиц инициализации C, а не только после входа в main. + SETC OBJMODE ; Выбирает C28x object mode, требуемый стандартным COFF startup процессора F28335. + EALLOW ; Разрешает запись защищённого регистра WDCR перед запуском C runtime. + MOVZ DP, #7029h>>6 ; Адрес слова WDCR=0x7029 из карты F28335; DP выбирает соответствующую страницу по 64 слова. + MOV @7029h, #0068h ; Значение 0x0068 содержит контрольные биты WDCHK=101 и WDDIS=1, как официальный TI startup. + EDIS ; Возвращает защиту системных регистров перед переходом в библиотечную инициализацию. + LB _c_int00 ; Применяет штатную ROM-модель инициализации и затем запускает текущий main 167. + .end ; Завершает модуль, не добавляя произвольных данных рядом с CSM-паролями сектора A. diff --git a/c/protocan-boot/projects/ccs/f28335/flash_update.c b/c/protocan-boot/projects/ccs/f28335/flash_update.c new file mode 100644 index 0000000..aae9388 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/flash_update.c @@ -0,0 +1,33 @@ +#include "DSP2833x_Device.h" /* Предоставляет реальные типы C28x, частоту SYSCLKOUT, CSM и маскирование IRQ. */ +#include "../../../ports/tms320f28335/f28335_flash_update.h" /* Подключает проверяемый алгоритм staging SCI8 и аппаратный контракт записи. */ +#include "Flash2833x_API_Library.h" /* Использует официальный TI Flash API v2.10 для F28335, а не запись Flash обычным указателем. */ +#include /* Копирует код и таблицы TI API из постоянного сектора A во внутреннюю RAM до операции Flash. */ +extern Uint16 FlashApiLoadStart, FlashApiLoadEnd, FlashApiRunStart; /* Символы LOAD/RUN задаёт linker в адресуемых словах CPU. */ +static FLASH_ST flash_status; /* Диагностика TI хранится во внутренней RAM во время стирания и программирования. */ +static bool erase_flash(void *user) /* Стирает только область приложения, сохраняя постоянный загрузчик. */ +{ /* Даже IRQ из сектора A запрещены, поскольку F28335 имеет общий банк Flash для A–H. */ + Uint16 saved, status; (void)user; /* Сохраняет прежнее состояние IRQ и точный результат TI API. */ + saved = __disable_interrupts(); status = Flash_Erase(0x00FEU, &flash_status); __restore_interrupts(saved); /* Бит 0 — сектор A; маска FE выбирает только B–H согласно TI API v2.10. */ + return status == STATUS_SUCCESS; /* Ошибка erase запрещает любую последующую публикацию FAB1. */ +} /* После возврата TI API банк Flash снова доступен коду постоянного загрузчика. */ +static bool program_flash(void *user, uint32_t address, uint16_t *data, unsigned int words) /* Записывает и проверяет одну ограниченную порцию Flash. */ +{ /* Аппаратный слой повторно защищает сектор A независимо от валидатора SCI8. */ + Uint16 saved, status; (void)user; /* Результат API и маска IRQ не размещаются в обновляемой Flash. */ + if (!words || address < F28335_FLASH_APP_START || address >= F28335_FLASH_APP_STOP || words > F28335_FLASH_APP_STOP - address) return false; /* Не допускает даже частичного выхода за B–H, включая CSM и аппаратный boot. */ + saved = __disable_interrupts(); status = Flash_Program((Uint16 *)address, data, words, &flash_status); /* Во время программирования процессор выполняет только скопированный в RAM TI API. */ + if (!status) status = Flash_Verify((Uint16 *)address, data, words, &flash_status); /* Проверяет фактические слова до подтверждения этой порции. */ + __restore_interrupts(saved); return status == STATUS_SUCCESS; /* Возвращает исходное состояние IRQ даже при отказе записи или readback. */ +} /* Общий writer опубликует FAB1 лишь после успешной записи остальных порций. */ +static uint16_t read_flash(void *user, uint32_t address) /* Читает физическую Flash для итоговой проверки FAB1/CRC. */ +{ /* Этот callback вызывается только после окончания аппаратных операций TI API. */ + (void)user; return *(volatile Uint16 *)address; /* Адрес уже ограничен общим валидатором диапазоном приложения B–H. */ +} /* Программирование не подменяется чтением staging EEPROM. */ +bool F28335Boot_FlashProgram(f28335_flash_update_t *s) /* Единственная точка фактической записи внутренней Flash из CAN COMMIT. */ +{ /* Постоянный загрузчик может вернуться к CAN recovery при любой ошибке. */ + f28335_flash_ops_t ops; /* Аппаратные операции передаются проверяемому транспортно-независимому writer. */ + if (CsmRegs.CSMSCR.bit.SECURE) return false; /* Защищённый CSM запрещает стирание до любого вызова TI API. */ + memcpy(&FlashApiRunStart, &FlashApiLoadStart, &FlashApiLoadEnd - &FlashApiLoadStart); /* API и его константы должны быть в RAM даже при сохранении сектора A. */ + Flash_CPUScaleFactor = (Uint32)(1048576.0L * (200.0L * (long double)SYSCLKOUT / 1000000000.0L)); /* Формула TI IQ20 использует реальную частоту SYSCLKOUT в герцах. */ + Flash_CallbackPtr = 0; ops.erase = erase_flash; ops.program = program_flash; ops.read = read_flash; ops.user = 0; /* Исключает callback во Flash во время занятости общего банка A–H. */ + return f28335_flash_update_program(s, &ops); /* Итоговый ACK COMMIT появляется только после CRC физической Flash; REBOOT остаётся отдельной командой клиента. */ +} /* Постоянный boot, handoff и EEPROM-параметры не программируются. */ diff --git a/c/protocan-boot/projects/ccs/f28335/main.c b/c/protocan-boot/projects/ccs/f28335/main.c new file mode 100644 index 0000000..fa829d2 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/main.c @@ -0,0 +1,127 @@ +#include "DSP2833x_Device.h" /* Использует действующую частоту и штатную карту регистров той же платы 167. */ +#include "DSP2833x_Examples.h" /* Предоставляет InitSysCtrl, InitPieCtrl, InitFlash и управление Timer1. */ +#include "../../../ports/tms320f28335/f28335_can_boot.h" /* Подключает адрес, сервисы и очередь существующего загрузчика. */ +#include "../../../ports/tms320f28335/f28335_boot_platform.h" /* Использует общий handoff, SPI и энергонезависимый A/B-журнал. */ +#include /* Копирует ramfuncs до настройки времен доступа Flash. */ +extern Uint16 RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart; /* Адреса LOAD/RUN задаёт отдельный linker загрузчика в словах C28x. */ +static f28335_boot_store_t image_store; /* Журнал загрузки остаётся в RAM E000..FFFF до перехода в приложение. */ +interrupt void boot_tick(void) /* Timer1 продолжает миллисекундные тайм-ауты общего CAN/SPI порта. */ +{ /* Этот ISR принадлежит постоянному загрузчику, а не кандидату приложения. */ + CpuTimer1.InterruptCount++; /* Один тик равен одной миллисекунде согласно ConfigCpuTimer ниже. */ + ServiceDog(); /* Длительные CRC/SPI операции загрузчика не должны сбрасывать аппарат во время обновления. */ +} /* Возвращает управление основному циклу загрузчика. */ +interrupt void boot_can_rx(void) /* CAN IRQ выполняет только короткий перенос принятых кадров в общую очередь. */ +{ /* Запись EEPROM, CRC и публикация pending остаются в главном цикле. */ + F28335CanBoot_RxISR(); /* Читает только выделенные mailbox 3 и 6 существующего адаптера. */ + PieCtrlRegs.PIEACK.all = 0x0100U; /* Бит 8 подтверждает группу PIE9, в которой находится ECAN0INTA. */ +} /* Позволяет принять следующее окно CAN, пока main занят SPI. */ +static void boot_can_init(void) /* Настраивает тот же физический CAN-A и 250 кбит/с, что приложение 167. */ +{ /* Загрузчик не использует прикладные mailbox 0..2 и не меняет адрес общего порта. */ + Uint32 shadow; /* Защищённые eCAN-регистры изменяются только полными 32-битными обращениями. */ + EALLOW; /* Разрешает настройку мультиплексора, eCAN и таблицы векторов. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1; /* GPIO30 служит CANRXA, как в штатном InitCan проекта. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1; /* GPIO31 служит CANTXA того же трансивера. */ + ECanaRegs.CANTIOC.all = 8UL; /* Бит TXFUNC включает функцию CAN у выхода контроллера. */ + ECanaRegs.CANRIOC.all = 8UL; /* Бит RXFUNC включает аппаратный вход CAN. */ + ECanaRegs.CANME.all = 0UL; /* Изменяет mailbox и фильтры только при выключенных ящиках. */ + ECanaRegs.CANMIM.all = 0UL; /* Ни один старый mailbox не должен создавать IRQ во время настройки. */ + ECanaRegs.CANMIL.all = 0UL; /* Направляет служебные mailbox на ECAN0INTA группы PIE9. */ + ECanaRegs.CANMC.all = 0x00003080UL; /* SCB=1 выбирает eCAN, ABO=1 автоматическое восстановление, CCR=1 режим настройки битового времени; SRES остаётся нулём. */ + while (!ECanaRegs.CANES.bit.CCE) {} /* Не пишет CANBTC до аппаратного подтверждения режима настройки. */ + shadow = ((Uint32)(CLKMULT * 3L - 1L) << 16) | 0x0000017AUL; /* BRP=CLKMULT*3-1, SJW=1, TSEG1=15, TSEG2=2 как в приложении: 250000 бит/с при текущем SYSCLKOUT. */ + ECanaRegs.CANBTC.all = shadow; /* Передаёт параметры одним 32-битным обращением к eCAN. */ + ECanaRegs.CANMC.all &= ~0x00001000UL; /* Снимает CCR после настройки тактов CAN. */ + while (ECanaRegs.CANES.bit.CCE) {} /* Ждёт возврата контроллера к обычной работе перед включением фильтров. */ + ECanaRegs.CANTA.all = 0xFFFFFFFFUL; /* Удаляет старые TX ACK, которые не относятся к новой сессии. */ + ECanaRegs.CANRMP.all = 0xFFFFFFFFUL; /* Удаляет старые RX-флаги до включения IRQ. */ + ECanaRegs.CANRML.all = 0xFFFFFFFFUL; /* Начинает контроль потери mailbox с чистого состояния. */ + ECanaRegs.CANGIF0.all = 0xFFFFFFFFUL; /* Снимает накопленные флаги линии CAN0. */ + ECanaRegs.CANGIM.all = 1UL; /* I0EN разрешает mailbox IRQ по линии 0; ошибки не требуют прикладного ISR. */ + PieVectTable.ECAN0INTA = &boot_can_rx; /* Использует постоянный обработчик загрузчика вместо кода RAM-приложения. */ + PieCtrlRegs.PIEIER9.bit.INTx5 = 1; /* Разрешает ECAN0INTA в группе PIE9. */ + EDIS; /* Возвращает защиту аппаратной конфигурации. */ + IER |= M_INT9; /* Разрешает группе CAN доставлять IRQ ядру после общего EINT. */ +} /* Общий порт затем настроит адресные mailbox 3/4/6. */ +static unsigned int boot_periph_id(void) /* Повторяет аппаратное чтение Mode из peripher.c, чтобы после reset адрес загрузчика совпадал с приложением. */ +{ /* Четыре активных низким уровнем перемычки существующей ПМ35 задают номера 1–16. */ + unsigned int periph_id; /* Номер является ID PERIPH из Excel, а не уменьшенным на единицу индексом старого CAN. */ + EALLOW; /* Разрешает настройку только четырёх входов адресных перемычек. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO20=0; /* GPIO20 работает входом адреса с весом 2, как в get_Mode приложения. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO21=0; /* GPIO21 работает входом адреса с весом 1, а не альтернативной периферией. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO22=0; /* GPIO22 работает входом адреса с весом 4. */ + GpioCtrlRegs.GPBMUX2.bit.GPIO51=0; /* GPIO51 работает входом адреса с весом 8. */ + GpioCtrlRegs.GPADIR.bit.GPIO20=0; /* Запрещает выходной драйвер, чтобы загрузчик не воздействовал на перемычку. */ + GpioCtrlRegs.GPADIR.bit.GPIO21=0; /* Оставляет младшую адресную перемычку входом. */ + GpioCtrlRegs.GPADIR.bit.GPIO22=0; /* Оставляет третий разряд аппаратного номера входом. */ + GpioCtrlRegs.GPBDIR.bit.GPIO51=0; /* Оставляет старшую перемычку входом порта B. */ + EDIS; /* Восстанавливает защиту конфигурации GPIO до чтения физического номера. */ + periph_id=1U+!GpioDataRegs.GPADAT.bit.GPIO21; /* Штатный Mode начинается с 1; замкнутая GPIO21 добавляет единицу. */ + periph_id+=2U*!GpioDataRegs.GPADAT.bit.GPIO20; /* Замкнутая GPIO20 добавляет два к номеру платы. */ + periph_id+=4U*!GpioDataRegs.GPADAT.bit.GPIO22; /* Замкнутая GPIO22 добавляет четыре к номеру платы. */ + periph_id+=8U*!GpioDataRegs.GPBDAT.bit.GPIO51; /* Замкнутая GPIO51 добавляет восемь; аппаратный диапазон заканчивается на 16. */ + return periph_id; /* Общий CAN-порт преобразует номер 16 в Type 2 / Device 0 согласно Excel. */ +} /* Приложение и recovery используют один и тот же физический адрес без общего значения 3/7. */ +static bool ram_word(void *user, uint32_t address, uint16_t value) /* Аппаратная запись одного слова уже проверенной таблицы SCI8. */ +{ /* Повторяет нижнюю защиту RAM даже при ошибке вызывающего слоя. */ + (void)user; /* Контекст не нужен для единственной внутренней RAM данного F28335. */ + if (address < 0x8000UL || address >= 0xE000UL) return false; /* Не позволяет таблице затронуть периферию, handoff, стек или RAM загрузчика. */ + *(volatile Uint16 *)address = value; /* Адрес измеряется в 16-битных словах C28x, значение уже декодировано из SCI8. */ + return true; /* Сообщает полную запись слова, а не частичное выполнение секции. */ +} /* После загрузки всех слов общий store вернёт проверенную точку входа. */ +static uint16_t flash_word(void *user, uint32_t address) /* Читает только фиксированный заголовок и проверенный диапазон приложения ниже сектора A. */ +{ /* Загрузчик остаётся во Flash A, поэтому чтение H–B не меняет выполняемый код. */ + (void)user; /* Единственная внутренняя Flash не требует отдельного контекста источника. */ + return *(volatile Uint16 *)address; /* C28x адресует Flash 16-битными словами; разбиение на октеты выполняет общий валидатор CRC. */ +} /* Никакая запись или стирание Flash при выборе источника запуска не выполняется. */ +static void start_application(uint32_t entry, unsigned int source) /* Передаёт управление Flash либо EEPROM только после проверки соответствующего образа. */ +{ /* Останавливает собственные IRQ до C startup приложения, который заново настроит периферию и рабочую RAM. */ + DINT; IER = 0U; IFR = 0U; /* Старые прерывания не должны войти в очередь или стек завершённого загрузчика. */ + CpuTimer1Regs.TCR.bit.TSS = 1; /* Прекращает миллисекундные IRQ до запуска прикладного InitSysCtrl. */ + ECanaRegs.CANMIM.all = 0UL; /* Не доставляет CAN IRQ во время смены векторов приложения. */ + F28335Boot_SetRunning(source); /* Сохраняет достоверный источник: 0/1 для EEPROM A/B либо FE для проверенной Flash. */ + ((void (*)(void))entry)(); /* Вызывает watchdog-safe startup Flash или проверенную точку C runtime RAM-образа. */ + for (;;) {} /* Ошибочный возврат приложения не использует перезаписанное состояние загрузчика. */ +} /* Возврат к boot происходит только аппаратным reset с согласованным handoff. */ +void F28335Boot_Quiesce(void) /* Перед повторным входом загрузчика его собственные IRQ будут отключены общим Reset. */ +{ /* Силовые выходы загрузчик не включает; прикладная остановка выполняется до входа в него. */ + CpuTimer2Regs.TCR.bit.TSS = 1; /* Удерживает старый SPI Timer2 остановленным перед watchdog reset. */ +} /* Общий аппаратный слой сохранит session и включит watchdog. */ +void main(void) /* Постоянный загрузчик запускается аппаратным Flash boot по адресу 33FFF6. */ +{ /* Пустая EEPROM и неподтверждённый кандидат оставляют доступным CAN recovery. */ + f28335_boot_io_t io; /* Доступ к M95M02 предоставляет существующий переносимый SPI-порт. */ + unsigned int slot, session, periph_id; /* Слот, сессия handoff и физический номер PERIPH сохраняются отдельно от адресов памяти. */ + uint32_t entry, started; /* Адрес запуска измеряется словами CPU; started хранит миллисекунды стартового окна CAN. */ + InitSysCtrl(); /* Повторяет PLL и SYSCLKOUT проекта 167, отключая watchdog на раннем старте. */ + DINT; /* Не использует IRQ до настройки таблицы векторов и Timer1. */ + IER = 0U; IFR = 0U; /* Исключает доставку старых прерываний после watchdog reset. */ + memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, &RamfuncsLoadEnd - &RamfuncsLoadStart); /* Переносит InitFlash в RAM до изменения времен доступа Flash. */ + InitFlash(); /* Настраивает доступ к постоянному коду по штатной процедуре TI. */ + InitPieCtrl(); /* Очищает разрешения и флаги всех групп PIE перед установкой двух собственных векторов. */ + InitCpuTimers(); /* Останавливает Timer0/1/2 и сбрасывает их управляющие структуры. */ + ConfigCpuTimer(&CpuTimer1, SYSCLKOUT / 1000000L, 1000UL); /* Период 1000 мкс даёт единый миллисекундный tick для протокола и SPI WIP. */ + EALLOW; PieVectTable.XINT13 = &boot_tick; EDIS; /* Привязывает прямое прерывание Timer1 к постоянному ISR загрузчика. */ + CpuTimer1Regs.TCR.all = 0x4020U; /* Разрешает прерывание Timer1 и запускает счётчик, как приложение 167. */ + IER |= M_INT13; /* Разрешает миллисекундные прерывания ядра. */ + periph_id=boot_periph_id(); /* Читает реальные перемычки до адресных mailbox и до ответа на ENTER_BOOT после reset. */ + boot_can_init(); /* Настраивает трансивер и физическую скорость до общих фильтров и первой передачи. */ + session = F28335Boot_RequestedSession(); /* Потребляет только достоверный запрос приложения с magic и XOR-контролем. */ + F28335CanBoot_Init(periph_id); /* Открывает журнал и адресные Boot mailbox только для физического PERIPH данной платы. */ + PieCtrlRegs.PIECTRL.bit.ENPIE = 1; /* Разрешает таблицу PIE после записи обоих используемых векторов. */ + EINT; /* Приём окна CAN продолжается во время синхронных SPI-транзакций main. */ + if (session) F28335CanBoot_Resume(session); /* Отвечает ENTER_BOOT после reset с той же session и остаётся в recovery. */ + else { /* Обычный reset даёт CAN окно, затем предпочитает проверенную внутреннюю Flash и использует EEPROM как резерв. */ + started = F28335Boot_Now(); /* Отсчитывает три секунды от готового CAN, а не от начала настройки PLL и SPI. */ + while ((uint32_t)(F28335Boot_Now()-started)<3000UL && !F28335CanBoot_Active()) { F28335CanBoot_Service(); ServiceDog(); } /* ENTER_BOOT удерживает recovery; обычный PING не изменяет выбранный источник запуска. */ + F28335CanBoot_Service(); /* Разбирает кадр на границе трёхсекундного окна до последней проверки активного сеанса. */ + if (!F28335CanBoot_Active()) { /* Не запускает основную или резервную программу поверх открытого сеанса CAN Boot. */ + if (f28335_flash_app_validate(flash_word, 0, &entry)) start_application(entry, F28335_BOOT_FLASH_SLOT); /* Flash приоритетна только при правильном FAB1, допустимых адресах и совпавшей CRC всех LOAD-секций. */ + io.read = F28335Boot_Read; io.write = F28335Boot_Write; io.user = 0; /* Передаёт store ту же аппаратную реализацию, что обслуживает CAN. */ + if (f28335_boot_open(&image_store, &io) && f28335_boot_select(&image_store, &slot) && slot < 2U && f28335_boot_load(&image_store, slot, ram_word, 0, &entry)) { /* Проверяет CRC/SCI8, сохраняет attempted до пробного запуска и копирует только допустимую RAM. */ + start_application(entry, slot); /* Резервный EEPROM-образ получает прежние trial/CONFIRM и автоматический откат A/B. */ + } /* При ошибке чтения, CRC, таблицы или журнала не выполняет неизвестный entry. */ + F28335CanBoot_Init(periph_id); /* При переходе в recovery перечитывает журнал, сохраняя прежний физический адрес платы. */ + } /* Открытый CAN-сеанс сохраняет метаданные, выбранный слот и подтверждения без повторного Init. */ + } /* Завершает выбор между адресным входом и обычным запуском приложения. */ + F28335Boot_SetRunning(F28335_AB_NONE); /* Отмечает режим загрузчика, сохраняя уже восстановленную session в RAM автомата. */ + for (;;) { F28335CanBoot_Service(); ServiceDog(); } /* Обслуживает обновления и остаётся доступным при пустой/повреждённой EEPROM. */ +} /* Нормальный выход выполняется только через запуск RAM-приложения либо watchdog reset. */ diff --git a/c/protocan-boot/projects/ccs/f28335/shared_boot.c b/c/protocan-boot/projects/ccs/f28335/shared_boot.c new file mode 100644 index 0000000..733eb5d --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/shared_boot.c @@ -0,0 +1,5 @@ +#include "../../../src/pcan_boot.c" /* Подключает единственный общий автомат ProtoCAN Boot и CRC32. */ +#include "../../../ports/tms320f28335/f28335_boot_store.c" /* Использует проверенный A/B-журнал, readback, SCI8 и откат. */ +#include "../../../ports/tms320f28335/f28335_flash_app.c" /* Проверяет FAB1 и CRC приложения ниже сектора A перед выбором основного Flash либо резервной EEPROM. */ +#include "../../../ports/tms320f28335/f28335_boot_hw.c" /* Подключает те же SPI, watchdog и handoff, что RAM-приложение. */ +#include "../../../ports/tms320f28335/f28335_can_boot.c" /* F28335_BOOT_LOADER=1 разрешает запись слотов только постоянному загрузчику. */ diff --git a/c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml b/c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml new file mode 100644 index 0000000..d074222 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/src/pcan_boot.c b/c/protocan-boot/src/pcan_boot.c index 2748d03..607fd63 100644 --- a/c/protocan-boot/src/pcan_boot.c +++ b/c/protocan-boot/src/pcan_boot.c @@ -89,6 +89,17 @@ static bool send_status(pcan_boot_t *boot, pcan_boot_byte_t command, pcan_boot_b return send_frame(boot, PCAN_BOOT_MSG_STATUS, body, data, 8U); } +uint32_t pcan_boot_crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length) /* Публичный readback использует тот же полином и отражение, что приём DATA. */ +{ /* Не создаёт второго аппаратно зависимого варианта CRC в портах NOR/EEPROM. */ + return crc32_update(crc, data, length); /* Продолжает ранее полученное состояние либо начинает с нуля. */ +} /* Сохраняет существующую wire-совместимость всех портов. */ +bool pcan_boot_report_busy(pcan_boot_t *boot, pcan_boot_byte_t command, uint32_t now_ms) /* Позволяет синхронному erase отвечать, пока аппаратная операция ещё не завершена. */ +{ /* Порт вызывает функцию только в контексте main с живым экземпляром сессии. */ + if (boot == NULL) return false; /* Не обращается к неинициализированному экземпляру аппаратного порта. */ + boot->now_ms = boot->last_activity_ms = now_ms; /* Продвижение erase/verify считается живой активностью: длинная операция не должна сама истечь по тайм-ауту сессии. */ + return send_status(boot, command, PCAN_BOOT_STATUS_BUSY); /* Номер следующего блока и CRC берутся из настоящего состояния ядра. */ +} /* Окончательный OK/ошибку по завершении callback отправляет обычный автомат. */ + /* IDENTIFY имеет отдельный тип сообщения DISCOVERY и Body=1. Он доступен * без открытия сессии, поэтому обнаружение устройства не должно запускать обновление. */ static bool send_identity(pcan_boot_t *boot) @@ -205,7 +216,7 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, pcan_boot_byte_t command = (pcan_boot_byte_t)(body & 0xFFU); if (dlc != ((command == PCAN_BOOT_CMD_BEGIN_IMAGE || command == PCAN_BOOT_CMD_BEGIN_COMPAT) ? 8U : - (command == PCAN_BOOT_CMD_DEVICE_NAME || command == PCAN_BOOT_CMD_MEMORY_INFO) ? 1U : 0U)) { + (command == PCAN_BOOT_CMD_DEVICE_NAME || command == PCAN_BOOT_CMD_MEMORY_INFO || command == PCAN_BOOT_CMD_SELECT_MEMORY) ? 1U : 0U)) { /* Выбор памяти имеет ровно один октет и не может читать отсутствующий payload. */ return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_SIZE); } if (command == PCAN_BOOT_CMD_PING) { @@ -258,6 +269,13 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, boot->last_activity_ms=boot->now_ms; switch (command) { + case PCAN_BOOT_CMD_SELECT_MEMORY: { /* Явное назначение Flash не меняет поведение прежних клиентов без этой команды. */ + pcan_boot_status_t status; /* Точный отказ порта передаётся клиенту без подмены успешным ACK. */ + if (boot->state != PCAN_BOOT_STATE_METADATA || boot->have_image || boot->have_compat) return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); /* После начала метаданных, приёма либо проверки запрещает менять цель записи. */ + if (!boot->port.select_memory) return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_COMMAND); /* Старый загрузчик отклоняет новую цель до ERASE и передачи образа. */ + status = boot->port.select_memory(boot->port_user, data[0], &boot->config); /* Порт проверяет поддержку выбранной физической памяти и задаёт её режим. */ + return send_status(boot, command, status); /* Ответ защищён исходной адресацией и текущей ненулевой сессией. */ + } /* Остальные команды используют выбранную конфигурацию слотов. */ case PCAN_BOOT_CMD_BEGIN_IMAGE: if(boot->state==PCAN_BOOT_STATE_READY_TO_ERASE && boot->manifest.image_size==get_u32(data) && boot->manifest.image_crc32==get_u32(data+4)) return send_status(boot,command,PCAN_BOOT_STATUS_OK); diff --git a/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h b/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h index 00842d5..bd2cf58 100644 --- a/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h +++ b/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h @@ -9,5 +9,5 @@ static struct { struct MBOX MBOX3, MBOX4, MBOX6; } ECanaMboxes; static struct { struct test_reg CANME,CANMD,CANRMP,CANRML,CANMIM,CANTA,CANAA,CANTRS,CANTRR; } ECanaRegs; static struct { struct test_reg LAM3,LAM6; } ECanaLAMRegs; static struct { unsigned long InterruptCount; } CpuTimer1; -static struct { unsigned WDCR; } SysCtrlRegs; +/* Watchdog/reset моделируются callbacks; неиспользуемая глобальная копия SysCtrlRegs не требуется. */ #endif diff --git a/c/protocan-boot/tests/run_tests.py b/c/protocan-boot/tests/run_tests.py index 5180dea..0abe1ee 100644 --- a/c/protocan-boot/tests/run_tests.py +++ b/c/protocan-boot/tests/run_tests.py @@ -12,16 +12,18 @@ if not cc: store = 'ports/tms320f28335/f28335_boot_store.c' cases = [ ('core', [], ['src/pcan_boot.c', 'tests/test_pcan_boot.c']), + ('busy', ['-DPCAN_BOOT_WIDE_BYTES'], ['src/pcan_boot.c', 'tests/test_pcan_busy.c']), # Длительный NOR erase с BUSY продлевает session и сохраняет wire-поля ответа. ('store_native', [], [store, 'tests/test_f28335_boot_store.c']), ('store_wide', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'tests/test_f28335_boot_store.c']), ('loader', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), ('application', ['-DPCAN_BOOT_WIDE_BYTES', '-DF28335_BOOT_LOADER=0'], [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), + ('f2812_nor', ['-DPCAN_BOOT_WIDE_BYTES', '-DBOOT2812_HOST'], ['src/pcan_boot.c', 'ports/tms320f2812/nor_flash.c', 'ports/tms320f2812/boot_store.c', 'tests/test_f2812_nor.c']), # Проверяет настоящий AMD driver, NOR manifest, SCI8 и восстановление после обрывов записи. ] with tempfile.TemporaryDirectory(prefix='f28335-ab-') as tmp: for name, defines, sources in cases: exe = Path(tmp) / (name + '.exe') - subprocess.run([cc, '-std=c99', '-Wall', '-Wextra', '-Werror', '-Iinclude', + subprocess.run([cc, '-std=c99', '-Wall', '-Wextra', '-Werror', '-Wno-misleading-indentation', '-Iinclude', # GCC допускает существующие однострочные циклы старых аппаратных моделей без подавления остальных ошибок. '-Itests/f28335_stubs', *defines, *sources, '-o', str(exe)], cwd=root, check=True) sample = os.environ.get('F28335_SAMPLE_IMAGE') if name == 'store_wide' else None subprocess.run([str(exe), *([sample] if sample else [])], check=True, timeout=30) diff --git a/c/protocan-boot/tests/test_f2812_nor.c b/c/protocan-boot/tests/test_f2812_nor.c new file mode 100644 index 0000000..08ac4ff --- /dev/null +++ b/c/protocan-boot/tests/test_f2812_nor.c @@ -0,0 +1,83 @@ +#include "../ports/tms320f2812/boot2812.h" /* Проверяет реальные callbacks NOR и общий ProtoCAN codec в wide-octet режиме. */ +#include /* Любое нарушение границ, публикации или CRC завершает тест ошибкой. */ +#include /* Модель физической x16 памяти использует ровно 16 бит на слово даже на ПК. */ +#include /* Сообщает результат поведенческих сценариев без физического JTAG. */ +#include /* Подготавливает память и отдельные структуры C-ядра перед серией. */ +static uint16_t memory[0x80000]; /* AM29LV800BT содержит 512K слов x16, то есть 1 МиБ. */ +static unsigned int state, selected, bad_id, erases, programmed, busy_calls, loaded_words, stuck; /* Состояния относятся только к модели командной шины AMD. */ +static long budget = -1; /* Отрицательное значение разрешает записи, ноль моделирует исчезновение питания перед очередным word program. */ +static unsigned long clock_ms; /* Детерминированные часы позволяют проверить ограниченный выход из polling. */ +unsigned long Boot2812_Now(void) { return clock_ms++; } /* Продвигает миллисекунды без зависимости теста от wall clock ПК. */ +void Boot2812_Busy(void) { ++busy_calls; } /* Подтверждает, что длительное ожидание вызывает разрешённый сервис BUSY. */ +void NorModel_LoadWord(uint32_t target, unsigned int value) /* Получает только реальные записи валидатора в разрешённую RAM приложения. */ +{ /* Тестовый образ ниже содержит пять слов H0. */ + assert(target >= 0x3F8000UL && target < 0x3F8005UL); assert(value == 0U); ++loaded_words; /* Неверный адрес либо повреждённый payload не может скрыться в аппаратной заглушке. */ +} /* Запись в адресное пространство процесса ПК отсутствует. */ +unsigned int NorModel_Read(unsigned long word) /* Имитирует обычное чтение либо режим autoselect чипа. */ +{ /* Все обращения обязаны оставаться внутри установленной физической NOR. */ + assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Выход на соседнюю XINTF-память является ошибкой драйвера. */ + if (selected) return word == BOOT2812_NOR_BASE ? (bad_id ? 2U : 1U) : 0x22DAU; /* Модель отличает правильный AMD от неподходящего производителя. */ + if (stuck && word >= BOOT2812_IMAGE_WORD) return 0U; /* DQ7=0/DQ5=0 удерживают erase busy до программного тайм-аута. */ + return memory[word - BOOT2812_NOR_BASE]; /* Возвращает настоящие 16-битные данные модели. */ +} /* Чтение не выполняет скрытых записей и не исправляет повреждённые данные. */ +void NorModel_Write(unsigned long word, unsigned int value) /* Проверяет настоящий unlock state machine драйвера, а не принимает готовые запросы erase. */ +{ /* Командные адреса трактуются как x16 смещения согласно datasheet AMD. */ + assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Любой командный цикл ограничен физическим чипом. */ + if (state == 3U) { /* После A0 следующий цикл обязательно содержит программируемое слово данных. */ + if (budget != 0) { memory[word - BOOT2812_NOR_BASE] &= (uint16_t)value; ++programmed; if (budget > 0) --budget; } /* NOR программирует только переходы 1→0; обрыв питания оставляет прежнее слово. */ + state = 0U; return; /* Программирование одного слова завершает командную последовательность. */ + } /* Значение F0 в payload не должно ошибочно интерпретироваться как отдельная команда Reset. */ + if (value == 0xF0U) { state = selected = 0U; return; } /* Reset возвращает обычное чтение независимо от предыдущей незавершённой команды. */ + if (state == 0U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 1U; } /* Первый unlock-цикл проверяется вместе с адресом. */ + else if (state == 1U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 2U; } /* Второй цикл исключает ошибочную x8 адресацию. */ + else if (state == 2U) { /* Третий цикл выбирает только одну из поддерживаемых безопасных команд. */ + assert(word == BOOT2812_NOR_BASE + 0x555UL); /* Командный регистр находится по x16 смещению 555h. */ + if (value == 0x90U) { selected = 1U; state = 0U; } /* Autoselect не изменяет содержимое памяти. */ + else if (value == 0xA0U) state = 3U; /* Следующий цикл будет word program. */ + else { assert(value == 0x80U); state = 4U; } /* Стирание требует второй unlock-пары, а не одного произвольного слова. */ + } /* Завершает декодирование третьего такта AMD. */ + else if (state == 4U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 5U; } /* Проверяет четвёртый цикл Sector Erase. */ + else if (state == 5U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 6U; } /* Проверяет пятый цикл Sector Erase. */ + else { /* Шестой цикл выбирает только разрешённый отдельный сектор. */ + unsigned long count = word == BOOT2812_META_WORD ? 0x2000UL : 0x8000UL, i; /* Модель различает обычные и последние top-boot сектора. */ + assert(value == 0x30U); assert(word == BOOT2812_META_WORD || word == BOOT2812_IMAGE_WORD || word == BOOT2812_IMAGE_WORD + 0x8000UL || word == BOOT2812_IMAGE_WORD + 0x10000UL); /* Запрещает Chip Erase и любые соседние секторы legacy/FPGA. */ + for (i = 0; i < count; ++i) memory[word - BOOT2812_NOR_BASE + i] = 0xFFFFU; /* Реально стирает все слова выбранного сектора модели. */ + ++erases; state = 0U; /* Сохраняет число аппаратных sector erase для проверки отказов до разрушительных циклов. */ + } /* Завершает разрешённую операцию command bus. */ +} /* Модель не предоставляет драйверу обходного пути прямой записи массива. */ +static pcan_boot_byte_t image[40]; /* Небольшой полный SCI8: заголовок 22, секция 6+10, терминатор 2 октета. */ +static pcan_boot_manifest_t manifest; /* Metadata используют те же размеры и совместимость, что настоящий клиент. */ +static void make_image(void) /* Создаёт независимо определённый SCI8 с entry=3F8000 и пятью нулевыми словами H0. */ +{ /* Нулевой payload облегчает точную проверку каждого перенесённого слова. */ + memset(image, 0, sizeof(image)); image[0] = 0xAAU; image[1] = 8U; image[18] = 0x3FU; image[21] = 0x80U; image[22] = 5U; image[24] = 0x3FU; image[27] = 0x80U; /* Адрес TI передаётся старшим словом вперёд, внутри слова — little endian. */ + memset(&manifest, 0, sizeof(manifest)); manifest.image_size = 40UL; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); /* Начальная CRC вычисляется общим codec по независимому массиву файла. */ + manifest.product_type = BOOT2812_PRODUCT; manifest.hardware_revision_min = manifest.hardware_revision_max = 1U; /* Проверяет исключительно совместимый профиль F2812. */ +} /* Последующие сценарии меняют данные с новой CRC, чтобы отделить ошибки структуры от ошибок передачи. */ +static void save_image(void) /* Заполняет слоты через настоящие production callbacks, а не memcpy в образ. */ +{ /* Каждая порция соответствует одному восьмиоктетному CAN DATA. */ + unsigned int i; assert(Boot2812_Erase(0, 0U)); /* Перед каждой полной передачей удаляет marker и три полных сектора образа. */ + for (i = 0; i < 40U; i += 8U) assert(Boot2812_Write(0, 0U, i, image + i, 8U)); /* Проверяет упаковку октетов и readback каждого x16 слова. */ +} /* Только после завершения записи разрешены VERIFY и COMMIT. */ +int main(void) /* Проверяет драйвер, SCI8, publication и независимость соседних данных платы. */ +{ /* Все операции используют модель, физический CAN/JTAG не открывается. */ + unsigned long i; uint32_t entry; unsigned int before, cut; /* Счётчики контролируют защищённые диапазоны и обрывы manifest. */ + for (i = 0; i < 0x80000UL; ++i) memory[i] = 0x5AA5U; make_image(); /* Заполняет весь чип контрольным значением, включая старые данные и FPGA. */ + bad_id = 1U; before = erases; assert(!Boot2812_Erase(0, 0U) && erases == before); bad_id = 0U; /* Неподходящий производитель блокируется до первого sector erase. */ + assert(!Boot2812_NorErase(0x100000UL) && !Boot2812_NorErase(BOOT2812_IMAGE_WORD + 1UL)); /* Не разрешает старую область либо адрес внутри разрешённого сектора вместо его точного начала. */ + assert(!Boot2812_NorProgram(0x130000UL, 0U)); /* FPGA-образ запрещён даже при ошибочном прямом вызове нижнего драйвера. */ + save_image(); assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_OK); /* Реальный NOR readback и формат SCI8 должны совпасть с входом. */ + assert(!Boot2812_Load(&entry)); assert(Boot2812_Commit(0, 0U, &manifest)); loaded_words = 0U; assert(Boot2812_Load(&entry) && entry == 0x3F8000UL && loaded_words == 5U); /* До COMMIT загрузка запрещена, после него переносятся ровно проверенные слова H0. */ + before = programmed; assert(!Boot2812_NorProgram(BOOT2812_IMAGE_WORD, 0xFFFFU) && programmed == before); /* Перевод 0→1 отклоняется без лишней попытки аппаратного program. */ + for (cut = 0; cut <= 12U; ++cut) { /* Проверяет публикацию при обрыве на каждом месте manifest из двенадцати слов. */ + bool committed; save_image(); budget = (long)cut; committed = Boot2812_Commit(0, 0U, &manifest); budget = -1; /* Останавливает только циклы NOR word program, не подменяя механизм публикации. */ + loaded_words = 0U; assert(Boot2812_Load(&entry) == committed); /* Незавершённая публикация остаётся recovery; полностью опубликованный образ запускается. */ + } /* Предыдущие legacy-данные всё время остаются за пределами разрешённого erase. */ + save_image(); memory[BOOT2812_IMAGE_WORD - BOOT2812_NOR_BASE + 15UL] ^= 1U; assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_CRC_ERROR); /* Порча физической NOR обнаруживается независимо от принятой потоковой CRC. */ + make_image(); image[18] = 0U; image[21] = 0x90U; image[24] = 0U; image[27] = 0x90U; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); save_image(); /* Формирует целостную, но опасную секцию в L1 работающего загрузчика. */ + assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_INVALID_STATE && !Boot2812_Commit(0, 0U, &manifest)); /* Корректная CRC не разрешает перезапись очереди и состояния сессии. */ + make_image(); stuck = 1U; before = busy_calls; assert(!Boot2812_NorErase(BOOT2812_IMAGE_WORD) && busy_calls > before); stuck = 0U; /* Постоянный DQ7 busy даёт ограниченный отказ и вызывает живой сервис BUSY. */ + for (i = 0; i < 0x60000UL; ++i) assert(memory[i] == 0x5AA5U); /* Сохраняет весь нижний участок старого firmware, параметров и FPGA, а не одну контрольную точку. */ + for (i = 0x78000UL; i < 0x7E000UL; ++i) assert(memory[i] == 0x5AA5U); /* Промежуточные top-boot сектора 15/16/17 также не стираются. */ + puts("F2812 NOR: AMD commands, ID, bounds, CRC, SCI8, torn commit, timeout and legacy/FPGA preservation: OK"); /* Перечисляет программно проверенные свойства аппаратного порта. */ + return 0; /* Успех означает завершение всех граничных и отказных сценариев. */ +} /* Политика аппаратного boot/CPLD дополнительно проверяется на реальной плате. */ diff --git a/c/protocan-boot/tests/test_f28335_can_boot.c b/c/protocan-boot/tests/test_f28335_can_boot.c index 2c2ac74..9d1bc6a 100644 --- a/c/protocan-boot/tests/test_f28335_can_boot.c +++ b/c/protocan-boot/tests/test_f28335_can_boot.c @@ -12,34 +12,64 @@ void ServiceDog(void); static unsigned char memory[0x40000]; static unsigned int running=255,resets,reset_arg,dog_feeds; static int fail_write; +static unsigned int write_calls; /* Счётчик аппаратных записей доказывает, что чужие CAN-команды не касаются EEPROM. */ void ServiceDog(void) { ++dog_feeds; } bool F28335Boot_Read(void *u,uint32_t a,pcan_boot_byte_t *p,unsigned int n) { unsigned i; (void)u; assert(a+n<=sizeof(memory)); for(i=0;i>(i*8))&255; } +static void address_isolation(void) /* Проверяет все 32 назначения Excel, аппаратный RX-фильтр и защиту записи от соседних плат. */ +{ /* Одна модель последовательно представляет каждый физический PERIPH и получает команды всем остальным. */ + unsigned int periph,peer,type,command_id,before=write_calls; /* Сохраняет счётчик записи до проверки, чтобы обнаружить любой побочный эффект чужого кадра. */ + for(periph=0U;periph<32U;++periph) { /* Покрывает обе границы Type 1/2 и все четырёхбитные Device ID. */ + F28335CanBoot_Init(periph); /* Тот же production Init используется RAM-приложением и Flash recovery. */ + assert(addressed && boot.config.device_type==1U+periph/16U && boot.config.device_id==periph%16U); /* Сверяет независимую ожидаемую раскладку Excel со всей конфигурацией устройства. */ + assert((ECanaMboxes.MBOX3.MSGID.all&0x07F00000UL)==((uint32_t)(1U+periph/16U)<<24|((uint32_t)(periph%16U)<<20))); /* Проверяет аппаратный фильтр, а не только программный parser. */ + for(peer=0U;peer<32U;++peer) { /* Включает пары задатчик↔УМП1/УМП2 и совпадающий Device ID в другом Type. */ + if(peer==periph) continue; /* Собственный адрес должен обслуживаться штатными сценариями ниже, поэтому здесь проверяются только чужие. */ + for(type=9U;type<=11U;++type) { /* Проверяет управляющий сервис и оба пространства данных слотов A/B. */ + for(command_id=2U;command_id<=9U;++command_id) { /* ENTER, метаданные, ERASE, VERIFY, COMMIT, CONFIRM и REBOOT должны игнорировать чужой адрес. */ + uint32_t id=pcan_boot_make_id(1,0,1U+peer/16U,peer%16U,type,type==9U?0x100U|command_id:0U); /* Формирует реальный 29-битный запрос соседнему PERIPH с ненулевой сессией. */ + assert(!pcan_boot_process(&boot,id,0,0)); /* Ядро не должно подтверждать или выполнять команду, адресованную другой плате. */ + ECanaRegs.CANRMP.all=8UL; ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|id; /* Моделирует доставку чужого кадра железом вопреки аппаратному фильтру. */ + ECanaMboxes.MBOX3.MSGCTRL.all=0U; ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0U; ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=0U; /* Исключает RTR как причину отказа, проверяя именно адрес. */ + F28335CanBoot_RxISR(); assert(head==0U && tail==0U && !tx_busy); /* Дополнительная ISR-защита не ставит чужую команду в очередь и не отправляет ответ. */ + } /* Завершает проверку изменяющих команд для выбранного пространства MsgType. */ + } /* Завершает проверку данных A/B и управляющего сервиса соседа. */ + } /* Переходит к следующему чужому номеру без перезаписи модели EEPROM. */ + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,7,9,0x102),0,0)); /* Прежний общий адрес 3/7 больше не разрешает вход в загрузчик ни одной платы. */ + } /* Заканчивает проверку уникальности всей таблицы PERIPH. */ + F28335CanBoot_Init(32U); assert(!addressed && !(ECanaRegs.CANME.all&88UL)); /* Недопустимый номер выключает Boot mailbox вместо перехода на общий адрес. */ + F28335CanBoot_Resume(1U); F28335CanBoot_Service(); assert(write_calls==before); /* Неверный адрес и все чужие команды не выполняют ни одной аппаратной записи. */ +} /* Последующие регрессии проверяют успешное обновление задатчика по адресу 1/8. */ int main(void) { pcan_boot_byte_t image[40]={0xAA,8},meta[8],compat[8]={0x33,0x28,1,1,2,0,1,1}; unsigned i,slot; pcan_boot_manifest_t m; memset(memory,0xA5,sizeof(memory)); image[21]=0x80; image[22]=5; image[27]=0x80; - F28335CanBoot_Init(); assert(boot.config.max_image_size==130560 && boot.config.slot_count==2); + address_isolation(); F28335CanBoot_Init(8U); assert(boot.config.max_image_size==130560 && boot.config.slot_count==2); /* Проверяет изоляцию всей шины перед штатной передачей задатчику. */ if(!F28335_BOOT_LOADER) { /* SPI-ROM application without Flash-loader handoff cannot erase anything. */ command(2,0,0); assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE && !reset_requested); + running=F28335_BOOT_FLASH_SLOT; F28335CanBoot_Init(8U); /* Достоверный handoff постоянного boot разрешает CAN-сервис защищённому Flash-приложению. */ + assert(confirmed && F28335CanBoot_WatchdogAllowed()); /* Flash не выдаётся за неподтверждённый EEPROM-кандидат и сохраняет штатное обслуживание watchdog. */ + command(12,0,0); assert(!F28335CanBoot_Active()); /* Диагностический PING не должен открывать сеанс прошивки или удерживать обычный запуск. */ + command(2,0,0); assert(reset_requested && reset_session==1U && F28335CanBoot_Active()); /* ENTER_BOOT из Flash планирует переход с той же session без прямой записи EEPROM. */ + running=255U; F28335CanBoot_Init(8U); /* Возвращает исходный SPI-ROM сценарий перед прежними тестами trial/CONFIRM и отката. */ memset(&m,0,sizeof(m));m.image_size=40;m.image_crc32=f28335_boot_crc(0,image,40); m.product_type=0x2833;m.hardware_revision_min=m.hardware_revision_max=1; assert(f28335_boot_prepare(&store,0)); for(i=0;i<40;i+=8)assert(f28335_boot_write(&store,0,i,image+i,8)); assert(f28335_boot_commit(&store,0,&m)); assert(f28335_boot_select(&store,&slot)); - running=0; F28335CanBoot_Init(); + running=0; F28335CanBoot_Init(8U); /* Пробное приложение сохраняет адрес задатчика после handoff постоянного загрузчика. */ assert(!F28335CanBoot_WatchdogAllowed()); command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE); F28335CanBoot_Ready(); @@ -55,7 +85,7 @@ int main(void) command(3,meta,8);command(4,compat,8);assert(boot.target_slot==0); command(5,0,0); for(i=0;i<5;++i) { tx_busy=0; assert(pcan_boot_process(&boot, - pcan_boot_make_id(1,0,3,7,10,i),image+i*8,8)); } + pcan_boot_make_id(1,0,1,8,10,i),image+i*8,8)); } /* Данные первого слота передаются только адресу задатчика. */ command(6,0,0);assert(boot.state==PCAN_BOOT_STATE_VERIFIED); command(7,0,0);assert(store.pending==0 && boot.state==PCAN_BOOT_STATE_COMMITTED); command(7,0,0);assert(boot.last_status==0); @@ -67,16 +97,16 @@ int main(void) } command(12,0,0); assert((ECanaMboxes.MBOX4.MSGID.all&65535)==12); command(13,0,0); assert(ECanaMboxes.MBOX4.MDH.all==130560); - meta[0]=0;command(14,meta,1); assert(ECanaMboxes.MBOX4.MDL.all==0x33383246UL); /* F283 */ + meta[0]=0;command(14,meta,1); assert(ECanaMboxes.MBOX4.MDL.all==0x6164615AUL); /* Первые четыре октета ASCII имени Zadatchik равны «Zada». */ meta[0]=3;command(15,meta,1);assert(ECanaMboxes.MBOX4.MDL.all==0x3FEFCUL); - assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,6,9,0x102),0,0)); + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,1,6,9,0x102),0,0)); /* Адрес УМП2 1/6 не должен открывать сессию задатчика 1/8. */ tx_busy=0; assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),0,0)); assert(boot.discovery_pending); pcan_boot_poll(&boot,boot.discovery_at); assert(!boot.discovery_pending && (ECanaMboxes.MBOX4.MSGID.all&65535)==1); assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x102),0,0)); head=tail=0; ECanaRegs.CANRMP.all=8; - ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|pcan_boot_make_id(1,0,3,7,9,12); + ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|pcan_boot_make_id(1,0,1,8,9,12); /* Собственный PING задатчика проходит очередь после проверки чужих адресов. */ ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0; F28335CanBoot_RxISR(); assert(head==1 && tail==0); tx_busy=0; F28335CanBoot_Service(); assert(tail==1); diff --git a/c/protocan-boot/tests/test_pcan_busy.c b/c/protocan-boot/tests/test_pcan_busy.c new file mode 100644 index 0000000..a7f0b72 --- /dev/null +++ b/c/protocan-boot/tests/test_pcan_busy.c @@ -0,0 +1,22 @@ +#include "../include/pcan_boot.h" /* Проверяет публичный BUSY codec и продление сессии на настоящем ядре. */ +#include /* Несовпадение состояния или wire-полей завершает тест ненулевым результатом. */ +#include /* Инициализирует опциональные поля конфигурации без аппаратных зависимостей. */ +static unsigned int status, body; /* Сохраняет наблюдаемые поля последнего настоящего STATUS кадра. */ +static bool send_frame(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Модель заменяет только физическую отправку CAN. */ +{ /* Содержимое статуса формирует production send_status, а не этот тест. */ + (void)user; assert(length == 8U && pcan_boot_id_msg_type(id) == 12U); status = data[0]; body = pcan_boot_id_msg_body(id); return true; /* Проверяет тип, длину и сохранённую session/command. */ +} /* Передача считается физически принятой аппаратным портом. */ +static bool erase(void *user, pcan_boot_byte_t slot) { (void)user; return slot == 0U; } /* Минимальный single-slot callback удовлетворяет обязательному контракту init. */ +static bool write_data(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) { (void)user; (void)offset; (void)data; return slot == 0U && length <= 8U; } /* Тест не программирует никакое реальное хранилище. */ +int main(void) /* Проверяет, что операция длиннее исходного session timeout остаётся живой при BUSY. */ +{ /* Без этой проверки длительный NOR erase мог бы закончиться уже отменённой сессией. */ + pcan_boot_t boot; pcan_boot_config_t config; pcan_boot_port_t port; /* Использует тот же экземпляр автомата, что аппаратные проекты. */ + memset(&config, 0, sizeof(config)); memset(&port, 0, sizeof(port)); config.slot_count = 1U; config.active_slot = 0U; config.session_timeout_ms = 30000UL; /* Сессия истекает через 30 секунд реального бездействия. */ + port.send = send_frame; port.erase_slot = erase; port.write_slot = write_data; assert(pcan_boot_init(&boot, &config, &port, 0)); /* Не обходит production валидацию обязательных callbacks. */ + assert(pcan_boot_process(&boot, pcan_boot_make_id(1U, 0U, 0U, 0U, 9U, 0x0102U), 0, 0U)); /* Открывает session=1 штатной командой ENTER_BOOT. */ + assert(pcan_boot_report_busy(&boot, 5U, 40000UL) && status == 1U && body == 0x0105U); /* BUSY долгого ERASE содержит исходную session и обновляет часы активности после сорока секунд. */ + pcan_boot_poll(&boot, 69999UL); assert(boot.state == PCAN_BOOT_STATE_METADATA); /* Почти 30 секунд после последнего BUSY ещё не означают тайм-аут. */ + pcan_boot_poll(&boot, 70000UL); assert(boot.state == PCAN_BOOT_STATE_IDLE); /* После полного интервала без прогресса сессия снова отменяется обычным способом. */ + assert(!pcan_boot_report_busy(0, 5U, 0UL)); /* Неинициализированный порт не должен вызывать аппаратный send. */ + return 0; /* Все проверки используют одно производственное ядро и его codec. */ +} /* Криптография и аппаратные сроки конкретной NOR не моделируются этим unit-тестом. */ diff --git a/c/protocan-boot/vendor/ti/README.md b/c/protocan-boot/vendor/ti/README.md new file mode 100644 index 0000000..d16ec89 --- /dev/null +++ b/c/protocan-boot/vendor/ti/README.md @@ -0,0 +1,20 @@ +# Поддержка TI C2000 для самостоятельных проектов + +Здесь сохранён минимальный необходимый набор device headers, peripheral linker, +GlobalVariableDefs, SysCtrl, CpuTimers, PieCtrl и usDelay. Для F28335 также +подключён ADC_cal. Полные исходные copyright/version comments TI сохранены. + +- `f28335`: DSP2833x Header Files/Common Sources **v1.20**, вариант рабочей + платы 167 из `Source/External/v120`. В нём сохранены русские пояснения и + действующие XCLKIN=30 МГц, CLKMULT=2, SYSCLKOUT=60 МГц. +- `f2812`: DSP281x Header Files/Common Sources **v1.20**, вариант рабочей + платы ПМ67 из `22220/ural/TMS_new_bus/Src/v120`. Используется штатный + PLLCR=10 при XCLKIN=30 МГц, SYSCLKOUT=150 МГц. Сохранено исходное имя + регистра `PIECRTL` SDK и секция `.fast_run` у usDelay; linker проекта + размещает её во внутренней Flash для вызовов из раннего InitSysCtrl. + +Это существующая поддержка производителя; код аппаратных портов ProtoCAN +находится отдельно в `ports`, а настройки платы — в проектах CCS. Перенос +исходников TI устраняет зависимость от соседнего checkout конкретной прошивки. +Установленный TI compiler/runtime по-прежнему требуется; `libc`/RTS не +копируются в репозиторий. diff --git a/c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd b/c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd new file mode 100644 index 0000000..0b9ae9c --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd @@ -0,0 +1,102 @@ +/* +// TI File $Revision: /main/4 $ +// Checkin $Date: July 9, 2009 17:39:29 $ +//########################################################################### +// +// FILE: DSP281x_Headers_nonBIOS.cmd +// +// TITLE: DSP281x Peripheral registers linker command file +// +// DESCRIPTION: +// +// This file is for use in Non-BIOS applications. +// +// Linker command file to place the peripheral structures +// used within the DSP28 headerfiles into the correct memory +// mapped locations. +// +// This version of the file includes the PieVectorTable structure. +// For BIOS applications, please use the DSP281x_Headers_BIOS.cmd file +// which does not include the PieVectorTable structure. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### +*/ + +MEMORY +{ + PAGE 0: /* Program Memory */ + + PAGE 1: /* Data Memory */ + + DEV_EMU : origin = 0x000880, length = 0x000180 /* device emulation registers */ + PIE_VECT : origin = 0x000D00, length = 0x000100 /* PIE Vector Table */ + FLASH_REGS : origin = 0x000A80, length = 0x000060 /* FLASH registers */ + CSM : origin = 0x000AE0, length = 0x000010 /* code security module registers */ + XINTF : origin = 0x000B20, length = 0x000020 /* external interface registers */ + CPU_TIMER0 : origin = 0x000C00, length = 0x000008 /* CPU Timer0 registers */ + CPU_TIMER1 : origin = 0x000C08, length = 0x000008 /* CPU Timer1 registers */ + CPU_TIMER2 : origin = 0x000C10, length = 0x000008 /* CPU Timer2 registers */ + PIE_CTRL : origin = 0x000CE0, length = 0x000020 /* PIE control registers */ + ECANA : origin = 0x006000, length = 0x000040 /* eCAN control and status registers */ + ECANA_LAM : origin = 0x006040, length = 0x000040 /* eCAN local acceptance masks */ + ECANA_MOTS : origin = 0x006080, length = 0x000040 /* eCAN message object time stamps */ + ECANA_MOTO : origin = 0x0060C0, length = 0x000040 /* eCAN object time-out registers */ + ECANA_MBOX : origin = 0x006100, length = 0x000100 /* eCAN mailboxes */ + SYSTEM : origin = 0x007010, length = 0x000020 /* System control registers */ + SPIA : origin = 0x007040, length = 0x000010 /* SPI registers */ + SCIA : origin = 0x007050, length = 0x000010 /* SCI-A registers */ + XINTRUPT : origin = 0x007070, length = 0x000010 /* external interrupt registers */ + GPIOMUX : origin = 0x0070C0, length = 0x000020 /* GPIO mux registers */ + GPIODAT : origin = 0x0070E0, length = 0x000020 /* GPIO data registers */ + ADC : origin = 0x007100, length = 0x000020 /* ADC registers */ + EVA : origin = 0x007400, length = 0x000040 /* Event Manager A registers */ + EVB : origin = 0x007500, length = 0x000040 /* Event Manager B registers */ + SCIB : origin = 0x007750, length = 0x000010 /* SCI-B registers */ + MCBSPA : origin = 0x007800, length = 0x000040 /* McBSP registers */ + CSM_PWL : origin = 0x3F7FF8, length = 0x000008 /* Part of FLASHA. CSM password locations. */ +} + + +SECTIONS +{ + PieVectTableFile : > PIE_VECT, PAGE = 1 + +/*** Peripheral Frame 0 Register Structures ***/ + DevEmuRegsFile : > DEV_EMU, PAGE = 1 + FlashRegsFile : > FLASH_REGS, PAGE = 1 + CsmRegsFile : > CSM, PAGE = 1 + XintfRegsFile : > XINTF, PAGE = 1 + CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1 + CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1 + CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1 + PieCtrlRegsFile : > PIE_CTRL, PAGE = 1 + +/*** Peripheral Frame 1 Register Structures ***/ + ECanaRegsFile : > ECANA, PAGE = 1 + ECanaLAMRegsFile : > ECANA_LAM PAGE = 1 + ECanaMboxesFile : > ECANA_MBOX PAGE = 1 + ECanaMOTSRegsFile : > ECANA_MOTS PAGE = 1 + ECanaMOTORegsFile : > ECANA_MOTO PAGE = 1 + +/*** Peripheral Frame 2 Register Structures ***/ + SysCtrlRegsFile : > SYSTEM, PAGE = 1 + SpiaRegsFile : > SPIA, PAGE = 1 + SciaRegsFile : > SCIA, PAGE = 1 + XIntruptRegsFile : > XINTRUPT, PAGE = 1 + GpioMuxRegsFile : > GPIOMUX, PAGE = 1 + GpioDataRegsFile : > GPIODAT PAGE = 1 + AdcRegsFile : > ADC, PAGE = 1 + EvaRegsFile : > EVA, PAGE = 1 + EvbRegsFile : > EVB, PAGE = 1 + ScibRegsFile : > SCIB, PAGE = 1 + McbspaRegsFile : > MCBSPA, PAGE = 1 + +/*** Code Security Module Register Structures ***/ + CsmPwlFile : > CSM_PWL, PAGE = 1 +} + + +/******************* end of file ************************/ diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h new file mode 100644 index 0000000..e617abd --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h @@ -0,0 +1,123 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 15:22:28 $ +//########################################################################### +// +// FILE: DSP281x_DefaultIsr.h +// +// TITLE: DSP281x Devices Default Interrupt Service Routines Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEFAULT_ISR_H +#define DSP281x_DEFAULT_ISR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// Default Interrupt Service Routine Declarations: +// +// The following function prototypes are for the +// default ISR routines used with the default PIE vector table. +// This default vector table is found in the DSP28_PieVect.h +// file. +// + +// Non-Peripheral Interrupts: +interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1 +interrupt void INT14_ISR(void); // CPU-Timer2 +interrupt void DATALOG_ISR(void); // Datalogging interrupt +interrupt void RTOSINT_ISR(void); // RTOS interrupt +interrupt void EMUINT_ISR(void); // Emulation interrupt +interrupt void NMI_ISR(void); // Non-maskable interrupt +interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP +interrupt void USER1_ISR(void); // User Defined trap 1 +interrupt void USER2_ISR(void); // User Defined trap 2 +interrupt void USER3_ISR(void); // User Defined trap 3 +interrupt void USER4_ISR(void); // User Defined trap 4 +interrupt void USER5_ISR(void); // User Defined trap 5 +interrupt void USER6_ISR(void); // User Defined trap 6 +interrupt void USER7_ISR(void); // User Defined trap 7 +interrupt void USER8_ISR(void); // User Defined trap 8 +interrupt void USER9_ISR(void); // User Defined trap 9 +interrupt void USER10_ISR(void); // User Defined trap 10 +interrupt void USER11_ISR(void); // User Defined trap 11 +interrupt void USER12_ISR(void); // User Defined trap 12 + +// Group 1 PIE Interrupt Service Routines: +interrupt void PDPINTA_ISR(void); // EV-A +interrupt void PDPINTB_ISR(void); // EV-B +interrupt void XINT1_ISR(void); +interrupt void XINT2_ISR(void); +interrupt void ADCINT_ISR(void); // ADC +interrupt void TINT0_ISR(void); // Timer 0 +interrupt void WAKEINT_ISR(void); // WD + +// Group 2 PIE Interrupt Service Routines: +interrupt void CMP1INT_ISR(void); // EV-A +interrupt void CMP2INT_ISR(void); // EV-A +interrupt void CMP3INT_ISR(void); // EV-A +interrupt void T1PINT_ISR(void); // EV-A +interrupt void T1CINT_ISR(void); // EV-A +interrupt void T1UFINT_ISR(void); // EV-A +interrupt void T1OFINT_ISR(void); // EV-A + +// Group 3 PIE Interrupt Service Routines: +interrupt void T2PINT_ISR(void); // EV-A +interrupt void T2CINT_ISR(void); // EV-A +interrupt void T2UFINT_ISR(void); // EV-A +interrupt void T2OFINT_ISR(void); // EV-A +interrupt void CAPINT1_ISR(void); // EV-A +interrupt void CAPINT2_ISR(void); // EV-A +interrupt void CAPINT3_ISR(void); // EV-A + +// Group 4 PIE Interrupt Service Routines: +interrupt void CMP4INT_ISR(void); // EV-B +interrupt void CMP5INT_ISR(void); // EV-B +interrupt void CMP6INT_ISR(void); // EV-B +interrupt void T3PINT_ISR(void); // EV-B +interrupt void T3CINT_ISR(void); // EV-B +interrupt void T3UFINT_ISR(void); // EV-B +interrupt void T3OFINT_ISR(void); // EV-B + +// Group 5 PIE Interrupt Service Routines: +interrupt void T4PINT_ISR(void); // EV-B +interrupt void T4CINT_ISR(void); // EV-B +interrupt void T4UFINT_ISR(void); // EV-B +interrupt void T4OFINT_ISR(void); // EV-B +interrupt void CAPINT4_ISR(void); // EV-B +interrupt void CAPINT5_ISR(void); // EV-B +interrupt void CAPINT6_ISR(void); // EV-B + +// Group 6 PIE Interrupt Service Routines: +interrupt void SPIRXINTA_ISR(void); // SPI +interrupt void SPITXINTA_ISR(void); // SPI +interrupt void MRINTA_ISR(void); // McBSP +interrupt void MXINTA_ISR(void); // McBSP + + +// Group 9 PIE Interrupt Service Routines: +interrupt void SCIRXINTA_ISR(void); // SCI-A +interrupt void SCITXINTA_ISR(void); // SCI-A +interrupt void SCIRXINTB_ISR(void); // SCI-B +interrupt void SCITXINTB_ISR(void); // SCI-B +interrupt void ECAN0INTA_ISR(void); // eCAN +interrupt void ECAN1INTA_ISR(void); // eCAN + + +// Catch-all for Reserved Locations For testing purposes: +interrupt void PIE_RESERVED(void); // Reserved for test +interrupt void rsvd_ISR(void); // for test + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEFAULT_ISR_H definition + diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h new file mode 100644 index 0000000..4a8cd6a --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h @@ -0,0 +1,88 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: April 25, 2007 11:04:51 $ +//########################################################################### +// +// FILE: DSP281x_Examples.h +// +// TITLE: DSP281x Device Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_EXAMPLES_H +#define DSP281x_EXAMPLES_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*----------------------------------------------------------------------------- + Specify the clock rate of the CPU (SYSCLKOUT) in nS. + + Take into account the input clock frequency and the PLL multiplier + selected in SysCtrl.c (0xA by default). + + Use one of the values provided, or define your own. + The trailing L is required tells the compiler to treat + the number as a 64-bit value. + + Only one statement should be uncommented. + + Example: CLKIN is a 30MHz crystal. + + In SysCtrl.c the user specified PLLCR = 0xA for a + 150Mhz CPU clock (SYSCLKOUT = 150MHz). + + In this case, the CPU_RATE will be 6.667L + Uncomment the line: #define CPU_RATE 6.667L +-----------------------------------------------------------------------------*/ +//#define CPU_RATE 6.667L // for a 150MHz CPU clock speed (SYSCLKOUT) +#define CPU_RATE 7.143L // for a 140MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 8.333L // for a 120MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 10.000L // for a 100MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 13.330L // for a 75MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 20.000L // for a 50MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 33.333L // for a 30MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 41.667L // for a 24MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 50.000L // for a 20MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 66.667L // for a 15MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 100.000L // for a 10MHz CPU clock speed (SYSCLKOUT) + +//---------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- +// Include Example Header Files: +// + +#include "DSP281x_GlobalPrototypes.h" // Prototypes for global functions within the + // .c files. + +#include "DSP281x_SWPrioritizedIsrLevels.h" // Used for Software Prioritization of ISR's + + +// Include files not used with DSP/BIOS +#ifndef DSP28_BIOS +#include "DSP281x_DefaultISR.h" +#endif + + +// DO NOT MODIFY THIS LINE. +#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L) + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_EXAMPELS_H definition + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h new file mode 100644 index 0000000..65bfb6c --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h @@ -0,0 +1,87 @@ +// TI File $Revision: /main/7 $ +// Checkin $Date: July 9, 2009 13:14:00 $ +//########################################################################### +// +// FILE: DSP281x_GlobalPrototypes.h +// +// TITLE: Global prototypes for DSP28 Examples +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_GLOBALPROTOTYPES_H +#define DSP281x_GLOBALPROTOTYPES_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/*---- shared global function prototypes -----------------------------------*/ +extern void InitAdc(void); +extern void InitPeripherals(void); +extern void InitECan(void); +extern void InitEv(void); +extern void InitGpio(void); +extern void InitMcbsp(void); +extern void InitPieCtrl(void); +extern void InitPieVectTable(void); +extern void EnableInterrupts(void); +extern void DisableInterrupts(void); +extern void InitSci(void); +extern void InitSpi(void); +extern void InitSysCtrl(void); +extern void InitXintf(void); +extern void InitXIntrupt(void); +extern void InitPll(Uint16 val); +extern void InitPeripheralClocks(void); + +// McBSP functions +// DSP281x_Mcbsp.c +extern void InitMcbspGpio(void); +extern void delay_loop(void); +extern void InitMcbspa8bit(void); +extern void InitMcbspa12bit(void); +extern void InitMcbspa16bit(void); +extern void InitMcbspa20bit(void); +extern void InitMcbspa24bit(void); +extern void InitMcbspa32bit(void); + +// Watchdog functions +// DSP28_SysCtrl.c +extern void KickDog(void); +extern void DisableDog(void); +extern Uint16 CsmUnlock(void); + +// DSP28_DBGIER.asm +extern void SetDBGIER(Uint16 dbgier); + +// DSP281x_usDelay.asm +extern void DSP28x_usDelay(Uint32 Count); + + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results +extern void InitFlash(void); + + +void MemCopy(Uint16 *SourceAddr, Uint16* SourceEndAddr, Uint16* DestAddr); + + +//--------------------------------------------------------------------------- +// External symbols created by the linker cmd file +// DSP28 examples will use these to relocate code from one LOAD location +// in either Flash or XINTF to a different RUN location in internal +// RAM +extern Uint16 RamfuncsLoadStart; +extern Uint16 RamfuncsLoadEnd; +extern Uint16 RamfuncsRunStart; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // - end of DSP281x_GLOBALPROTOTYPES_H + diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h new file mode 100644 index 0000000..7495566 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h @@ -0,0 +1,5881 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 15:22:36 $ +//########################################################################### +// +// FILE: DSP281x_SWPrioritizedIsrLevels.h +// +// TITLE: DSP28 Devices Software Prioritized Interrupt Service Routine +// Level definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SW_PRIORITZIED_ISR_H +#define DSP281x_SW_PRIORITZIED_ISR_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//------------------------------------------------------------------------------- +// Interrupt Enable Register Allocation For F2810/12 Devices: +//------------------------------------------------------------------------------- +// Interrupts can be enabled/disabled using the CPU interrupt enable register +// (IER) and the PIE interrupt enable registers (PIIER1 to PIEIER12). The table +// below lists the allocation of the various interrupts to these registers: +// +//----------------------------------------------------------------------------------- +// CPU | PIEIER1 to PIEIER12 | +// IER | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +// =====|=========|=========|=========|=========|=========|=========|=======|=======| +// INT1 |PDPINTA |PDPINTB | resvd | XINT1 | XINT2 |ADCINT | TINT0 |WAKEINT| +// | (EV-A) | (EV-B) | | | | | | | +// INT2 |CMP1INT |CMP2INT |CMP3INT |T1PINT |T1CINT |T1UFINT |T1OFINT| resvd | +// | (EV-A) | (EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) | | +// INT3 |T2PINT |T2CINT |T2UFINT |T2OFINT |CAPINT1 |CAPINT2 |CAPINT3| resvd | +// | (EV-A) | (EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) | | +// INT4 |CMP4INT |CMP5INT |CMP6INT |T3PINT |T3CINT |T3UFINT |T3OFINT| resvd | +// | (EV-B) | (EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) | | +// INT5 |T4PINT |T4CINT |T4UFINT |T4OFINT |CAPINT4 |CAPINT5 |CAPINT6| resvd | +// | (EV-B) | (EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) | | +// INT6 |SPIRXINTA|SPITXINTA| resvd | resvd | MRINTA | MXINTA | resvd | resvd | +// | (SPI-A) | (SPI-A) | | |(McBSP-A)|(McBSP-A)| | | +// INT7 | resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT8 | resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT9 |SCIRXINTA|SCITXINTA|SCIRXINTB|SCITXINTB|ECAN0INTA|ECAN1INTA| resvd | resvd | +// | (SCI-A) | (SCI-A) |(SCI-B) |(SCI-B) |(ECAN-A) |(ECAN-A) | | | +// INT10| resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT11| resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT12| resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +//------------------------------------------------------------------------------- +// INT13| INT13 +// INT14| INT14 +// INT15| DATALOG +// INT16| RTOSINT +//------------------------------------------------------------------------------- +// +//------------------------------------------------------------------------------- +// Set "Global" Interrupt Priority Level (IER register): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the CPU +// interrupts. This is termed as the "global" priority. The priority level +// must be a number between 1 (highest) to 16 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used. +// +// Note: The priority levels below are used to calculate the IER register +// interrupt masks MINT1 to MINT16. +// +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 16 = lowest priority +#define INT1PL 1 // Group1 Interrupts (PIEIER1) +#define INT2PL 4 // Group2 Interrupts (PIEIER2) +#define INT3PL 2 // Group3 Interrupts (PIEIER3) +#define INT4PL 4 // Group4 Interrupts (PIEIER4) +#define INT5PL 5 // Group5 Interrupts (PIEIER5) +#define INT6PL 3 // Group6 Interrupts (PIEIER6) +#define INT7PL 0 // reserved +#define INT8PL 0 // reserved +#define INT9PL 3 // Group9 Interrupts (PIEIER9) +#define INT10PL 0 // reserved +#define INT11PL 0 // reserved +#define INT12PL 0 // reserved +#define INT13PL 4 // XINT3 +#define INT14PL 4 // INT14 (TINT2) +#define INT15PL 4 // DATALOG +#define INT16PL 4 // RTOSINT + +//------------------------------------------------------------------------------- +// Set "Group" Interrupt Priority Level (PIEIER1 to PIEIER12 registers): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the PIE +// interrupts. This is termed as the "group" priority. The priority level +// must be a number between 1 (highest) to 8 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used: +// +// Note: The priority levels below are used to calculate the following +// PIEIER register interrupt masks: +// MG11 to MG18 +// MG21 to MG28 +// MG31 to MG38 +// MG41 to MG48 +// MG51 to MG58 +// MG61 to MG68 +// MG71 to MG78 +// MG81 to MG88 +// MG91 to MG98 +// MG101 to MG108 +// MG111 to MG118 +// MG121 to MG128 +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 8 = lowest priority +// +#define G11PL 7 // PDPINTA (EV-A) +#define G12PL 6 // PDPINTB (EV-B) +#define G13PL 0 // reserved +#define G14PL 1 // XINT1 (External) +#define G15PL 3 // XINT2 (External) +#define G16PL 2 // ADCINT (ADC) +#define G17PL 1 // TINT0 (CPU Timer 0) +#define G18PL 5 // WAKEINT (WD/LPM) + +#define G21PL 4 // CMP1INT (EV-A) +#define G22PL 3 // CMP2INT (EV-A) +#define G23PL 2 // CMP3INT (EV-A) +#define G24PL 1 // T1PINT (EV-A) +#define G25PL 5 // T1CINT (EV-A) +#define G26PL 6 // T1UFINT (EV-A) +#define G27PL 7 // T1OFINT (EV-A) +#define G28PL 0 // reserved + +#define G31PL 1 // T2PINT (EV-A) +#define G32PL 1 // T2CINT (EV-A) +#define G33PL 1 // T2UFINT (EV-A) +#define G34PL 2 // T2OFINT (EV-A) +#define G35PL 2 // CAPINT1 (EV-A) +#define G36PL 1 // CAPINT2 (EV-A) +#define G37PL 3 // CAPINT3 (EV-A) +#define G38PL 0 // reserved + +#define G41PL 2 // CMP4INT (EV-B) +#define G42PL 1 // CMP5INT (EV-B) +#define G43PL 3 // CMP6INT (EV-B) +#define G44PL 3 // T3PINT (EV-B) +#define G45PL 2 // T3CINT (EV-B) +#define G46PL 2 // T3UFINT (EV-B) +#define G47PL 1 // T3OFINT (EV-B) +#define G48PL 0 // reserved + +#define G51PL 1 // T4PINT (EV-B) +#define G52PL 7 // T4CINT (EV-B) +#define G53PL 2 // T4UFINT (EV-B) +#define G54PL 6 // T4OFINT (EV-B) +#define G55PL 5 // CAPINT4 (EV-B) +#define G56PL 6 // CAPINT5 (EV-B) +#define G57PL 7 // CAPINT6 (EV-B) +#define G58PL 0 // reserved + +#define G61PL 3 // SPIRXINTA (SPI-A) +#define G62PL 1 // SPITXINTA (SPI-A) +#define G63PL 0 // reserved +#define G64PL 0 // reserved +#define G65PL 2 // MRINTA (McBSP-A) +#define G66PL 1 // MXINTA (McBSP-A) +#define G67PL 0 // reserved +#define G68PL 0 // reserved + +#define G71PL 0 // reserved +#define G72PL 0 // reserved +#define G73PL 0 // reserved +#define G74PL 0 // reserved +#define G75PL 0 // reserved +#define G76PL 0 // reserved +#define G77PL 0 // reserved +#define G78PL 0 // reserved + +#define G81PL 0 // reserved +#define G82PL 0 // reserved +#define G83PL 0 // reserved +#define G84PL 0 // reserved +#define G85PL 0 // reserved +#define G86PL 0 // reserved +#define G87PL 0 // reserved +#define G88PL 0 // reserved + +#define G91PL 1 // SCIRXINTA (SCI-A) +#define G92PL 5 // SCITXINTA (SCI-A) +#define G93PL 3 // SCIRXINTB (SCI-B) +#define G94PL 4 // SCITXINTB (SCI-B) +#define G95PL 1 // ECAN0INTA (ECAN-A) +#define G96PL 1 // ECAN1INTA (ECAN-A) +#define G97PL 0 // reserved +#define G98PL 0 // reserved + +#define G101PL 0 // reserved +#define G102PL 0 // reserved +#define G103PL 0 // reserved +#define G104PL 0 // reserved +#define G105PL 0 // reserved +#define G106PL 0 // reserved +#define G107PL 0 // reserved +#define G108PL 0 // reserved + +#define G111PL 0 // reserved +#define G112PL 0 // reserved +#define G113PL 0 // reserved +#define G114PL 0 // reserved +#define G115PL 0 // reserved +#define G116PL 0 // reserved +#define G117PL 0 // reserved +#define G118PL 0 // reserved + +#define G121PL 0 // reserved +#define G122PL 0 // reserved +#define G123PL 0 // reserved +#define G124PL 0 // reserved +#define G125PL 0 // reserved +#define G126PL 0 // reserved +#define G127PL 0 // reserved +#define G128PL 0 // reserved + + +// There should be no need to modify code below this line +//------------------------------------------------------------------------------- +// Automatically generate IER interrupt masks MINT1 to MINT16: +// + +// Beginning of MINT1: +#if (INT1PL == 0) +#define MINT1_1PL ~(1 << 0) +#else +#define MINT1_1PL 0xFFFF +#endif + +#if (INT2PL >= INT1PL) || (INT2PL == 0) +#define MINT1_2PL ~(1 << 1) +#else +#define MINT1_2PL 0xFFFF +#endif + +#if (INT3PL >= INT1PL) || (INT3PL == 0) +#define MINT1_3PL ~(1 << 2) +#else +#define MINT1_3PL 0xFFFF +#endif + +#if (INT4PL >= INT1PL) || (INT4PL == 0) +#define MINT1_4PL ~(1 << 3) +#else +#define MINT1_4PL 0xFFFF +#endif + +#if (INT5PL >= INT1PL) || (INT5PL == 0) +#define MINT1_5PL ~(1 << 4) +#else +#define MINT1_5PL 0xFFFF +#endif + +#if (INT6PL >= INT1PL) || (INT6PL == 0) +#define MINT1_6PL ~(1 << 5) +#else +#define MINT1_6PL 0xFFFF +#endif + +#if (INT7PL >= INT1PL) || (INT7PL == 0) +#define MINT1_7PL ~(1 << 6) +#else +#define MINT1_7PL 0xFFFF +#endif + +#if (INT8PL >= INT1PL) || (INT8PL == 0) +#define MINT1_8PL ~(1 << 7) +#else +#define MINT1_8PL 0xFFFF +#endif + +#if (INT9PL >= INT1PL) || (INT9PL == 0) +#define MINT1_9PL ~(1 << 8) +#else +#define MINT1_9PL 0xFFFF +#endif + +#if (INT10PL >= INT1PL) || (INT10PL == 0) +#define MINT1_10PL ~(1 << 9) +#else +#define MINT1_10PL 0xFFFF +#endif + +#if (INT11PL >= INT1PL) || (INT11PL == 0) +#define MINT1_11PL ~(1 << 10) +#else +#define MINT1_11PL 0xFFFF +#endif + +#if (INT12PL >= INT1PL) || (INT12PL == 0) +#define MINT1_12PL ~(1 << 11) +#else +#define MINT1_12PL 0xFFFF +#endif + +#if (INT13PL >= INT1PL) || (INT13PL == 0) +#define MINT1_13PL ~(1 << 12) +#else +#define MINT1_13PL 0xFFFF +#endif + +#if (INT14PL >= INT1PL) || (INT14PL == 0) +#define MINT1_14PL ~(1 << 13) +#else +#define MINT1_14PL 0xFFFF +#endif + +#if (INT15PL >= INT1PL) || (INT15PL == 0) +#define MINT1_15PL ~(1 << 14) +#else +#define MINT1_15PL 0xFFFF +#endif + +#if (INT16PL >= INT1PL) || (INT16PL == 0) +#define MINT1_16PL ~(1 << 15) +#else +#define MINT1_16PL 0xFFFF +#endif + +#define MINT1 (MINT1_1PL & MINT1_2PL & MINT1_3PL & MINT1_4PL & \ + MINT1_5PL & MINT1_6PL & MINT1_7PL & MINT1_8PL & \ + MINT1_9PL & MINT1_10PL & MINT1_11PL & MINT1_12PL & \ + MINT1_13PL & MINT1_14PL & MINT1_15PL & MINT1_16PL) +// End Of MINT1. + +// Beginning of MINT2: +#if (INT1PL >= INT2PL) || (INT1PL == 0) +#define MINT2_1PL ~(1 << 0) +#else +#define MINT2_1PL 0xFFFF +#endif + +#if (INT2PL == 0) +#define MINT2_2PL ~(1 << 1) +#else +#define MINT2_2PL 0xFFFF +#endif + +#if (INT3PL >= INT2PL) || (INT3PL == 0) +#define MINT2_3PL ~(1 << 2) +#else +#define MINT2_3PL 0xFFFF +#endif + +#if (INT4PL >= INT2PL) || (INT4PL == 0) +#define MINT2_4PL ~(1 << 3) +#else +#define MINT2_4PL 0xFFFF +#endif + +#if (INT5PL >= INT2PL) || (INT5PL == 0) +#define MINT2_5PL ~(1 << 4) +#else +#define MINT2_5PL 0xFFFF +#endif + +#if (INT6PL >= INT2PL) || (INT6PL == 0) +#define MINT2_6PL ~(1 << 5) +#else +#define MINT2_6PL 0xFFFF +#endif + +#if (INT7PL >= INT2PL) || (INT7PL == 0) +#define MINT2_7PL ~(1 << 6) +#else +#define MINT2_7PL 0xFFFF +#endif + +#if (INT8PL >= INT2PL) || (INT8PL == 0) +#define MINT2_8PL ~(1 << 7) +#else +#define MINT2_8PL 0xFFFF +#endif + +#if (INT9PL >= INT2PL) || (INT9PL == 0) +#define MINT2_9PL ~(1 << 8) +#else +#define MINT2_9PL 0xFFFF +#endif + +#if (INT10PL >= INT2PL) || (INT10PL == 0) +#define MINT2_10PL ~(1 << 9) +#else +#define MINT2_10PL 0xFFFF +#endif + +#if (INT11PL >= INT2PL) || (INT11PL == 0) +#define MINT2_11PL ~(1 << 10) +#else +#define MINT2_11PL 0xFFFF +#endif + +#if (INT12PL >= INT2PL) || (INT12PL == 0) +#define MINT2_12PL ~(1 << 11) +#else +#define MINT2_12PL 0xFFFF +#endif + +#if (INT13PL >= INT2PL) || (INT13PL == 0) +#define MINT2_13PL ~(1 << 12) +#else +#define MINT2_13PL 0xFFFF +#endif + +#if (INT14PL >= INT2PL) || (INT14PL == 0) +#define MINT2_14PL ~(1 << 13) +#else +#define MINT2_14PL 0xFFFF +#endif + +#if (INT15PL >= INT2PL) || (INT15PL == 0) +#define MINT2_15PL ~(1 << 14) +#else +#define MINT2_15PL 0xFFFF +#endif + +#if (INT16PL >= INT2PL) || (INT16PL == 0) +#define MINT2_16PL ~(1 << 15) +#else +#define MINT2_16PL 0xFFFF +#endif + +#define MINT2 (MINT2_1PL & MINT2_2PL & MINT2_3PL & MINT2_4PL & \ + MINT2_5PL & MINT2_6PL & MINT2_7PL & MINT2_8PL & \ + MINT2_9PL & MINT2_10PL & MINT2_11PL & MINT2_12PL & \ + MINT2_13PL & MINT2_14PL & MINT2_15PL & MINT2_16PL) +// End Of MINT2. + +// Beginning of MINT3: +#if (INT1PL >= INT3PL) || (INT1PL == 0) +#define MINT3_1PL ~(1 << 0) +#else +#define MINT3_1PL 0xFFFF +#endif + +#if (INT2PL >= INT3PL) || (INT2PL == 0) +#define MINT3_2PL ~(1 << 1) +#else +#define MINT3_2PL 0xFFFF +#endif + +#if (INT3PL == 0) +#define MINT3_3PL ~(1 << 2) +#else +#define MINT3_3PL 0xFFFF +#endif + +#if (INT4PL >= INT3PL) || (INT4PL == 0) +#define MINT3_4PL ~(1 << 3) +#else +#define MINT3_4PL 0xFFFF +#endif + +#if (INT5PL >= INT3PL) || (INT5PL == 0) +#define MINT3_5PL ~(1 << 4) +#else +#define MINT3_5PL 0xFFFF +#endif + +#if (INT6PL >= INT3PL) || (INT6PL == 0) +#define MINT3_6PL ~(1 << 5) +#else +#define MINT3_6PL 0xFFFF +#endif + +#if (INT7PL >= INT3PL) || (INT7PL == 0) +#define MINT3_7PL ~(1 << 6) +#else +#define MINT3_7PL 0xFFFF +#endif + +#if (INT8PL >= INT3PL) || (INT8PL == 0) +#define MINT3_8PL ~(1 << 7) +#else +#define MINT3_8PL 0xFFFF +#endif + +#if (INT9PL >= INT3PL) || (INT9PL == 0) +#define MINT3_9PL ~(1 << 8) +#else +#define MINT3_9PL 0xFFFF +#endif + +#if (INT10PL >= INT3PL) || (INT10PL == 0) +#define MINT3_10PL ~(1 << 9) +#else +#define MINT3_10PL 0xFFFF +#endif + +#if (INT11PL >= INT3PL) || (INT11PL == 0) +#define MINT3_11PL ~(1 << 10) +#else +#define MINT3_11PL 0xFFFF +#endif + +#if (INT12PL >= INT3PL) || (INT12PL == 0) +#define MINT3_12PL ~(1 << 11) +#else +#define MINT3_12PL 0xFFFF +#endif + +#if (INT13PL >= INT3PL) || (INT13PL == 0) +#define MINT3_13PL ~(1 << 12) +#else +#define MINT3_13PL 0xFFFF +#endif + +#if (INT14PL >= INT3PL) || (INT14PL == 0) +#define MINT3_14PL ~(1 << 13) +#else +#define MINT3_14PL 0xFFFF +#endif + +#if (INT15PL >= INT3PL) || (INT15PL == 0) +#define MINT3_15PL ~(1 << 14) +#else +#define MINT3_15PL 0xFFFF +#endif + +#if (INT16PL >= INT3PL) || (INT16PL == 0) +#define MINT3_16PL ~(1 << 15) +#else +#define MINT3_16PL 0xFFFF +#endif + +#define MINT3 (MINT3_1PL & MINT3_2PL & MINT3_3PL & MINT3_4PL & \ + MINT3_5PL & MINT3_6PL & MINT3_7PL & MINT3_8PL & \ + MINT3_9PL & MINT3_10PL & MINT3_11PL & MINT3_12PL & \ + MINT3_13PL & MINT3_14PL & MINT3_15PL & MINT3_16PL) +// End Of MINT3. + +// Beginning of MINT4: +#if (INT1PL >= INT4PL) || (INT1PL == 0) +#define MINT4_1PL ~(1 << 0) +#else +#define MINT4_1PL 0xFFFF +#endif + +#if (INT2PL >= INT4PL) || (INT2PL == 0) +#define MINT4_2PL ~(1 << 1) +#else +#define MINT4_2PL 0xFFFF +#endif + +#if (INT3PL >= INT4PL) || (INT3PL == 0) +#define MINT4_3PL ~(1 << 2) +#else +#define MINT4_3PL 0xFFFF +#endif + +#if (INT4PL == 0) +#define MINT4_4PL ~(1 << 3) +#else +#define MINT4_4PL 0xFFFF +#endif + +#if (INT5PL >= INT4PL) || (INT5PL == 0) +#define MINT4_5PL ~(1 << 4) +#else +#define MINT4_5PL 0xFFFF +#endif + +#if (INT6PL >= INT4PL) || (INT6PL == 0) +#define MINT4_6PL ~(1 << 5) +#else +#define MINT4_6PL 0xFFFF +#endif + +#if (INT7PL >= INT4PL) || (INT7PL == 0) +#define MINT4_7PL ~(1 << 6) +#else +#define MINT4_7PL 0xFFFF +#endif + +#if (INT8PL >= INT4PL) || (INT8PL == 0) +#define MINT4_8PL ~(1 << 7) +#else +#define MINT4_8PL 0xFFFF +#endif + +#if (INT9PL >= INT4PL) || (INT9PL == 0) +#define MINT4_9PL ~(1 << 8) +#else +#define MINT4_9PL 0xFFFF +#endif + +#if (INT10PL >= INT4PL) || (INT10PL == 0) +#define MINT4_10PL ~(1 << 9) +#else +#define MINT4_10PL 0xFFFF +#endif + +#if (INT11PL >= INT4PL) || (INT11PL == 0) +#define MINT4_11PL ~(1 << 10) +#else +#define MINT4_11PL 0xFFFF +#endif + +#if (INT12PL >= INT4PL) || (INT12PL == 0) +#define MINT4_12PL ~(1 << 11) +#else +#define MINT4_12PL 0xFFFF +#endif + +#if (INT13PL >= INT4PL) || (INT13PL == 0) +#define MINT4_13PL ~(1 << 12) +#else +#define MINT4_13PL 0xFFFF +#endif + +#if (INT14PL >= INT4PL) || (INT14PL == 0) +#define MINT4_14PL ~(1 << 13) +#else +#define MINT4_14PL 0xFFFF +#endif + +#if (INT15PL >= INT4PL) || (INT15PL == 0) +#define MINT4_15PL ~(1 << 14) +#else +#define MINT4_15PL 0xFFFF +#endif + +#if (INT16PL >= INT4PL) || (INT16PL == 0) +#define MINT4_16PL ~(1 << 15) +#else +#define MINT4_16PL 0xFFFF +#endif + +#define MINT4 (MINT4_1PL & MINT4_2PL & MINT4_3PL & MINT4_4PL & \ + MINT4_5PL & MINT4_6PL & MINT4_7PL & MINT4_8PL & \ + MINT4_9PL & MINT4_10PL & MINT4_11PL & MINT4_12PL & \ + MINT4_13PL & MINT4_14PL & MINT4_15PL & MINT4_16PL) +// End Of MINT4. + +// Beginning of MINT5: +#if (INT1PL >= INT5PL) || (INT1PL == 0) +#define MINT5_1PL ~(1 << 0) +#else +#define MINT5_1PL 0xFFFF +#endif + +#if (INT2PL >= INT5PL) || (INT2PL == 0) +#define MINT5_2PL ~(1 << 1) +#else +#define MINT5_2PL 0xFFFF +#endif + +#if (INT3PL >= INT5PL) || (INT3PL == 0) +#define MINT5_3PL ~(1 << 2) +#else +#define MINT5_3PL 0xFFFF +#endif + +#if (INT4PL >= INT5PL) || (INT4PL == 0) +#define MINT5_4PL ~(1 << 3) +#else +#define MINT5_4PL 0xFFFF +#endif + +#if (INT5PL == 0) +#define MINT5_5PL ~(1 << 4) +#else +#define MINT5_5PL 0xFFFF +#endif + +#if (INT6PL >= INT5PL) || (INT6PL == 0) +#define MINT5_6PL ~(1 << 5) +#else +#define MINT5_6PL 0xFFFF +#endif + +#if (INT7PL >= INT5PL) || (INT7PL == 0) +#define MINT5_7PL ~(1 << 6) +#else +#define MINT5_7PL 0xFFFF +#endif + +#if (INT8PL >= INT5PL) || (INT8PL == 0) +#define MINT5_8PL ~(1 << 7) +#else +#define MINT5_8PL 0xFFFF +#endif + +#if (INT9PL >= INT5PL) || (INT9PL == 0) +#define MINT5_9PL ~(1 << 8) +#else +#define MINT5_9PL 0xFFFF +#endif + +#if (INT10PL >= INT5PL) || (INT10PL == 0) +#define MINT5_10PL ~(1 << 9) +#else +#define MINT5_10PL 0xFFFF +#endif + +#if (INT11PL >= INT5PL) || (INT11PL == 0) +#define MINT5_11PL ~(1 << 10) +#else +#define MINT5_11PL 0xFFFF +#endif + +#if (INT12PL >= INT5PL) || (INT12PL == 0) +#define MINT5_12PL ~(1 << 11) +#else +#define MINT5_12PL 0xFFFF +#endif + +#if (INT13PL >= INT5PL) || (INT13PL == 0) +#define MINT5_13PL ~(1 << 12) +#else +#define MINT5_13PL 0xFFFF +#endif + +#if (INT14PL >= INT5PL) || (INT14PL == 0) +#define MINT5_14PL ~(1 << 13) +#else +#define MINT5_14PL 0xFFFF +#endif + +#if (INT15PL >= INT5PL) || (INT15PL == 0) +#define MINT5_15PL ~(1 << 14) +#else +#define MINT5_15PL 0xFFFF +#endif + +#if (INT16PL >= INT5PL) || (INT16PL == 0) +#define MINT5_16PL ~(1 << 15) +#else +#define MINT5_16PL 0xFFFF +#endif + +#define MINT5 (MINT5_1PL & MINT5_2PL & MINT5_3PL & MINT5_4PL & \ + MINT5_5PL & MINT5_6PL & MINT5_7PL & MINT5_8PL & \ + MINT5_9PL & MINT5_10PL & MINT5_11PL & MINT5_12PL & \ + MINT5_13PL & MINT5_14PL & MINT5_15PL & MINT5_16PL) +// End Of MINT5. + +// Beginning of MINT6: +#if (INT1PL >= INT6PL) || (INT1PL == 0) +#define MINT6_1PL ~(1 << 0) +#else +#define MINT6_1PL 0xFFFF +#endif + +#if (INT2PL >= INT6PL) || (INT2PL == 0) +#define MINT6_2PL ~(1 << 1) +#else +#define MINT6_2PL 0xFFFF +#endif + +#if (INT3PL >= INT6PL) || (INT3PL == 0) +#define MINT6_3PL ~(1 << 2) +#else +#define MINT6_3PL 0xFFFF +#endif + +#if (INT4PL >= INT6PL) || (INT4PL == 0) +#define MINT6_4PL ~(1 << 3) +#else +#define MINT6_4PL 0xFFFF +#endif + +#if (INT5PL >= INT6PL) || (INT5PL == 0) +#define MINT6_5PL ~(1 << 4) +#else +#define MINT6_5PL 0xFFFF +#endif + +#if (INT6PL == 0) +#define MINT6_6PL ~(1 << 5) +#else +#define MINT6_6PL 0xFFFF +#endif + +#if (INT7PL >= INT6PL) || (INT7PL == 0) +#define MINT6_7PL ~(1 << 6) +#else +#define MINT6_7PL 0xFFFF +#endif + +#if (INT8PL >= INT6PL) || (INT8PL == 0) +#define MINT6_8PL ~(1 << 7) +#else +#define MINT6_8PL 0xFFFF +#endif + +#if (INT9PL >= INT6PL) || (INT9PL == 0) +#define MINT6_9PL ~(1 << 8) +#else +#define MINT6_9PL 0xFFFF +#endif + +#if (INT10PL >= INT6PL) || (INT10PL == 0) +#define MINT6_10PL ~(1 << 9) +#else +#define MINT6_10PL 0xFFFF +#endif + +#if (INT11PL >= INT6PL) || (INT11PL == 0) +#define MINT6_11PL ~(1 << 10) +#else +#define MINT6_11PL 0xFFFF +#endif + +#if (INT12PL >= INT6PL) || (INT12PL == 0) +#define MINT6_12PL ~(1 << 11) +#else +#define MINT6_12PL 0xFFFF +#endif + +#if (INT13PL >= INT6PL) || (INT13PL == 0) +#define MINT6_13PL ~(1 << 12) +#else +#define MINT6_13PL 0xFFFF +#endif + +#if (INT14PL >= INT6PL) || (INT14PL == 0) +#define MINT6_14PL ~(1 << 13) +#else +#define MINT6_14PL 0xFFFF +#endif + +#if (INT15PL >= INT6PL) || (INT15PL == 0) +#define MINT6_15PL ~(1 << 14) +#else +#define MINT6_15PL 0xFFFF +#endif + +#if (INT16PL >= INT6PL) || (INT16PL == 0) +#define MINT6_16PL ~(1 << 15) +#else +#define MINT6_16PL 0xFFFF +#endif + +#define MINT6 (MINT6_1PL & MINT6_2PL & MINT6_3PL & MINT6_4PL & \ + MINT6_5PL & MINT6_6PL & MINT6_7PL & MINT6_8PL & \ + MINT6_9PL & MINT6_10PL & MINT6_11PL & MINT6_12PL & \ + MINT6_13PL & MINT6_14PL & MINT6_15PL & MINT6_16PL) +// End Of MINT6. + +// Beginning of MINT7: +#if (INT1PL >= INT7PL) || (INT1PL == 0) +#define MINT7_1PL ~(1 << 0) +#else +#define MINT7_1PL 0xFFFF +#endif + +#if (INT2PL >= INT7PL) || (INT2PL == 0) +#define MINT7_2PL ~(1 << 1) +#else +#define MINT7_2PL 0xFFFF +#endif + +#if (INT3PL >= INT7PL) || (INT3PL == 0) +#define MINT7_3PL ~(1 << 2) +#else +#define MINT7_3PL 0xFFFF +#endif + +#if (INT4PL >= INT7PL) || (INT4PL == 0) +#define MINT7_4PL ~(1 << 3) +#else +#define MINT7_4PL 0xFFFF +#endif + +#if (INT5PL >= INT7PL) || (INT5PL == 0) +#define MINT7_5PL ~(1 << 4) +#else +#define MINT7_5PL 0xFFFF +#endif + +#if (INT6PL >= INT7PL) || (INT6PL == 0) +#define MINT7_6PL ~(1 << 5) +#else +#define MINT7_6PL 0xFFFF +#endif + +#if (INT7PL == 0) +#define MINT7_7PL ~(1 << 6) +#else +#define MINT7_7PL 0xFFFF +#endif + +#if (INT8PL >= INT7PL) || (INT8PL == 0) +#define MINT7_8PL ~(1 << 7) +#else +#define MINT7_8PL 0xFFFF +#endif + +#if (INT9PL >= INT7PL) || (INT9PL == 0) +#define MINT7_9PL ~(1 << 8) +#else +#define MINT7_9PL 0xFFFF +#endif + +#if (INT10PL >= INT7PL) || (INT10PL == 0) +#define MINT7_10PL ~(1 << 9) +#else +#define MINT7_10PL 0xFFFF +#endif + +#if (INT11PL >= INT7PL) || (INT11PL == 0) +#define MINT7_11PL ~(1 << 10) +#else +#define MINT7_11PL 0xFFFF +#endif + +#if (INT12PL >= INT7PL) || (INT12PL == 0) +#define MINT7_12PL ~(1 << 11) +#else +#define MINT7_12PL 0xFFFF +#endif + +#if (INT13PL >= INT7PL) || (INT13PL == 0) +#define MINT7_13PL ~(1 << 12) +#else +#define MINT7_13PL 0xFFFF +#endif + +#if (INT14PL >= INT7PL) || (INT14PL == 0) +#define MINT7_14PL ~(1 << 13) +#else +#define MINT7_14PL 0xFFFF +#endif + +#if (INT15PL >= INT7PL) || (INT15PL == 0) +#define MINT7_15PL ~(1 << 14) +#else +#define MINT7_15PL 0xFFFF +#endif + +#if (INT16PL >= INT7PL) || (INT16PL == 0) +#define MINT7_16PL ~(1 << 15) +#else +#define MINT7_16PL 0xFFFF +#endif + +#define MINT7 (MINT7_1PL & MINT7_2PL & MINT7_3PL & MINT7_4PL & \ + MINT7_5PL & MINT7_6PL & MINT7_7PL & MINT7_8PL & \ + MINT7_9PL & MINT7_10PL & MINT7_11PL & MINT7_12PL & \ + MINT7_13PL & MINT7_14PL & MINT7_15PL & MINT7_16PL) +// End Of MINT7. + +// Beginning of MINT8: +#if (INT1PL >= INT8PL) || (INT1PL == 0) +#define MINT8_1PL ~(1 << 0) +#else +#define MINT8_1PL 0xFFFF +#endif + +#if (INT2PL >= INT8PL) || (INT2PL == 0) +#define MINT8_2PL ~(1 << 1) +#else +#define MINT8_2PL 0xFFFF +#endif + +#if (INT3PL >= INT8PL) || (INT3PL == 0) +#define MINT8_3PL ~(1 << 2) +#else +#define MINT8_3PL 0xFFFF +#endif + +#if (INT4PL >= INT8PL) || (INT4PL == 0) +#define MINT8_4PL ~(1 << 3) +#else +#define MINT8_4PL 0xFFFF +#endif + +#if (INT5PL >= INT8PL) || (INT5PL == 0) +#define MINT8_5PL ~(1 << 4) +#else +#define MINT8_5PL 0xFFFF +#endif + +#if (INT6PL >= INT8PL) || (INT6PL == 0) +#define MINT8_6PL ~(1 << 5) +#else +#define MINT8_6PL 0xFFFF +#endif + +#if (INT7PL >= INT8PL) || (INT7PL == 0) +#define MINT8_7PL ~(1 << 6) +#else +#define MINT8_7PL 0xFFFF +#endif + +#if (INT8PL == 0) +#define MINT8_8PL ~(1 << 7) +#else +#define MINT8_8PL 0xFFFF +#endif + +#if (INT9PL >= INT8PL) || (INT9PL == 0) +#define MINT8_9PL ~(1 << 8) +#else +#define MINT8_9PL 0xFFFF +#endif + +#if (INT10PL >= INT8PL) || (INT10PL == 0) +#define MINT8_10PL ~(1 << 9) +#else +#define MINT8_10PL 0xFFFF +#endif + +#if (INT11PL >= INT8PL) || (INT11PL == 0) +#define MINT8_11PL ~(1 << 10) +#else +#define MINT8_11PL 0xFFFF +#endif + +#if (INT12PL >= INT8PL) || (INT12PL == 0) +#define MINT8_12PL ~(1 << 11) +#else +#define MINT8_12PL 0xFFFF +#endif + +#if (INT13PL >= INT8PL) || (INT13PL == 0) +#define MINT8_13PL ~(1 << 12) +#else +#define MINT8_13PL 0xFFFF +#endif + +#if (INT14PL >= INT8PL) || (INT14PL == 0) +#define MINT8_14PL ~(1 << 13) +#else +#define MINT8_14PL 0xFFFF +#endif + +#if (INT15PL >= INT8PL) || (INT15PL == 0) +#define MINT8_15PL ~(1 << 14) +#else +#define MINT8_15PL 0xFFFF +#endif + +#if (INT16PL >= INT8PL) || (INT16PL == 0) +#define MINT8_16PL ~(1 << 15) +#else +#define MINT8_16PL 0xFFFF +#endif + +#define MINT8 (MINT8_1PL & MINT8_2PL & MINT8_3PL & MINT8_4PL & \ + MINT8_5PL & MINT8_6PL & MINT8_7PL & MINT8_8PL & \ + MINT8_9PL & MINT8_10PL & MINT8_11PL & MINT8_12PL & \ + MINT8_13PL & MINT8_14PL & MINT8_15PL & MINT8_16PL) +// End Of MINT8. + +// Beginning of MINT9: +#if (INT1PL >= INT9PL) || (INT1PL == 0) +#define MINT9_1PL ~(1 << 0) +#else +#define MINT9_1PL 0xFFFF +#endif + +#if (INT2PL >= INT9PL) || (INT2PL == 0) +#define MINT9_2PL ~(1 << 1) +#else +#define MINT9_2PL 0xFFFF +#endif + +#if (INT3PL >= INT9PL) || (INT3PL == 0) +#define MINT9_3PL ~(1 << 2) +#else +#define MINT9_3PL 0xFFFF +#endif + +#if (INT4PL >= INT9PL) || (INT4PL == 0) +#define MINT9_4PL ~(1 << 3) +#else +#define MINT9_4PL 0xFFFF +#endif + +#if (INT5PL >= INT9PL) || (INT5PL == 0) +#define MINT9_5PL ~(1 << 4) +#else +#define MINT9_5PL 0xFFFF +#endif + +#if (INT6PL >= INT9PL) || (INT6PL == 0) +#define MINT9_6PL ~(1 << 5) +#else +#define MINT9_6PL 0xFFFF +#endif + +#if (INT7PL >= INT9PL) || (INT7PL == 0) +#define MINT9_7PL ~(1 << 6) +#else +#define MINT9_7PL 0xFFFF +#endif + +#if (INT8PL >= INT9PL) || (INT8PL == 0) +#define MINT9_8PL ~(1 << 7) +#else +#define MINT9_8PL 0xFFFF +#endif + +#if (INT9PL == 0) +#define MINT9_9PL ~(1 << 8) +#else +#define MINT9_9PL 0xFFFF +#endif + +#if (INT10PL >= INT9PL) || (INT10PL == 0) +#define MINT9_10PL ~(1 << 9) +#else +#define MINT9_10PL 0xFFFF +#endif + +#if (INT11PL >= INT9PL) || (INT11PL == 0) +#define MINT9_11PL ~(1 << 10) +#else +#define MINT9_11PL 0xFFFF +#endif + +#if (INT12PL >= INT9PL) || (INT12PL == 0) +#define MINT9_12PL ~(1 << 11) +#else +#define MINT9_12PL 0xFFFF +#endif + +#if (INT13PL >= INT9PL) || (INT13PL == 0) +#define MINT9_13PL ~(1 << 12) +#else +#define MINT9_13PL 0xFFFF +#endif + +#if (INT14PL >= INT9PL) || (INT14PL == 0) +#define MINT9_14PL ~(1 << 13) +#else +#define MINT9_14PL 0xFFFF +#endif + +#if (INT15PL >= INT9PL) || (INT15PL == 0) +#define MINT9_15PL ~(1 << 14) +#else +#define MINT9_15PL 0xFFFF +#endif + +#if (INT16PL >= INT9PL) || (INT16PL == 0) +#define MINT9_16PL ~(1 << 15) +#else +#define MINT9_16PL 0xFFFF +#endif + +#define MINT9 (MINT9_1PL & MINT9_2PL & MINT9_3PL & MINT9_4PL & \ + MINT9_5PL & MINT9_6PL & MINT9_7PL & MINT9_8PL & \ + MINT9_9PL & MINT9_10PL & MINT9_11PL & MINT9_12PL & \ + MINT9_13PL & MINT9_14PL & MINT9_15PL & MINT9_16PL) +// End Of MINT9. + +// Beginning of MINT10: +#if (INT1PL >= INT10PL) || (INT1PL == 0) +#define MINT10_1PL ~(1 << 0) +#else +#define MINT10_1PL 0xFFFF +#endif + +#if (INT2PL >= INT10PL) || (INT2PL == 0) +#define MINT10_2PL ~(1 << 1) +#else +#define MINT10_2PL 0xFFFF +#endif + +#if (INT3PL >= INT10PL) || (INT3PL == 0) +#define MINT10_3PL ~(1 << 2) +#else +#define MINT10_3PL 0xFFFF +#endif + +#if (INT4PL >= INT10PL) || (INT4PL == 0) +#define MINT10_4PL ~(1 << 3) +#else +#define MINT10_4PL 0xFFFF +#endif + +#if (INT5PL >= INT10PL) || (INT5PL == 0) +#define MINT10_5PL ~(1 << 4) +#else +#define MINT10_5PL 0xFFFF +#endif + +#if (INT6PL >= INT10PL) || (INT6PL == 0) +#define MINT10_6PL ~(1 << 5) +#else +#define MINT10_6PL 0xFFFF +#endif + +#if (INT7PL >= INT10PL) || (INT7PL == 0) +#define MINT10_7PL ~(1 << 6) +#else +#define MINT10_7PL 0xFFFF +#endif + +#if (INT8PL >= INT10PL) || (INT8PL == 0) +#define MINT10_8PL ~(1 << 7) +#else +#define MINT10_8PL 0xFFFF +#endif + +#if (INT9PL >= INT10PL) || (INT9PL == 0) +#define MINT10_9PL ~(1 << 8) +#else +#define MINT10_9PL 0xFFFF +#endif + +#if (INT10PL == 0) +#define MINT10_10PL ~(1 << 9) +#else +#define MINT10_10PL 0xFFFF +#endif + +#if (INT11PL >= INT10PL) || (INT11PL == 0) +#define MINT10_11PL ~(1 << 10) +#else +#define MINT10_11PL 0xFFFF +#endif + +#if (INT12PL >= INT10PL) || (INT12PL == 0) +#define MINT10_12PL ~(1 << 11) +#else +#define MINT10_12PL 0xFFFF +#endif + +#if (INT13PL >= INT10PL) || (INT13PL == 0) +#define MINT10_13PL ~(1 << 12) +#else +#define MINT10_13PL 0xFFFF +#endif + +#if (INT14PL >= INT10PL) || (INT14PL == 0) +#define MINT10_14PL ~(1 << 13) +#else +#define MINT10_14PL 0xFFFF +#endif + +#if (INT15PL >= INT10PL) || (INT15PL == 0) +#define MINT10_15PL ~(1 << 14) +#else +#define MINT10_15PL 0xFFFF +#endif + +#if (INT16PL >= INT10PL) || (INT16PL == 0) +#define MINT10_16PL ~(1 << 15) +#else +#define MINT10_16PL 0xFFFF +#endif + +#define MINT10 (MINT10_1PL & MINT10_2PL & MINT10_3PL & MINT10_4PL & \ + MINT10_5PL & MINT10_6PL & MINT10_7PL & MINT10_8PL & \ + MINT10_9PL & MINT10_10PL & MINT10_11PL & MINT10_12PL & \ + MINT10_13PL & MINT10_14PL & MINT10_15PL & MINT10_16PL) +// End Of MINT10. + +// Beginning of MINT11: +#if (INT1PL >= INT11PL) || (INT1PL == 0) +#define MINT11_1PL ~(1 << 0) +#else +#define MINT11_1PL 0xFFFF +#endif + +#if (INT2PL >= INT11PL) || (INT2PL == 0) +#define MINT11_2PL ~(1 << 1) +#else +#define MINT11_2PL 0xFFFF +#endif + +#if (INT3PL >= INT11PL) || (INT3PL == 0) +#define MINT11_3PL ~(1 << 2) +#else +#define MINT11_3PL 0xFFFF +#endif + +#if (INT4PL >= INT11PL) || (INT4PL == 0) +#define MINT11_4PL ~(1 << 3) +#else +#define MINT11_4PL 0xFFFF +#endif + +#if (INT5PL >= INT11PL) || (INT5PL == 0) +#define MINT11_5PL ~(1 << 4) +#else +#define MINT11_5PL 0xFFFF +#endif + +#if (INT6PL >= INT11PL) || (INT6PL == 0) +#define MINT11_6PL ~(1 << 5) +#else +#define MINT11_6PL 0xFFFF +#endif + +#if (INT7PL >= INT11PL) || (INT7PL == 0) +#define MINT11_7PL ~(1 << 6) +#else +#define MINT11_7PL 0xFFFF +#endif + +#if (INT8PL >= INT11PL) || (INT8PL == 0) +#define MINT11_8PL ~(1 << 7) +#else +#define MINT11_8PL 0xFFFF +#endif + +#if (INT9PL >= INT11PL) || (INT9PL == 0) +#define MINT11_9PL ~(1 << 8) +#else +#define MINT11_9PL 0xFFFF +#endif + +#if (INT10PL >= INT11PL) || (INT10PL == 0) +#define MINT11_10PL ~(1 << 9) +#else +#define MINT11_10PL 0xFFFF +#endif + +#if (INT11PL == 0) +#define MINT11_11PL ~(1 << 10) +#else +#define MINT11_11PL 0xFFFF +#endif + +#if (INT12PL >= INT11PL) || (INT12PL == 0) +#define MINT11_12PL ~(1 << 11) +#else +#define MINT11_12PL 0xFFFF +#endif + +#if (INT13PL >= INT11PL) || (INT13PL == 0) +#define MINT11_13PL ~(1 << 12) +#else +#define MINT11_13PL 0xFFFF +#endif + +#if (INT14PL >= INT11PL) || (INT14PL == 0) +#define MINT11_14PL ~(1 << 13) +#else +#define MINT11_14PL 0xFFFF +#endif + +#if (INT15PL >= INT11PL) || (INT15PL == 0) +#define MINT11_15PL ~(1 << 14) +#else +#define MINT11_15PL 0xFFFF +#endif + +#if (INT16PL >= INT11PL) || (INT16PL == 0) +#define MINT11_16PL ~(1 << 15) +#else +#define MINT11_16PL 0xFFFF +#endif + +#define MINT11 (MINT11_1PL & MINT11_2PL & MINT11_3PL & MINT11_4PL & \ + MINT11_5PL & MINT11_6PL & MINT11_7PL & MINT11_8PL & \ + MINT11_9PL & MINT11_10PL & MINT11_11PL & MINT11_12PL & \ + MINT11_13PL & MINT11_14PL & MINT11_15PL & MINT11_16PL) +// End Of MINT11. + +// Beginning of MINT12: +#if (INT1PL >= INT12PL) || (INT1PL == 0) +#define MINT12_1PL ~(1 << 0) +#else +#define MINT12_1PL 0xFFFF +#endif + +#if (INT2PL >= INT12PL) || (INT2PL == 0) +#define MINT12_2PL ~(1 << 1) +#else +#define MINT12_2PL 0xFFFF +#endif + +#if (INT3PL >= INT12PL) || (INT3PL == 0) +#define MINT12_3PL ~(1 << 2) +#else +#define MINT12_3PL 0xFFFF +#endif + +#if (INT4PL >= INT12PL) || (INT4PL == 0) +#define MINT12_4PL ~(1 << 3) +#else +#define MINT12_4PL 0xFFFF +#endif + +#if (INT5PL >= INT12PL) || (INT5PL == 0) +#define MINT12_5PL ~(1 << 4) +#else +#define MINT12_5PL 0xFFFF +#endif + +#if (INT6PL >= INT12PL) || (INT6PL == 0) +#define MINT12_6PL ~(1 << 5) +#else +#define MINT12_6PL 0xFFFF +#endif + +#if (INT7PL >= INT12PL) || (INT7PL == 0) +#define MINT12_7PL ~(1 << 6) +#else +#define MINT12_7PL 0xFFFF +#endif + +#if (INT8PL >= INT12PL) || (INT8PL == 0) +#define MINT12_8PL ~(1 << 7) +#else +#define MINT12_8PL 0xFFFF +#endif + +#if (INT9PL >= INT12PL) || (INT9PL == 0) +#define MINT12_9PL ~(1 << 8) +#else +#define MINT12_9PL 0xFFFF +#endif + +#if (INT10PL >= INT12PL) || (INT10PL == 0) +#define MINT12_10PL ~(1 << 9) +#else +#define MINT12_10PL 0xFFFF +#endif + +#if (INT11PL >= INT12PL) || (INT11PL == 0) +#define MINT12_11PL ~(1 << 10) +#else +#define MINT12_11PL 0xFFFF +#endif + +#if (INT12PL == 0) +#define MINT12_12PL ~(1 << 11) +#else +#define MINT12_12PL 0xFFFF +#endif + +#if (INT13PL >= INT12PL) || (INT13PL == 0) +#define MINT12_13PL ~(1 << 12) +#else +#define MINT12_13PL 0xFFFF +#endif + +#if (INT14PL >= INT12PL) || (INT14PL == 0) +#define MINT12_14PL ~(1 << 13) +#else +#define MINT12_14PL 0xFFFF +#endif + +#if (INT15PL >= INT12PL) || (INT15PL == 0) +#define MINT12_15PL ~(1 << 14) +#else +#define MINT12_15PL 0xFFFF +#endif + +#if (INT16PL >= INT12PL) || (INT16PL == 0) +#define MINT12_16PL ~(1 << 15) +#else +#define MINT12_16PL 0xFFFF +#endif + +#define MINT12 (MINT12_1PL & MINT12_2PL & MINT12_3PL & MINT12_4PL & \ + MINT12_5PL & MINT12_6PL & MINT12_7PL & MINT12_8PL & \ + MINT12_9PL & MINT12_10PL & MINT12_11PL & MINT12_12PL & \ + MINT12_13PL & MINT12_14PL & MINT12_15PL & MINT12_16PL) +// End Of MINT12. + +// Beginning of MINT13: +#if (INT1PL >= INT13PL) || (INT1PL == 0) +#define MINT13_1PL ~(1 << 0) +#else +#define MINT13_1PL 0xFFFF +#endif + +#if (INT2PL >= INT13PL) || (INT2PL == 0) +#define MINT13_2PL ~(1 << 1) +#else +#define MINT13_2PL 0xFFFF +#endif + +#if (INT3PL >= INT13PL) || (INT3PL == 0) +#define MINT13_3PL ~(1 << 2) +#else +#define MINT13_3PL 0xFFFF +#endif + +#if (INT4PL >= INT13PL) || (INT4PL == 0) +#define MINT13_4PL ~(1 << 3) +#else +#define MINT13_4PL 0xFFFF +#endif + +#if (INT5PL >= INT13PL) || (INT5PL == 0) +#define MINT13_5PL ~(1 << 4) +#else +#define MINT13_5PL 0xFFFF +#endif + +#if (INT6PL >= INT13PL) || (INT6PL == 0) +#define MINT13_6PL ~(1 << 5) +#else +#define MINT13_6PL 0xFFFF +#endif + +#if (INT7PL >= INT13PL) || (INT7PL == 0) +#define MINT13_7PL ~(1 << 6) +#else +#define MINT13_7PL 0xFFFF +#endif + +#if (INT8PL >= INT13PL) || (INT8PL == 0) +#define MINT13_8PL ~(1 << 7) +#else +#define MINT13_8PL 0xFFFF +#endif + +#if (INT9PL >= INT13PL) || (INT9PL == 0) +#define MINT13_9PL ~(1 << 8) +#else +#define MINT13_9PL 0xFFFF +#endif + +#if (INT10PL >= INT13PL) || (INT10PL == 0) +#define MINT13_10PL ~(1 << 9) +#else +#define MINT13_10PL 0xFFFF +#endif + +#if (INT11PL >= INT13PL) || (INT11PL == 0) +#define MINT13_11PL ~(1 << 10) +#else +#define MINT13_11PL 0xFFFF +#endif + +#define MINT13_12PL ~(1 << 11) + +#if (INT13PL == 0) +#define MINT13_13PL ~(1 << 12) +#else +#define MINT13_13PL 0xFFFF +#endif + +#if (INT14PL >= INT13PL) || (INT14PL == 0) +#define MINT13_14PL ~(1 << 13) +#else +#define MINT13_14PL 0xFFFF +#endif + +#if (INT15PL >= INT13PL) || (INT15PL == 0) +#define MINT13_15PL ~(1 << 14) +#else +#define MINT13_15PL 0xFFFF +#endif + +#if (INT16PL >= INT13PL) || (INT16PL == 0) +#define MINT13_16PL ~(1 << 15) +#else +#define MINT13_16PL 0xFFFF +#endif + +#define MINT13 (MINT13_1PL & MINT13_2PL & MINT13_3PL & MINT13_4PL & \ + MINT13_5PL & MINT13_6PL & MINT13_7PL & MINT13_8PL & \ + MINT13_9PL & MINT13_10PL & MINT13_11PL & MINT13_12PL & \ + MINT13_13PL & MINT13_14PL & MINT13_15PL & MINT13_16PL) +// End Of MINT13. + +// Beginning of MINT14: +#if (INT1PL >= INT14PL) || (INT1PL == 0) +#define MINT14_1PL ~(1 << 0) +#else +#define MINT14_1PL 0xFFFF +#endif + +#if (INT2PL >= INT14PL) || (INT2PL == 0) +#define MINT14_2PL ~(1 << 1) +#else +#define MINT14_2PL 0xFFFF +#endif + +#if (INT3PL >= INT14PL) || (INT3PL == 0) +#define MINT14_3PL ~(1 << 2) +#else +#define MINT14_3PL 0xFFFF +#endif + +#if (INT4PL >= INT14PL) || (INT4PL == 0) +#define MINT14_4PL ~(1 << 3) +#else +#define MINT14_4PL 0xFFFF +#endif + +#if (INT5PL >= INT14PL) || (INT5PL == 0) +#define MINT14_5PL ~(1 << 4) +#else +#define MINT14_5PL 0xFFFF +#endif + +#if (INT6PL >= INT14PL) || (INT6PL == 0) +#define MINT14_6PL ~(1 << 5) +#else +#define MINT14_6PL 0xFFFF +#endif + +#if (INT7PL >= INT14PL) || (INT7PL == 0) +#define MINT14_7PL ~(1 << 6) +#else +#define MINT14_7PL 0xFFFF +#endif + +#if (INT8PL >= INT14PL) || (INT8PL == 0) +#define MINT14_8PL ~(1 << 7) +#else +#define MINT14_8PL 0xFFFF +#endif + +#if (INT9PL >= INT14PL) || (INT9PL == 0) +#define MINT14_9PL ~(1 << 8) +#else +#define MINT14_9PL 0xFFFF +#endif + +#if (INT10PL >= INT14PL) || (INT10PL == 0) +#define MINT14_10PL ~(1 << 9) +#else +#define MINT14_10PL 0xFFFF +#endif + +#if (INT11PL >= INT14PL) || (INT11PL == 0) +#define MINT14_11PL ~(1 << 10) +#else +#define MINT14_11PL 0xFFFF +#endif + +#if (INT12PL >= INT14PL) || (INT12PL == 0) +#define MINT14_12PL ~(1 << 11) +#else +#define MINT14_12PL 0xFFFF +#endif + +#if (INT13PL >= INT14PL) || (INT13PL == 0) +#define MINT14_13PL ~(1 << 12) +#else +#define MINT14_13PL 0xFFFF +#endif + +#define MINT14_14PL ~(1 << 13) + +#if (INT15PL >= INT14PL) || (INT15PL == 0) +#define MINT14_15PL ~(1 << 14) +#else +#define MINT14_15PL 0xFFFF +#endif + +#if (INT16PL >= INT14PL) || (INT16PL == 0) +#define MINT14_16PL ~(1 << 15) +#else +#define MINT14_16PL 0xFFFF +#endif + +#define MINT14 (MINT14_1PL & MINT14_2PL & MINT14_3PL & MINT14_4PL & \ + MINT14_5PL & MINT14_6PL & MINT14_7PL & MINT14_8PL & \ + MINT14_9PL & MINT14_10PL & MINT14_11PL & MINT14_12PL & \ + MINT14_13PL & MINT14_14PL & MINT14_15PL & MINT14_16PL) +// End Of MINT14. + +// Beginning of MINT15: +#if (INT1PL >= INT15PL) || (INT1PL == 0) +#define MINT15_1PL ~(1 << 0) +#else +#define MINT15_1PL 0xFFFF +#endif + +#if (INT2PL >= INT15PL) || (INT2PL == 0) +#define MINT15_2PL ~(1 << 1) +#else +#define MINT15_2PL 0xFFFF +#endif + +#if (INT3PL >= INT15PL) || (INT3PL == 0) +#define MINT15_3PL ~(1 << 2) +#else +#define MINT15_3PL 0xFFFF +#endif + +#if (INT4PL >= INT15PL) || (INT4PL == 0) +#define MINT15_4PL ~(1 << 3) +#else +#define MINT15_4PL 0xFFFF +#endif + +#if (INT5PL >= INT15PL) || (INT5PL == 0) +#define MINT15_5PL ~(1 << 4) +#else +#define MINT15_5PL 0xFFFF +#endif + +#if (INT6PL >= INT15PL) || (INT6PL == 0) +#define MINT15_6PL ~(1 << 5) +#else +#define MINT15_6PL 0xFFFF +#endif + +#if (INT7PL >= INT15PL) || (INT7PL == 0) +#define MINT15_7PL ~(1 << 6) +#else +#define MINT15_7PL 0xFFFF +#endif + +#if (INT8PL >= INT15PL) || (INT8PL == 0) +#define MINT15_8PL ~(1 << 7) +#else +#define MINT15_8PL 0xFFFF +#endif + +#if (INT9PL >= INT15PL) || (INT9PL == 0) +#define MINT15_9PL ~(1 << 8) +#else +#define MINT15_9PL 0xFFFF +#endif + +#if (INT10PL >= INT15PL) || (INT10PL == 0) +#define MINT15_10PL ~(1 << 9) +#else +#define MINT15_10PL 0xFFFF +#endif + +#if (INT11PL >= INT15PL) || (INT11PL == 0) +#define MINT15_11PL ~(1 << 10) +#else +#define MINT15_11PL 0xFFFF +#endif + +#if (INT12PL >= INT15PL) || (INT12PL == 0) +#define MINT15_12PL ~(1 << 11) +#else +#define MINT15_12PL 0xFFFF +#endif + +#if (INT13PL >= INT15PL) || (INT13PL == 0) +#define MINT15_13PL ~(1 << 12) +#else +#define MINT15_13PL 0xFFFF +#endif + +#if (INT14PL >= INT15PL) || (INT14PL == 0) +#define MINT15_14PL ~(1 << 13) +#else +#define MINT15_14PL 0xFFFF +#endif + +#define MINT15_15PL ~(1 << 14) + +#if (INT16PL >= INT15PL) || (INT16PL == 0) +#define MINT15_16PL ~(1 << 15) +#else +#define MINT15_16PL 0xFFFF +#endif + +#define MINT15 (MINT15_1PL & MINT15_2PL & MINT15_3PL & MINT15_4PL & \ + MINT15_5PL & MINT15_6PL & MINT15_7PL & MINT15_8PL & \ + MINT15_9PL & MINT15_10PL & MINT15_11PL & MINT15_12PL & \ + MINT15_13PL & MINT15_14PL & MINT15_15PL & MINT15_16PL) +// End Of MINT15. + +// Beginning of MINT16: +#if (INT1PL >= INT16PL) || (INT1PL == 0) +#define MINT16_1PL ~(1 << 0) +#else +#define MINT16_1PL 0xFFFF +#endif + +#if (INT2PL >= INT16PL) || (INT2PL == 0) +#define MINT16_2PL ~(1 << 1) +#else +#define MINT16_2PL 0xFFFF +#endif + +#if (INT3PL >= INT16PL) || (INT3PL == 0) +#define MINT16_3PL ~(1 << 2) +#else +#define MINT16_3PL 0xFFFF +#endif + +#if (INT4PL >= INT16PL) || (INT4PL == 0) +#define MINT16_4PL ~(1 << 3) +#else +#define MINT16_4PL 0xFFFF +#endif + +#if (INT5PL >= INT16PL) || (INT5PL == 0) +#define MINT16_5PL ~(1 << 4) +#else +#define MINT16_5PL 0xFFFF +#endif + +#if (INT6PL >= INT16PL) || (INT6PL == 0) +#define MINT16_6PL ~(1 << 5) +#else +#define MINT16_6PL 0xFFFF +#endif + +#if (INT7PL >= INT16PL) || (INT7PL == 0) +#define MINT16_7PL ~(1 << 6) +#else +#define MINT16_7PL 0xFFFF +#endif + +#if (INT8PL >= INT16PL) || (INT8PL == 0) +#define MINT16_8PL ~(1 << 7) +#else +#define MINT16_8PL 0xFFFF +#endif + +#if (INT9PL >= INT16PL) || (INT9PL == 0) +#define MINT16_9PL ~(1 << 8) +#else +#define MINT16_9PL 0xFFFF +#endif + +#if (INT10PL >= INT16PL) || (INT10PL == 0) +#define MINT16_10PL ~(1 << 9) +#else +#define MINT16_10PL 0xFFFF +#endif + +#if (INT11PL >= INT16PL) || (INT11PL == 0) +#define MINT16_11PL ~(1 << 10) +#else +#define MINT16_11PL 0xFFFF +#endif + +#if (INT12PL >= INT16PL) || (INT12PL == 0) +#define MINT16_12PL ~(1 << 11) +#else +#define MINT16_12PL 0xFFFF +#endif + +#if (INT13PL >= INT16PL) || (INT13PL == 0) +#define MINT16_13PL ~(1 << 12) +#else +#define MINT16_13PL 0xFFFF +#endif + +#if (INT14PL >= INT16PL) || (INT14PL == 0) +#define MINT16_14PL ~(1 << 13) +#else +#define MINT16_14PL 0xFFFF +#endif + +#if (INT15PL >= INT16PL) || (INT15PL == 0) +#define MINT16_15PL ~(1 << 14) +#else +#define MINT16_15PL 0xFFFF +#endif + +#define MINT16_16PL ~(1 << 15) + +#define MINT16 (MINT16_1PL & MINT16_2PL & MINT16_3PL & MINT16_4PL & \ + MINT16_5PL & MINT16_6PL & MINT16_7PL & MINT16_8PL & \ + MINT16_9PL & MINT16_10PL & MINT16_11PL & MINT16_12PL & \ + MINT16_13PL & MINT16_14PL & MINT16_15PL & MINT16_16PL) +// End Of MINT16. + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG11 to MG18: + +// Beginning of MG11: +#if (G12PL >= G11PL) || (G12PL == 0) +#define MG11_12PL ~(1 << 1) +#else +#define MG11_12PL 0xFFFF +#endif + +#if (G13PL >= G11PL) || (G13PL == 0) +#define MG11_13PL ~(1 << 2) +#else +#define MG11_13PL 0xFFFF +#endif + +#if (G14PL >= G11PL) || (G14PL == 0) +#define MG11_14PL ~(1 << 3) +#else +#define MG11_14PL 0xFFFF +#endif + +#if (G15PL >= G11PL) || (G15PL == 0) +#define MG11_15PL ~(1 << 4) +#else +#define MG11_15PL 0xFFFF +#endif + +#if (G16PL >= G11PL) || (G16PL == 0) +#define MG11_16PL ~(1 << 5) +#else +#define MG11_16PL 0xFFFF +#endif + +#if (G17PL >= G11PL) || (G17PL == 0) +#define MG11_17PL ~(1 << 6) +#else +#define MG11_17PL 0xFFFF +#endif + +#if (G18PL >= G11PL) || (G18PL == 0) +#define MG11_18PL ~(1 << 7) +#else +#define MG11_18PL 0xFFFF +#endif + +#define MG11_11PL 0x00FE +#define MG11 (MG11_11PL & MG11_12PL & MG11_13PL & MG11_14PL & \ + MG11_15PL & MG11_16PL & MG11_17PL & MG11_18PL) +// End of MG11: + +// Beginning of MG12: +#if (G11PL >= G12PL) || (G11PL == 0) +#define MG12_11PL ~(1) +#else +#define MG12_11PL 0xFFFF +#endif +#if (G13PL >= G12PL) || (G13PL == 0) +#define MG12_13PL ~(1 << 2) +#else +#define MG12_13PL 0xFFFF +#endif +#if (G14PL >= G12PL) || (G14PL == 0) +#define MG12_14PL ~(1 << 3) +#else +#define MG12_14PL 0xFFFF +#endif +#if (G15PL >= G12PL) || (G15PL == 0) +#define MG12_15PL ~(1 << 4) +#else +#define MG12_15PL 0xFFFF +#endif +#if (G16PL >= G12PL) || (G16PL == 0) +#define MG12_16PL ~(1 << 5) +#else +#define MG12_16PL 0xFFFF +#endif +#if (G17PL >= G12PL) || (G17PL == 0) +#define MG12_17PL ~(1 << 6) +#else +#define MG12_17PL 0xFFFF +#endif +#if (G18PL >= G12PL) || (G18PL == 0) +#define MG12_18PL ~(1 << 7) +#else +#define MG12_18PL 0xFFFF +#endif +#define MG12_12PL 0x00FD +#define MG12 (MG12_11PL & MG12_12PL & MG12_13PL & MG12_14PL & \ + MG12_15PL & MG12_16PL & MG12_17PL & MG12_18PL) +// End of MG12: + +// Beginning of MG13: +#if (G11PL >= G13PL) || (G11PL == 0) +#define MG13_11PL ~(1) +#else +#define MG13_11PL 0xFFFF +#endif +#if (G12PL >= G13PL) || (G12PL == 0) +#define MG13_12PL ~(1 << 1) +#else +#define MG13_12PL 0xFFFF +#endif +#if (G14PL >= G13PL) || (G14PL == 0) +#define MG13_14PL ~(1 << 3) +#else +#define MG13_14PL 0xFFFF +#endif +#if (G15PL >= G13PL) || (G15PL == 0) +#define MG13_15PL ~(1 << 4) +#else +#define MG13_15PL 0xFFFF +#endif +#if (G16PL >= G13PL) || (G16PL == 0) +#define MG13_16PL ~(1 << 5) +#else +#define MG13_16PL 0xFFFF +#endif +#if (G17PL >= G13PL) || (G17PL == 0) +#define MG13_17PL ~(1 << 6) +#else +#define MG13_17PL 0xFFFF +#endif +#if (G18PL >= G13PL) || (G18PL == 0) +#define MG13_18PL ~(1 << 7) +#else +#define MG13_18PL 0xFFFF +#endif +#define MG13_13PL 0x00FB +#define MG13 (MG13_11PL & MG13_12PL & MG13_13PL & MG13_14PL & \ + MG13_15PL & MG13_16PL & MG13_17PL & MG13_18PL) +// End of MG13: + +// Beginning of MG14: +#if (G11PL >= G14PL) || (G11PL == 0) +#define MG14_11PL ~(1) +#else +#define MG14_11PL 0xFFFF +#endif +#if (G12PL >= G14PL) || (G12PL == 0) +#define MG14_12PL ~(1 << 1) +#else +#define MG14_12PL 0xFFFF +#endif +#if (G13PL >= G14PL) || (G13PL == 0) +#define MG14_13PL ~(1 << 2) +#else +#define MG14_13PL 0xFFFF +#endif +#if (G15PL >= G14PL) || (G15PL == 0) +#define MG14_15PL ~(1 << 4) +#else +#define MG14_15PL 0xFFFF +#endif +#if (G16PL >= G14PL) || (G16PL == 0) +#define MG14_16PL ~(1 << 5) +#else +#define MG14_16PL 0xFFFF +#endif +#if (G17PL >= G14PL) || (G17PL == 0) +#define MG14_17PL ~(1 << 6) +#else +#define MG14_17PL 0xFFFF +#endif +#if (G18PL >= G14PL) || (G18PL == 0) +#define MG14_18PL ~(1 << 7) +#else +#define MG14_18PL 0xFFFF +#endif +#define MG14_14PL 0x00F7 +#define MG14 (MG14_11PL & MG14_12PL & MG14_13PL & MG14_14PL & \ + MG14_15PL & MG14_16PL & MG14_17PL & MG14_18PL) +// End of MG14: + +// Beginning of MG15: +#if (G11PL >= G15PL) || (G11PL == 0) +#define MG15_11PL ~(1) +#else +#define MG15_11PL 0xFFFF +#endif +#if (G12PL >= G15PL) || (G12PL == 0) +#define MG15_12PL ~(1 << 1) +#else +#define MG15_12PL 0xFFFF +#endif +#if (G13PL >= G15PL) || (G13PL == 0) +#define MG15_13PL ~(1 << 2) +#else +#define MG15_13PL 0xFFFF +#endif +#if (G14PL >= G15PL) || (G14PL == 0) +#define MG15_14PL ~(1 << 3) +#else +#define MG15_14PL 0xFFFF +#endif +#if (G16PL >= G15PL) || (G16PL == 0) +#define MG15_16PL ~(1 << 5) +#else +#define MG15_16PL 0xFFFF +#endif +#if (G17PL >= G15PL) || (G17PL == 0) +#define MG15_17PL ~(1 << 6) +#else +#define MG15_17PL 0xFFFF +#endif +#if (G18PL >= G15PL) || (G18PL == 0) +#define MG15_18PL ~(1 << 7) +#else +#define MG15_18PL 0xFFFF +#endif +#define MG15_15PL 0x00EF +#define MG15 (MG15_11PL & MG15_12PL & MG15_13PL & MG15_14PL & \ + MG15_15PL & MG15_16PL & MG15_17PL & MG15_18PL) +// End of MG15: + +// Beginning of MG16: +#if (G11PL >= G16PL) || (G11PL == 0) +#define MG16_11PL ~(1) +#else +#define MG16_11PL 0xFFFF +#endif +#if (G12PL >= G16PL) || (G12PL == 0) +#define MG16_12PL ~(1 << 1) +#else +#define MG16_12PL 0xFFFF +#endif +#if (G13PL >= G16PL) || (G13PL == 0) +#define MG16_13PL ~(1 << 2) +#else +#define MG16_13PL 0xFFFF +#endif +#if (G14PL >= G16PL) || (G14PL == 0) +#define MG16_14PL ~(1 << 3) +#else +#define MG16_14PL 0xFFFF +#endif +#if (G15PL >= G16PL) || (G15PL == 0) +#define MG16_15PL ~(1 << 4) +#else +#define MG16_15PL 0xFFFF +#endif +#if (G17PL >= G16PL) || (G17PL == 0) +#define MG16_17PL ~(1 << 6) +#else +#define MG16_17PL 0xFFFF +#endif +#if (G18PL >= G16PL) || (G18PL == 0) +#define MG16_18PL ~(1 << 7) +#else +#define MG16_18PL 0xFFFF +#endif +#define MG16_16PL 0x00DF +#define MG16 (MG16_11PL & MG16_12PL & MG16_13PL & MG16_14PL & \ + MG16_15PL & MG16_16PL & MG16_17PL & MG16_18PL) +// End of MG16: + +// Beginning of MG17: +#if (G11PL >= G17PL) || (G11PL == 0) +#define MG17_11PL ~(1) +#else +#define MG17_11PL 0xFFFF +#endif +#if (G12PL >= G17PL) || (G12PL == 0) +#define MG17_12PL ~(1 << 1) +#else +#define MG17_12PL 0xFFFF +#endif +#if (G13PL >= G17PL) || (G13PL == 0) +#define MG17_13PL ~(1 << 2) +#else +#define MG17_13PL 0xFFFF +#endif +#if (G14PL >= G17PL) || (G14PL == 0) +#define MG17_14PL ~(1 << 3) +#else +#define MG17_14PL 0xFFFF +#endif +#if (G15PL >= G17PL) || (G15PL == 0) +#define MG17_15PL ~(1 << 4) +#else +#define MG17_15PL 0xFFFF +#endif +#if (G16PL >= G17PL) || (G16PL == 0) +#define MG17_16PL ~(1 << 5) +#else +#define MG17_16PL 0xFFFF +#endif +#if (G18PL >= G17PL) || (G18PL == 0) +#define MG17_18PL ~(1 << 7) +#else +#define MG17_18PL 0xFFFF +#endif +#define MG17_17PL 0x00BF +#define MG17 (MG17_11PL & MG17_12PL & MG17_13PL & MG17_14PL & \ + MG17_15PL & MG17_16PL & MG17_17PL & MG17_18PL) +// End of MG17: + +// Beginning of MG18: +#if (G11PL >= G18PL) || (G11PL == 0) +#define MG18_11PL ~(1) +#else +#define MG18_11PL 0xFFFF +#endif +#if (G12PL >= G18PL) || (G12PL == 0) +#define MG18_12PL ~(1 << 1) +#else +#define MG18_12PL 0xFFFF +#endif +#if (G13PL >= G18PL) || (G13PL == 0) +#define MG18_13PL ~(1 << 2) +#else +#define MG18_13PL 0xFFFF +#endif +#if (G14PL >= G18PL) || (G14PL == 0) +#define MG18_14PL ~(1 << 3) +#else +#define MG18_14PL 0xFFFF +#endif +#if (G15PL >= G18PL) || (G15PL == 0) +#define MG18_15PL ~(1 << 4) +#else +#define MG18_15PL 0xFFFF +#endif +#if (G16PL >= G18PL) || (G16PL == 0) +#define MG18_16PL ~(1 << 5) +#else +#define MG18_16PL 0xFFFF +#endif +#if (G17PL >= G18PL) || (G17PL == 0) +#define MG18_17PL ~(1 << 6) +#else +#define MG18_17PL 0xFFFF +#endif +#define MG18_18PL 0x007F +#define MG18 (MG18_11PL & MG18_12PL & MG18_13PL & MG18_14PL & \ + MG18_15PL & MG18_16PL & MG18_17PL & MG18_18PL) +// End of MG18: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG21 to MG28: +// + +// Beginning of MG21: +#if (G22PL >= G21PL) || (G22PL == 0) +#define MG21_12PL ~(1 << 1) +#else +#define MG21_12PL 0xFFFF +#endif +#if (G23PL >= G21PL) || (G23PL == 0) +#define MG21_13PL ~(1 << 2) +#else +#define MG21_13PL 0xFFFF +#endif +#if (G24PL >= G21PL) || (G24PL == 0) +#define MG21_14PL ~(1 << 3) +#else +#define MG21_14PL 0xFFFF +#endif +#if (G25PL >= G21PL) || (G25PL == 0) +#define MG21_15PL ~(1 << 4) +#else +#define MG21_15PL 0xFFFF +#endif +#if (G26PL >= G21PL) || (G26PL == 0) +#define MG21_16PL ~(1 << 5) +#else +#define MG21_16PL 0xFFFF +#endif +#if (G27PL >= G21PL) || (G27PL == 0) +#define MG21_17PL ~(1 << 6) +#else +#define MG21_17PL 0xFFFF +#endif +#if (G28PL >= G21PL) || (G28PL == 0) +#define MG21_18PL ~(1 << 7) +#else +#define MG21_18PL 0xFFFF +#endif +#define MG21_11PL 0x00FE +#define MG21 (MG21_11PL & MG21_12PL & MG21_13PL & MG21_14PL & \ + MG21_15PL & MG21_16PL & MG21_17PL & MG21_18PL) +// End of MG21: + +// Beginning of MG22: +#if (G21PL >= G22PL) || (G21PL == 0) +#define MG22_11PL ~(1) +#else +#define MG22_11PL 0xFFFF +#endif +#if (G23PL >= G22PL) || (G23PL == 0) +#define MG22_13PL ~(1 << 2) +#else +#define MG22_13PL 0xFFFF +#endif +#if (G24PL >= G22PL) || (G24PL == 0) +#define MG22_14PL ~(1 << 3) +#else +#define MG22_14PL 0xFFFF +#endif +#if (G25PL >= G22PL) || (G25PL == 0) +#define MG22_15PL ~(1 << 4) +#else +#define MG22_15PL 0xFFFF +#endif +#if (G26PL >= G22PL) || (G26PL == 0) +#define MG22_16PL ~(1 << 5) +#else +#define MG22_16PL 0xFFFF +#endif +#if (G27PL >= G22PL) || (G27PL == 0) +#define MG22_17PL ~(1 << 6) +#else +#define MG22_17PL 0xFFFF +#endif +#if (G28PL >= G22PL) || (G28PL == 0) +#define MG22_18PL ~(1 << 7) +#else +#define MG22_18PL 0xFFFF +#endif +#define MG22_12PL 0x00FD +#define MG22 (MG22_11PL & MG22_12PL & MG22_13PL & MG22_14PL & \ + MG22_15PL & MG22_16PL & MG22_17PL & MG22_18PL) +// End of MG22: + +// Beginning of MG23: +#if (G21PL >= G23PL) || (G21PL == 0) +#define MG23_11PL ~(1) +#else +#define MG23_11PL 0xFFFF +#endif +#if (G22PL >= G23PL) || (G22PL == 0) +#define MG23_12PL ~(1 << 1) +#else +#define MG23_12PL 0xFFFF +#endif +#if (G24PL >= G23PL) || (G24PL == 0) +#define MG23_14PL ~(1 << 3) +#else +#define MG23_14PL 0xFFFF +#endif +#if (G25PL >= G23PL) || (G25PL == 0) +#define MG23_15PL ~(1 << 4) +#else +#define MG23_15PL 0xFFFF +#endif +#if (G26PL >= G23PL) || (G26PL == 0) +#define MG23_16PL ~(1 << 5) +#else +#define MG23_16PL 0xFFFF +#endif +#if (G27PL >= G23PL) || (G27PL == 0) +#define MG23_17PL ~(1 << 6) +#else +#define MG23_17PL 0xFFFF +#endif +#if (G28PL >= G23PL) || (G28PL == 0) +#define MG23_18PL ~(1 << 7) +#else +#define MG23_18PL 0xFFFF +#endif +#define MG23_13PL 0x00FB +#define MG23 (MG23_11PL & MG23_12PL & MG23_13PL & MG23_14PL & \ + MG23_15PL & MG23_16PL & MG23_17PL & MG23_18PL) +// End of MG23: + +// Beginning of MG24: +#if (G21PL >= G24PL) || (G21PL == 0) +#define MG24_11PL ~(1) +#else +#define MG24_11PL 0xFFFF +#endif +#if (G22PL >= G24PL) || (G22PL == 0) +#define MG24_12PL ~(1 << 1) +#else +#define MG24_12PL 0xFFFF +#endif +#if (G23PL >= G24PL) || (G23PL == 0) +#define MG24_13PL ~(1 << 2) +#else +#define MG24_13PL 0xFFFF +#endif +#if (G25PL >= G24PL) || (G25PL == 0) +#define MG24_15PL ~(1 << 4) +#else +#define MG24_15PL 0xFFFF +#endif +#if (G26PL >= G24PL) || (G26PL == 0) +#define MG24_16PL ~(1 << 5) +#else +#define MG24_16PL 0xFFFF +#endif +#if (G27PL >= G24PL) || (G27PL == 0) +#define MG24_17PL ~(1 << 6) +#else +#define MG24_17PL 0xFFFF +#endif +#if (G28PL >= G24PL) || (G28PL == 0) +#define MG24_18PL ~(1 << 7) +#else +#define MG24_18PL 0xFFFF +#endif +#define MG24_14PL 0x00F7 +#define MG24 (MG24_11PL & MG24_12PL & MG24_13PL & MG24_14PL & \ + MG24_15PL & MG24_16PL & MG24_17PL & MG24_18PL) +// End of MG24: + +// Beginning of MG25: +#if (G21PL >= G25PL) || (G21PL == 0) +#define MG25_11PL ~(1) +#else +#define MG25_11PL 0xFFFF +#endif +#if (G22PL >= G25PL) || (G22PL == 0) +#define MG25_12PL ~(1 << 1) +#else +#define MG25_12PL 0xFFFF +#endif +#if (G23PL >= G25PL) || (G23PL == 0) +#define MG25_13PL ~(1 << 2) +#else +#define MG25_13PL 0xFFFF +#endif +#if (G24PL >= G25PL) || (G24PL == 0) +#define MG25_14PL ~(1 << 3) +#else +#define MG25_14PL 0xFFFF +#endif +#if (G26PL >= G25PL) || (G26PL == 0) +#define MG25_16PL ~(1 << 5) +#else +#define MG25_16PL 0xFFFF +#endif +#if (G27PL >= G25PL) || (G27PL == 0) +#define MG25_17PL ~(1 << 6) +#else +#define MG25_17PL 0xFFFF +#endif +#if (G28PL >= G25PL) || (G28PL == 0) +#define MG25_18PL ~(1 << 7) +#else +#define MG25_18PL 0xFFFF +#endif +#define MG25_15PL 0x00EF +#define MG25 (MG25_11PL & MG25_12PL & MG25_13PL & MG25_14PL & \ + MG25_15PL & MG25_16PL & MG25_17PL & MG25_18PL) +// End of MG25: + +// Beginning of MG26: +#if (G21PL >= G26PL) || (G21PL == 0) +#define MG26_11PL ~(1) +#else +#define MG26_11PL 0xFFFF +#endif +#if (G22PL >= G26PL) || (G22PL == 0) +#define MG26_12PL ~(1 << 1) +#else +#define MG26_12PL 0xFFFF +#endif +#if (G23PL >= G26PL) || (G23PL == 0) +#define MG26_13PL ~(1 << 2) +#else +#define MG26_13PL 0xFFFF +#endif +#if (G24PL >= G26PL) || (G24PL == 0) +#define MG26_14PL ~(1 << 3) +#else +#define MG26_14PL 0xFFFF +#endif +#if (G25PL >= G26PL) || (G25PL == 0) +#define MG26_15PL ~(1 << 4) +#else +#define MG26_15PL 0xFFFF +#endif +#if (G27PL >= G26PL) || (G27PL == 0) +#define MG26_17PL ~(1 << 6) +#else +#define MG26_17PL 0xFFFF +#endif +#if (G28PL >= G26PL) || (G28PL == 0) +#define MG26_18PL ~(1 << 7) +#else +#define MG26_18PL 0xFFFF +#endif +#define MG26_16PL 0x00DF +#define MG26 (MG26_11PL & MG26_12PL & MG26_13PL & MG26_14PL & \ + MG26_15PL & MG26_16PL & MG26_17PL & MG26_18PL) +// End of MG26: + +// Beginning of MG27: +#if (G21PL >= G27PL) || (G21PL == 0) +#define MG27_11PL ~(1) +#else +#define MG27_11PL 0xFFFF +#endif +#if (G22PL >= G27PL) || (G22PL == 0) +#define MG27_12PL ~(1 << 1) +#else +#define MG27_12PL 0xFFFF +#endif +#if (G23PL >= G27PL) || (G23PL == 0) +#define MG27_13PL ~(1 << 2) +#else +#define MG27_13PL 0xFFFF +#endif +#if (G24PL >= G27PL) || (G24PL == 0) +#define MG27_14PL ~(1 << 3) +#else +#define MG27_14PL 0xFFFF +#endif +#if (G25PL >= G27PL) || (G25PL == 0) +#define MG27_15PL ~(1 << 4) +#else +#define MG27_15PL 0xFFFF +#endif +#if (G26PL >= G27PL) || (G26PL == 0) +#define MG27_16PL ~(1 << 5) +#else +#define MG27_16PL 0xFFFF +#endif +#if (G28PL >= G27PL) || (G28PL == 0) +#define MG27_18PL ~(1 << 7) +#else +#define MG27_18PL 0xFFFF +#endif +#define MG27_17PL 0x00BF +#define MG27 (MG27_11PL & MG27_12PL & MG27_13PL & MG27_14PL & \ + MG27_15PL & MG27_16PL & MG27_17PL & MG27_18PL) +// End of MG27: + +// Beginning of MG28: +#if (G21PL >= G28PL) || (G21PL == 0) +#define MG28_11PL ~(1) +#else +#define MG28_11PL 0xFFFF +#endif +#if (G22PL >= G28PL) || (G22PL == 0) +#define MG28_12PL ~(1 << 1) +#else +#define MG28_12PL 0xFFFF +#endif +#if (G23PL >= G28PL) || (G23PL == 0) +#define MG28_13PL ~(1 << 2) +#else +#define MG28_13PL 0xFFFF +#endif +#if (G24PL >= G28PL) || (G24PL == 0) +#define MG28_14PL ~(1 << 3) +#else +#define MG28_14PL 0xFFFF +#endif +#if (G25PL >= G28PL) || (G25PL == 0) +#define MG28_15PL ~(1 << 4) +#else +#define MG28_15PL 0xFFFF +#endif +#if (G26PL >= G28PL) || (G26PL == 0) +#define MG28_16PL ~(1 << 5) +#else +#define MG28_16PL 0xFFFF +#endif +#if (G27PL >= G28PL) || (G27PL == 0) +#define MG28_17PL ~(1 << 6) +#else +#define MG28_17PL 0xFFFF +#endif +#define MG28_18PL 0x007F +#define MG28 (MG28_11PL & MG28_12PL & MG28_13PL & MG28_14PL & \ + MG28_15PL & MG28_16PL & MG28_17PL & MG28_18PL) +// End of MG28: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG31 to MG38: +// + +// Beginning of MG31: +#if (G32PL >= G31PL) || (G32PL == 0) +#define MG31_12PL ~(1 << 1) +#else +#define MG31_12PL 0xFFFF +#endif +#if (G33PL >= G31PL) || (G33PL == 0) +#define MG31_13PL ~(1 << 2) +#else +#define MG31_13PL 0xFFFF +#endif +#if (G34PL >= G31PL) || (G34PL == 0) +#define MG31_14PL ~(1 << 3) +#else +#define MG31_14PL 0xFFFF +#endif +#if (G35PL >= G31PL) || (G35PL == 0) +#define MG31_15PL ~(1 << 4) +#else +#define MG31_15PL 0xFFFF +#endif +#if (G36PL >= G31PL) || (G36PL == 0) +#define MG31_16PL ~(1 << 5) +#else +#define MG31_16PL 0xFFFF +#endif +#if (G37PL >= G31PL) || (G37PL == 0) +#define MG31_17PL ~(1 << 6) +#else +#define MG31_17PL 0xFFFF +#endif +#if (G38PL >= G31PL) || (G38PL == 0) +#define MG31_18PL ~(1 << 7) +#else +#define MG31_18PL 0xFFFF +#endif +#define MG31_11PL 0x00FE +#define MG31 (MG31_11PL & MG31_12PL & MG31_13PL & MG31_14PL & \ + MG31_15PL & MG31_16PL & MG31_17PL & MG31_18PL) +// End of MG31: + +// Beginning of MG32: +#if (G31PL >= G32PL) || (G31PL == 0) +#define MG32_11PL ~(1) +#else +#define MG32_11PL 0xFFFF +#endif +#if (G33PL >= G32PL) || (G33PL == 0) +#define MG32_13PL ~(1 << 2) +#else +#define MG32_13PL 0xFFFF +#endif +#if (G34PL >= G32PL) || (G34PL == 0) +#define MG32_14PL ~(1 << 3) +#else +#define MG32_14PL 0xFFFF +#endif +#if (G35PL >= G32PL) || (G35PL == 0) +#define MG32_15PL ~(1 << 4) +#else +#define MG32_15PL 0xFFFF +#endif +#if (G36PL >= G32PL) || (G36PL == 0) +#define MG32_16PL ~(1 << 5) +#else +#define MG32_16PL 0xFFFF +#endif +#if (G37PL >= G32PL) || (G37PL == 0) +#define MG32_17PL ~(1 << 6) +#else +#define MG32_17PL 0xFFFF +#endif +#if (G38PL >= G32PL) || (G38PL == 0) +#define MG32_18PL ~(1 << 7) +#else +#define MG32_18PL 0xFFFF +#endif +#define MG32_12PL 0x00FD +#define MG32 (MG32_11PL & MG32_12PL & MG32_13PL & MG32_14PL & \ + MG32_15PL & MG32_16PL & MG32_17PL & MG32_18PL) +// End of MG32: + +// Beginning of MG33: +#if (G31PL >= G33PL) || (G31PL == 0) +#define MG33_11PL ~(1) +#else +#define MG33_11PL 0xFFFF +#endif +#if (G32PL >= G33PL) || (G32PL == 0) +#define MG33_12PL ~(1 << 1) +#else +#define MG33_12PL 0xFFFF +#endif +#if (G34PL >= G33PL) || (G34PL == 0) +#define MG33_14PL ~(1 << 3) +#else +#define MG33_14PL 0xFFFF +#endif +#if (G35PL >= G33PL) || (G35PL == 0) +#define MG33_15PL ~(1 << 4) +#else +#define MG33_15PL 0xFFFF +#endif +#if (G36PL >= G33PL) || (G36PL == 0) +#define MG33_16PL ~(1 << 5) +#else +#define MG33_16PL 0xFFFF +#endif +#if (G37PL >= G33PL) || (G37PL == 0) +#define MG33_17PL ~(1 << 6) +#else +#define MG33_17PL 0xFFFF +#endif +#if (G38PL >= G33PL) || (G38PL == 0) +#define MG33_18PL ~(1 << 7) +#else +#define MG33_18PL 0xFFFF +#endif +#define MG33_13PL 0x00FB +#define MG33 (MG33_11PL & MG33_12PL & MG33_13PL & MG33_14PL & \ + MG33_15PL & MG33_16PL & MG33_17PL & MG33_18PL) +// End of MG33: + +// Beginning of MG34: +#if (G31PL >= G34PL) || (G31PL == 0) +#define MG34_11PL ~(1) +#else +#define MG34_11PL 0xFFFF +#endif +#if (G32PL >= G34PL) || (G32PL == 0) +#define MG34_12PL ~(1 << 1) +#else +#define MG34_12PL 0xFFFF +#endif +#if (G33PL >= G34PL) || (G33PL == 0) +#define MG34_13PL ~(1 << 2) +#else +#define MG34_13PL 0xFFFF +#endif +#if (G35PL >= G34PL) || (G35PL == 0) +#define MG34_15PL ~(1 << 4) +#else +#define MG34_15PL 0xFFFF +#endif +#if (G36PL >= G34PL) || (G36PL == 0) +#define MG34_16PL ~(1 << 5) +#else +#define MG34_16PL 0xFFFF +#endif +#if (G37PL >= G34PL) || (G37PL == 0) +#define MG34_17PL ~(1 << 6) +#else +#define MG34_17PL 0xFFFF +#endif +#if (G38PL >= G34PL) || (G38PL == 0) +#define MG34_18PL ~(1 << 7) +#else +#define MG34_18PL 0xFFFF +#endif +#define MG34_14PL 0x00F7 +#define MG34 (MG34_11PL & MG34_12PL & MG34_13PL & MG34_14PL & \ + MG34_15PL & MG34_16PL & MG34_17PL & MG34_18PL) +// End of MG34: + +// Beginning of MG35: +#if (G31PL >= G35PL) || (G31PL == 0) +#define MG35_11PL ~(1) +#else +#define MG35_11PL 0xFFFF +#endif +#if (G32PL >= G35PL) || (G32PL == 0) +#define MG35_12PL ~(1 << 1) +#else +#define MG35_12PL 0xFFFF +#endif +#if (G33PL >= G35PL) || (G33PL == 0) +#define MG35_13PL ~(1 << 2) +#else +#define MG35_13PL 0xFFFF +#endif +#if (G34PL >= G35PL) || (G34PL == 0) +#define MG35_14PL ~(1 << 3) +#else +#define MG35_14PL 0xFFFF +#endif +#if (G36PL >= G35PL) || (G36PL == 0) +#define MG35_16PL ~(1 << 5) +#else +#define MG35_16PL 0xFFFF +#endif +#if (G37PL >= G35PL) || (G37PL == 0) +#define MG35_17PL ~(1 << 6) +#else +#define MG35_17PL 0xFFFF +#endif +#if (G38PL >= G35PL) || (G38PL == 0) +#define MG35_18PL ~(1 << 7) +#else +#define MG35_18PL 0xFFFF +#endif +#define MG35_15PL 0x00EF +#define MG35 (MG35_11PL & MG35_12PL & MG35_13PL & MG35_14PL & \ + MG35_15PL & MG35_16PL & MG35_17PL & MG35_18PL) +// End of MG35: + +// Beginning of MG36: +#if (G31PL >= G36PL) || (G31PL == 0) +#define MG36_11PL ~(1) +#else +#define MG36_11PL 0xFFFF +#endif +#if (G32PL >= G36PL) || (G32PL == 0) +#define MG36_12PL ~(1 << 1) +#else +#define MG36_12PL 0xFFFF +#endif +#if (G33PL >= G36PL) || (G33PL == 0) +#define MG36_13PL ~(1 << 2) +#else +#define MG36_13PL 0xFFFF +#endif +#if (G34PL >= G36PL) || (G34PL == 0) +#define MG36_14PL ~(1 << 3) +#else +#define MG36_14PL 0xFFFF +#endif +#if (G35PL >= G36PL) || (G35PL == 0) +#define MG36_15PL ~(1 << 4) +#else +#define MG36_15PL 0xFFFF +#endif +#if (G37PL >= G36PL) || (G37PL == 0) +#define MG36_17PL ~(1 << 6) +#else +#define MG36_17PL 0xFFFF +#endif +#if (G38PL >= G36PL) || (G38PL == 0) +#define MG36_18PL ~(1 << 7) +#else +#define MG36_18PL 0xFFFF +#endif +#define MG36_16PL 0x00DF +#define MG36 (MG36_11PL & MG36_12PL & MG36_13PL & MG36_14PL & \ + MG36_15PL & MG36_16PL & MG36_17PL & MG36_18PL) +// End of MG36: + +// Beginning of MG37: +#if (G31PL >= G37PL) || (G31PL == 0) +#define MG37_11PL ~(1) +#else +#define MG37_11PL 0xFFFF +#endif +#if (G32PL >= G37PL) || (G32PL == 0) +#define MG37_12PL ~(1 << 1) +#else +#define MG37_12PL 0xFFFF +#endif +#if (G33PL >= G37PL) || (G33PL == 0) +#define MG37_13PL ~(1 << 2) +#else +#define MG37_13PL 0xFFFF +#endif +#if (G34PL >= G37PL) || (G34PL == 0) +#define MG37_14PL ~(1 << 3) +#else +#define MG37_14PL 0xFFFF +#endif +#if (G35PL >= G37PL) || (G35PL == 0) +#define MG37_15PL ~(1 << 4) +#else +#define MG37_15PL 0xFFFF +#endif +#if (G36PL >= G37PL) || (G36PL == 0) +#define MG37_16PL ~(1 << 5) +#else +#define MG37_16PL 0xFFFF +#endif +#if (G38PL >= G37PL) || (G38PL == 0) +#define MG37_18PL ~(1 << 7) +#else +#define MG37_18PL 0xFFFF +#endif +#define MG37_17PL 0x00BF +#define MG37 (MG37_11PL & MG37_12PL & MG37_13PL & MG37_14PL & \ + MG37_15PL & MG37_16PL & MG37_17PL & MG37_18PL) +// End of MG37: + +// Beginning of MG38: +#if (G31PL >= G38PL) || (G31PL == 0) +#define MG38_11PL ~(1) +#else +#define MG38_11PL 0xFFFF +#endif +#if (G32PL >= G38PL) || (G32PL == 0) +#define MG38_12PL ~(1 << 1) +#else +#define MG38_12PL 0xFFFF +#endif +#if (G33PL >= G38PL) || (G33PL == 0) +#define MG38_13PL ~(1 << 2) +#else +#define MG38_13PL 0xFFFF +#endif +#if (G34PL >= G38PL) || (G34PL == 0) +#define MG38_14PL ~(1 << 3) +#else +#define MG38_14PL 0xFFFF +#endif +#if (G35PL >= G38PL) || (G35PL == 0) +#define MG38_15PL ~(1 << 4) +#else +#define MG38_15PL 0xFFFF +#endif +#if (G36PL >= G38PL) || (G36PL == 0) +#define MG38_16PL ~(1 << 5) +#else +#define MG38_16PL 0xFFFF +#endif +#if (G37PL >= G38PL) || (G37PL == 0) +#define MG38_17PL ~(1 << 6) +#else +#define MG38_17PL 0xFFFF +#endif +#define MG38_18PL 0x007F +#define MG38 (MG38_11PL & MG38_12PL & MG38_13PL & MG38_14PL & \ + MG38_15PL & MG38_16PL & MG38_17PL & MG38_18PL) +// End of MG38: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG41 to MG48: +// + +// Beginning of MG41: +#if (G42PL >= G41PL) || (G42PL == 0) +#define MG41_12PL ~(1 << 1) +#else +#define MG41_12PL 0xFFFF +#endif +#if (G43PL >= G41PL) || (G43PL == 0) +#define MG41_13PL ~(1 << 2) +#else +#define MG41_13PL 0xFFFF +#endif +#if (G44PL >= G41PL) || (G44PL == 0) +#define MG41_14PL ~(1 << 3) +#else +#define MG41_14PL 0xFFFF +#endif +#if (G45PL >= G41PL) || (G45PL == 0) +#define MG41_15PL ~(1 << 4) +#else +#define MG41_15PL 0xFFFF +#endif +#if (G46PL >= G41PL) || (G46PL == 0) +#define MG41_16PL ~(1 << 5) +#else +#define MG41_16PL 0xFFFF +#endif +#if (G47PL >= G41PL) || (G47PL == 0) +#define MG41_17PL ~(1 << 6) +#else +#define MG41_17PL 0xFFFF +#endif +#if (G48PL >= G41PL) || (G48PL == 0) +#define MG41_18PL ~(1 << 7) +#else +#define MG41_18PL 0xFFFF +#endif +#define MG41_11PL 0x00FE +#define MG41 (MG41_11PL & MG41_12PL & MG41_13PL & MG41_14PL & \ + MG41_15PL & MG41_16PL & MG41_17PL & MG41_18PL) +// End of MG41: + +// Beginning of MG42: +#if (G41PL >= G42PL) || (G41PL == 0) +#define MG42_11PL ~(1) +#else +#define MG42_11PL 0xFFFF +#endif +#if (G43PL >= G42PL) || (G43PL == 0) +#define MG42_13PL ~(1 << 2) +#else +#define MG42_13PL 0xFFFF +#endif +#if (G44PL >= G42PL) || (G44PL == 0) +#define MG42_14PL ~(1 << 3) +#else +#define MG42_14PL 0xFFFF +#endif +#if (G45PL >= G42PL) || (G45PL == 0) +#define MG42_15PL ~(1 << 4) +#else +#define MG42_15PL 0xFFFF +#endif +#if (G46PL >= G42PL) || (G46PL == 0) +#define MG42_16PL ~(1 << 5) +#else +#define MG42_16PL 0xFFFF +#endif +#if (G47PL >= G42PL) || (G47PL == 0) +#define MG42_17PL ~(1 << 6) +#else +#define MG42_17PL 0xFFFF +#endif +#if (G48PL >= G42PL) || (G48PL == 0) +#define MG42_18PL ~(1 << 7) +#else +#define MG42_18PL 0xFFFF +#endif +#define MG42_12PL 0x00FD +#define MG42 (MG42_11PL & MG42_12PL & MG42_13PL & MG42_14PL & \ + MG42_15PL & MG42_16PL & MG42_17PL & MG42_18PL) +// End of MG42: + +// Beginning of MG43: +#if (G41PL >= G43PL) || (G41PL == 0) +#define MG43_11PL ~(1) +#else +#define MG43_11PL 0xFFFF +#endif +#if (G42PL >= G43PL) || (G42PL == 0) +#define MG43_12PL ~(1 << 1) +#else +#define MG43_12PL 0xFFFF +#endif +#if (G44PL >= G43PL) || (G44PL == 0) +#define MG43_14PL ~(1 << 3) +#else +#define MG43_14PL 0xFFFF +#endif +#if (G45PL >= G43PL) || (G45PL == 0) +#define MG43_15PL ~(1 << 4) +#else +#define MG43_15PL 0xFFFF +#endif +#if (G46PL >= G43PL) || (G46PL == 0) +#define MG43_16PL ~(1 << 5) +#else +#define MG43_16PL 0xFFFF +#endif +#if (G47PL >= G43PL) || (G47PL == 0) +#define MG43_17PL ~(1 << 6) +#else +#define MG43_17PL 0xFFFF +#endif +#if (G48PL >= G43PL) || (G48PL == 0) +#define MG43_18PL ~(1 << 7) +#else +#define MG43_18PL 0xFFFF +#endif +#define MG43_13PL 0x00FB +#define MG43 (MG43_11PL & MG43_12PL & MG43_13PL & MG43_14PL & \ + MG43_15PL & MG43_16PL & MG43_17PL & MG43_18PL) +// End of MG43: + +// Beginning of MG44: +#if (G41PL >= G44PL) || (G41PL == 0) +#define MG44_11PL ~(1) +#else +#define MG44_11PL 0xFFFF +#endif +#if (G42PL >= G44PL) || (G42PL == 0) +#define MG44_12PL ~(1 << 1) +#else +#define MG44_12PL 0xFFFF +#endif +#if (G43PL >= G44PL) || (G43PL == 0) +#define MG44_13PL ~(1 << 2) +#else +#define MG44_13PL 0xFFFF +#endif +#if (G45PL >= G44PL) || (G45PL == 0) +#define MG44_15PL ~(1 << 4) +#else +#define MG44_15PL 0xFFFF +#endif +#if (G46PL >= G44PL) || (G46PL == 0) +#define MG44_16PL ~(1 << 5) +#else +#define MG44_16PL 0xFFFF +#endif +#if (G47PL >= G44PL) || (G47PL == 0) +#define MG44_17PL ~(1 << 6) +#else +#define MG44_17PL 0xFFFF +#endif +#if (G48PL >= G44PL) || (G48PL == 0) +#define MG44_18PL ~(1 << 7) +#else +#define MG44_18PL 0xFFFF +#endif +#define MG44_14PL 0x00F7 +#define MG44 (MG44_11PL & MG44_12PL & MG44_13PL & MG44_14PL & \ + MG44_15PL & MG44_16PL & MG44_17PL & MG44_18PL) +// End of MG44: + +// Beginning of MG45: +#if (G41PL >= G45PL) || (G41PL == 0) +#define MG45_11PL ~(1) +#else +#define MG45_11PL 0xFFFF +#endif +#if (G42PL >= G45PL) || (G42PL == 0) +#define MG45_12PL ~(1 << 1) +#else +#define MG45_12PL 0xFFFF +#endif +#if (G43PL >= G45PL) || (G43PL == 0) +#define MG45_13PL ~(1 << 2) +#else +#define MG45_13PL 0xFFFF +#endif +#if (G44PL >= G45PL) || (G44PL == 0) +#define MG45_14PL ~(1 << 3) +#else +#define MG45_14PL 0xFFFF +#endif +#if (G46PL >= G45PL) || (G46PL == 0) +#define MG45_16PL ~(1 << 5) +#else +#define MG45_16PL 0xFFFF +#endif +#if (G47PL >= G45PL) || (G47PL == 0) +#define MG45_17PL ~(1 << 6) +#else +#define MG45_17PL 0xFFFF +#endif +#if (G48PL >= G45PL) || (G48PL == 0) +#define MG45_18PL ~(1 << 7) +#else +#define MG45_18PL 0xFFFF +#endif +#define MG45_15PL 0x00EF +#define MG45 (MG45_11PL & MG45_12PL & MG45_13PL & MG45_14PL & \ + MG45_15PL & MG45_16PL & MG45_17PL & MG45_18PL) +// End of MG45: + +// Beginning of MG46: +#if (G41PL >= G46PL) || (G41PL == 0) +#define MG46_11PL ~(1) +#else +#define MG46_11PL 0xFFFF +#endif +#if (G42PL >= G46PL) || (G42PL == 0) +#define MG46_12PL ~(1 << 1) +#else +#define MG46_12PL 0xFFFF +#endif +#if (G43PL >= G46PL) || (G43PL == 0) +#define MG46_13PL ~(1 << 2) +#else +#define MG46_13PL 0xFFFF +#endif +#if (G44PL >= G46PL) || (G44PL == 0) +#define MG46_14PL ~(1 << 3) +#else +#define MG46_14PL 0xFFFF +#endif +#if (G45PL >= G46PL) || (G45PL == 0) +#define MG46_15PL ~(1 << 4) +#else +#define MG46_15PL 0xFFFF +#endif +#if (G47PL >= G46PL) || (G47PL == 0) +#define MG46_17PL ~(1 << 6) +#else +#define MG46_17PL 0xFFFF +#endif +#if (G48PL >= G46PL) || (G48PL == 0) +#define MG46_18PL ~(1 << 7) +#else +#define MG46_18PL 0xFFFF +#endif +#define MG46_16PL 0x00DF +#define MG46 (MG46_11PL & MG46_12PL & MG46_13PL & MG46_14PL & \ + MG46_15PL & MG46_16PL & MG46_17PL & MG46_18PL) +// End of MG46: + +// Beginning of MG47: +#if (G41PL >= G47PL) || (G41PL == 0) +#define MG47_11PL ~(1) +#else +#define MG47_11PL 0xFFFF +#endif +#if (G42PL >= G47PL) || (G42PL == 0) +#define MG47_12PL ~(1 << 1) +#else +#define MG47_12PL 0xFFFF +#endif +#if (G43PL >= G47PL) || (G43PL == 0) +#define MG47_13PL ~(1 << 2) +#else +#define MG47_13PL 0xFFFF +#endif +#if (G44PL >= G47PL) || (G44PL == 0) +#define MG47_14PL ~(1 << 3) +#else +#define MG47_14PL 0xFFFF +#endif +#if (G45PL >= G47PL) || (G45PL == 0) +#define MG47_15PL ~(1 << 4) +#else +#define MG47_15PL 0xFFFF +#endif +#if (G46PL >= G47PL) || (G46PL == 0) +#define MG47_16PL ~(1 << 5) +#else +#define MG47_16PL 0xFFFF +#endif +#if (G48PL >= G47PL) || (G48PL == 0) +#define MG47_18PL ~(1 << 7) +#else +#define MG47_18PL 0xFFFF +#endif +#define MG47_17PL 0x00BF +#define MG47 (MG47_11PL & MG47_12PL & MG47_13PL & MG47_14PL & \ + MG47_15PL & MG47_16PL & MG47_17PL & MG47_18PL) +// End of MG47: + +// Beginning of MG48: +#if (G41PL >= G48PL) || (G41PL == 0) +#define MG48_11PL ~(1) +#else +#define MG48_11PL 0xFFFF +#endif +#if (G42PL >= G48PL) || (G42PL == 0) +#define MG48_12PL ~(1 << 1) +#else +#define MG48_12PL 0xFFFF +#endif +#if (G43PL >= G48PL) || (G43PL == 0) +#define MG48_13PL ~(1 << 2) +#else +#define MG48_13PL 0xFFFF +#endif +#if (G44PL >= G48PL) || (G44PL == 0) +#define MG48_14PL ~(1 << 3) +#else +#define MG48_14PL 0xFFFF +#endif +#if (G45PL >= G48PL) || (G45PL == 0) +#define MG48_15PL ~(1 << 4) +#else +#define MG48_15PL 0xFFFF +#endif +#if (G46PL >= G48PL) || (G46PL == 0) +#define MG48_16PL ~(1 << 5) +#else +#define MG48_16PL 0xFFFF +#endif +#if (G47PL >= G48PL) || (G47PL == 0) +#define MG48_17PL ~(1 << 6) +#else +#define MG48_17PL 0xFFFF +#endif +#define MG48_18PL 0x007F +#define MG48 (MG48_11PL & MG48_12PL & MG48_13PL & MG48_14PL & \ + MG48_15PL & MG48_16PL & MG48_17PL & MG48_18PL) +// End of MG48: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG51 to MG58: +// + +// Beginning of MG51: +#if (G52PL >= G51PL) || (G52PL == 0) +#define MG51_12PL ~(1 << 1) +#else +#define MG51_12PL 0xFFFF +#endif +#if (G53PL >= G51PL) || (G53PL == 0) +#define MG51_13PL ~(1 << 2) +#else +#define MG51_13PL 0xFFFF +#endif +#if (G54PL >= G51PL) || (G54PL == 0) +#define MG51_14PL ~(1 << 3) +#else +#define MG51_14PL 0xFFFF +#endif +#if (G55PL >= G51PL) || (G55PL == 0) +#define MG51_15PL ~(1 << 4) +#else +#define MG51_15PL 0xFFFF +#endif +#if (G56PL >= G51PL) || (G56PL == 0) +#define MG51_16PL ~(1 << 5) +#else +#define MG51_16PL 0xFFFF +#endif +#if (G57PL >= G51PL) || (G57PL == 0) +#define MG51_17PL ~(1 << 6) +#else +#define MG51_17PL 0xFFFF +#endif +#if (G58PL >= G51PL) || (G58PL == 0) +#define MG51_18PL ~(1 << 7) +#else +#define MG51_18PL 0xFFFF +#endif +#define MG51_11PL 0x00FE +#define MG51 (MG51_11PL & MG51_12PL & MG51_13PL & MG51_14PL & \ + MG51_15PL & MG51_16PL & MG51_17PL & MG51_18PL) +// End of MG51: + +// Beginning of MG52: +#if (G51PL >= G52PL) || (G51PL == 0) +#define MG52_11PL ~(1) +#else +#define MG52_11PL 0xFFFF +#endif +#if (G53PL >= G52PL) || (G53PL == 0) +#define MG52_13PL ~(1 << 2) +#else +#define MG52_13PL 0xFFFF +#endif +#if (G54PL >= G52PL) || (G54PL == 0) +#define MG52_14PL ~(1 << 3) +#else +#define MG52_14PL 0xFFFF +#endif +#if (G55PL >= G52PL) || (G55PL == 0) +#define MG52_15PL ~(1 << 4) +#else +#define MG52_15PL 0xFFFF +#endif +#if (G56PL >= G52PL) || (G56PL == 0) +#define MG52_16PL ~(1 << 5) +#else +#define MG52_16PL 0xFFFF +#endif +#if (G57PL >= G52PL) || (G57PL == 0) +#define MG52_17PL ~(1 << 6) +#else +#define MG52_17PL 0xFFFF +#endif +#if (G58PL >= G52PL) || (G58PL == 0) +#define MG52_18PL ~(1 << 7) +#else +#define MG52_18PL 0xFFFF +#endif +#define MG52_12PL 0x00FD +#define MG52 (MG52_11PL & MG52_12PL & MG52_13PL & MG52_14PL & \ + MG52_15PL & MG52_16PL & MG52_17PL & MG52_18PL) +// End of MG52: + +// Beginning of MG53: +#if (G51PL >= G53PL) || (G51PL == 0) +#define MG53_11PL ~(1) +#else +#define MG53_11PL 0xFFFF +#endif +#if (G52PL >= G53PL) || (G52PL == 0) +#define MG53_12PL ~(1 << 1) +#else +#define MG53_12PL 0xFFFF +#endif +#if (G54PL >= G53PL) || (G54PL == 0) +#define MG53_14PL ~(1 << 3) +#else +#define MG53_14PL 0xFFFF +#endif +#if (G55PL >= G53PL) || (G55PL == 0) +#define MG53_15PL ~(1 << 4) +#else +#define MG53_15PL 0xFFFF +#endif +#if (G56PL >= G53PL) || (G56PL == 0) +#define MG53_16PL ~(1 << 5) +#else +#define MG53_16PL 0xFFFF +#endif +#if (G57PL >= G53PL) || (G57PL == 0) +#define MG53_17PL ~(1 << 6) +#else +#define MG53_17PL 0xFFFF +#endif +#if (G58PL >= G53PL) || (G58PL == 0) +#define MG53_18PL ~(1 << 7) +#else +#define MG53_18PL 0xFFFF +#endif +#define MG53_13PL 0x00FB +#define MG53 (MG53_11PL & MG53_12PL & MG53_13PL & MG53_14PL & \ + MG53_15PL & MG53_16PL & MG53_17PL & MG53_18PL) +// End of MG53: + +// Beginning of MG54: +#if (G51PL >= G54PL) || (G51PL == 0) +#define MG54_11PL ~(1) +#else +#define MG54_11PL 0xFFFF +#endif +#if (G52PL >= G54PL) || (G52PL == 0) +#define MG54_12PL ~(1 << 1) +#else +#define MG54_12PL 0xFFFF +#endif +#if (G53PL >= G54PL) || (G53PL == 0) +#define MG54_13PL ~(1 << 2) +#else +#define MG54_13PL 0xFFFF +#endif +#if (G55PL >= G54PL) || (G55PL == 0) +#define MG54_15PL ~(1 << 4) +#else +#define MG54_15PL 0xFFFF +#endif +#if (G56PL >= G54PL) || (G56PL == 0) +#define MG54_16PL ~(1 << 5) +#else +#define MG54_16PL 0xFFFF +#endif +#if (G57PL >= G54PL) || (G57PL == 0) +#define MG54_17PL ~(1 << 6) +#else +#define MG54_17PL 0xFFFF +#endif +#if (G58PL >= G54PL) || (G58PL == 0) +#define MG54_18PL ~(1 << 7) +#else +#define MG54_18PL 0xFFFF +#endif +#define MG54_14PL 0x00F7 +#define MG54 (MG54_11PL & MG54_12PL & MG54_13PL & MG54_14PL & \ + MG54_15PL & MG54_16PL & MG54_17PL & MG54_18PL) +// End of MG54: + +// Beginning of MG55: +#if (G51PL >= G55PL) || (G51PL == 0) +#define MG55_11PL ~(1) +#else +#define MG55_11PL 0xFFFF +#endif +#if (G52PL >= G55PL) || (G52PL == 0) +#define MG55_12PL ~(1 << 1) +#else +#define MG55_12PL 0xFFFF +#endif +#if (G53PL >= G55PL) || (G53PL == 0) +#define MG55_13PL ~(1 << 2) +#else +#define MG55_13PL 0xFFFF +#endif +#if (G54PL >= G55PL) || (G54PL == 0) +#define MG55_14PL ~(1 << 3) +#else +#define MG55_14PL 0xFFFF +#endif +#if (G56PL >= G55PL) || (G56PL == 0) +#define MG55_16PL ~(1 << 5) +#else +#define MG55_16PL 0xFFFF +#endif +#if (G57PL >= G55PL) || (G57PL == 0) +#define MG55_17PL ~(1 << 6) +#else +#define MG55_17PL 0xFFFF +#endif +#if (G58PL >= G55PL) || (G58PL == 0) +#define MG55_18PL ~(1 << 7) +#else +#define MG55_18PL 0xFFFF +#endif +#define MG55_15PL 0x00EF +#define MG55 (MG55_11PL & MG55_12PL & MG55_13PL & MG55_14PL & \ + MG55_15PL & MG55_16PL & MG55_17PL & MG55_18PL) +// End of MG55: + +// Beginning of MG56: +#if (G51PL >= G56PL) || (G51PL == 0) +#define MG56_11PL ~(1) +#else +#define MG56_11PL 0xFFFF +#endif +#if (G52PL >= G56PL) || (G52PL == 0) +#define MG56_12PL ~(1 << 1) +#else +#define MG56_12PL 0xFFFF +#endif +#if (G53PL >= G56PL) || (G53PL == 0) +#define MG56_13PL ~(1 << 2) +#else +#define MG56_13PL 0xFFFF +#endif +#if (G54PL >= G56PL) || (G54PL == 0) +#define MG56_14PL ~(1 << 3) +#else +#define MG56_14PL 0xFFFF +#endif +#if (G55PL >= G56PL) || (G55PL == 0) +#define MG56_15PL ~(1 << 4) +#else +#define MG56_15PL 0xFFFF +#endif +#if (G57PL >= G56PL) || (G57PL == 0) +#define MG56_17PL ~(1 << 6) +#else +#define MG56_17PL 0xFFFF +#endif +#if (G58PL >= G56PL) || (G58PL == 0) +#define MG56_18PL ~(1 << 7) +#else +#define MG56_18PL 0xFFFF +#endif +#define MG56_16PL 0x00DF +#define MG56 (MG56_11PL & MG56_12PL & MG56_13PL & MG56_14PL & \ + MG56_15PL & MG56_16PL & MG56_17PL & MG56_18PL) +// End of MG56: + +// Beginning of MG57: +#if (G51PL >= G57PL) || (G51PL == 0) +#define MG57_11PL ~(1) +#else +#define MG57_11PL 0xFFFF +#endif +#if (G52PL >= G57PL) || (G52PL == 0) +#define MG57_12PL ~(1 << 1) +#else +#define MG57_12PL 0xFFFF +#endif +#if (G53PL >= G57PL) || (G53PL == 0) +#define MG57_13PL ~(1 << 2) +#else +#define MG57_13PL 0xFFFF +#endif +#if (G54PL >= G57PL) || (G54PL == 0) +#define MG57_14PL ~(1 << 3) +#else +#define MG57_14PL 0xFFFF +#endif +#if (G55PL >= G57PL) || (G55PL == 0) +#define MG57_15PL ~(1 << 4) +#else +#define MG57_15PL 0xFFFF +#endif +#if (G56PL >= G57PL) || (G56PL == 0) +#define MG57_16PL ~(1 << 5) +#else +#define MG57_16PL 0xFFFF +#endif +#if (G58PL >= G57PL) || (G58PL == 0) +#define MG57_18PL ~(1 << 7) +#else +#define MG57_18PL 0xFFFF +#endif +#define MG57_17PL 0x00BF +#define MG57 (MG57_11PL & MG57_12PL & MG57_13PL & MG57_14PL & \ + MG57_15PL & MG57_16PL & MG57_17PL & MG57_18PL) +// End of MG57: + +// Beginning of MG58: +#if (G51PL >= G58PL) || (G51PL == 0) +#define MG58_11PL ~(1) +#else +#define MG58_11PL 0xFFFF +#endif +#if (G52PL >= G58PL) || (G52PL == 0) +#define MG58_12PL ~(1 << 1) +#else +#define MG58_12PL 0xFFFF +#endif +#if (G53PL >= G58PL) || (G53PL == 0) +#define MG58_13PL ~(1 << 2) +#else +#define MG58_13PL 0xFFFF +#endif +#if (G54PL >= G58PL) || (G54PL == 0) +#define MG58_14PL ~(1 << 3) +#else +#define MG58_14PL 0xFFFF +#endif +#if (G55PL >= G58PL) || (G55PL == 0) +#define MG58_15PL ~(1 << 4) +#else +#define MG58_15PL 0xFFFF +#endif +#if (G56PL >= G58PL) || (G56PL == 0) +#define MG58_16PL ~(1 << 5) +#else +#define MG58_16PL 0xFFFF +#endif +#if (G57PL >= G58PL) || (G57PL == 0) +#define MG58_17PL ~(1 << 6) +#else +#define MG58_17PL 0xFFFF +#endif +#define MG58_18PL 0x007F +#define MG58 (MG58_11PL & MG58_12PL & MG58_13PL & MG58_14PL & \ + MG58_15PL & MG58_16PL & MG58_17PL & MG58_18PL) +// End of MG58: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG61 to MG68: +// + +// Beginning of MG61: +#if (G62PL >= G61PL) || (G62PL == 0) +#define MG61_12PL ~(1 << 1) +#else +#define MG61_12PL 0xFFFF +#endif +#if (G63PL >= G61PL) || (G63PL == 0) +#define MG61_13PL ~(1 << 2) +#else +#define MG61_13PL 0xFFFF +#endif +#if (G64PL >= G61PL) || (G64PL == 0) +#define MG61_14PL ~(1 << 3) +#else +#define MG61_14PL 0xFFFF +#endif +#if (G65PL >= G61PL) || (G65PL == 0) +#define MG61_15PL ~(1 << 4) +#else +#define MG61_15PL 0xFFFF +#endif +#if (G66PL >= G61PL) || (G66PL == 0) +#define MG61_16PL ~(1 << 5) +#else +#define MG61_16PL 0xFFFF +#endif +#if (G67PL >= G61PL) || (G67PL == 0) +#define MG61_17PL ~(1 << 6) +#else +#define MG61_17PL 0xFFFF +#endif +#if (G68PL >= G61PL) || (G68PL == 0) +#define MG61_18PL ~(1 << 7) +#else +#define MG61_18PL 0xFFFF +#endif +#define MG61_11PL 0x00FE +#define MG61 (MG61_11PL & MG61_12PL & MG61_13PL & MG61_14PL & \ + MG61_15PL & MG61_16PL & MG61_17PL & MG61_18PL) +// End of MG61: + +// Beginning of MG62: +#if (G61PL >= G62PL) || (G61PL == 0) +#define MG62_11PL ~(1) +#else +#define MG62_11PL 0xFFFF +#endif +#if (G63PL >= G62PL) || (G63PL == 0) +#define MG62_13PL ~(1 << 2) +#else +#define MG62_13PL 0xFFFF +#endif +#if (G64PL >= G62PL) || (G64PL == 0) +#define MG62_14PL ~(1 << 3) +#else +#define MG62_14PL 0xFFFF +#endif +#if (G65PL >= G62PL) || (G65PL == 0) +#define MG62_15PL ~(1 << 4) +#else +#define MG62_15PL 0xFFFF +#endif +#if (G66PL >= G62PL) || (G66PL == 0) +#define MG62_16PL ~(1 << 5) +#else +#define MG62_16PL 0xFFFF +#endif +#if (G67PL >= G62PL) || (G67PL == 0) +#define MG62_17PL ~(1 << 6) +#else +#define MG62_17PL 0xFFFF +#endif +#if (G68PL >= G62PL) || (G68PL == 0) +#define MG62_18PL ~(1 << 7) +#else +#define MG62_18PL 0xFFFF +#endif +#define MG62_12PL 0x00FD +#define MG62 (MG62_11PL & MG62_12PL & MG62_13PL & MG62_14PL & \ + MG62_15PL & MG62_16PL & MG62_17PL & MG62_18PL) +// End of MG62: + +// Beginning of MG63: +#if (G61PL >= G63PL) || (G61PL == 0) +#define MG63_11PL ~(1) +#else +#define MG63_11PL 0xFFFF +#endif +#if (G62PL >= G63PL) || (G62PL == 0) +#define MG63_12PL ~(1 << 1) +#else +#define MG63_12PL 0xFFFF +#endif +#if (G64PL >= G63PL) || (G64PL == 0) +#define MG63_14PL ~(1 << 3) +#else +#define MG63_14PL 0xFFFF +#endif +#if (G65PL >= G63PL) || (G65PL == 0) +#define MG63_15PL ~(1 << 4) +#else +#define MG63_15PL 0xFFFF +#endif +#if (G66PL >= G63PL) || (G66PL == 0) +#define MG63_16PL ~(1 << 5) +#else +#define MG63_16PL 0xFFFF +#endif +#if (G67PL >= G63PL) || (G67PL == 0) +#define MG63_17PL ~(1 << 6) +#else +#define MG63_17PL 0xFFFF +#endif +#if (G68PL >= G63PL) || (G68PL == 0) +#define MG63_18PL ~(1 << 7) +#else +#define MG63_18PL 0xFFFF +#endif +#define MG63_13PL 0x00FB +#define MG63 (MG63_11PL & MG63_12PL & MG63_13PL & MG63_14PL & \ + MG63_15PL & MG63_16PL & MG63_17PL & MG63_18PL) +// End of MG63: + +// Beginning of MG64: +#if (G61PL >= G64PL) || (G61PL == 0) +#define MG64_11PL ~(1) +#else +#define MG64_11PL 0xFFFF +#endif +#if (G62PL >= G64PL) || (G62PL == 0) +#define MG64_12PL ~(1 << 1) +#else +#define MG64_12PL 0xFFFF +#endif +#if (G63PL >= G64PL) || (G63PL == 0) +#define MG64_13PL ~(1 << 2) +#else +#define MG64_13PL 0xFFFF +#endif +#if (G65PL >= G64PL) || (G65PL == 0) +#define MG64_15PL ~(1 << 4) +#else +#define MG64_15PL 0xFFFF +#endif +#if (G66PL >= G64PL) || (G66PL == 0) +#define MG64_16PL ~(1 << 5) +#else +#define MG64_16PL 0xFFFF +#endif +#if (G67PL >= G64PL) || (G67PL == 0) +#define MG64_17PL ~(1 << 6) +#else +#define MG64_17PL 0xFFFF +#endif +#if (G68PL >= G64PL) || (G68PL == 0) +#define MG64_18PL ~(1 << 7) +#else +#define MG64_18PL 0xFFFF +#endif +#define MG64_14PL 0x00F7 +#define MG64 (MG64_11PL & MG64_12PL & MG64_13PL & MG64_14PL & \ + MG64_15PL & MG64_16PL & MG64_17PL & MG64_18PL) +// End of MG64: + +// Beginning of MG65: +#if (G61PL >= G65PL) || (G61PL == 0) +#define MG65_11PL ~(1) +#else +#define MG65_11PL 0xFFFF +#endif +#if (G62PL >= G65PL) || (G62PL == 0) +#define MG65_12PL ~(1 << 1) +#else +#define MG65_12PL 0xFFFF +#endif +#if (G63PL >= G65PL) || (G63PL == 0) +#define MG65_13PL ~(1 << 2) +#else +#define MG65_13PL 0xFFFF +#endif +#if (G64PL >= G65PL) || (G64PL == 0) +#define MG65_14PL ~(1 << 3) +#else +#define MG65_14PL 0xFFFF +#endif +#if (G66PL >= G65PL) || (G66PL == 0) +#define MG65_16PL ~(1 << 5) +#else +#define MG65_16PL 0xFFFF +#endif +#if (G67PL >= G65PL) || (G67PL == 0) +#define MG65_17PL ~(1 << 6) +#else +#define MG65_17PL 0xFFFF +#endif +#if (G68PL >= G65PL) || (G68PL == 0) +#define MG65_18PL ~(1 << 7) +#else +#define MG65_18PL 0xFFFF +#endif +#define MG65_15PL 0x00EF +#define MG65 (MG65_11PL & MG65_12PL & MG65_13PL & MG65_14PL & \ + MG65_15PL & MG65_16PL & MG65_17PL & MG65_18PL) +// End of MG65: + +// Beginning of MG66: +#if (G61PL >= G66PL) || (G61PL == 0) +#define MG66_11PL ~(1) +#else +#define MG66_11PL 0xFFFF +#endif +#if (G62PL >= G66PL) || (G62PL == 0) +#define MG66_12PL ~(1 << 1) +#else +#define MG66_12PL 0xFFFF +#endif +#if (G63PL >= G66PL) || (G63PL == 0) +#define MG66_13PL ~(1 << 2) +#else +#define MG66_13PL 0xFFFF +#endif +#if (G64PL >= G66PL) || (G64PL == 0) +#define MG66_14PL ~(1 << 3) +#else +#define MG66_14PL 0xFFFF +#endif +#if (G65PL >= G66PL) || (G65PL == 0) +#define MG66_15PL ~(1 << 4) +#else +#define MG66_15PL 0xFFFF +#endif +#if (G67PL >= G66PL) || (G67PL == 0) +#define MG66_17PL ~(1 << 6) +#else +#define MG66_17PL 0xFFFF +#endif +#if (G68PL >= G66PL) || (G68PL == 0) +#define MG66_18PL ~(1 << 7) +#else +#define MG66_18PL 0xFFFF +#endif +#define MG66_16PL 0x00DF +#define MG66 (MG66_11PL & MG66_12PL & MG66_13PL & MG66_14PL & \ + MG66_15PL & MG66_16PL & MG66_17PL & MG66_18PL) +// End of MG66: + +// Beginning of MG67: +#if (G61PL >= G67PL) || (G61PL == 0) +#define MG67_11PL ~(1) +#else +#define MG67_11PL 0xFFFF +#endif +#if (G62PL >= G67PL) || (G62PL == 0) +#define MG67_12PL ~(1 << 1) +#else +#define MG67_12PL 0xFFFF +#endif +#if (G63PL >= G67PL) || (G63PL == 0) +#define MG67_13PL ~(1 << 2) +#else +#define MG67_13PL 0xFFFF +#endif +#if (G64PL >= G67PL) || (G64PL == 0) +#define MG67_14PL ~(1 << 3) +#else +#define MG67_14PL 0xFFFF +#endif +#if (G65PL >= G67PL) || (G65PL == 0) +#define MG67_15PL ~(1 << 4) +#else +#define MG67_15PL 0xFFFF +#endif +#if (G66PL >= G67PL) || (G66PL == 0) +#define MG67_16PL ~(1 << 5) +#else +#define MG67_16PL 0xFFFF +#endif +#if (G68PL >= G67PL) || (G68PL == 0) +#define MG67_18PL ~(1 << 7) +#else +#define MG67_18PL 0xFFFF +#endif +#define MG67_17PL 0x00BF +#define MG67 (MG67_11PL & MG67_12PL & MG67_13PL & MG67_14PL & \ + MG67_15PL & MG67_16PL & MG67_17PL & MG67_18PL) +// End of MG67: + +// Beginning of MG68: +#if (G61PL >= G68PL) || (G61PL == 0) +#define MG68_11PL ~(1) +#else +#define MG68_11PL 0xFFFF +#endif +#if (G62PL >= G68PL) || (G62PL == 0) +#define MG68_12PL ~(1 << 1) +#else +#define MG68_12PL 0xFFFF +#endif +#if (G63PL >= G68PL) || (G63PL == 0) +#define MG68_13PL ~(1 << 2) +#else +#define MG68_13PL 0xFFFF +#endif +#if (G64PL >= G68PL) || (G64PL == 0) +#define MG68_14PL ~(1 << 3) +#else +#define MG68_14PL 0xFFFF +#endif +#if (G65PL >= G68PL) || (G65PL == 0) +#define MG68_15PL ~(1 << 4) +#else +#define MG68_15PL 0xFFFF +#endif +#if (G66PL >= G68PL) || (G66PL == 0) +#define MG68_16PL ~(1 << 5) +#else +#define MG68_16PL 0xFFFF +#endif +#if (G67PL >= G68PL) || (G67PL == 0) +#define MG68_17PL ~(1 << 6) +#else +#define MG68_17PL 0xFFFF +#endif +#define MG68_18PL 0x007F +#define MG68 (MG68_11PL & MG68_12PL & MG68_13PL & MG68_14PL & \ + MG68_15PL & MG68_16PL & MG68_17PL & MG68_18PL) +// End of MG68: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG71 to MG78: +// + +// Beginning of MG71: +#if (G72PL >= G71PL) || (G72PL == 0) +#define MG71_12PL ~(1 << 1) +#else +#define MG71_12PL 0xFFFF +#endif +#if (G73PL >= G71PL) || (G73PL == 0) +#define MG71_13PL ~(1 << 2) +#else +#define MG71_13PL 0xFFFF +#endif +#if (G74PL >= G71PL) || (G74PL == 0) +#define MG71_14PL ~(1 << 3) +#else +#define MG71_14PL 0xFFFF +#endif +#if (G75PL >= G71PL) || (G75PL == 0) +#define MG71_15PL ~(1 << 4) +#else +#define MG71_15PL 0xFFFF +#endif +#if (G76PL >= G71PL) || (G76PL == 0) +#define MG71_16PL ~(1 << 5) +#else +#define MG71_16PL 0xFFFF +#endif +#if (G77PL >= G71PL) || (G77PL == 0) +#define MG71_17PL ~(1 << 6) +#else +#define MG71_17PL 0xFFFF +#endif +#if (G78PL >= G71PL) || (G78PL == 0) +#define MG71_18PL ~(1 << 7) +#else +#define MG71_18PL 0xFFFF +#endif +#define MG71_11PL 0x00FE +#define MG71 (MG71_11PL & MG71_12PL & MG71_13PL & MG71_14PL & \ + MG71_15PL & MG71_16PL & MG71_17PL & MG71_18PL) +// End of MG71: + +// Beginning of MG72: +#if (G71PL >= G72PL) || (G71PL == 0) +#define MG72_11PL ~(1) +#else +#define MG72_11PL 0xFFFF +#endif +#if (G73PL >= G72PL) || (G73PL == 0) +#define MG72_13PL ~(1 << 2) +#else +#define MG72_13PL 0xFFFF +#endif +#if (G74PL >= G72PL) || (G74PL == 0) +#define MG72_14PL ~(1 << 3) +#else +#define MG72_14PL 0xFFFF +#endif +#if (G75PL >= G72PL) || (G75PL == 0) +#define MG72_15PL ~(1 << 4) +#else +#define MG72_15PL 0xFFFF +#endif +#if (G76PL >= G72PL) || (G76PL == 0) +#define MG72_16PL ~(1 << 5) +#else +#define MG72_16PL 0xFFFF +#endif +#if (G77PL >= G72PL) || (G77PL == 0) +#define MG72_17PL ~(1 << 6) +#else +#define MG72_17PL 0xFFFF +#endif +#if (G78PL >= G72PL) || (G78PL == 0) +#define MG72_18PL ~(1 << 7) +#else +#define MG72_18PL 0xFFFF +#endif +#define MG72_12PL 0x00FD +#define MG72 (MG72_11PL & MG72_12PL & MG72_13PL & MG72_14PL & \ + MG72_15PL & MG72_16PL & MG72_17PL & MG72_18PL) +// End of MG72: + +// Beginning of MG73: +#if (G71PL >= G73PL) || (G71PL == 0) +#define MG73_11PL ~(1) +#else +#define MG73_11PL 0xFFFF +#endif +#if (G72PL >= G73PL) || (G72PL == 0) +#define MG73_12PL ~(1 << 1) +#else +#define MG73_12PL 0xFFFF +#endif +#if (G74PL >= G73PL) || (G74PL == 0) +#define MG73_14PL ~(1 << 3) +#else +#define MG73_14PL 0xFFFF +#endif +#if (G75PL >= G73PL) || (G75PL == 0) +#define MG73_15PL ~(1 << 4) +#else +#define MG73_15PL 0xFFFF +#endif +#if (G76PL >= G73PL) || (G76PL == 0) +#define MG73_16PL ~(1 << 5) +#else +#define MG73_16PL 0xFFFF +#endif +#if (G77PL >= G73PL) || (G77PL == 0) +#define MG73_17PL ~(1 << 6) +#else +#define MG73_17PL 0xFFFF +#endif +#if (G78PL >= G73PL) || (G78PL == 0) +#define MG73_18PL ~(1 << 7) +#else +#define MG73_18PL 0xFFFF +#endif +#define MG73_13PL 0x00FB +#define MG73 (MG73_11PL & MG73_12PL & MG73_13PL & MG73_14PL & \ + MG73_15PL & MG73_16PL & MG73_17PL & MG73_18PL) +// End of MG73: + +// Beginning of MG74: +#if (G71PL >= G74PL) || (G71PL == 0) +#define MG74_11PL ~(1) +#else +#define MG74_11PL 0xFFFF +#endif +#if (G72PL >= G74PL) || (G72PL == 0) +#define MG74_12PL ~(1 << 1) +#else +#define MG74_12PL 0xFFFF +#endif +#if (G73PL >= G74PL) || (G73PL == 0) +#define MG74_13PL ~(1 << 2) +#else +#define MG74_13PL 0xFFFF +#endif +#if (G75PL >= G74PL) || (G75PL == 0) +#define MG74_15PL ~(1 << 4) +#else +#define MG74_15PL 0xFFFF +#endif +#if (G76PL >= G74PL) || (G76PL == 0) +#define MG74_16PL ~(1 << 5) +#else +#define MG74_16PL 0xFFFF +#endif +#if (G77PL >= G74PL) || (G77PL == 0) +#define MG74_17PL ~(1 << 6) +#else +#define MG74_17PL 0xFFFF +#endif +#if (G78PL >= G74PL) || (G78PL == 0) +#define MG74_18PL ~(1 << 7) +#else +#define MG74_18PL 0xFFFF +#endif +#define MG74_14PL 0x00F7 +#define MG74 (MG74_11PL & MG74_12PL & MG74_13PL & MG74_14PL & \ + MG74_15PL & MG74_16PL & MG74_17PL & MG74_18PL) +// End of MG74: + +// Beginning of MG75: +#if (G71PL >= G75PL) || (G71PL == 0) +#define MG75_11PL ~(1) +#else +#define MG75_11PL 0xFFFF +#endif +#if (G72PL >= G75PL) || (G72PL == 0) +#define MG75_12PL ~(1 << 1) +#else +#define MG75_12PL 0xFFFF +#endif +#if (G73PL >= G75PL) || (G73PL == 0) +#define MG75_13PL ~(1 << 2) +#else +#define MG75_13PL 0xFFFF +#endif +#if (G74PL >= G75PL) || (G74PL == 0) +#define MG75_14PL ~(1 << 3) +#else +#define MG75_14PL 0xFFFF +#endif +#if (G76PL >= G75PL) || (G76PL == 0) +#define MG75_16PL ~(1 << 5) +#else +#define MG75_16PL 0xFFFF +#endif +#if (G77PL >= G75PL) || (G77PL == 0) +#define MG75_17PL ~(1 << 6) +#else +#define MG75_17PL 0xFFFF +#endif +#if (G78PL >= G75PL) || (G78PL == 0) +#define MG75_18PL ~(1 << 7) +#else +#define MG75_18PL 0xFFFF +#endif +#define MG75_15PL 0x00EF +#define MG75 (MG75_11PL & MG75_12PL & MG75_13PL & MG75_14PL & \ + MG75_15PL & MG75_16PL & MG75_17PL & MG75_18PL) +// End of MG75: + +// Beginning of MG76: +#if (G71PL >= G76PL) || (G71PL == 0) +#define MG76_11PL ~(1) +#else +#define MG76_11PL 0xFFFF +#endif +#if (G72PL >= G76PL) || (G72PL == 0) +#define MG76_12PL ~(1 << 1) +#else +#define MG76_12PL 0xFFFF +#endif +#if (G73PL >= G76PL) || (G73PL == 0) +#define MG76_13PL ~(1 << 2) +#else +#define MG76_13PL 0xFFFF +#endif +#if (G74PL >= G76PL) || (G74PL == 0) +#define MG76_14PL ~(1 << 3) +#else +#define MG76_14PL 0xFFFF +#endif +#if (G75PL >= G76PL) || (G75PL == 0) +#define MG76_15PL ~(1 << 4) +#else +#define MG76_15PL 0xFFFF +#endif +#if (G77PL >= G76PL) || (G77PL == 0) +#define MG76_17PL ~(1 << 6) +#else +#define MG76_17PL 0xFFFF +#endif +#if (G78PL >= G76PL) || (G78PL == 0) +#define MG76_18PL ~(1 << 7) +#else +#define MG76_18PL 0xFFFF +#endif +#define MG76_16PL 0x00DF +#define MG76 (MG76_11PL & MG76_12PL & MG76_13PL & MG76_14PL & \ + MG76_15PL & MG76_16PL & MG76_17PL & MG76_18PL) +// End of MG76: + +// Beginning of MG77: +#if (G71PL >= G77PL) || (G71PL == 0) +#define MG77_11PL ~(1) +#else +#define MG77_11PL 0xFFFF +#endif +#if (G72PL >= G77PL) || (G72PL == 0) +#define MG77_12PL ~(1 << 1) +#else +#define MG77_12PL 0xFFFF +#endif +#if (G73PL >= G77PL) || (G73PL == 0) +#define MG77_13PL ~(1 << 2) +#else +#define MG77_13PL 0xFFFF +#endif +#if (G74PL >= G77PL) || (G74PL == 0) +#define MG77_14PL ~(1 << 3) +#else +#define MG77_14PL 0xFFFF +#endif +#if (G75PL >= G77PL) || (G75PL == 0) +#define MG77_15PL ~(1 << 4) +#else +#define MG77_15PL 0xFFFF +#endif +#if (G76PL >= G77PL) || (G76PL == 0) +#define MG77_16PL ~(1 << 5) +#else +#define MG77_16PL 0xFFFF +#endif +#if (G78PL >= G77PL) || (G78PL == 0) +#define MG77_18PL ~(1 << 7) +#else +#define MG77_18PL 0xFFFF +#endif +#define MG77_17PL 0x00BF +#define MG77 (MG77_11PL & MG77_12PL & MG77_13PL & MG77_14PL & \ + MG77_15PL & MG77_16PL & MG77_17PL & MG77_18PL) +// End of MG77: + +// Beginning of MG78: +#if (G71PL >= G78PL) || (G71PL == 0) +#define MG78_11PL ~(1) +#else +#define MG78_11PL 0xFFFF +#endif +#if (G72PL >= G78PL) || (G72PL == 0) +#define MG78_12PL ~(1 << 1) +#else +#define MG78_12PL 0xFFFF +#endif +#if (G73PL >= G78PL) || (G73PL == 0) +#define MG78_13PL ~(1 << 2) +#else +#define MG78_13PL 0xFFFF +#endif +#if (G74PL >= G78PL) || (G74PL == 0) +#define MG78_14PL ~(1 << 3) +#else +#define MG78_14PL 0xFFFF +#endif +#if (G75PL >= G78PL) || (G75PL == 0) +#define MG78_15PL ~(1 << 4) +#else +#define MG78_15PL 0xFFFF +#endif +#if (G76PL >= G78PL) || (G76PL == 0) +#define MG78_16PL ~(1 << 5) +#else +#define MG78_16PL 0xFFFF +#endif +#if (G77PL >= G78PL) || (G77PL == 0) +#define MG78_17PL ~(1 << 6) +#else +#define MG78_17PL 0xFFFF +#endif +#define MG78_18PL 0x007F +#define MG78 (MG78_11PL & MG78_12PL & MG78_13PL & MG78_14PL & \ + MG78_15PL & MG78_16PL & MG78_17PL & MG78_18PL) +// End of MG78: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG81 to MG88: +// + +// Beginning of MG81: +#if (G82PL >= G81PL) || (G82PL == 0) +#define MG81_12PL ~(1 << 1) +#else +#define MG81_12PL 0xFFFF +#endif +#if (G83PL >= G81PL) || (G83PL == 0) +#define MG81_13PL ~(1 << 2) +#else +#define MG81_13PL 0xFFFF +#endif +#if (G84PL >= G81PL) || (G84PL == 0) +#define MG81_14PL ~(1 << 3) +#else +#define MG81_14PL 0xFFFF +#endif +#if (G85PL >= G81PL) || (G85PL == 0) +#define MG81_15PL ~(1 << 4) +#else +#define MG81_15PL 0xFFFF +#endif +#if (G86PL >= G81PL) || (G86PL == 0) +#define MG81_16PL ~(1 << 5) +#else +#define MG81_16PL 0xFFFF +#endif +#if (G87PL >= G81PL) || (G87PL == 0) +#define MG81_17PL ~(1 << 6) +#else +#define MG81_17PL 0xFFFF +#endif +#if (G88PL >= G81PL) || (G88PL == 0) +#define MG81_18PL ~(1 << 7) +#else +#define MG81_18PL 0xFFFF +#endif +#define MG81_11PL 0x00FE +#define MG81 (MG81_11PL & MG81_12PL & MG81_13PL & MG81_14PL & \ + MG81_15PL & MG81_16PL & MG81_17PL & MG81_18PL) +// End of MG81: + +// Beginning of MG82: +#if (G81PL >= G82PL) || (G81PL == 0) +#define MG82_11PL ~(1) +#else +#define MG82_11PL 0xFFFF +#endif +#if (G83PL >= G82PL) || (G83PL == 0) +#define MG82_13PL ~(1 << 2) +#else +#define MG82_13PL 0xFFFF +#endif +#if (G84PL >= G82PL) || (G84PL == 0) +#define MG82_14PL ~(1 << 3) +#else +#define MG82_14PL 0xFFFF +#endif +#if (G85PL >= G82PL) || (G85PL == 0) +#define MG82_15PL ~(1 << 4) +#else +#define MG82_15PL 0xFFFF +#endif +#if (G86PL >= G82PL) || (G86PL == 0) +#define MG82_16PL ~(1 << 5) +#else +#define MG82_16PL 0xFFFF +#endif +#if (G87PL >= G82PL) || (G87PL == 0) +#define MG82_17PL ~(1 << 6) +#else +#define MG82_17PL 0xFFFF +#endif +#if (G88PL >= G82PL) || (G88PL == 0) +#define MG82_18PL ~(1 << 7) +#else +#define MG82_18PL 0xFFFF +#endif +#define MG82_12PL 0x00FD +#define MG82 (MG82_11PL & MG82_12PL & MG82_13PL & MG82_14PL & \ + MG82_15PL & MG82_16PL & MG82_17PL & MG82_18PL) +// End of MG82: + +// Beginning of MG83: +#if (G81PL >= G83PL) || (G81PL == 0) +#define MG83_11PL ~(1) +#else +#define MG83_11PL 0xFFFF +#endif +#if (G82PL >= G83PL) || (G82PL == 0) +#define MG83_12PL ~(1 << 1) +#else +#define MG83_12PL 0xFFFF +#endif +#if (G84PL >= G83PL) || (G84PL == 0) +#define MG83_14PL ~(1 << 3) +#else +#define MG83_14PL 0xFFFF +#endif +#if (G85PL >= G83PL) || (G85PL == 0) +#define MG83_15PL ~(1 << 4) +#else +#define MG83_15PL 0xFFFF +#endif +#if (G86PL >= G83PL) || (G86PL == 0) +#define MG83_16PL ~(1 << 5) +#else +#define MG83_16PL 0xFFFF +#endif +#if (G87PL >= G83PL) || (G87PL == 0) +#define MG83_17PL ~(1 << 6) +#else +#define MG83_17PL 0xFFFF +#endif +#if (G88PL >= G83PL) || (G88PL == 0) +#define MG83_18PL ~(1 << 7) +#else +#define MG83_18PL 0xFFFF +#endif +#define MG83_13PL 0x00FB +#define MG83 (MG83_11PL & MG83_12PL & MG83_13PL & MG83_14PL & \ + MG83_15PL & MG83_16PL & MG83_17PL & MG83_18PL) +// End of MG83: + +// Beginning of MG84: +#if (G81PL >= G84PL) || (G81PL == 0) +#define MG84_11PL ~(1) +#else +#define MG84_11PL 0xFFFF +#endif +#if (G82PL >= G84PL) || (G82PL == 0) +#define MG84_12PL ~(1 << 1) +#else +#define MG84_12PL 0xFFFF +#endif +#if (G83PL >= G84PL) || (G83PL == 0) +#define MG84_13PL ~(1 << 2) +#else +#define MG84_13PL 0xFFFF +#endif +#if (G85PL >= G84PL) || (G85PL == 0) +#define MG84_15PL ~(1 << 4) +#else +#define MG84_15PL 0xFFFF +#endif +#if (G86PL >= G84PL) || (G86PL == 0) +#define MG84_16PL ~(1 << 5) +#else +#define MG84_16PL 0xFFFF +#endif +#if (G87PL >= G84PL) || (G87PL == 0) +#define MG84_17PL ~(1 << 6) +#else +#define MG84_17PL 0xFFFF +#endif +#if (G88PL >= G84PL) || (G88PL == 0) +#define MG84_18PL ~(1 << 7) +#else +#define MG84_18PL 0xFFFF +#endif +#define MG84_14PL 0x00F7 +#define MG84 (MG84_11PL & MG84_12PL & MG84_13PL & MG84_14PL & \ + MG84_15PL & MG84_16PL & MG84_17PL & MG84_18PL) +// End of MG84: + +// Beginning of MG85: +#if (G81PL >= G85PL) || (G81PL == 0) +#define MG85_11PL ~(1) +#else +#define MG85_11PL 0xFFFF +#endif +#if (G82PL >= G85PL) || (G82PL == 0) +#define MG85_12PL ~(1 << 1) +#else +#define MG85_12PL 0xFFFF +#endif +#if (G83PL >= G85PL) || (G83PL == 0) +#define MG85_13PL ~(1 << 2) +#else +#define MG85_13PL 0xFFFF +#endif +#if (G84PL >= G85PL) || (G84PL == 0) +#define MG85_14PL ~(1 << 3) +#else +#define MG85_14PL 0xFFFF +#endif +#if (G86PL >= G85PL) || (G86PL == 0) +#define MG85_16PL ~(1 << 5) +#else +#define MG85_16PL 0xFFFF +#endif +#if (G87PL >= G85PL) || (G87PL == 0) +#define MG85_17PL ~(1 << 6) +#else +#define MG85_17PL 0xFFFF +#endif +#if (G88PL >= G85PL) || (G88PL == 0) +#define MG85_18PL ~(1 << 7) +#else +#define MG85_18PL 0xFFFF +#endif +#define MG85_15PL 0x00EF +#define MG85 (MG85_11PL & MG85_12PL & MG85_13PL & MG85_14PL & \ + MG85_15PL & MG85_16PL & MG85_17PL & MG85_18PL) +// End of MG85: + +// Beginning of MG86: +#if (G81PL >= G86PL) || (G81PL == 0) +#define MG86_11PL ~(1) +#else +#define MG86_11PL 0xFFFF +#endif +#if (G82PL >= G86PL) || (G82PL == 0) +#define MG86_12PL ~(1 << 1) +#else +#define MG86_12PL 0xFFFF +#endif +#if (G83PL >= G86PL) || (G83PL == 0) +#define MG86_13PL ~(1 << 2) +#else +#define MG86_13PL 0xFFFF +#endif +#if (G84PL >= G86PL) || (G84PL == 0) +#define MG86_14PL ~(1 << 3) +#else +#define MG86_14PL 0xFFFF +#endif +#if (G85PL >= G86PL) || (G85PL == 0) +#define MG86_15PL ~(1 << 4) +#else +#define MG86_15PL 0xFFFF +#endif +#if (G87PL >= G86PL) || (G87PL == 0) +#define MG86_17PL ~(1 << 6) +#else +#define MG86_17PL 0xFFFF +#endif +#if (G88PL >= G86PL) || (G88PL == 0) +#define MG86_18PL ~(1 << 7) +#else +#define MG86_18PL 0xFFFF +#endif +#define MG86_16PL 0x00DF +#define MG86 (MG86_11PL & MG86_12PL & MG86_13PL & MG86_14PL & \ + MG86_15PL & MG86_16PL & MG86_17PL & MG86_18PL) +// End of MG86: + +// Beginning of MG87: +#if (G81PL >= G87PL) || (G81PL == 0) +#define MG87_11PL ~(1) +#else +#define MG87_11PL 0xFFFF +#endif +#if (G82PL >= G87PL) || (G82PL == 0) +#define MG87_12PL ~(1 << 1) +#else +#define MG87_12PL 0xFFFF +#endif +#if (G83PL >= G87PL) || (G83PL == 0) +#define MG87_13PL ~(1 << 2) +#else +#define MG87_13PL 0xFFFF +#endif +#if (G84PL >= G87PL) || (G84PL == 0) +#define MG87_14PL ~(1 << 3) +#else +#define MG87_14PL 0xFFFF +#endif +#if (G85PL >= G87PL) || (G85PL == 0) +#define MG87_15PL ~(1 << 4) +#else +#define MG87_15PL 0xFFFF +#endif +#if (G86PL >= G87PL) || (G86PL == 0) +#define MG87_16PL ~(1 << 5) +#else +#define MG87_16PL 0xFFFF +#endif +#if (G88PL >= G87PL) || (G88PL == 0) +#define MG87_18PL ~(1 << 7) +#else +#define MG87_18PL 0xFFFF +#endif +#define MG87_17PL 0x00BF +#define MG87 (MG87_11PL & MG87_12PL & MG87_13PL & MG87_14PL & \ + MG87_15PL & MG87_16PL & MG87_17PL & MG87_18PL) +// End of MG87: + +// Beginning of MG88: +#if (G81PL >= G88PL) || (G81PL == 0) +#define MG88_11PL ~(1) +#else +#define MG88_11PL 0xFFFF +#endif +#if (G82PL >= G88PL) || (G82PL == 0) +#define MG88_12PL ~(1 << 1) +#else +#define MG88_12PL 0xFFFF +#endif +#if (G83PL >= G88PL) || (G83PL == 0) +#define MG88_13PL ~(1 << 2) +#else +#define MG88_13PL 0xFFFF +#endif +#if (G84PL >= G88PL) || (G84PL == 0) +#define MG88_14PL ~(1 << 3) +#else +#define MG88_14PL 0xFFFF +#endif +#if (G85PL >= G88PL) || (G85PL == 0) +#define MG88_15PL ~(1 << 4) +#else +#define MG88_15PL 0xFFFF +#endif +#if (G86PL >= G88PL) || (G86PL == 0) +#define MG88_16PL ~(1 << 5) +#else +#define MG88_16PL 0xFFFF +#endif +#if (G87PL >= G88PL) || (G87PL == 0) +#define MG88_17PL ~(1 << 6) +#else +#define MG88_17PL 0xFFFF +#endif +#define MG88_18PL 0x007F +#define MG88 (MG88_11PL & MG88_12PL & MG88_13PL & MG88_14PL & \ + MG88_15PL & MG88_16PL & MG88_17PL & MG88_18PL) +// End of MG88: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG91 to MG98: +// + +// Beginning of MG91: +#if (G92PL >= G91PL) || (G92PL == 0) +#define MG91_12PL ~(1 << 1) +#else +#define MG91_12PL 0xFFFF +#endif +#if (G93PL >= G91PL) || (G93PL == 0) +#define MG91_13PL ~(1 << 2) +#else +#define MG91_13PL 0xFFFF +#endif +#if (G94PL >= G91PL) || (G94PL == 0) +#define MG91_14PL ~(1 << 3) +#else +#define MG91_14PL 0xFFFF +#endif +#if (G95PL >= G91PL) || (G95PL == 0) +#define MG91_15PL ~(1 << 4) +#else +#define MG91_15PL 0xFFFF +#endif +#if (G96PL >= G91PL) || (G96PL == 0) +#define MG91_16PL ~(1 << 5) +#else +#define MG91_16PL 0xFFFF +#endif +#if (G97PL >= G91PL) || (G97PL == 0) +#define MG91_17PL ~(1 << 6) +#else +#define MG91_17PL 0xFFFF +#endif +#if (G98PL >= G91PL) || (G98PL == 0) +#define MG91_18PL ~(1 << 7) +#else +#define MG91_18PL 0xFFFF +#endif +#define MG91_11PL 0x00FE +#define MG91 (MG91_11PL & MG91_12PL & MG91_13PL & MG91_14PL & \ + MG91_15PL & MG91_16PL & MG91_17PL & MG91_18PL) +// End of MG91: + +// Beginning of MG92: +#if (G91PL >= G92PL) || (G91PL == 0) +#define MG92_11PL ~(1) +#else +#define MG92_11PL 0xFFFF +#endif +#if (G93PL >= G92PL) || (G93PL == 0) +#define MG92_13PL ~(1 << 2) +#else +#define MG92_13PL 0xFFFF +#endif +#if (G94PL >= G92PL) || (G94PL == 0) +#define MG92_14PL ~(1 << 3) +#else +#define MG92_14PL 0xFFFF +#endif +#if (G95PL >= G92PL) || (G95PL == 0) +#define MG92_15PL ~(1 << 4) +#else +#define MG92_15PL 0xFFFF +#endif +#if (G96PL >= G92PL) || (G96PL == 0) +#define MG92_16PL ~(1 << 5) +#else +#define MG92_16PL 0xFFFF +#endif +#if (G97PL >= G92PL) || (G97PL == 0) +#define MG92_17PL ~(1 << 6) +#else +#define MG92_17PL 0xFFFF +#endif +#if (G98PL >= G92PL) || (G98PL == 0) +#define MG92_18PL ~(1 << 7) +#else +#define MG92_18PL 0xFFFF +#endif +#define MG92_12PL 0x00FD +#define MG92 (MG92_11PL & MG92_12PL & MG92_13PL & MG92_14PL & \ + MG92_15PL & MG92_16PL & MG92_17PL & MG92_18PL) +// End of MG92: + +// Beginning of MG93: +#if (G91PL >= G93PL) || (G91PL == 0) +#define MG93_11PL ~(1) +#else +#define MG93_11PL 0xFFFF +#endif +#if (G92PL >= G93PL) || (G92PL == 0) +#define MG93_12PL ~(1 << 1) +#else +#define MG93_12PL 0xFFFF +#endif +#if (G94PL >= G93PL) || (G94PL == 0) +#define MG93_14PL ~(1 << 3) +#else +#define MG93_14PL 0xFFFF +#endif +#if (G95PL >= G93PL) || (G95PL == 0) +#define MG93_15PL ~(1 << 4) +#else +#define MG93_15PL 0xFFFF +#endif +#if (G96PL >= G93PL) || (G96PL == 0) +#define MG93_16PL ~(1 << 5) +#else +#define MG93_16PL 0xFFFF +#endif +#if (G97PL >= G93PL) || (G97PL == 0) +#define MG93_17PL ~(1 << 6) +#else +#define MG93_17PL 0xFFFF +#endif +#if (G98PL >= G93PL) || (G98PL == 0) +#define MG93_18PL ~(1 << 7) +#else +#define MG93_18PL 0xFFFF +#endif +#define MG93_13PL 0x00FB +#define MG93 (MG93_11PL & MG93_12PL & MG93_13PL & MG93_14PL & \ + MG93_15PL & MG93_16PL & MG93_17PL & MG93_18PL) +// End of MG93: + +// Beginning of MG94: +#if (G91PL >= G94PL) || (G91PL == 0) +#define MG94_11PL ~(1) +#else +#define MG94_11PL 0xFFFF +#endif +#if (G92PL >= G94PL) || (G92PL == 0) +#define MG94_12PL ~(1 << 1) +#else +#define MG94_12PL 0xFFFF +#endif +#if (G93PL >= G94PL) || (G93PL == 0) +#define MG94_13PL ~(1 << 2) +#else +#define MG94_13PL 0xFFFF +#endif +#if (G95PL >= G94PL) || (G95PL == 0) +#define MG94_15PL ~(1 << 4) +#else +#define MG94_15PL 0xFFFF +#endif +#if (G96PL >= G94PL) || (G96PL == 0) +#define MG94_16PL ~(1 << 5) +#else +#define MG94_16PL 0xFFFF +#endif +#if (G97PL >= G94PL) || (G97PL == 0) +#define MG94_17PL ~(1 << 6) +#else +#define MG94_17PL 0xFFFF +#endif +#if (G98PL >= G94PL) || (G98PL == 0) +#define MG94_18PL ~(1 << 7) +#else +#define MG94_18PL 0xFFFF +#endif +#define MG94_14PL 0x00F7 +#define MG94 (MG94_11PL & MG94_12PL & MG94_13PL & MG94_14PL & \ + MG94_15PL & MG94_16PL & MG94_17PL & MG94_18PL) +// End of MG94: + +// Beginning of MG95: +#if (G91PL >= G95PL) || (G91PL == 0) +#define MG95_11PL ~(1) +#else +#define MG95_11PL 0xFFFF +#endif +#if (G92PL >= G95PL) || (G92PL == 0) +#define MG95_12PL ~(1 << 1) +#else +#define MG95_12PL 0xFFFF +#endif +#if (G93PL >= G95PL) || (G93PL == 0) +#define MG95_13PL ~(1 << 2) +#else +#define MG95_13PL 0xFFFF +#endif +#if (G94PL >= G95PL) || (G94PL == 0) +#define MG95_14PL ~(1 << 3) +#else +#define MG95_14PL 0xFFFF +#endif +#if (G96PL >= G95PL) || (G96PL == 0) +#define MG95_16PL ~(1 << 5) +#else +#define MG95_16PL 0xFFFF +#endif +#if (G97PL >= G95PL) || (G97PL == 0) +#define MG95_17PL ~(1 << 6) +#else +#define MG95_17PL 0xFFFF +#endif +#if (G98PL >= G95PL) || (G98PL == 0) +#define MG95_18PL ~(1 << 7) +#else +#define MG95_18PL 0xFFFF +#endif +#define MG95_15PL 0x00EF +#define MG95 (MG95_11PL & MG95_12PL & MG95_13PL & MG95_14PL & \ + MG95_15PL & MG95_16PL & MG95_17PL & MG95_18PL) +// End of MG95: + +// Beginning of MG96: +#if (G91PL >= G96PL) || (G91PL == 0) +#define MG96_11PL ~(1) +#else +#define MG96_11PL 0xFFFF +#endif +#if (G92PL >= G96PL) || (G92PL == 0) +#define MG96_12PL ~(1 << 1) +#else +#define MG96_12PL 0xFFFF +#endif +#if (G93PL >= G96PL) || (G93PL == 0) +#define MG96_13PL ~(1 << 2) +#else +#define MG96_13PL 0xFFFF +#endif +#if (G94PL >= G96PL) || (G94PL == 0) +#define MG96_14PL ~(1 << 3) +#else +#define MG96_14PL 0xFFFF +#endif +#if (G95PL >= G96PL) || (G95PL == 0) +#define MG96_15PL ~(1 << 4) +#else +#define MG96_15PL 0xFFFF +#endif +#if (G97PL >= G96PL) || (G97PL == 0) +#define MG96_17PL ~(1 << 6) +#else +#define MG96_17PL 0xFFFF +#endif +#if (G98PL >= G96PL) || (G98PL == 0) +#define MG96_18PL ~(1 << 7) +#else +#define MG96_18PL 0xFFFF +#endif +#define MG96_16PL 0x00DF +#define MG96 (MG96_11PL & MG96_12PL & MG96_13PL & MG96_14PL & \ + MG96_15PL & MG96_16PL & MG96_17PL & MG96_18PL) +// End of MG96: + +// Beginning of MG97: +#if (G91PL >= G97PL) || (G91PL == 0) +#define MG97_11PL ~(1) +#else +#define MG97_11PL 0xFFFF +#endif +#if (G92PL >= G97PL) || (G92PL == 0) +#define MG97_12PL ~(1 << 1) +#else +#define MG97_12PL 0xFFFF +#endif +#if (G93PL >= G97PL) || (G93PL == 0) +#define MG97_13PL ~(1 << 2) +#else +#define MG97_13PL 0xFFFF +#endif +#if (G94PL >= G97PL) || (G94PL == 0) +#define MG97_14PL ~(1 << 3) +#else +#define MG97_14PL 0xFFFF +#endif +#if (G95PL >= G97PL) || (G95PL == 0) +#define MG97_15PL ~(1 << 4) +#else +#define MG97_15PL 0xFFFF +#endif +#if (G96PL >= G97PL) || (G96PL == 0) +#define MG97_16PL ~(1 << 5) +#else +#define MG97_16PL 0xFFFF +#endif +#if (G98PL >= G97PL) || (G98PL == 0) +#define MG97_18PL ~(1 << 7) +#else +#define MG97_18PL 0xFFFF +#endif +#define MG97_17PL 0x00BF +#define MG97 (MG97_11PL & MG97_12PL & MG97_13PL & MG97_14PL & \ + MG97_15PL & MG97_16PL & MG97_17PL & MG97_18PL) +// End of MG97: + +// Beginning of MG98: +#if (G91PL >= G98PL) || (G91PL == 0) +#define MG98_11PL ~(1) +#else +#define MG98_11PL 0xFFFF +#endif +#if (G92PL >= G98PL) || (G92PL == 0) +#define MG98_12PL ~(1 << 1) +#else +#define MG98_12PL 0xFFFF +#endif +#if (G93PL >= G98PL) || (G93PL == 0) +#define MG98_13PL ~(1 << 2) +#else +#define MG98_13PL 0xFFFF +#endif +#if (G94PL >= G98PL) || (G94PL == 0) +#define MG98_14PL ~(1 << 3) +#else +#define MG98_14PL 0xFFFF +#endif +#if (G95PL >= G98PL) || (G95PL == 0) +#define MG98_15PL ~(1 << 4) +#else +#define MG98_15PL 0xFFFF +#endif +#if (G96PL >= G98PL) || (G96PL == 0) +#define MG98_16PL ~(1 << 5) +#else +#define MG98_16PL 0xFFFF +#endif +#if (G97PL >= G98PL) || (G97PL == 0) +#define MG98_17PL ~(1 << 6) +#else +#define MG98_17PL 0xFFFF +#endif +#define MG98_18PL 0x007F +#define MG98 (MG98_11PL & MG98_12PL & MG98_13PL & MG98_14PL & \ + MG98_15PL & MG98_16PL & MG98_17PL & MG98_18PL) +// End of MG98: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG101 to MG108: +// + +// Beginning of MG101: +#if (G102PL >= G101PL) || (G102PL == 0) +#define MG101_12PL ~(1 << 1) +#else +#define MG101_12PL 0xFFFF +#endif +#if (G103PL >= G101PL) || (G103PL == 0) +#define MG101_13PL ~(1 << 2) +#else +#define MG101_13PL 0xFFFF +#endif +#if (G104PL >= G101PL) || (G104PL == 0) +#define MG101_14PL ~(1 << 3) +#else +#define MG101_14PL 0xFFFF +#endif +#if (G105PL >= G101PL) || (G105PL == 0) +#define MG101_15PL ~(1 << 4) +#else +#define MG101_15PL 0xFFFF +#endif +#if (G106PL >= G101PL) || (G106PL == 0) +#define MG101_16PL ~(1 << 5) +#else +#define MG101_16PL 0xFFFF +#endif +#if (G107PL >= G101PL) || (G107PL == 0) +#define MG101_17PL ~(1 << 6) +#else +#define MG101_17PL 0xFFFF +#endif +#if (G108PL >= G101PL) || (G108PL == 0) +#define MG101_18PL ~(1 << 7) +#else +#define MG101_18PL 0xFFFF +#endif +#define MG101_11PL 0x00FE +#define MG101 (MG101_11PL & MG101_12PL & MG101_13PL & MG101_14PL & \ + MG101_15PL & MG101_16PL & MG101_17PL & MG101_18PL) +// End of MG101: + +// Beginning of MG102: +#if (G101PL >= G102PL) || (G101PL == 0) +#define MG102_11PL ~(1) +#else +#define MG102_11PL 0xFFFF +#endif +#if (G103PL >= G102PL) || (G103PL == 0) +#define MG102_13PL ~(1 << 2) +#else +#define MG102_13PL 0xFFFF +#endif +#if (G104PL >= G102PL) || (G104PL == 0) +#define MG102_14PL ~(1 << 3) +#else +#define MG102_14PL 0xFFFF +#endif +#if (G105PL >= G102PL) || (G105PL == 0) +#define MG102_15PL ~(1 << 4) +#else +#define MG102_15PL 0xFFFF +#endif +#if (G106PL >= G102PL) || (G106PL == 0) +#define MG102_16PL ~(1 << 5) +#else +#define MG102_16PL 0xFFFF +#endif +#if (G107PL >= G102PL) || (G107PL == 0) +#define MG102_17PL ~(1 << 6) +#else +#define MG102_17PL 0xFFFF +#endif +#if (G108PL >= G102PL) || (G108PL == 0) +#define MG102_18PL ~(1 << 7) +#else +#define MG102_18PL 0xFFFF +#endif +#define MG102_12PL 0x00FD +#define MG102 (MG102_11PL & MG102_12PL & MG102_13PL & MG102_14PL & \ + MG102_15PL & MG102_16PL & MG102_17PL & MG102_18PL) +// End of MG102: + +// Beginning of MG103: +#if (G101PL >= G103PL) || (G101PL == 0) +#define MG103_11PL ~(1) +#else +#define MG103_11PL 0xFFFF +#endif +#if (G102PL >= G103PL) || (G102PL == 0) +#define MG103_12PL ~(1 << 1) +#else +#define MG103_12PL 0xFFFF +#endif +#if (G104PL >= G103PL) || (G104PL == 0) +#define MG103_14PL ~(1 << 3) +#else +#define MG103_14PL 0xFFFF +#endif +#if (G105PL >= G103PL) || (G105PL == 0) +#define MG103_15PL ~(1 << 4) +#else +#define MG103_15PL 0xFFFF +#endif +#if (G106PL >= G103PL) || (G106PL == 0) +#define MG103_16PL ~(1 << 5) +#else +#define MG103_16PL 0xFFFF +#endif +#if (G107PL >= G103PL) || (G107PL == 0) +#define MG103_17PL ~(1 << 6) +#else +#define MG103_17PL 0xFFFF +#endif +#if (G108PL >= G103PL) || (G108PL == 0) +#define MG103_18PL ~(1 << 7) +#else +#define MG103_18PL 0xFFFF +#endif +#define MG103_13PL 0x00FB +#define MG103 (MG103_11PL & MG103_12PL & MG103_13PL & MG103_14PL & \ + MG103_15PL & MG103_16PL & MG103_17PL & MG103_18PL) +// End of MG103: + +// Beginning of MG104: +#if (G101PL >= G104PL) || (G101PL == 0) +#define MG104_11PL ~(1) +#else +#define MG104_11PL 0xFFFF +#endif +#if (G102PL >= G104PL) || (G102PL == 0) +#define MG104_12PL ~(1 << 1) +#else +#define MG104_12PL 0xFFFF +#endif +#if (G103PL >= G104PL) || (G103PL == 0) +#define MG104_13PL ~(1 << 2) +#else +#define MG104_13PL 0xFFFF +#endif +#if (G105PL >= G104PL) || (G105PL == 0) +#define MG104_15PL ~(1 << 4) +#else +#define MG104_15PL 0xFFFF +#endif +#if (G106PL >= G104PL) || (G106PL == 0) +#define MG104_16PL ~(1 << 5) +#else +#define MG104_16PL 0xFFFF +#endif +#if (G107PL >= G104PL) || (G107PL == 0) +#define MG104_17PL ~(1 << 6) +#else +#define MG104_17PL 0xFFFF +#endif +#if (G108PL >= G104PL) || (G108PL == 0) +#define MG104_18PL ~(1 << 7) +#else +#define MG104_18PL 0xFFFF +#endif +#define MG104_14PL 0x00F7 +#define MG104 (MG104_11PL & MG104_12PL & MG104_13PL & MG104_14PL & \ + MG104_15PL & MG104_16PL & MG104_17PL & MG104_18PL) +// End of MG104: + +// Beginning of MG105: +#if (G101PL >= G105PL) || (G101PL == 0) +#define MG105_11PL ~(1) +#else +#define MG105_11PL 0xFFFF +#endif +#if (G102PL >= G105PL) || (G102PL == 0) +#define MG105_12PL ~(1 << 1) +#else +#define MG105_12PL 0xFFFF +#endif +#if (G103PL >= G105PL) || (G103PL == 0) +#define MG105_13PL ~(1 << 2) +#else +#define MG105_13PL 0xFFFF +#endif +#if (G104PL >= G105PL) || (G104PL == 0) +#define MG105_14PL ~(1 << 3) +#else +#define MG105_14PL 0xFFFF +#endif +#if (G106PL >= G105PL) || (G106PL == 0) +#define MG105_16PL ~(1 << 5) +#else +#define MG105_16PL 0xFFFF +#endif +#if (G107PL >= G105PL) || (G107PL == 0) +#define MG105_17PL ~(1 << 6) +#else +#define MG105_17PL 0xFFFF +#endif +#if (G108PL >= G105PL) || (G108PL == 0) +#define MG105_18PL ~(1 << 7) +#else +#define MG105_18PL 0xFFFF +#endif +#define MG105_15PL 0x00EF +#define MG105 (MG105_11PL & MG105_12PL & MG105_13PL & MG105_14PL & \ + MG105_15PL & MG105_16PL & MG105_17PL & MG105_18PL) +// End of MG105: + +// Beginning of MG106: +#if (G101PL >= G106PL) || (G101PL == 0) +#define MG106_11PL ~(1) +#else +#define MG106_11PL 0xFFFF +#endif +#if (G102PL >= G106PL) || (G102PL == 0) +#define MG106_12PL ~(1 << 1) +#else +#define MG106_12PL 0xFFFF +#endif +#if (G103PL >= G106PL) || (G103PL == 0) +#define MG106_13PL ~(1 << 2) +#else +#define MG106_13PL 0xFFFF +#endif +#if (G104PL >= G106PL) || (G104PL == 0) +#define MG106_14PL ~(1 << 3) +#else +#define MG106_14PL 0xFFFF +#endif +#if (G105PL >= G106PL) || (G105PL == 0) +#define MG106_15PL ~(1 << 4) +#else +#define MG106_15PL 0xFFFF +#endif +#if (G107PL >= G106PL) || (G107PL == 0) +#define MG106_17PL ~(1 << 6) +#else +#define MG106_17PL 0xFFFF +#endif +#if (G108PL >= G106PL) || (G108PL == 0) +#define MG106_18PL ~(1 << 7) +#else +#define MG106_18PL 0xFFFF +#endif +#define MG106_16PL 0x00DF +#define MG106 (MG106_11PL & MG106_12PL & MG106_13PL & MG106_14PL & \ + MG106_15PL & MG106_16PL & MG106_17PL & MG106_18PL) +// End of MG106: + +// Beginning of MG107: +#if (G101PL >= G107PL) || (G101PL == 0) +#define MG107_11PL ~(1) +#else +#define MG107_11PL 0xFFFF +#endif +#if (G102PL >= G107PL) || (G102PL == 0) +#define MG107_12PL ~(1 << 1) +#else +#define MG107_12PL 0xFFFF +#endif +#if (G103PL >= G107PL) || (G103PL == 0) +#define MG107_13PL ~(1 << 2) +#else +#define MG107_13PL 0xFFFF +#endif +#if (G104PL >= G107PL) || (G104PL == 0) +#define MG107_14PL ~(1 << 3) +#else +#define MG107_14PL 0xFFFF +#endif +#if (G105PL >= G107PL) || (G105PL == 0) +#define MG107_15PL ~(1 << 4) +#else +#define MG107_15PL 0xFFFF +#endif +#if (G106PL >= G107PL) || (G106PL == 0) +#define MG107_16PL ~(1 << 5) +#else +#define MG107_16PL 0xFFFF +#endif +#if (G108PL >= G107PL) || (G108PL == 0) +#define MG107_18PL ~(1 << 7) +#else +#define MG107_18PL 0xFFFF +#endif +#define MG107_17PL 0x00BF +#define MG107 (MG107_11PL & MG107_12PL & MG107_13PL & MG107_14PL & \ + MG107_15PL & MG107_16PL & MG107_17PL & MG107_18PL) +// End of MG107: + +// Beginning of MG108: +#if (G101PL >= G108PL) || (G101PL == 0) +#define MG108_11PL ~(1) +#else +#define MG108_11PL 0xFFFF +#endif +#if (G102PL >= G108PL) || (G102PL == 0) +#define MG108_12PL ~(1 << 1) +#else +#define MG108_12PL 0xFFFF +#endif +#if (G103PL >= G108PL) || (G103PL == 0) +#define MG108_13PL ~(1 << 2) +#else +#define MG108_13PL 0xFFFF +#endif +#if (G104PL >= G108PL) || (G104PL == 0) +#define MG108_14PL ~(1 << 3) +#else +#define MG108_14PL 0xFFFF +#endif +#if (G105PL >= G108PL) || (G105PL == 0) +#define MG108_15PL ~(1 << 4) +#else +#define MG108_15PL 0xFFFF +#endif +#if (G106PL >= G108PL) || (G106PL == 0) +#define MG108_16PL ~(1 << 5) +#else +#define MG108_16PL 0xFFFF +#endif +#if (G107PL >= G108PL) || (G107PL == 0) +#define MG108_17PL ~(1 << 6) +#else +#define MG108_17PL 0xFFFF +#endif +#define MG108_18PL 0x007F +#define MG108 (MG108_11PL & MG108_12PL & MG108_13PL & MG108_14PL & \ + MG108_15PL & MG108_16PL & MG108_17PL & MG108_18PL) +// End of MG108: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG111 to MG118: +// + +// Beginning of MG111: +#if (G112PL >= G111PL) || (G112PL == 0) +#define MG111_12PL ~(1 << 1) +#else +#define MG111_12PL 0xFFFF +#endif +#if (G113PL >= G111PL) || (G113PL == 0) +#define MG111_13PL ~(1 << 2) +#else +#define MG111_13PL 0xFFFF +#endif +#if (G114PL >= G111PL) || (G114PL == 0) +#define MG111_14PL ~(1 << 3) +#else +#define MG111_14PL 0xFFFF +#endif +#if (G115PL >= G111PL) || (G115PL == 0) +#define MG111_15PL ~(1 << 4) +#else +#define MG111_15PL 0xFFFF +#endif +#if (G116PL >= G111PL) || (G116PL == 0) +#define MG111_16PL ~(1 << 5) +#else +#define MG111_16PL 0xFFFF +#endif +#if (G117PL >= G111PL) || (G117PL == 0) +#define MG111_17PL ~(1 << 6) +#else +#define MG111_17PL 0xFFFF +#endif +#if (G118PL >= G111PL) || (G118PL == 0) +#define MG111_18PL ~(1 << 7) +#else +#define MG111_18PL 0xFFFF +#endif +#define MG111_11PL 0x00FE +#define MG111 (MG111_11PL & MG111_12PL & MG111_13PL & MG111_14PL & \ + MG111_15PL & MG111_16PL & MG111_17PL & MG111_18PL) +// End of MG111: + +// Beginning of MG112: +#if (G111PL >= G112PL) || (G111PL == 0) +#define MG112_11PL ~(1) +#else +#define MG112_11PL 0xFFFF +#endif +#if (G113PL >= G112PL) || (G113PL == 0) +#define MG112_13PL ~(1 << 2) +#else +#define MG112_13PL 0xFFFF +#endif +#if (G114PL >= G112PL) || (G114PL == 0) +#define MG112_14PL ~(1 << 3) +#else +#define MG112_14PL 0xFFFF +#endif +#if (G115PL >= G112PL) || (G115PL == 0) +#define MG112_15PL ~(1 << 4) +#else +#define MG112_15PL 0xFFFF +#endif +#if (G116PL >= G112PL) || (G116PL == 0) +#define MG112_16PL ~(1 << 5) +#else +#define MG112_16PL 0xFFFF +#endif +#if (G117PL >= G112PL) || (G117PL == 0) +#define MG112_17PL ~(1 << 6) +#else +#define MG112_17PL 0xFFFF +#endif +#if (G118PL >= G112PL) || (G118PL == 0) +#define MG112_18PL ~(1 << 7) +#else +#define MG112_18PL 0xFFFF +#endif +#define MG112_12PL 0x00FD +#define MG112 (MG112_11PL & MG112_12PL & MG112_13PL & MG112_14PL & \ + MG112_15PL & MG112_16PL & MG112_17PL & MG112_18PL) +// End of MG112: + +// Beginning of MG113: +#if (G111PL >= G113PL) || (G111PL == 0) +#define MG113_11PL ~(1) +#else +#define MG113_11PL 0xFFFF +#endif +#if (G112PL >= G113PL) || (G112PL == 0) +#define MG113_12PL ~(1 << 1) +#else +#define MG113_12PL 0xFFFF +#endif +#if (G114PL >= G113PL) || (G114PL == 0) +#define MG113_14PL ~(1 << 3) +#else +#define MG113_14PL 0xFFFF +#endif +#if (G115PL >= G113PL) || (G115PL == 0) +#define MG113_15PL ~(1 << 4) +#else +#define MG113_15PL 0xFFFF +#endif +#if (G116PL >= G113PL) || (G116PL == 0) +#define MG113_16PL ~(1 << 5) +#else +#define MG113_16PL 0xFFFF +#endif +#if (G117PL >= G113PL) || (G117PL == 0) +#define MG113_17PL ~(1 << 6) +#else +#define MG113_17PL 0xFFFF +#endif +#if (G118PL >= G113PL) || (G118PL == 0) +#define MG113_18PL ~(1 << 7) +#else +#define MG113_18PL 0xFFFF +#endif +#define MG113_13PL 0x00FB +#define MG113 (MG113_11PL & MG113_12PL & MG113_13PL & MG113_14PL & \ + MG113_15PL & MG113_16PL & MG113_17PL & MG113_18PL) +// End of MG113: + +// Beginning of MG114: +#if (G111PL >= G114PL) || (G111PL == 0) +#define MG114_11PL ~(1) +#else +#define MG114_11PL 0xFFFF +#endif +#if (G112PL >= G114PL) || (G112PL == 0) +#define MG114_12PL ~(1 << 1) +#else +#define MG114_12PL 0xFFFF +#endif +#if (G113PL >= G114PL) || (G113PL == 0) +#define MG114_13PL ~(1 << 2) +#else +#define MG114_13PL 0xFFFF +#endif +#if (G115PL >= G114PL) || (G115PL == 0) +#define MG114_15PL ~(1 << 4) +#else +#define MG114_15PL 0xFFFF +#endif +#if (G116PL >= G114PL) || (G116PL == 0) +#define MG114_16PL ~(1 << 5) +#else +#define MG114_16PL 0xFFFF +#endif +#if (G117PL >= G114PL) || (G117PL == 0) +#define MG114_17PL ~(1 << 6) +#else +#define MG114_17PL 0xFFFF +#endif +#if (G118PL >= G114PL) || (G118PL == 0) +#define MG114_18PL ~(1 << 7) +#else +#define MG114_18PL 0xFFFF +#endif +#define MG114_14PL 0x00F7 +#define MG114 (MG114_11PL & MG114_12PL & MG114_13PL & MG114_14PL & \ + MG114_15PL & MG114_16PL & MG114_17PL & MG114_18PL) +// End of MG114: + +// Beginning of MG115: +#if (G111PL >= G115PL) || (G111PL == 0) +#define MG115_11PL ~(1) +#else +#define MG115_11PL 0xFFFF +#endif +#if (G112PL >= G115PL) || (G112PL == 0) +#define MG115_12PL ~(1 << 1) +#else +#define MG115_12PL 0xFFFF +#endif +#if (G113PL >= G115PL) || (G113PL == 0) +#define MG115_13PL ~(1 << 2) +#else +#define MG115_13PL 0xFFFF +#endif +#if (G114PL >= G115PL) || (G114PL == 0) +#define MG115_14PL ~(1 << 3) +#else +#define MG115_14PL 0xFFFF +#endif +#if (G116PL >= G115PL) || (G116PL == 0) +#define MG115_16PL ~(1 << 5) +#else +#define MG115_16PL 0xFFFF +#endif +#if (G117PL >= G115PL) || (G117PL == 0) +#define MG115_17PL ~(1 << 6) +#else +#define MG115_17PL 0xFFFF +#endif +#if (G118PL >= G115PL) || (G118PL == 0) +#define MG115_18PL ~(1 << 7) +#else +#define MG115_18PL 0xFFFF +#endif +#define MG115_15PL 0x00EF +#define MG115 (MG115_11PL & MG115_12PL & MG115_13PL & MG115_14PL & \ + MG115_15PL & MG115_16PL & MG115_17PL & MG115_18PL) +// End of MG115: + +// Beginning of MG116: +#if (G111PL >= G116PL) || (G111PL == 0) +#define MG116_11PL ~(1) +#else +#define MG116_11PL 0xFFFF +#endif +#if (G112PL >= G116PL) || (G112PL == 0) +#define MG116_12PL ~(1 << 1) +#else +#define MG116_12PL 0xFFFF +#endif +#if (G113PL >= G116PL) || (G113PL == 0) +#define MG116_13PL ~(1 << 2) +#else +#define MG116_13PL 0xFFFF +#endif +#if (G114PL >= G116PL) || (G114PL == 0) +#define MG116_14PL ~(1 << 3) +#else +#define MG116_14PL 0xFFFF +#endif +#if (G115PL >= G116PL) || (G115PL == 0) +#define MG116_15PL ~(1 << 4) +#else +#define MG116_15PL 0xFFFF +#endif +#if (G117PL >= G116PL) || (G117PL == 0) +#define MG116_17PL ~(1 << 6) +#else +#define MG116_17PL 0xFFFF +#endif +#if (G118PL >= G116PL) || (G118PL == 0) +#define MG116_18PL ~(1 << 7) +#else +#define MG116_18PL 0xFFFF +#endif +#define MG116_16PL 0x00DF +#define MG116 (MG116_11PL & MG116_12PL & MG116_13PL & MG116_14PL & \ + MG116_15PL & MG116_16PL & MG116_17PL & MG116_18PL) +// End of MG116: + +// Beginning of MG117: +#if (G111PL >= G117PL) || (G111PL == 0) +#define MG117_11PL ~(1) +#else +#define MG117_11PL 0xFFFF +#endif +#if (G112PL >= G117PL) || (G112PL == 0) +#define MG117_12PL ~(1 << 1) +#else +#define MG117_12PL 0xFFFF +#endif +#if (G113PL >= G117PL) || (G113PL == 0) +#define MG117_13PL ~(1 << 2) +#else +#define MG117_13PL 0xFFFF +#endif +#if (G114PL >= G117PL) || (G114PL == 0) +#define MG117_14PL ~(1 << 3) +#else +#define MG117_14PL 0xFFFF +#endif +#if (G115PL >= G117PL) || (G115PL == 0) +#define MG117_15PL ~(1 << 4) +#else +#define MG117_15PL 0xFFFF +#endif +#if (G116PL >= G117PL) || (G116PL == 0) +#define MG117_16PL ~(1 << 5) +#else +#define MG117_16PL 0xFFFF +#endif +#if (G118PL >= G117PL) || (G118PL == 0) +#define MG117_18PL ~(1 << 7) +#else +#define MG117_18PL 0xFFFF +#endif +#define MG117_17PL 0x00BF +#define MG117 (MG117_11PL & MG117_12PL & MG117_13PL & MG117_14PL & \ + MG117_15PL & MG117_16PL & MG117_17PL & MG117_18PL) +// End of MG117: + +// Beginning of MG118: +#if (G111PL >= G118PL) || (G111PL == 0) +#define MG118_11PL ~(1) +#else +#define MG118_11PL 0xFFFF +#endif +#if (G112PL >= G118PL) || (G112PL == 0) +#define MG118_12PL ~(1 << 1) +#else +#define MG118_12PL 0xFFFF +#endif +#if (G113PL >= G118PL) || (G113PL == 0) +#define MG118_13PL ~(1 << 2) +#else +#define MG118_13PL 0xFFFF +#endif +#if (G114PL >= G118PL) || (G114PL == 0) +#define MG118_14PL ~(1 << 3) +#else +#define MG118_14PL 0xFFFF +#endif +#if (G115PL >= G118PL) || (G115PL == 0) +#define MG118_15PL ~(1 << 4) +#else +#define MG118_15PL 0xFFFF +#endif +#if (G116PL >= G118PL) || (G116PL == 0) +#define MG118_16PL ~(1 << 5) +#else +#define MG118_16PL 0xFFFF +#endif +#if (G117PL >= G118PL) || (G117PL == 0) +#define MG118_17PL ~(1 << 6) +#else +#define MG118_17PL 0xFFFF +#endif +#define MG118_18PL 0x007F +#define MG118 (MG118_11PL & MG118_12PL & MG118_13PL & MG118_14PL & \ + MG118_15PL & MG118_16PL & MG118_17PL & MG118_18PL) +// End of MG118: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG121 to MG128: +// + +// Beginning of MG121: +#if (G122PL >= G121PL) || (G122PL == 0) +#define MG121_12PL ~(1 << 1) +#else +#define MG121_12PL 0xFFFF +#endif +#if (G123PL >= G121PL) || (G123PL == 0) +#define MG121_13PL ~(1 << 2) +#else +#define MG121_13PL 0xFFFF +#endif +#if (G124PL >= G121PL) || (G124PL == 0) +#define MG121_14PL ~(1 << 3) +#else +#define MG121_14PL 0xFFFF +#endif +#if (G125PL >= G121PL) || (G125PL == 0) +#define MG121_15PL ~(1 << 4) +#else +#define MG121_15PL 0xFFFF +#endif +#if (G126PL >= G121PL) || (G126PL == 0) +#define MG121_16PL ~(1 << 5) +#else +#define MG121_16PL 0xFFFF +#endif +#if (G127PL >= G121PL) || (G127PL == 0) +#define MG121_17PL ~(1 << 6) +#else +#define MG121_17PL 0xFFFF +#endif +#if (G128PL >= G121PL) || (G128PL == 0) +#define MG121_18PL ~(1 << 7) +#else +#define MG121_18PL 0xFFFF +#endif +#define MG121_11PL 0x00FE +#define MG121 (MG121_11PL & MG121_12PL & MG121_13PL & MG121_14PL & \ + MG121_15PL & MG121_16PL & MG121_17PL & MG121_18PL) +// End of MG121: + +// Beginning of MG121: +#if (G121PL >= G122PL) || (G121PL == 0) +#define MG122_11PL ~(1) +#else +#define MG122_11PL 0xFFFF +#endif +#if (G123PL >= G122PL) || (G123PL == 0) +#define MG122_13PL ~(1 << 2) +#else +#define MG122_13PL 0xFFFF +#endif +#if (G124PL >= G122PL) || (G124PL == 0) +#define MG122_14PL ~(1 << 3) +#else +#define MG122_14PL 0xFFFF +#endif +#if (G125PL >= G122PL) || (G125PL == 0) +#define MG122_15PL ~(1 << 4) +#else +#define MG122_15PL 0xFFFF +#endif +#if (G126PL >= G122PL) || (G126PL == 0) +#define MG122_16PL ~(1 << 5) +#else +#define MG122_16PL 0xFFFF +#endif +#if (G127PL >= G122PL) || (G127PL == 0) +#define MG122_17PL ~(1 << 6) +#else +#define MG122_17PL 0xFFFF +#endif +#if (G128PL >= G122PL) || (G128PL == 0) +#define MG122_18PL ~(1 << 7) +#else +#define MG122_18PL 0xFFFF +#endif +#define MG122_12PL 0x00FD +#define MG122 (MG122_11PL & MG122_12PL & MG122_13PL & MG122_14PL & \ + MG122_15PL & MG122_16PL & MG122_17PL & MG122_18PL) +// End of MG122: + +// Beginning of MG123: +#if (G121PL >= G123PL) || (G121PL == 0) +#define MG123_11PL ~(1) +#else +#define MG123_11PL 0xFFFF +#endif +#if (G122PL >= G123PL) || (G122PL == 0) +#define MG123_12PL ~(1 << 1) +#else +#define MG123_12PL 0xFFFF +#endif +#if (G124PL >= G123PL) || (G124PL == 0) +#define MG123_14PL ~(1 << 3) +#else +#define MG123_14PL 0xFFFF +#endif +#if (G125PL >= G123PL) || (G125PL == 0) +#define MG123_15PL ~(1 << 4) +#else +#define MG123_15PL 0xFFFF +#endif +#if (G126PL >= G123PL) || (G126PL == 0) +#define MG123_16PL ~(1 << 5) +#else +#define MG123_16PL 0xFFFF +#endif +#if (G127PL >= G123PL) || (G127PL == 0) +#define MG123_17PL ~(1 << 6) +#else +#define MG123_17PL 0xFFFF +#endif +#if (G128PL >= G123PL) || (G128PL == 0) +#define MG123_18PL ~(1 << 7) +#else +#define MG123_18PL 0xFFFF +#endif +#define MG123_13PL 0x00FB +#define MG123 (MG123_11PL & MG123_12PL & MG123_13PL & MG123_14PL & \ + MG123_15PL & MG123_16PL & MG123_17PL & MG123_18PL) +// End of MG123: + +// Beginning of MG124: +#if (G121PL >= G124PL) || (G121PL == 0) +#define MG124_11PL ~(1) +#else +#define MG124_11PL 0xFFFF +#endif +#if (G122PL >= G124PL) || (G122PL == 0) +#define MG124_12PL ~(1 << 1) +#else +#define MG124_12PL 0xFFFF +#endif +#if (G123PL >= G124PL) || (G123PL == 0) +#define MG124_13PL ~(1 << 2) +#else +#define MG124_13PL 0xFFFF +#endif +#if (G125PL >= G124PL) || (G125PL == 0) +#define MG124_15PL ~(1 << 4) +#else +#define MG124_15PL 0xFFFF +#endif +#if (G126PL >= G124PL) || (G126PL == 0) +#define MG124_16PL ~(1 << 5) +#else +#define MG124_16PL 0xFFFF +#endif +#if (G127PL >= G124PL) || (G127PL == 0) +#define MG124_17PL ~(1 << 6) +#else +#define MG124_17PL 0xFFFF +#endif +#if (G128PL >= G124PL) || (G128PL == 0) +#define MG124_18PL ~(1 << 7) +#else +#define MG124_18PL 0xFFFF +#endif +#define MG124_14PL 0x00F7 +#define MG124 (MG124_11PL & MG124_12PL & MG124_13PL & MG124_14PL & \ + MG124_15PL & MG124_16PL & MG124_17PL & MG124_18PL) +// End of MG124: + +// Beginning of MG125: +#if (G121PL >= G125PL) || (G121PL == 0) +#define MG125_11PL ~(1) +#else +#define MG125_11PL 0xFFFF +#endif +#if (G122PL >= G125PL) || (G122PL == 0) +#define MG125_12PL ~(1 << 1) +#else +#define MG125_12PL 0xFFFF +#endif +#if (G123PL >= G125PL) || (G123PL == 0) +#define MG125_13PL ~(1 << 2) +#else +#define MG125_13PL 0xFFFF +#endif +#if (G124PL >= G125PL) || (G124PL == 0) +#define MG125_14PL ~(1 << 3) +#else +#define MG125_14PL 0xFFFF +#endif +#if (G126PL >= G125PL) || (G126PL == 0) +#define MG125_16PL ~(1 << 5) +#else +#define MG125_16PL 0xFFFF +#endif +#if (G127PL >= G125PL) || (G127PL == 0) +#define MG125_17PL ~(1 << 6) +#else +#define MG125_17PL 0xFFFF +#endif +#if (G128PL >= G125PL) || (G128PL == 0) +#define MG125_18PL ~(1 << 7) +#else +#define MG125_18PL 0xFFFF +#endif +#define MG125_15PL 0x00EF +#define MG125 (MG125_11PL & MG125_12PL & MG125_13PL & MG125_14PL & \ + MG125_15PL & MG125_16PL & MG125_17PL & MG125_18PL) +// End of MG125: + +// Beginning of MG126: +#if (G121PL >= G126PL) || (G121PL == 0) +#define MG126_11PL ~(1) +#else +#define MG126_11PL 0xFFFF +#endif +#if (G122PL >= G126PL) || (G122PL == 0) +#define MG126_12PL ~(1 << 1) +#else +#define MG126_12PL 0xFFFF +#endif +#if (G123PL >= G126PL) || (G123PL == 0) +#define MG126_13PL ~(1 << 2) +#else +#define MG126_13PL 0xFFFF +#endif +#if (G124PL >= G126PL) || (G124PL == 0) +#define MG126_14PL ~(1 << 3) +#else +#define MG126_14PL 0xFFFF +#endif +#if (G125PL >= G126PL) || (G125PL == 0) +#define MG126_15PL ~(1 << 4) +#else +#define MG126_15PL 0xFFFF +#endif +#if (G127PL >= G126PL) || (G127PL == 0) +#define MG126_17PL ~(1 << 6) +#else +#define MG126_17PL 0xFFFF +#endif +#if (G128PL >= G126PL) || (G128PL == 0) +#define MG126_18PL ~(1 << 7) +#else +#define MG126_18PL 0xFFFF +#endif +#define MG126_16PL 0x00DF +#define MG126 (MG126_11PL & MG126_12PL & MG126_13PL & MG126_14PL & \ + MG126_15PL & MG126_16PL & MG126_17PL & MG126_18PL) +// End of MG126: + +// Beginning of MG127: +#if (G121PL >= G127PL) || (G121PL == 0) +#define MG127_11PL ~(1) +#else +#define MG127_11PL 0xFFFF +#endif +#if (G122PL >= G127PL) || (G122PL == 0) +#define MG127_12PL ~(1 << 1) +#else +#define MG127_12PL 0xFFFF +#endif +#if (G123PL >= G127PL) || (G123PL == 0) +#define MG127_13PL ~(1 << 2) +#else +#define MG127_13PL 0xFFFF +#endif +#if (G124PL >= G127PL) || (G124PL == 0) +#define MG127_14PL ~(1 << 3) +#else +#define MG127_14PL 0xFFFF +#endif +#if (G125PL >= G127PL) || (G125PL == 0) +#define MG127_15PL ~(1 << 4) +#else +#define MG127_15PL 0xFFFF +#endif +#if (G126PL >= G127PL) || (G126PL == 0) +#define MG127_16PL ~(1 << 5) +#else +#define MG127_16PL 0xFFFF +#endif +#if (G128PL >= G127PL) || (G128PL == 0) +#define MG127_18PL ~(1 << 7) +#else +#define MG127_18PL 0xFFFF +#endif +#define MG127_17PL 0x00BF +#define MG127 (MG127_11PL & MG127_12PL & MG127_13PL & MG127_14PL & \ + MG127_15PL & MG127_16PL & MG127_17PL & MG127_18PL) +// End of MG127: + +// Beginning of MG128: +#if (G121PL >= G128PL) || (G121PL == 0) +#define MG128_11PL ~(1) +#else +#define MG128_11PL 0xFFFF +#endif +#if (G122PL >= G128PL) || (G122PL == 0) +#define MG128_12PL ~(1 << 1) +#else +#define MG128_12PL 0xFFFF +#endif +#if (G123PL >= G128PL) || (G123PL == 0) +#define MG128_13PL ~(1 << 2) +#else +#define MG128_13PL 0xFFFF +#endif +#if (G124PL >= G128PL) || (G124PL == 0) +#define MG128_14PL ~(1 << 3) +#else +#define MG128_14PL 0xFFFF +#endif +#if (G125PL >= G128PL) || (G125PL == 0) +#define MG128_15PL ~(1 << 4) +#else +#define MG128_15PL 0xFFFF +#endif +#if (G126PL >= G128PL) || (G126PL == 0) +#define MG128_16PL ~(1 << 5) +#else +#define MG128_16PL 0xFFFF +#endif +#if (G127PL >= G128PL) || (G127PL == 0) +#define MG128_17PL ~(1 << 6) +#else +#define MG128_17PL 0xFFFF +#endif +#define MG128_18PL 0x007F +#define MG128 (MG128_11PL & MG128_12PL & MG128_13PL & MG128_14PL & \ + MG128_15PL & MG128_16PL & MG128_17PL & MG128_18PL) +// End of MG128: + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // eof + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h new file mode 100644 index 0000000..e6b5e40 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h @@ -0,0 +1,224 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 19, 2007 15:09:18 $ +//########################################################################### +// +// FILE: DSP281x_Adc.h +// +// TITLE: DSP281x Device ADC Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + + +#ifndef DSP281x_ADC_H +#define DSP281x_ADC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// ADC Individual Register Bit Definitions: + +struct ADCTRL1_BITS { // bits description + Uint16 rsvd1:4; // 3:0 reserved + Uint16 SEQ_CASC:1; // 4 Cascaded sequencer mode + Uint16 SEQ_OVRD:1; // 5 Sequencer override + Uint16 CONT_RUN:1; // 6 Continuous run + Uint16 CPS:1; // 7 ADC core clock pre-scalar + Uint16 ACQ_PS:4; // 11:8 Acquisition window size + Uint16 SUSMOD:2; // 13:12 Emulation suspend mode + Uint16 RESET:1; // 14 ADC reset + Uint16 rsvd2:1; // 15 reserved +}; + + +union ADCTRL1_REG { + Uint16 all; + struct ADCTRL1_BITS bit; +}; + + +struct ADCTRL2_BITS { // bits description + Uint16 EVB_SOC_SEQ2:1; // 0 Event manager B SOC mask for SEQ2 + Uint16 rsvd1:1; // 1 reserved + Uint16 INT_MOD_SEQ2:1; // 2 SEQ2 Interrupt mode + Uint16 INT_ENA_SEQ2:1; // 3 SEQ2 Interrupt enable + Uint16 rsvd2:1; // 4 reserved + Uint16 SOC_SEQ2:1; // 5 Start of conversion for SEQ2 + Uint16 RST_SEQ2:1; // 6 Reset SEQ2 + Uint16 EXT_SOC_SEQ1:1; // 7 External start of conversion for SEQ1 + Uint16 EVA_SOC_SEQ1:1; // 8 Event manager A SOC mask for SEQ1 + Uint16 rsvd3:1; // 9 reserved + Uint16 INT_MOD_SEQ1:1; // 10 SEQ1 Interrupt mode + Uint16 INT_ENA_SEQ1:1; // 11 SEQ1 Interrupt enable + Uint16 rsvd4:1; // 12 reserved + Uint16 SOC_SEQ1:1; // 13 Start of conversion trigger for SEQ1 + Uint16 RST_SEQ1:1; // 14 Restart sequencer 1 + Uint16 EVB_SOC_SEQ:1; // 15 EVB SOC enable +}; + + +union ADCTRL2_REG { + Uint16 all; + struct ADCTRL2_BITS bit; +}; + + +struct ADCASEQSR_BITS { // bits description + Uint16 SEQ1_STATE:4; // 3:0 SEQ1 state + Uint16 SEQ2_STATE:3; // 6:4 SEQ2 state + Uint16 rsvd1:1; // 7 reserved + Uint16 SEQ_CNTR:4; // 11:8 Sequencing counter status + Uint16 rsvd2:4; // 15:12 reserved +}; + +union ADCASEQSR_REG { + Uint16 all; + struct ADCASEQSR_BITS bit; +}; + + +struct ADCMAXCONV_BITS { // bits description + Uint16 MAX_CONV1:4; // 3:0 Max number of conversions + Uint16 MAX_CONV2:3; // 6:4 Max number of conversions + Uint16 rsvd1:9; // 15:7 reserved +}; + +union ADCMAXCONV_REG { + Uint16 all; + struct ADCMAXCONV_BITS bit; +}; + + +struct ADCCHSELSEQ1_BITS { // bits description + Uint16 CONV00:4; // 3:0 Conversion selection 00 + Uint16 CONV01:4; // 7:4 Conversion selection 01 + Uint16 CONV02:4; // 11:8 Conversion selection 02 + Uint16 CONV03:4; // 15:12 Conversion selection 03 +}; + +union ADCCHSELSEQ1_REG{ + Uint16 all; + struct ADCCHSELSEQ1_BITS bit; +}; + +struct ADCCHSELSEQ2_BITS { // bits description + Uint16 CONV04:4; // 3:0 Conversion selection 04 + Uint16 CONV05:4; // 7:4 Conversion selection 05 + Uint16 CONV06:4; // 11:8 Conversion selection 06 + Uint16 CONV07:4; // 15:12 Conversion selection 07 +}; + +union ADCCHSELSEQ2_REG{ + Uint16 all; + struct ADCCHSELSEQ2_BITS bit; +}; + +struct ADCCHSELSEQ3_BITS { // bits description + Uint16 CONV08:4; // 3:0 Conversion selection 08 + Uint16 CONV09:4; // 7:4 Conversion selection 09 + Uint16 CONV10:4; // 11:8 Conversion selection 10 + Uint16 CONV11:4; // 15:12 Conversion selection 11 +}; + +union ADCCHSELSEQ3_REG{ + Uint16 all; + struct ADCCHSELSEQ3_BITS bit; +}; + +struct ADCCHSELSEQ4_BITS { // bits description + Uint16 CONV12:4; // 3:0 Conversion selection 12 + Uint16 CONV13:4; // 7:4 Conversion selection 13 + Uint16 CONV14:4; // 11:8 Conversion selection 14 + Uint16 CONV15:4; // 15:12 Conversion selection 15 +}; + +union ADCCHSELSEQ4_REG { + Uint16 all; + struct ADCCHSELSEQ4_BITS bit; +}; + +struct ADCTRL3_BITS { // bits description + Uint16 SMODE_SEL:1; // 0 Sampling mode select + Uint16 ADCCLKPS:4; // 4:1 ADC core clock divider + Uint16 ADCPWDN:1; // 5 ADC powerdown + Uint16 ADCBGRFDN:2; // 7:6 ADC bandgap/ref power down + Uint16 ADCEXTREF:1; // 8 ADC external reference + Uint16 rsvd1:7; // 15:9 reserved +}; + +union ADCTRL3_REG { + Uint16 all; + struct ADCTRL3_BITS bit; +}; + + +struct ADCST_BITS { // bits description + Uint16 INT_SEQ1:1; // 0 SEQ1 Interrupt flag + Uint16 INT_SEQ2:1; // 1 SEQ2 Interrupt flag + Uint16 SEQ1_BSY:1; // 2 SEQ1 busy status + Uint16 SEQ2_BSY:1; // 3 SEQ2 busy status + Uint16 INT_SEQ1_CLR:1; // 4 SEQ1 Interrupt clear + Uint16 INT_SEQ2_CLR:1; // 5 SEQ2 Interrupt clear + Uint16 EOS_BUF1:1; // 6 End of sequence buffer1 + Uint16 EOS_BUF2:1; // 7 End of sequence buffer2 + Uint16 rsvd1:8; // 15:8 reserved +}; + + +union ADCST_REG { + Uint16 all; + struct ADCST_BITS bit; +}; + + +struct ADC_REGS { + union ADCTRL1_REG ADCTRL1; // ADC Control 1 + union ADCTRL2_REG ADCTRL2; // ADC Control 2 + union ADCMAXCONV_REG ADCMAXCONV; // Max conversions + union ADCCHSELSEQ1_REG ADCCHSELSEQ1; // Channel select sequencing control 1 + union ADCCHSELSEQ2_REG ADCCHSELSEQ2; // Channel select sequencing control 2 + union ADCCHSELSEQ3_REG ADCCHSELSEQ3; // Channel select sequencing control 3 + union ADCCHSELSEQ4_REG ADCCHSELSEQ4; // Channel select sequencing control 4 + union ADCASEQSR_REG ADCASEQSR; // Autosequence status register + Uint16 ADCRESULT0; // Conversion Result Buffer 0 + Uint16 ADCRESULT1; // Conversion Result Buffer 1 + Uint16 ADCRESULT2; // Conversion Result Buffer 2 + Uint16 ADCRESULT3; // Conversion Result Buffer 3 + Uint16 ADCRESULT4; // Conversion Result Buffer 4 + Uint16 ADCRESULT5; // Conversion Result Buffer 5 + Uint16 ADCRESULT6; // Conversion Result Buffer 6 + Uint16 ADCRESULT7; // Conversion Result Buffer 7 + Uint16 ADCRESULT8; // Conversion Result Buffer 8 + Uint16 ADCRESULT9; // Conversion Result Buffer 9 + Uint16 ADCRESULT10; // Conversion Result Buffer 10 + Uint16 ADCRESULT11; // Conversion Result Buffer 11 + Uint16 ADCRESULT12; // Conversion Result Buffer 12 + Uint16 ADCRESULT13; // Conversion Result Buffer 13 + Uint16 ADCRESULT14; // Conversion Result Buffer 14 + Uint16 ADCRESULT15; // Conversion Result Buffer 15 + union ADCTRL3_REG ADCTRL3; // ADC Control 3 + union ADCST_REG ADCST; // ADC Status Register +}; + + +//--------------------------------------------------------------------------- +// ADC External References & Function Declarations: +// +extern volatile struct ADC_REGS AdcRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + + +#endif // end of DSP281x_ADC_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h new file mode 100644 index 0000000..ffe1784 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h @@ -0,0 +1,184 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: July 9, 2009 17:08:54 $ +//########################################################################### +// +// FILE: DSP281x_CpuTimers.h +// +// TITLE: DSP281x CPU 32-bit Timers Register Definitions. +// +// NOTES: CpuTimer2 is reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use this timer in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_CPU_TIMERS_H +#define DSP281x_CPU_TIMERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// CPU Timer Register Bit Definitions: +// +// +// TCR: Control register bit definitions: +struct TCR_BITS { // bits description + Uint16 rsvd1:4; // 3:0 reserved + Uint16 TSS:1; // 4 Timer Start/Stop + Uint16 TRB:1; // 5 Timer reload + Uint16 rsvd2:4; // 9:6 reserved + Uint16 SOFT:1; // 10 Emulation modes + Uint16 FREE:1; // 11 + Uint16 rsvd3:2; // 12:13 reserved + Uint16 TIE:1; // 14 Output enable + Uint16 TIF:1; // 15 Interrupt flag +}; + +union TCR_REG { + Uint16 all; + struct TCR_BITS bit; +}; + +// TPR: Pre-scale low bit definitions: +struct TPR_BITS { // bits description + Uint16 TDDR:8; // 7:0 Divide-down low + Uint16 PSC:8; // 15:8 Prescale counter low +}; + +union TPR_REG { + Uint16 all; + struct TPR_BITS bit; +}; + +// TPRH: Pre-scale high bit definitions: +struct TPRH_BITS { // bits description + Uint16 TDDRH:8; // 7:0 Divide-down high + Uint16 PSCH:8; // 15:8 Prescale counter high +}; + +union TPRH_REG { + Uint16 all; + struct TPRH_BITS bit; +}; + +// TIM, TIMH: Timer register definitions: +struct TIM_REG { + Uint16 LSW; + Uint16 MSW; +}; + +union TIM_GROUP { + Uint32 all; + struct TIM_REG half; +}; + +// PRD, PRDH: Period register definitions: +struct PRD_REG { + Uint16 LSW; + Uint16 MSW; +}; + +union PRD_GROUP { + Uint32 all; + struct PRD_REG half; +}; + +//--------------------------------------------------------------------------- +// CPU Timer Register File: +// +struct CPUTIMER_REGS { + union TIM_GROUP TIM; // Timer counter register + union PRD_GROUP PRD; // Period register + union TCR_REG TCR; // Timer control register + Uint16 rsvd1; // reserved + union TPR_REG TPR; // Timer pre-scale low + union TPRH_REG TPRH; // Timer pre-scale high +}; + +//--------------------------------------------------------------------------- +// CPU Timer Support Variables: +// +struct CPUTIMER_VARS { + volatile struct CPUTIMER_REGS *RegsAddr; + Uint32 InterruptCount; + float CPUFreqInMHz; + float PeriodInUSec; +}; + +//--------------------------------------------------------------------------- +// Function prototypes and external definitions: +// +void InitCpuTimers(void); +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period); + +extern volatile struct CPUTIMER_REGS CpuTimer0Regs; +extern struct CPUTIMER_VARS CpuTimer0; + +// CpuTimer2 is reserved when using DSP BIOS & other RTOS +extern volatile struct CPUTIMER_REGS CpuTimer1Regs; +extern volatile struct CPUTIMER_REGS CpuTimer2Regs; + +extern struct CPUTIMER_VARS CpuTimer1; +extern struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// Usefull Timer Operations: +// +// Start Timer: +#define StartCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 0 + +// Stop Timer: +#define StopCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +#define ReloadCpuTimer0() CpuTimer0Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +#define ReadCpuTimer0Counter() CpuTimer0Regs.TIM.all + +// Read 32-Bit Period Value: +#define ReadCpuTimer0Period() CpuTimer0Regs.PRD.all + +// CpuTimer2 is reserved by DSP BIOS & other RTOS +// Do not use this timer if you ever plan on integrating +// DSP-BIOS or another realtime OS. + +// Start Timer: +#define StartCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 0 +#define StartCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 0 + +// Stop Timer: +#define StopCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 1 +#define StopCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +#define ReloadCpuTimer1() CpuTimer1Regs.TCR.bit.TRB = 1 +#define ReloadCpuTimer2() CpuTimer2Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +#define ReadCpuTimer1Counter() CpuTimer1Regs.TIM.all +#define ReadCpuTimer2Counter() CpuTimer2Regs.TIM.all + +// Read 32-Bit Period Value: +#define ReadCpuTimer1Period() CpuTimer1Regs.PRD.all +#define ReadCpuTimer2Period() CpuTimer2Regs.PRD.all + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_CPU_TIMERS_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h new file mode 100644 index 0000000..e55f671 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h @@ -0,0 +1,123 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:38 $ +//########################################################################### +// +// FILE: DSP281x_DefaultIsr.h +// +// TITLE: DSP281x Devices Default Interrupt Service Routines Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEFAULT_ISR_H +#define DSP281x_DEFAULT_ISR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// Default Interrupt Service Routine Declarations: +// +// The following function prototypes are for the +// default ISR routines used with the default PIE vector table. +// This default vector table is found in the DSP281x_PieVect.h +// file. +// + +// Non-Peripheral Interrupts: +interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1 +interrupt void INT14_ISR(void); // CPU-Timer2 +interrupt void DATALOG_ISR(void); // Datalogging interrupt +interrupt void RTOSINT_ISR(void); // RTOS interrupt +interrupt void EMUINT_ISR(void); // Emulation interrupt +interrupt void NMI_ISR(void); // Non-maskable interrupt +interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP +interrupt void USER1_ISR(void); // User Defined trap 1 +interrupt void USER2_ISR(void); // User Defined trap 2 +interrupt void USER3_ISR(void); // User Defined trap 3 +interrupt void USER4_ISR(void); // User Defined trap 4 +interrupt void USER5_ISR(void); // User Defined trap 5 +interrupt void USER6_ISR(void); // User Defined trap 6 +interrupt void USER7_ISR(void); // User Defined trap 7 +interrupt void USER8_ISR(void); // User Defined trap 8 +interrupt void USER9_ISR(void); // User Defined trap 9 +interrupt void USER10_ISR(void); // User Defined trap 10 +interrupt void USER11_ISR(void); // User Defined trap 11 +interrupt void USER12_ISR(void); // User Defined trap 12 + +// Group 1 PIE Interrupt Service Routines: +interrupt void PDPINTA_ISR(void); // EV-A +interrupt void PDPINTB_ISR(void); // EV-B +interrupt void XINT1_ISR(void); +interrupt void XINT2_ISR(void); +interrupt void ADCINT_ISR(void); // ADC +interrupt void TINT0_ISR(void); // Timer 0 +interrupt void WAKEINT_ISR(void); // WD + +// Group 2 PIE Interrupt Service Routines: +interrupt void CMP1INT_ISR(void); // EV-A +interrupt void CMP2INT_ISR(void); // EV-A +interrupt void CMP3INT_ISR(void); // EV-A +interrupt void T1PINT_ISR(void); // EV-A +interrupt void T1CINT_ISR(void); // EV-A +interrupt void T1UFINT_ISR(void); // EV-A +interrupt void T1OFINT_ISR(void); // EV-A + +// Group 3 PIE Interrupt Service Routines: +interrupt void T2PINT_ISR(void); // EV-A +interrupt void T2CINT_ISR(void); // EV-A +interrupt void T2UFINT_ISR(void); // EV-A +interrupt void T2OFINT_ISR(void); // EV-A +interrupt void CAPINT1_ISR(void); // EV-A +interrupt void CAPINT2_ISR(void); // EV-A +interrupt void CAPINT3_ISR(void); // EV-A + +// Group 4 PIE Interrupt Service Routines: +interrupt void CMP4INT_ISR(void); // EV-B +interrupt void CMP5INT_ISR(void); // EV-B +interrupt void CMP6INT_ISR(void); // EV-B +interrupt void T3PINT_ISR(void); // EV-B +interrupt void T3CINT_ISR(void); // EV-B +interrupt void T3UFINT_ISR(void); // EV-B +interrupt void T3OFINT_ISR(void); // EV-B + +// Group 5 PIE Interrupt Service Routines: +interrupt void T4PINT_ISR(void); // EV-B +interrupt void T4CINT_ISR(void); // EV-B +interrupt void T4UFINT_ISR(void); // EV-B +interrupt void T4OFINT_ISR(void); // EV-B +interrupt void CAPINT4_ISR(void); // EV-B +interrupt void CAPINT5_ISR(void); // EV-B +interrupt void CAPINT6_ISR(void); // EV-B + +// Group 6 PIE Interrupt Service Routines: +interrupt void SPIRXINTA_ISR(void); // SPI +interrupt void SPITXINTA_ISR(void); // SPI +interrupt void MRINTA_ISR(void); // McBSP +interrupt void MXINTA_ISR(void); // McBSP + + +// Group 9 PIE Interrupt Service Routines: +interrupt void SCIRXINTA_ISR(void); // SCI-A +interrupt void SCITXINTA_ISR(void); // SCI-A +interrupt void SCIRXINTB_ISR(void); // SCI-B +interrupt void SCITXINTB_ISR(void); // SCI-B +interrupt void ECAN0INTA_ISR(void); // eCAN +interrupt void ECAN1INTA_ISR(void); // eCAN + + +// Catch-all for Reserved Locations For testing purposes: +interrupt void PIE_RESERVED(void); // Reserved for test +interrupt void rsvd_ISR(void); // for test + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEFAULT_ISR_H definition + diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h new file mode 100644 index 0000000..af37f2e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h @@ -0,0 +1,103 @@ +//########################################################################### +// +// FILE: DSP281x_DevEmu.h +// +// TITLE: DSP281x Device Emulation Register Definitions. +// +//########################################################################### +// +// Ver | dd mmm yyyy | Who | Description of changes +// =====|=============|======|=============================================== +// 1.00| 11 Sep 2003 | L.H. | Changes since previous version (v.58 Alpha) +// | | | As of Rev C silicon, DEVICEID is a 16-bit +// | | | register +// | | | Commented out the DFT test registers. These +// | | | are not needed as of Rev C silicon. +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEV_EMU_H +#define DSP281x_DEV_EMU_H + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// Device Emulation Register Bit Definitions: +// +// Device Configuration Register Bit Definitions +struct DEVICECNF_BITS { // bits description + Uint16 rsvd1:3; // 2:0 reserved + Uint16 VMAPS:1; // 3 VMAP Status + Uint16 rsvd2:1; // 4 reserved + Uint16 XRSn:1; // 5 XRSn Signal Status + Uint16 rsvd3:10; // 15:6 + Uint16 rsvd4:3; // 18:6 + Uint16 ENPROT:1; // 19 Enable/Disable pipeline protection + Uint16 rsvd5:12; // 31:20 reserved +}; + +union DEVICECNF_REG { + Uint32 all; + struct DEVICECNF_BITS bit; +}; + + +// Device ID Register Bit Definitions +struct DEVICEID_BITS { // bits description + Uint16 REVID:16; // 15:0 Silicon revision +}; + +union DEVICEID_REG { + Uint16 all; + struct DEVICEID_BITS bit; +}; + +// PARTID Register Bit Definitions +struct PARTID_BITS { // bits description + Uint16 PARTNO:8; // 7:0 Part Number + Uint16 PARTTYPE:8; // 15:8 Part Type +}; + +union PARTID_REG { + Uint16 all; + struct PARTID_BITS bit; +}; + +struct DEV_EMU_REGS { + union DEVICECNF_REG DEVICECNF; // device configuration + union PARTID_REG PARTID; // Part ID + union DEVICEID_REG DEVICEID; // Device ID + Uint16 PROTSTART; // Write-Read protection start + Uint16 PROTRANGE; // Write-Read protection range + Uint16 rsvd2[202]; +// These registers are no longer needed for Rev C and beyond +// Uint16 M0RAMDFT; +// Uint16 M1RAMDFT; +// Uint16 L0RAMDFT; +// Uint16 L1RAMDFT; +// Uint16 H0RAMDFT; +}; + +#define REVID DEVICEID // REVID replaces DEVICEID starting 281x header files v1.10 + // use #define to maintain code compatibility with v1.00 and older + + + +//--------------------------------------------------------------------------- +// Device Emulation Register References & Function Declarations: +// +extern volatile struct DEV_EMU_REGS DevEmuRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEV_EMU_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h new file mode 100644 index 0000000..e664028 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h @@ -0,0 +1,144 @@ +// TI File $Revision: /main/5 $ +// Checkin $Date: December 17, 2007 13:36:09 $ +//########################################################################### +// +// FILE: DSP281x_Device.h +// +// TITLE: DSP281x Device Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEVICE_H +#define DSP281x_DEVICE_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define TARGET 1 +//--------------------------------------------------------------------------- +// User To Select Target Device: + +#define DSP28_F2812 TARGET +#define DSP28_F2811 0 +#define DSP28_F2810 0 + +//--------------------------------------------------------------------------- +// Common CPU Definitions: +// + +extern cregister volatile unsigned int IFR; +extern cregister volatile unsigned int IER; + +#define EINT asm(" clrc INTM") +#define DINT asm(" setc INTM") +#define ERTM asm(" clrc DBGM") +#define DRTM asm(" setc DBGM") +#define EALLOW asm(" EALLOW") +#define EDIS asm(" EDIS") +#define ESTOP0 asm(" ESTOP0") + +#define M_INT1 0x0001 +#define M_INT2 0x0002 +#define M_INT3 0x0004 +#define M_INT4 0x0008 +#define M_INT5 0x0010 +#define M_INT6 0x0020 +#define M_INT7 0x0040 +#define M_INT8 0x0080 +#define M_INT9 0x0100 +#define M_INT10 0x0200 +#define M_INT11 0x0400 +#define M_INT12 0x0800 +#define M_INT13 0x1000 +#define M_INT14 0x2000 +#define M_DLOG 0x4000 +#define M_RTOS 0x8000 + +#define BIT0 0x0001 +#define BIT1 0x0002 +#define BIT2 0x0004 +#define BIT3 0x0008 +#define BIT4 0x0010 +#define BIT5 0x0020 +#define BIT6 0x0040 +#define BIT7 0x0080 +#define BIT8 0x0100 +#define BIT9 0x0200 +#define BIT10 0x0400 +#define BIT11 0x0800 +#define BIT12 0x1000 +#define BIT13 0x2000 +#define BIT14 0x4000 +#define BIT15 0x8000 + +#ifndef NULL + #define NULL 0 +#endif + + +//--------------------------------------------------------------------------- +// For Portability, User Is Recommended To Use Following Data Type Size +// Definitions For 16-bit and 32-Bit Signed/Unsigned Integers: +// + +#ifndef DSP28_DATA_TYPES +#define DSP28_DATA_TYPES +typedef int int16; +typedef long int32; +typedef long long int64; +typedef unsigned int Uint16; +typedef unsigned long Uint32; +typedef unsigned long long Uint64; +typedef float float32; +typedef long double float64; +#endif + +#define LOWORD(l)((short int)( (long int)(l) &0xFFFF)) +#define HIWORD(l)((short int)(((long int)(l)>>16)&0xFFFF)) + +#define LOBYTE(w)((char)( (short int)(w) &0xFF)) +#define HIBYTE(w)((char)(((short int)(w)>>8)&0xFF)) + +#define BYTE3(l)((char)(((long int)(l)>>24)&0xFF)) +#define BYTE2(l)((char)(((long int)(l)>>16)&0xFF)) +#define BYTE1(l)((char)(((long int)(l)>> 8)&0xFF)) +#define BYTE0(l)((char)( (long int)(l) &0xFF)) + +//--------------------------------------------------------------------------- +// Include All Peripheral Header Files: +// + +#include "DSP281x_SysCtrl.h" // System Control/Power Modes +#include "DSP281x_DevEmu.h" // Device Emulation Registers +#include "DSP281x_Xintf.h" // External Interface Registers +#include "DSP281x_CpuTimers.h" // 32-bit CPU Timers +#include "DSP281x_PieCtrl.h" // PIE Control Registers +#include "DSP281x_PieVect.h" // PIE Vector Table +#include "DSP281x_Spi.h" // SPI Registers +#include "DSP281x_Sci.h" // SCI Registers +#include "DSP281x_Mcbsp.h" // McBSP Registers +#include "DSP281x_ECan.h" // Enhanced eCAN Registers +#include "DSP281x_Gpio.h" // General Purpose I/O Registers +#include "DSP281x_Ev.h" // Event Manager Registers +#include "DSP281x_Adc.h" // ADC Registers +#include "DSP281x_XIntrupt.h" // External Interrupts + +#define XCLKIN 24000000 // external oscillator frequency +extern float SYSCLKOUT, LSPCLK, HSPCLK; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEVICE_H definition + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h new file mode 100644 index 0000000..7f26fc5 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h @@ -0,0 +1,1163 @@ +//########################################################################### +// +// FILE: DSP281x_ECan.h +// +// TITLE: DSP281x Device eCAN Register Definitions. +// +//########################################################################### +// +// Ver | dd mmm yyyy | Who | Description of changes +// =====|=============|======|=============================================== +// 1.00a| 07/21/2004 | H.J. |(i) Support for errata (as explained in SPRZ193E and above) incorporated +// |(ii) Changed the byte ordering to make it easy to use with the +// | default value of DBO bit (0). + +//########################################################################### + +#ifndef DSP281x_ECAN_H +#define DSP281x_ECAN_H + +/* These 2 lines have been added to support the C callable assembly workaround */ +/* This is to support the workaround for errata (as explained in SPRZ193E and above) */ + +extern void CanDoubleRead(Uint32 *StorePtr, volatile Uint32 *RegPtr); +extern void CanDoubleWrite(volatile Uint32 *RegPtr, Uint32 *LoadPtr); + +#ifdef __cplusplus +extern "C" { +#endif + + +/* --------------------------------------------------- */ +/* eCAN Control & Status Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Mailbox enable register (CANME) bit definitions */ +struct CANME_BITS { // bit description + Uint16 ME0:1; // 0 Enable Mailbox 0 + Uint16 ME1:1; // 1 Enable Mailbox 1 + Uint16 ME2:1; // 2 Enable Mailbox 2 + Uint16 ME3:1; // 3 Enable Mailbox 3 + Uint16 ME4:1; // 4 Enable Mailbox 4 + Uint16 ME5:1; // 5 Enable Mailbox 5 + Uint16 ME6:1; // 6 Enable Mailbox 6 + Uint16 ME7:1; // 7 Enable Mailbox 7 + Uint16 ME8:1; // 8 Enable Mailbox 8 + Uint16 ME9:1; // 9 Enable Mailbox 9 + Uint16 ME10:1; // 10 Enable Mailbox 10 + Uint16 ME11:1; // 11 Enable Mailbox 11 + Uint16 ME12:1; // 12 Enable Mailbox 12 + Uint16 ME13:1; // 13 Enable Mailbox 13 + Uint16 ME14:1; // 14 Enable Mailbox 14 + Uint16 ME15:1; // 15 Enable Mailbox 15 + Uint16 ME16:1; // 16 Enable Mailbox 16 + Uint16 ME17:1; // 17 Enable Mailbox 17 + Uint16 ME18:1; // 18 Enable Mailbox 18 + Uint16 ME19:1; // 19 Enable Mailbox 19 + Uint16 ME20:1; // 20 Enable Mailbox 20 + Uint16 ME21:1; // 21 Enable Mailbox 21 + Uint16 ME22:1; // 22 Enable Mailbox 22 + Uint16 ME23:1; // 23 Enable Mailbox 23 + Uint16 ME24:1; // 24 Enable Mailbox 24 + Uint16 ME25:1; // 25 Enable Mailbox 25 + Uint16 ME26:1; // 26 Enable Mailbox 26 + Uint16 ME27:1; // 27 Enable Mailbox 27 + Uint16 ME28:1; // 28 Enable Mailbox 28 + Uint16 ME29:1; // 29 Enable Mailbox 29 + Uint16 ME30:1; // 30 Enable Mailbox 30 + Uint16 ME31:1; // 31 Enable Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANME_REG { + Uint32 all; + struct CANME_BITS bit; +}; + +/* eCAN Mailbox direction register (CANMD) bit definitions */ +struct CANMD_BITS { // bit description + Uint16 MD0:1; // 0 0 -> Tx 1 -> Rx + Uint16 MD1:1; // 1 0 -> Tx 1 -> Rx + Uint16 MD2:1; // 2 0 -> Tx 1 -> Rx + Uint16 MD3:1; // 3 0 -> Tx 1 -> Rx + Uint16 MD4:1; // 4 0 -> Tx 1 -> Rx + Uint16 MD5:1; // 5 0 -> Tx 1 -> Rx + Uint16 MD6:1; // 6 0 -> Tx 1 -> Rx + Uint16 MD7:1; // 7 0 -> Tx 1 -> Rx + Uint16 MD8:1; // 8 0 -> Tx 1 -> Rx + Uint16 MD9:1; // 9 0 -> Tx 1 -> Rx + Uint16 MD10:1; // 10 0 -> Tx 1 -> Rx + Uint16 MD11:1; // 11 0 -> Tx 1 -> Rx + Uint16 MD12:1; // 12 0 -> Tx 1 -> Rx + Uint16 MD13:1; // 13 0 -> Tx 1 -> Rx + Uint16 MD14:1; // 14 0 -> Tx 1 -> Rx + Uint16 MD15:1; // 15 0 -> Tx 1 -> Rx + Uint16 MD16:1; // 16 0 -> Tx 1 -> Rx + Uint16 MD17:1; // 17 0 -> Tx 1 -> Rx + Uint16 MD18:1; // 18 0 -> Tx 1 -> Rx + Uint16 MD19:1; // 19 0 -> Tx 1 -> Rx + Uint16 MD20:1; // 20 0 -> Tx 1 -> Rx + Uint16 MD21:1; // 21 0 -> Tx 1 -> Rx + Uint16 MD22:1; // 22 0 -> Tx 1 -> Rx + Uint16 MD23:1; // 23 0 -> Tx 1 -> Rx + Uint16 MD24:1; // 24 0 -> Tx 1 -> Rx + Uint16 MD25:1; // 25 0 -> Tx 1 -> Rx + Uint16 MD26:1; // 26 0 -> Tx 1 -> Rx + Uint16 MD27:1; // 27 0 -> Tx 1 -> Rx + Uint16 MD28:1; // 28 0 -> Tx 1 -> Rx + Uint16 MD29:1; // 29 0 -> Tx 1 -> Rx + Uint16 MD30:1; // 30 0 -> Tx 1 -> Rx + Uint16 MD31:1; // 31 0 -> Tx 1 -> Rx + +}; + +/* Allow access to the bit fields or entire register */ +union CANMD_REG { + Uint32 all; + struct CANMD_BITS bit; +}; + +/* eCAN Transmit Request Set register (CANTRS) bit definitions */ +struct CANTRS_BITS { // bit description + Uint16 TRS0:1; // 0 TRS for Mailbox 0 + Uint16 TRS1:1; // 1 TRS for Mailbox 1 + Uint16 TRS2:1; // 2 TRS for Mailbox 2 + Uint16 TRS3:1; // 3 TRS for Mailbox 3 + Uint16 TRS4:1; // 4 TRS for Mailbox 4 + Uint16 TRS5:1; // 5 TRS for Mailbox 5 + Uint16 TRS6:1; // 6 TRS for Mailbox 6 + Uint16 TRS7:1; // 7 TRS for Mailbox 7 + Uint16 TRS8:1; // 8 TRS for Mailbox 8 + Uint16 TRS9:1; // 9 TRS for Mailbox 9 + Uint16 TRS10:1; // 10 TRS for Mailbox 10 + Uint16 TRS11:1; // 11 TRS for Mailbox 11 + Uint16 TRS12:1; // 12 TRS for Mailbox 12 + Uint16 TRS13:1; // 13 TRS for Mailbox 13 + Uint16 TRS14:1; // 14 TRS for Mailbox 14 + Uint16 TRS15:1; // 15 TRS for Mailbox 15 + Uint16 TRS16:1; // 16 TRS for Mailbox 16 + Uint16 TRS17:1; // 17 TRS for Mailbox 17 + Uint16 TRS18:1; // 18 TRS for Mailbox 18 + Uint16 TRS19:1; // 19 TRS for Mailbox 19 + Uint16 TRS20:1; // 20 TRS for Mailbox 20 + Uint16 TRS21:1; // 21 TRS for Mailbox 21 + Uint16 TRS22:1; // 22 TRS for Mailbox 22 + Uint16 TRS23:1; // 23 TRS for Mailbox 23 + Uint16 TRS24:1; // 24 TRS for Mailbox 24 + Uint16 TRS25:1; // 25 TRS for Mailbox 25 + Uint16 TRS26:1; // 26 TRS for Mailbox 26 + Uint16 TRS27:1; // 27 TRS for Mailbox 27 + Uint16 TRS28:1; // 28 TRS for Mailbox 28 + Uint16 TRS29:1; // 29 TRS for Mailbox 29 + Uint16 TRS30:1; // 30 TRS for Mailbox 30 + Uint16 TRS31:1; // 31 TRS for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTRS_REG { + Uint32 all; + struct CANTRS_BITS bit; +}; + +/* eCAN Transmit Request Reset register (CANTRR) bit definitions */ +struct CANTRR_BITS { // bit description + Uint16 TRR0:1; // 0 TRR for Mailbox 0 + Uint16 TRR1:1; // 1 TRR for Mailbox 1 + Uint16 TRR2:1; // 2 TRR for Mailbox 2 + Uint16 TRR3:1; // 3 TRR for Mailbox 3 + Uint16 TRR4:1; // 4 TRR for Mailbox 4 + Uint16 TRR5:1; // 5 TRR for Mailbox 5 + Uint16 TRR6:1; // 6 TRR for Mailbox 6 + Uint16 TRR7:1; // 7 TRR for Mailbox 7 + Uint16 TRR8:1; // 8 TRR for Mailbox 8 + Uint16 TRR9:1; // 9 TRR for Mailbox 9 + Uint16 TRR10:1; // 10 TRR for Mailbox 10 + Uint16 TRR11:1; // 11 TRR for Mailbox 11 + Uint16 TRR12:1; // 12 TRR for Mailbox 12 + Uint16 TRR13:1; // 13 TRR for Mailbox 13 + Uint16 TRR14:1; // 14 TRR for Mailbox 14 + Uint16 TRR15:1; // 15 TRR for Mailbox 15 + Uint16 TRR16:1; // 16 TRR for Mailbox 16 + Uint16 TRR17:1; // 17 TRR for Mailbox 17 + Uint16 TRR18:1; // 18 TRR for Mailbox 18 + Uint16 TRR19:1; // 19 TRR for Mailbox 19 + Uint16 TRR20:1; // 20 TRR for Mailbox 20 + Uint16 TRR21:1; // 21 TRR for Mailbox 21 + Uint16 TRR22:1; // 22 TRR for Mailbox 22 + Uint16 TRR23:1; // 23 TRR for Mailbox 23 + Uint16 TRR24:1; // 24 TRR for Mailbox 24 + Uint16 TRR25:1; // 25 TRR for Mailbox 25 + Uint16 TRR26:1; // 26 TRR for Mailbox 26 + Uint16 TRR27:1; // 27 TRR for Mailbox 27 + Uint16 TRR28:1; // 28 TRR for Mailbox 28 + Uint16 TRR29:1; // 29 TRR for Mailbox 29 + Uint16 TRR30:1; // 30 TRR for Mailbox 30 + Uint16 TRR31:1; // 31 TRR for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTRR_REG { + Uint32 all; + struct CANTRR_BITS bit; +}; + +/* eCAN Transmit Acknowledge register (CANTA) bit definitions */ +struct CANTA_BITS { // bit description + Uint16 TA0:1; // 0 TA for Mailbox 0 + Uint16 TA1:1; // 1 TA for Mailbox 1 + Uint16 TA2:1; // 2 TA for Mailbox 2 + Uint16 TA3:1; // 3 TA for Mailbox 3 + Uint16 TA4:1; // 4 TA for Mailbox 4 + Uint16 TA5:1; // 5 TA for Mailbox 5 + Uint16 TA6:1; // 6 TA for Mailbox 6 + Uint16 TA7:1; // 7 TA for Mailbox 7 + Uint16 TA8:1; // 8 TA for Mailbox 8 + Uint16 TA9:1; // 9 TA for Mailbox 9 + Uint16 TA10:1; // 10 TA for Mailbox 10 + Uint16 TA11:1; // 11 TA for Mailbox 11 + Uint16 TA12:1; // 12 TA for Mailbox 12 + Uint16 TA13:1; // 13 TA for Mailbox 13 + Uint16 TA14:1; // 14 TA for Mailbox 14 + Uint16 TA15:1; // 15 TA for Mailbox 15 + Uint16 TA16:1; // 16 TA for Mailbox 16 + Uint16 TA17:1; // 17 TA for Mailbox 17 + Uint16 TA18:1; // 18 TA for Mailbox 18 + Uint16 TA19:1; // 19 TA for Mailbox 19 + Uint16 TA20:1; // 20 TA for Mailbox 20 + Uint16 TA21:1; // 21 TA for Mailbox 21 + Uint16 TA22:1; // 22 TA for Mailbox 22 + Uint16 TA23:1; // 23 TA for Mailbox 23 + Uint16 TA24:1; // 24 TA for Mailbox 24 + Uint16 TA25:1; // 25 TA for Mailbox 25 + Uint16 TA26:1; // 26 TA for Mailbox 26 + Uint16 TA27:1; // 27 TA for Mailbox 27 + Uint16 TA28:1; // 28 TA for Mailbox 28 + Uint16 TA29:1; // 29 TA for Mailbox 29 + Uint16 TA30:1; // 30 TA for Mailbox 30 + Uint16 TA31:1; // 31 TA for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTA_REG { + Uint32 all; + struct CANTA_BITS bit; +}; + +/* eCAN Transmit Abort Acknowledge register (CANAA) bit definitions */ +struct CANAA_BITS { // bit description + Uint16 AA0:1; // 0 AA for Mailbox 0 + Uint16 AA1:1; // 1 AA for Mailbox 1 + Uint16 AA2:1; // 2 AA for Mailbox 2 + Uint16 AA3:1; // 3 AA for Mailbox 3 + Uint16 AA4:1; // 4 AA for Mailbox 4 + Uint16 AA5:1; // 5 AA for Mailbox 5 + Uint16 AA6:1; // 6 AA for Mailbox 6 + Uint16 AA7:1; // 7 AA for Mailbox 7 + Uint16 AA8:1; // 8 AA for Mailbox 8 + Uint16 AA9:1; // 9 AA for Mailbox 9 + Uint16 AA10:1; // 10 AA for Mailbox 10 + Uint16 AA11:1; // 11 AA for Mailbox 11 + Uint16 AA12:1; // 12 AA for Mailbox 12 + Uint16 AA13:1; // 13 AA for Mailbox 13 + Uint16 AA14:1; // 14 AA for Mailbox 14 + Uint16 AA15:1; // 15 AA for Mailbox 15 + Uint16 AA16:1; // 16 AA for Mailbox 16 + Uint16 AA17:1; // 17 AA for Mailbox 17 + Uint16 AA18:1; // 18 AA for Mailbox 18 + Uint16 AA19:1; // 19 AA for Mailbox 19 + Uint16 AA20:1; // 20 AA for Mailbox 20 + Uint16 AA21:1; // 21 AA for Mailbox 21 + Uint16 AA22:1; // 22 AA for Mailbox 22 + Uint16 AA23:1; // 23 AA for Mailbox 23 + Uint16 AA24:1; // 24 AA for Mailbox 24 + Uint16 AA25:1; // 25 AA for Mailbox 25 + Uint16 AA26:1; // 26 AA for Mailbox 26 + Uint16 AA27:1; // 27 AA for Mailbox 27 + Uint16 AA28:1; // 28 AA for Mailbox 28 + Uint16 AA29:1; // 29 AA for Mailbox 29 + Uint16 AA30:1; // 30 AA for Mailbox 30 + Uint16 AA31:1; // 31 AA for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANAA_REG { + Uint32 all; + struct CANAA_BITS bit; +}; + +/* eCAN Received Message Pending register (CANRMP) bit definitions */ +struct CANRMP_BITS { // bit description + Uint16 RMP0:1; // 0 RMP for Mailbox 0 + Uint16 RMP1:1; // 1 RMP for Mailbox 1 + Uint16 RMP2:1; // 2 RMP for Mailbox 2 + Uint16 RMP3:1; // 3 RMP for Mailbox 3 + Uint16 RMP4:1; // 4 RMP for Mailbox 4 + Uint16 RMP5:1; // 5 RMP for Mailbox 5 + Uint16 RMP6:1; // 6 RMP for Mailbox 6 + Uint16 RMP7:1; // 7 RMP for Mailbox 7 + Uint16 RMP8:1; // 8 RMP for Mailbox 8 + Uint16 RMP9:1; // 9 RMP for Mailbox 9 + Uint16 RMP10:1; // 10 RMP for Mailbox 10 + Uint16 RMP11:1; // 11 RMP for Mailbox 11 + Uint16 RMP12:1; // 12 RMP for Mailbox 12 + Uint16 RMP13:1; // 13 RMP for Mailbox 13 + Uint16 RMP14:1; // 14 RMP for Mailbox 14 + Uint16 RMP15:1; // 15 RMP for Mailbox 15 + Uint16 RMP16:1; // 16 RMP for Mailbox 16 + Uint16 RMP17:1; // 17 RMP for Mailbox 17 + Uint16 RMP18:1; // 18 RMP for Mailbox 18 + Uint16 RMP19:1; // 19 RMP for Mailbox 19 + Uint16 RMP20:1; // 20 RMP for Mailbox 20 + Uint16 RMP21:1; // 21 RMP for Mailbox 21 + Uint16 RMP22:1; // 22 RMP for Mailbox 22 + Uint16 RMP23:1; // 23 RMP for Mailbox 23 + Uint16 RMP24:1; // 24 RMP for Mailbox 24 + Uint16 RMP25:1; // 25 RMP for Mailbox 25 + Uint16 RMP26:1; // 26 RMP for Mailbox 26 + Uint16 RMP27:1; // 27 RMP for Mailbox 27 + Uint16 RMP28:1; // 28 RMP for Mailbox 28 + Uint16 RMP29:1; // 29 RMP for Mailbox 29 + Uint16 RMP30:1; // 30 RMP for Mailbox 30 + Uint16 RMP31:1; // 31 RMP for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANRMP_REG { + Uint32 all; + struct CANRMP_BITS bit; +}; + +/* eCAN Received Message Lost register (CANRML) bit definitions */ +struct CANRML_BITS { // bit description + Uint16 RML0:1; // 0 RML for Mailbox 0 + Uint16 RML1:1; // 1 RML for Mailbox 1 + Uint16 RML2:1; // 2 RML for Mailbox 2 + Uint16 RML3:1; // 3 RML for Mailbox 3 + Uint16 RML4:1; // 4 RML for Mailbox 4 + Uint16 RML5:1; // 5 RML for Mailbox 5 + Uint16 RML6:1; // 6 RML for Mailbox 6 + Uint16 RML7:1; // 7 RML for Mailbox 7 + Uint16 RML8:1; // 8 RML for Mailbox 8 + Uint16 RML9:1; // 9 RML for Mailbox 9 + Uint16 RML10:1; // 10 RML for Mailbox 10 + Uint16 RML11:1; // 11 RML for Mailbox 11 + Uint16 RML12:1; // 12 RML for Mailbox 12 + Uint16 RML13:1; // 13 RML for Mailbox 13 + Uint16 RML14:1; // 14 RML for Mailbox 14 + Uint16 RML15:1; // 15 RML for Mailbox 15 + Uint16 RML16:1; // 16 RML for Mailbox 16 + Uint16 RML17:1; // 17 RML for Mailbox 17 + Uint16 RML18:1; // 18 RML for Mailbox 18 + Uint16 RML19:1; // 19 RML for Mailbox 19 + Uint16 RML20:1; // 20 RML for Mailbox 20 + Uint16 RML21:1; // 21 RML for Mailbox 21 + Uint16 RML22:1; // 22 RML for Mailbox 22 + Uint16 RML23:1; // 23 RML for Mailbox 23 + Uint16 RML24:1; // 24 RML for Mailbox 24 + Uint16 RML25:1; // 25 RML for Mailbox 25 + Uint16 RML26:1; // 26 RML for Mailbox 26 + Uint16 RML27:1; // 27 RML for Mailbox 27 + Uint16 RML28:1; // 28 RML for Mailbox 28 + Uint16 RML29:1; // 29 RML for Mailbox 29 + Uint16 RML30:1; // 30 RML for Mailbox 30 + Uint16 RML31:1; // 31 RML for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANRML_REG { + Uint32 all; + struct CANRML_BITS bit; +}; + +/* eCAN Remote Frame Pending register (CANRFP) bit definitions */ +struct CANRFP_BITS { // bit description + Uint16 RFP0:1; // 0 RFP for Mailbox 0 + Uint16 RFP1:1; // 1 RFP for Mailbox 1 + Uint16 RFP2:1; // 2 RFP for Mailbox 2 + Uint16 RFP3:1; // 3 RFP for Mailbox 3 + Uint16 RFP4:1; // 4 RFP for Mailbox 4 + Uint16 RFP5:1; // 5 RFP for Mailbox 5 + Uint16 RFP6:1; // 6 RFP for Mailbox 6 + Uint16 RFP7:1; // 7 RFP for Mailbox 7 + Uint16 RFP8:1; // 8 RFP for Mailbox 8 + Uint16 RFP9:1; // 9 RFP for Mailbox 9 + Uint16 RFP10:1; // 10 RFP for Mailbox 10 + Uint16 RFP11:1; // 11 RFP for Mailbox 11 + Uint16 RFP12:1; // 12 RFP for Mailbox 12 + Uint16 RFP13:1; // 13 RFP for Mailbox 13 + Uint16 RFP14:1; // 14 RFP for Mailbox 14 + Uint16 RFP15:1; // 15 RFP for Mailbox 15 + Uint16 RFP16:1; // 16 RFP for Mailbox 16 + Uint16 RFP17:1; // 17 RFP for Mailbox 17 + Uint16 RFP18:1; // 18 RFP for Mailbox 18 + Uint16 RFP19:1; // 19 RFP for Mailbox 19 + Uint16 RFP20:1; // 20 RFP for Mailbox 20 + Uint16 RFP21:1; // 21 RFP for Mailbox 21 + Uint16 RFP22:1; // 22 RFP for Mailbox 22 + Uint16 RFP23:1; // 23 RFP for Mailbox 23 + Uint16 RFP24:1; // 24 RFP for Mailbox 24 + Uint16 RFP25:1; // 25 RFP for Mailbox 25 + Uint16 RFP26:1; // 26 RFP for Mailbox 26 + Uint16 RFP27:1; // 27 RFP for Mailbox 27 + Uint16 RFP28:1; // 28 RFP for Mailbox 28 + Uint16 RFP29:1; // 29 RFP for Mailbox 29 + Uint16 RFP30:1; // 30 RFP for Mailbox 30 + Uint16 RFP31:1; // 31 RFP for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANRFP_REG { + Uint32 all; + struct CANRFP_BITS bit; +}; + +/* eCAN Global Acceptance Mask register (CANGAM) bit definitions */ +struct CANGAM_BITS { // bits description + Uint16 GAM150:16; // 15:0 Global acceptance mask bits 0-15 + Uint16 GAM2816:13; // 28:16 Global acceptance mask bits 16-28 + Uint16 rsvd:2; // 30:29 reserved + Uint16 AMI:1; // 31 AMI bit +}; + +/* Allow access to the bit fields or entire register */ +union CANGAM_REG { + Uint32 all; + struct CANGAM_BITS bit; +}; + + +/* eCAN Master Control register (CANMC) bit definitions */ +struct CANMC_BITS { // bits description + Uint16 MBNR:5; // 4:0 MBX # for CDR bit + Uint16 SRES:1; // 5 Soft reset + Uint16 STM:1; // 6 Self-test mode + Uint16 ABO:1; // 7 Auto bus-on + Uint16 CDR:1; // 8 Change data request + Uint16 WUBA:1; // 9 Wake-up on bus activity + Uint16 DBO:1; // 10 Data-byte order + Uint16 PDR:1; // 11 Power-down mode request + Uint16 CCR:1; // 12 Change configuration request + Uint16 SCB:1; // 13 SCC compatibility bit + Uint16 TCC:1; // 14 TSC MSB clear bit + Uint16 MBCC:1; // 15 TSC clear bit thru mailbox 16 + Uint16 SUSP:1; // 16 SUSPEND free/soft bit + Uint16 rsvd:15; // 31:17 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANMC_REG { + Uint32 all; + struct CANMC_BITS bit; +}; + +/* eCAN Bit -timing configuration register (CANBTC) bit definitions */ +struct CANBTC_BITS { // bits description + Uint16 TSEG2REG:3; // 2:0 TSEG2 register value + Uint16 TSEG1REG:4; // 6:3 TSEG1 register value + Uint16 SAM:1; // 7 Sample-point setting + Uint16 SJWREG:2; // 9:8 Synchroniztion Jump Width register value + Uint16 rsvd1:6; // 15:10 reserved + Uint16 BRPREG:8; // 23:16 Baudrate prescaler register value + Uint16 rsvd2:8; // 31:24 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANBTC_REG { + Uint32 all; + struct CANBTC_BITS bit; +}; + +/* eCAN Error & Status register (CANES) bit definitions */ +struct CANES_BITS { // bits description + Uint16 TM:1; // 0 Transmit Mode + Uint16 RM:1; // 1 Receive Mode + Uint16 rsvd1:1; // 2 reserved + Uint16 PDA:1; // 3 Power-down acknowledge + Uint16 CCE:1; // 4 Change Configuration Enable + Uint16 SMA:1; // 5 Suspend Mode Acknowledge + Uint16 rsvd2:10; // 15:6 reserved + Uint16 EW:1; // 16 Warning status + Uint16 EP:1; // 17 Error Passive status + Uint16 BO:1; // 18 Bus-off status + Uint16 ACKE:1; // 19 Acknowledge error + Uint16 SE:1; // 20 Stuff error + Uint16 CRCE:1; // 21 CRC error + Uint16 SA1:1; // 22 Stuck at Dominant error + Uint16 BE:1; // 23 Bit error + Uint16 FE:1; // 24 Framing error + Uint16 rsvd3:7; // 31:25 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANES_REG { + Uint32 all; + struct CANES_BITS bit; +}; + + +/* eCAN Transmit Error Counter register (CANTEC) bit definitions */ +struct CANTEC_BITS { // bits description + Uint16 TEC:8; // 7:0 TEC + Uint16 rsvd1:8; // 15:8 reserved + Uint16 rsvd2:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANTEC_REG { + Uint32 all; + struct CANTEC_BITS bit; +}; + +/* eCAN Receive Error Counter register (CANREC) bit definitions */ +struct CANREC_BITS { // bits description + Uint16 REC:8; // 7:0 REC + Uint16 rsvd1:8; // 15:8 reserved + Uint16 rsvd2:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANREC_REG { + Uint32 all; + struct CANREC_BITS bit; +}; + +/* eCAN Global Interrupt Flag 0 (CANGIF0) bit definitions */ +struct CANGIF0_BITS { // bits description + Uint16 MIV0:5; // 4:0 Mailbox Interrupt Vector + Uint16 rsvd1:3; // 7:5 reserved + Uint16 WLIF0:1; // 8 Warning level interrupt flag + Uint16 EPIF0:1; // 9 Error-passive interrupt flag + Uint16 BOIF0:1; // 10 Bus-off interrupt flag + Uint16 RMLIF0:1; // 11 Received message lost interrupt flag + Uint16 WUIF0:1; // 12 Wakeup interrupt flag + Uint16 WDIF0:1; // 13 Write denied interrupt flag + Uint16 AAIF0:1; // 14 Abort Ack interrupt flag + Uint16 GMIF0:1; // 15 Global MBX interrupt flag + Uint16 TCOF0:1; // 16 TSC Overflow flag + Uint16 MTOF0:1; // 17 Mailbox Timeout flag + Uint16 rsvd2:14; // 31:18 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANGIF0_REG { + Uint32 all; + struct CANGIF0_BITS bit; +}; + +/* eCAN Global Interrupt Mask register (CANGIM) bit definitions */ +struct CANGIM_BITS { // bits description + Uint16 I0EN:1; // 0 Interrupt 0 enable + Uint16 I1EN:1; // 1 Interrupt 1 enable + Uint16 GIL:1; // 2 Global Interrupt Level + Uint16 rsvd1:5; // 7:3 reserved + Uint16 WLIM:1; // 8 Warning level interrupt mask + Uint16 EPIM:1; // 9 Error-passive interrupt mask + Uint16 BOIM:1; // 10 Bus-off interrupt mask + Uint16 RMLIM:1; // 11 Received message lost interrupt mask + Uint16 WUIM:1; // 12 Wakeup interrupt mask + Uint16 WDIM:1; // 13 Write denied interrupt mask + Uint16 AAIM:1; // 14 Abort Ack interrupt mask + Uint16 rsvd2:1; // 15 reserved + Uint16 TCOM:1; // 16 TSC overflow interrupt mask + Uint16 MTOM:1; // 17 MBX Timeout interrupt mask + Uint16 rsvd3:14; // 31:18 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANGIM_REG { + Uint32 all; + struct CANGIM_BITS bit; +}; + + +/* eCAN Global Interrupt Flag 1 (eCANGIF1) bit definitions */ +struct CANGIF1_BITS { // bits description + Uint16 MIV1:5; // 4:0 Mailbox Interrupt Vector + Uint16 rsvd1:3; // 7:5 reserved + Uint16 WLIF1:1; // 8 Warning level interrupt flag + Uint16 EPIF1:1; // 9 Error-passive interrupt flag + Uint16 BOIF1:1; // 10 Bus-off interrupt flag + Uint16 RMLIF1:1; // 11 Received message lost interrupt flag + Uint16 WUIF1:1; // 12 Wakeup interrupt flag + Uint16 WDIF1:1; // 13 Write denied interrupt flag + Uint16 AAIF1:1; // 14 Abort Ack interrupt flag + Uint16 GMIF1:1; // 15 Global MBX interrupt flag + Uint16 TCOF1:1; // 16 TSC Overflow flag + Uint16 MTOF1:1; // 17 Mailbox Timeout flag + Uint16 rsvd2:14; // 31:18 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANGIF1_REG { + Uint32 all; + struct CANGIF1_BITS bit; +}; + + +/* eCAN Mailbox Interrupt Mask register (CANMIM) bit definitions */ +struct CANMIM_BITS { // bit description + Uint16 MIM0:1; // 0 MIM for Mailbox 0 + Uint16 MIM1:1; // 1 MIM for Mailbox 1 + Uint16 MIM2:1; // 2 MIM for Mailbox 2 + Uint16 MIM3:1; // 3 MIM for Mailbox 3 + Uint16 MIM4:1; // 4 MIM for Mailbox 4 + Uint16 MIM5:1; // 5 MIM for Mailbox 5 + Uint16 MIM6:1; // 6 MIM for Mailbox 6 + Uint16 MIM7:1; // 7 MIM for Mailbox 7 + Uint16 MIM8:1; // 8 MIM for Mailbox 8 + Uint16 MIM9:1; // 9 MIM for Mailbox 9 + Uint16 MIM10:1; // 10 MIM for Mailbox 10 + Uint16 MIM11:1; // 11 MIM for Mailbox 11 + Uint16 MIM12:1; // 12 MIM for Mailbox 12 + Uint16 MIM13:1; // 13 MIM for Mailbox 13 + Uint16 MIM14:1; // 14 MIM for Mailbox 14 + Uint16 MIM15:1; // 15 MIM for Mailbox 15 + Uint16 MIM16:1; // 16 MIM for Mailbox 16 + Uint16 MIM17:1; // 17 MIM for Mailbox 17 + Uint16 MIM18:1; // 18 MIM for Mailbox 18 + Uint16 MIM19:1; // 19 MIM for Mailbox 19 + Uint16 MIM20:1; // 20 MIM for Mailbox 20 + Uint16 MIM21:1; // 21 MIM for Mailbox 21 + Uint16 MIM22:1; // 22 MIM for Mailbox 22 + Uint16 MIM23:1; // 23 MIM for Mailbox 23 + Uint16 MIM24:1; // 24 MIM for Mailbox 24 + Uint16 MIM25:1; // 25 MIM for Mailbox 25 + Uint16 MIM26:1; // 26 MIM for Mailbox 26 + Uint16 MIM27:1; // 27 MIM for Mailbox 27 + Uint16 MIM28:1; // 28 MIM for Mailbox 28 + Uint16 MIM29:1; // 29 MIM for Mailbox 29 + Uint16 MIM30:1; // 30 MIM for Mailbox 30 + Uint16 MIM31:1; // 31 MIM for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANMIM_REG { + Uint32 all; + struct CANMIM_BITS bit; +}; + +/* eCAN Mailbox Interrupt Level register (CANMIL) bit definitions */ +struct CANMIL_BITS { // bit description + Uint16 MIL0:1; // 0 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL1:1; // 1 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL2:1; // 2 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL3:1; // 3 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL4:1; // 4 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL5:1; // 5 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL6:1; // 6 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL7:1; // 7 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL8:1; // 8 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL9:1; // 9 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL10:1; // 10 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL11:1; // 11 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL12:1; // 12 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL13:1; // 13 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL14:1; // 14 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL15:1; // 15 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL16:1; // 16 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL17:1; // 17 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL18:1; // 18 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL19:1; // 19 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL20:1; // 20 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL21:1; // 21 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL22:1; // 22 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL23:1; // 23 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL24:1; // 24 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL25:1; // 25 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL26:1; // 26 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL27:1; // 27 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL28:1; // 28 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL29:1; // 29 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL30:1; // 30 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL31:1; // 31 0 -> Int 9.5 1 -> Int 9.6 + +}; + +/* Allow access to the bit fields or entire register */ +union CANMIL_REG { + Uint32 all; + struct CANMIL_BITS bit; +}; + + +/* eCAN Overwrite Protection Control register (CANOPC) bit definitions */ +struct CANOPC_BITS { // bit description + Uint16 OPC0:1; // 0 OPC for Mailbox 0 + Uint16 OPC1:1; // 1 OPC for Mailbox 1 + Uint16 OPC2:1; // 2 OPC for Mailbox 2 + Uint16 OPC3:1; // 3 OPC for Mailbox 3 + Uint16 OPC4:1; // 4 OPC for Mailbox 4 + Uint16 OPC5:1; // 5 OPC for Mailbox 5 + Uint16 OPC6:1; // 6 OPC for Mailbox 6 + Uint16 OPC7:1; // 7 OPC for Mailbox 7 + Uint16 OPC8:1; // 8 OPC for Mailbox 8 + Uint16 OPC9:1; // 9 OPC for Mailbox 9 + Uint16 OPC10:1; // 10 OPC for Mailbox 10 + Uint16 OPC11:1; // 11 OPC for Mailbox 11 + Uint16 OPC12:1; // 12 OPC for Mailbox 12 + Uint16 OPC13:1; // 13 OPC for Mailbox 13 + Uint16 OPC14:1; // 14 OPC for Mailbox 14 + Uint16 OPC15:1; // 15 OPC for Mailbox 15 + Uint16 OPC16:1; // 16 OPC for Mailbox 16 + Uint16 OPC17:1; // 17 OPC for Mailbox 17 + Uint16 OPC18:1; // 18 OPC for Mailbox 18 + Uint16 OPC19:1; // 19 OPC for Mailbox 19 + Uint16 OPC20:1; // 20 OPC for Mailbox 20 + Uint16 OPC21:1; // 21 OPC for Mailbox 21 + Uint16 OPC22:1; // 22 OPC for Mailbox 22 + Uint16 OPC23:1; // 23 OPC for Mailbox 23 + Uint16 OPC24:1; // 24 OPC for Mailbox 24 + Uint16 OPC25:1; // 25 OPC for Mailbox 25 + Uint16 OPC26:1; // 26 OPC for Mailbox 26 + Uint16 OPC27:1; // 27 OPC for Mailbox 27 + Uint16 OPC28:1; // 28 OPC for Mailbox 28 + Uint16 OPC29:1; // 29 OPC for Mailbox 29 + Uint16 OPC30:1; // 30 OPC for Mailbox 30 + Uint16 OPC31:1; // 31 OPC for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANOPC_REG { + Uint32 all; + struct CANOPC_BITS bit; +}; + + +/* eCAN TX I/O Control Register (CANTIOC) bit definitions */ +struct CANTIOC_BITS { // bits description + Uint16 rsvd1:3; // 2:0 reserved + Uint16 TXFUNC:1; // 3 TXFUNC + Uint16 rsvd2:12; // 15:4 reserved + Uint16 rsvd3:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANTIOC_REG { + Uint32 all; + struct CANTIOC_BITS bit; +}; + +/* eCAN RX I/O Control Register (CANRIOC) bit definitions */ +struct CANRIOC_BITS { // bits description + Uint16 rsvd1:3; // 2:0 reserved + Uint16 RXFUNC:1; // 3 RXFUNC + Uint16 rsvd2:12; // 15:4 reserved + Uint16 rsvd3:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANRIOC_REG { + Uint32 all; + struct CANRIOC_BITS bit; +}; + + +/* eCAN Time-out Control register (CANTOC) bit definitions */ +struct CANTOC_BITS { // bit description + Uint16 TOC0:1; // 0 TOC for Mailbox 0 + Uint16 TOC1:1; // 1 TOC for Mailbox 1 + Uint16 TOC2:1; // 2 TOC for Mailbox 2 + Uint16 TOC3:1; // 3 TOC for Mailbox 3 + Uint16 TOC4:1; // 4 TOC for Mailbox 4 + Uint16 TOC5:1; // 5 TOC for Mailbox 5 + Uint16 TOC6:1; // 6 TOC for Mailbox 6 + Uint16 TOC7:1; // 7 TOC for Mailbox 7 + Uint16 TOC8:1; // 8 TOC for Mailbox 8 + Uint16 TOC9:1; // 9 TOC for Mailbox 9 + Uint16 TOC10:1; // 10 TOC for Mailbox 10 + Uint16 TOC11:1; // 11 TOC for Mailbox 11 + Uint16 TOC12:1; // 12 TOC for Mailbox 12 + Uint16 TOC13:1; // 13 TOC for Mailbox 13 + Uint16 TOC14:1; // 14 TOC for Mailbox 14 + Uint16 TOC15:1; // 15 TOC for Mailbox 15 + Uint16 TOC16:1; // 16 TOC for Mailbox 16 + Uint16 TOC17:1; // 17 TOC for Mailbox 17 + Uint16 TOC18:1; // 18 TOC for Mailbox 18 + Uint16 TOC19:1; // 19 TOC for Mailbox 19 + Uint16 TOC20:1; // 20 TOC for Mailbox 20 + Uint16 TOC21:1; // 21 TOC for Mailbox 21 + Uint16 TOC22:1; // 22 TOC for Mailbox 22 + Uint16 TOC23:1; // 23 TOC for Mailbox 23 + Uint16 TOC24:1; // 24 TOC for Mailbox 24 + Uint16 TOC25:1; // 25 TOC for Mailbox 25 + Uint16 TOC26:1; // 26 TOC for Mailbox 26 + Uint16 TOC27:1; // 27 TOC for Mailbox 27 + Uint16 TOC28:1; // 28 TOC for Mailbox 28 + Uint16 TOC29:1; // 29 TOC for Mailbox 29 + Uint16 TOC30:1; // 30 TOC for Mailbox 30 + Uint16 TOC31:1; // 31 TOC for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTOC_REG { + Uint32 all; + struct CANTOC_BITS bit; +}; + + +/* eCAN Time-out Status register (CANTOS) bit definitions */ +struct CANTOS_BITS { // bit description + Uint16 TOS0:1; // 0 TOS for Mailbox 0 + Uint16 TOS1:1; // 1 TOS for Mailbox 1 + Uint16 TOS2:1; // 2 TOS for Mailbox 2 + Uint16 TOS3:1; // 3 TOS for Mailbox 3 + Uint16 TOS4:1; // 4 TOS for Mailbox 4 + Uint16 TOS5:1; // 5 TOS for Mailbox 5 + Uint16 TOS6:1; // 6 TOS for Mailbox 6 + Uint16 TOS7:1; // 7 TOS for Mailbox 7 + Uint16 TOS8:1; // 8 TOS for Mailbox 8 + Uint16 TOS9:1; // 9 TOS for Mailbox 9 + Uint16 TOS10:1; // 10 TOS for Mailbox 10 + Uint16 TOS11:1; // 11 TOS for Mailbox 11 + Uint16 TOS12:1; // 12 TOS for Mailbox 12 + Uint16 TOS13:1; // 13 TOS for Mailbox 13 + Uint16 TOS14:1; // 14 TOS for Mailbox 14 + Uint16 TOS15:1; // 15 TOS for Mailbox 15 + Uint16 TOS16:1; // 16 TOS for Mailbox 16 + Uint16 TOS17:1; // 17 TOS for Mailbox 17 + Uint16 TOS18:1; // 18 TOS for Mailbox 18 + Uint16 TOS19:1; // 19 TOS for Mailbox 19 + Uint16 TOS20:1; // 20 TOS for Mailbox 20 + Uint16 TOS21:1; // 21 TOS for Mailbox 21 + Uint16 TOS22:1; // 22 TOS for Mailbox 22 + Uint16 TOS23:1; // 23 TOS for Mailbox 23 + Uint16 TOS24:1; // 24 TOS for Mailbox 24 + Uint16 TOS25:1; // 25 TOS for Mailbox 25 + Uint16 TOS26:1; // 26 TOS for Mailbox 26 + Uint16 TOS27:1; // 27 TOS for Mailbox 27 + Uint16 TOS28:1; // 28 TOS for Mailbox 28 + Uint16 TOS29:1; // 29 TOS for Mailbox 29 + Uint16 TOS30:1; // 30 TOS for Mailbox 30 + Uint16 TOS31:1; // 31 TOS for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTOS_REG { + Uint32 all; + struct CANTOS_BITS bit; +}; + +/**************************************/ +/* eCAN Control & Status register file */ +/**************************************/ + +struct ECAN_REGS { + union CANME_REG CANME; // Mailbox Enable + union CANMD_REG CANMD; // Mailbox Direction + union CANTRS_REG CANTRS; // Transmit Request Set + union CANTRR_REG CANTRR; // Transmit Request Reset + union CANTA_REG CANTA; // Transmit Acknowledge + union CANAA_REG CANAA; // Abort Acknowledge + union CANRMP_REG CANRMP; // Received Message Pending + union CANRML_REG CANRML; // Received Message Lost + union CANRFP_REG CANRFP; // Remote Frame Pending + union CANGAM_REG CANGAM; // Global Acceptance Mask + union CANMC_REG CANMC; // Master Control + union CANBTC_REG CANBTC; // Bit Timing + union CANES_REG CANES; // Error Status + union CANTEC_REG CANTEC; // Transmit Error Counter + union CANREC_REG CANREC; // Receive Error Counter + union CANGIF0_REG CANGIF0; // Global Interrupt Flag 0 + union CANGIM_REG CANGIM; // Global Interrupt Mask 0 + union CANGIF1_REG CANGIF1; // Global Interrupt Flag 1 + union CANMIM_REG CANMIM; // Mailbox Interrupt Mask + union CANMIL_REG CANMIL; // Mailbox Interrupt Level + union CANOPC_REG CANOPC; // Overwrite Protection Control + union CANTIOC_REG CANTIOC; // TX I/O Control + union CANRIOC_REG CANRIOC; // RX I/O Control + Uint32 CANTSC; // Time-stamp counter + union CANTOC_REG CANTOC; // Time-out Control + union CANTOS_REG CANTOS; // Time-out Status + +}; + +/* --------------------------------------------------- */ +/* eCAN Mailbox Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Message ID (MSGID) bit definitions */ +struct CANMSGID_BITS { // bits description + Uint16 EXTMSGID_L:16; // 0:15 + Uint16 EXTMSGID_H:2; // 16:17 + Uint16 STDMSGID:11; // 18:28 + Uint16 AAM:1; // 29 + Uint16 AME:1; // 30 + Uint16 IDE:1; // 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANMSGID_REG { + Uint32 all; + struct CANMSGID_BITS bit; +}; + +/* eCAN Message Control Field (MSGCTRL) bit definitions */ +struct CANMSGCTRL_BITS { // bits description + Uint16 DLC:4; // 0:3 + Uint16 RTR:1; // 4 + Uint16 rsvd1:3; // 7:5 reserved + Uint16 TPL:5; // 12:8 + Uint16 rsvd2:3; // 15:13 reserved + Uint16 rsvd3:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANMSGCTRL_REG { + Uint32 all; + struct CANMSGCTRL_BITS bit; +}; + +/* eCAN Message Data Register low (MDR_L) word definitions */ +struct CANMDL_WORDS { // bits description + Uint16 LOW_WORD:16; // 0:15 + Uint16 HI_WORD:16; // 31:16 +}; + +/* eCAN Message Data Register low (MDR_L) byte definitions */ +struct CANMDL_BYTES { // bits description + Uint16 BYTE3:8; // 31:24 + Uint16 BYTE2:8; // 23:16 + Uint16 BYTE1:8; // 15:8 + Uint16 BYTE0:8; // 7:0 +}; + + +/* Allow access to the bit fields or entire register */ + +union CANMDL_REG { + Uint32 all; + struct CANMDL_WORDS word; + struct CANMDL_BYTES byte; +}; + + + +/* eCAN Message Data Register high (MDR_H) word definitions */ +struct CANMDH_WORDS { // bits description + Uint16 LOW_WORD:16; // 0:15 + Uint16 HI_WORD:16; // 31:16 +}; + +/* eCAN Message Data Register low (MDR_H) byte definitions */ +struct CANMDH_BYTES { // bits description + Uint16 BYTE7:8; // 63:56 + Uint16 BYTE6:8; // 55:48 + Uint16 BYTE5:8; // 47:40 + Uint16 BYTE4:8; // 39:32 +}; + +/* Allow access to the bit fields or entire register */ +union CANMDH_REG { + Uint32 all; + struct CANMDH_WORDS word; + struct CANMDH_BYTES byte; +}; + + +struct MBOX { + union CANMSGID_REG MSGID; + union CANMSGCTRL_REG MSGCTRL; + union CANMDL_REG MDL; + union CANMDH_REG MDH; +}; + +/**************************************/ +/* eCAN Mailboxes */ +/**************************************/ + +struct ECAN_MBOXES { + struct MBOX MBOX0; + struct MBOX MBOX1; + struct MBOX MBOX2; + struct MBOX MBOX3; + struct MBOX MBOX4; + struct MBOX MBOX5; + struct MBOX MBOX6; + struct MBOX MBOX7; + struct MBOX MBOX8; + struct MBOX MBOX9; + struct MBOX MBOX10; + struct MBOX MBOX11; + struct MBOX MBOX12; + struct MBOX MBOX13; + struct MBOX MBOX14; + struct MBOX MBOX15; + struct MBOX MBOX16; + struct MBOX MBOX17; + struct MBOX MBOX18; + struct MBOX MBOX19; + struct MBOX MBOX20; + struct MBOX MBOX21; + struct MBOX MBOX22; + struct MBOX MBOX23; + struct MBOX MBOX24; + struct MBOX MBOX25; + struct MBOX MBOX26; + struct MBOX MBOX27; + struct MBOX MBOX28; + struct MBOX MBOX29; + struct MBOX MBOX30; + struct MBOX MBOX31; +}; + +/* eCAN Local Acceptance Mask (LAM) bit definitions */ +struct CANLAM_BITS { // bits description + Uint16 LAM_L:16; // 0:15 + Uint16 LAM_H:13; // 16:28 + Uint16 rsvd1:2; // 29:30 reserved + Uint16 LAMI:1; // 31 +}; + +/* Allow access to the bit fields or entire register */ +union CANLAM_REG { + Uint32 all; + struct CANLAM_BITS bit; +}; + + +/**************************************/ +/* eCAN Local Acceptance Masks */ +/**************************************/ + +/* eCAN LAM File */ +struct LAM_REGS { + union CANLAM_REG LAM0; + union CANLAM_REG LAM1; + union CANLAM_REG LAM2; + union CANLAM_REG LAM3; + union CANLAM_REG LAM4; + union CANLAM_REG LAM5; + union CANLAM_REG LAM6; + union CANLAM_REG LAM7; + union CANLAM_REG LAM8; + union CANLAM_REG LAM9; + union CANLAM_REG LAM10; + union CANLAM_REG LAM11; + union CANLAM_REG LAM12; + union CANLAM_REG LAM13; + union CANLAM_REG LAM14; + union CANLAM_REG LAM15; + union CANLAM_REG LAM16; + union CANLAM_REG LAM17; + union CANLAM_REG LAM18; + union CANLAM_REG LAM19; + union CANLAM_REG LAM20; + union CANLAM_REG LAM21; + union CANLAM_REG LAM22; + union CANLAM_REG LAM23; + union CANLAM_REG LAM24; + union CANLAM_REG LAM25; + union CANLAM_REG LAM26; + union CANLAM_REG LAM27; + union CANLAM_REG LAM28; + union CANLAM_REG LAM29; + union CANLAM_REG LAM30; + union CANLAM_REG LAM31; +}; + +/* Mailbox MOTS File */ + +struct MOTS_REGS { + Uint32 MOTS0; + Uint32 MOTS1; + Uint32 MOTS2; + Uint32 MOTS3; + Uint32 MOTS4; + Uint32 MOTS5; + Uint32 MOTS6; + Uint32 MOTS7; + Uint32 MOTS8; + Uint32 MOTS9; + Uint32 MOTS10; + Uint32 MOTS11; + Uint32 MOTS12; + Uint32 MOTS13; + Uint32 MOTS14; + Uint32 MOTS15; + Uint32 MOTS16; + Uint32 MOTS17; + Uint32 MOTS18; + Uint32 MOTS19; + Uint32 MOTS20; + Uint32 MOTS21; + Uint32 MOTS22; + Uint32 MOTS23; + Uint32 MOTS24; + Uint32 MOTS25; + Uint32 MOTS26; + Uint32 MOTS27; + Uint32 MOTS28; + Uint32 MOTS29; + Uint32 MOTS30; + Uint32 MOTS31; +}; + +/* Mailbox MOTO File */ + +struct MOTO_REGS { + Uint32 MOTO0; + Uint32 MOTO1; + Uint32 MOTO2; + Uint32 MOTO3; + Uint32 MOTO4; + Uint32 MOTO5; + Uint32 MOTO6; + Uint32 MOTO7; + Uint32 MOTO8; + Uint32 MOTO9; + Uint32 MOTO10; + Uint32 MOTO11; + Uint32 MOTO12; + Uint32 MOTO13; + Uint32 MOTO14; + Uint32 MOTO15; + Uint32 MOTO16; + Uint32 MOTO17; + Uint32 MOTO18; + Uint32 MOTO19; + Uint32 MOTO20; + Uint32 MOTO21; + Uint32 MOTO22; + Uint32 MOTO23; + Uint32 MOTO24; + Uint32 MOTO25; + Uint32 MOTO26; + Uint32 MOTO27; + Uint32 MOTO28; + Uint32 MOTO29; + Uint32 MOTO30; + Uint32 MOTO31; +}; + + +//--------------------------------------------------------------------------- +// eCAN External References & Function Declarations: +// +extern volatile struct ECAN_REGS ECanaRegs; +extern volatile struct ECAN_MBOXES ECanaMboxes; +extern volatile struct LAM_REGS ECanaLAMRegs; +extern volatile struct MOTO_REGS ECanaMOTORegs; +extern volatile struct MOTS_REGS ECanaMOTSRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_ECAN.H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h new file mode 100644 index 0000000..092a5fd --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h @@ -0,0 +1,654 @@ +// TI File $Revision: /main/4 $ +// Checkin $Date: June 22, 2007 09:30:33 $ +//########################################################################### +// +// FILE: DSP281x_Ev.h +// +// TITLE: DSP281x Device Event Manager Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_EV_H +#define DSP281x_EV_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "DSP281x_Device.h" +/* --------------------------------------------------- */ +/* F2810/12 Event Manager (EV) GP Timer Registers */ +/* */ +/* ----------------------------------------------------*/ + +/* Overall Timer Control Register */ + +struct GPTCONA_BITS { + Uint16 T1PIN:2; // 1:0 Polarity of GP timer 1 compare + Uint16 T2PIN:2; // 3:2 Polarity of GP timer 2 compare + Uint16 T1CMPOE:1; // 4 Timer1 compare output + Uint16 T2CMPOE:1; // 5 Timer2 compare output + Uint16 TCMPOE:1; // 6 Compare output enable + Uint16 T1TOADC:2; // 8:7 Start ADC with timer 1 event + Uint16 T2TOADC:2; // 10:9 Start ADC with timer 2 event + Uint16 T1CTRIPE:1; // 11 Enable Timer 1 compare trip + Uint16 T2CTRIPE:1; // 12 Enable Timer 2 compare trip + Uint16 T1STAT:1; // 13 GP Timer 1 status (read only) + Uint16 T2STAT:1; // 14 GP Timer 2 status (read only) + Uint16 rsvd:1; // 15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union GPTCONA_REG { + Uint16 all; + struct GPTCONA_BITS bit; +}; + +struct GPTCONB_BITS { + Uint16 T3PIN:2; // 1:0 Polarity of GP timer 3 compare + Uint16 T4PIN:2; // 3:2 Polarity of GP timer 4 compare + Uint16 T3CMPOE:1; // 4 Timer3 compare output + Uint16 T4CMPOE:1; // 5 Timer4 compare output + Uint16 TCMPOE:1; // 6 Compare output enable + Uint16 T3TOADC:2; // 8:7 Start ADC with timer 3 event + Uint16 T4TOADC:2; // 10:9 Start ADC with timer 4 event + Uint16 T3CTRIPE:1; // 11 Timer 3 trip enable + Uint16 T4CTRIPE:1; // 12 Timer 4 trip enable + Uint16 T3STAT:1; // 13 GP Timer 3 status (read only) + Uint16 T4STAT:1; // 14 GP Timer 4 status (read only) + Uint16 rsvd2:1; // 15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union GPTCONB_REG { + Uint16 all; + struct GPTCONB_BITS bit; +}; + +/* Timer 1 Control Register bit defintions */ +struct T1CON_BITS { + Uint16 rsvd1:1; // 0 reserved + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 rsvd2:1; // 7 reserved + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T1CON_REG { + Uint16 all; + struct T1CON_BITS bit; +}; + + +/* Timer 2 Control Register bit defintions */ +struct T2CON_BITS { + Uint16 SET1PR:1; // 0 Period register select + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 T2SWT1:1; // 7 Start GP timer 2 with GP timer 1's enable + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T2CON_REG { + Uint16 all; + struct T2CON_BITS bit; +}; + +/* Timer 3 Control Register bit defintions */ +struct T3CON_BITS { + Uint16 rsvd1:1; // 0 reserved + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 rsvd2:1; // 7 reserved + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T3CON_REG { + Uint16 all; + struct T3CON_BITS bit; +}; + +/* Timer 4 Control Register bit defintions */ +struct T4CON_BITS { + Uint16 SET3PR:1; // 0 Period register select + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 T4SWT3:1; // 7 Start GP timer 2 with GP timer 1's enable + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T4CON_REG { + Uint16 all; + struct T4CON_BITS bit; +}; + + +struct EXTCONA_BITS { + Uint16 INDCOE:1; // 0 Independant compare output + Uint16 QEPIQUAL:1; // 1 QEP/CAP3 Index Qual Mode + Uint16 QEPIE:1; // 2 QEP index enable + Uint16 EVSOCE:1; // 3 EvA start of conversion output enable + Uint16 rsvd:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EXTCONA_REG { + Uint16 all; + struct EXTCONA_BITS bit; +}; + + +struct EXTCONB_BITS { + Uint16 INDCOE:1; // 0 Independant compare output + Uint16 QEPIQUAL:1; // 1 QEP/CAP3 Index Qual Mode + Uint16 QEPIE:1; // 2 QEP index enable + Uint16 EVSOCE:1; // 3 EvB start of conversion output enable + Uint16 rsvd:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EXTCONB_REG { + Uint16 all; + struct EXTCONA_BITS bit; +}; + + + +/* Compare Control Register */ +struct COMCONA_BITS { + Uint16 C1TRIPE:1; // 0 C1TRIP enable + Uint16 C2TRIPE:1; // 1 C2TRIP enable + Uint16 C3TRIPE:1; // 2 C3TRIP eanble + Uint16 rsvd:2; // 4:3 reserved + Uint16 FCMP1OE:1; // 5 Full compare 1 output enable + Uint16 FCMP2OE:1; // 6 Full compare 2 output enable + Uint16 FCMP3OE:1; // 7 Full compare 3 output enable + Uint16 PDPINTASTATUS:1;// 8 Current status of the PDPINTA pin + Uint16 FCOMPOE:1; // 9 Compare output enable + Uint16 ACTRLD:2; // 11:10 Action control register reload + Uint16 SVENABLE:1; // 12 Space vector PWM Mode enable + Uint16 CLD:2; // 14:13 Compare register reload condition + Uint16 CENABLE:1; // 15 Compare enable +}; + +/* Allow access to the bit fields or entire register */ +union COMCONA_REG { + Uint16 all; + struct COMCONA_BITS bit; +}; + +struct COMCONB_BITS { + Uint16 C4TRIPE:1; // 0 C4TRIP enable + Uint16 C5TRIPE:1; // 1 C5TRIP enable + Uint16 C6TRIPE:1; // 2 C6TRIP eanble + Uint16 rsvd:2; // 4:3 reserved + Uint16 FCMP4OE:1; // 5 Full compare 4 output enable + Uint16 FCMP5OE:1; // 6 Full compare 5 output enable + Uint16 FCMP6OE:1; // 7 Full compare 6 output enable + Uint16 PDPINTBSTATUS:1;// 8 Current status of the PDPINTB pin + Uint16 FCOMPOE:1; // 9 Compare output enable + Uint16 ACTRLD:2; // 11:10 Action control register reload + Uint16 SVENABLE:1; // 12 Space vector PWM Mode enable + Uint16 CLD:2; // 14:13 Compare register reload condition + Uint16 CENABLE:1; // 15 Compare enable +}; + +/* Allow access to the bit fields or entire register */ +union COMCONB_REG { + Uint16 all; + struct COMCONB_BITS bit; +}; + +/* Compare Action Control Register bit definitions */ + +struct ACTRA_BITS { + Uint16 CMP1ACT:2; // 1:0 Action on compare output pin 1 CMP1 + Uint16 CMP2ACT:2; // 3:2 Action on compare output pin 2 CMP2 + Uint16 CMP3ACT:2; // 5:4 Action on compare output pin 3 CMP3 + Uint16 CMP4ACT:2; // 7:6 Action on compare output pin 4 CMP4 + Uint16 CMP5ACT:2; // 9:8 Action on compare output pin 5 CMP5 + Uint16 CMP6ACT:2; // 11:10 Action on compare output pin 6 CMP6 + Uint16 D:3; // 14:12 Basic vector bits + Uint16 SVRDIR:1; // 15 Space vecor PWM rotation dir +}; + +/* Allow access to the bit fields or entire register */ +union ACTRA_REG { + Uint16 all; + struct ACTRA_BITS bit; +}; + +struct ACTRB_BITS { + Uint16 CMP7ACT:2; // 1:0 Action on compare output pin 7 CMP7 + Uint16 CMP8ACT:2; // 3:2 Action on compare output pin 8 CMP8 + Uint16 CMP9ACT:2; // 5:4 Action on compare output pin 9 CMP9 + Uint16 CMP10ACT:2; // 7:6 Action on compare output pin 10 CMP10 + Uint16 CMP11ACT:2; // 9:8 Action on compare output pin 11 CMP11 + Uint16 CMP12ACT:2; // 11:10 Action on compare output pin 12 CMP12 + Uint16 D:3; // 14:12 Basic vector bits + Uint16 SVRDIR:1; // 15 Space vecor PWM rotation dir +}; + +/* Allow access to the bit fields or entire register */ +union ACTRB_REG { + Uint16 all; + struct ACTRB_BITS bit; +}; + +/* Dead-Band Timer Control register bit definitions */ +struct DBTCON_BITS { + Uint16 rsvd1:2; // 1:0 reserved + Uint16 DBTPS:3; // 4:2 Dead-Band timer prescaler + Uint16 EDBT1:1; // 5 Dead-Band timer 1 enable + Uint16 EDBT2:1; // 6 Dead-Band timer 2 enable + Uint16 EDBT3:1; // 7 Dead-Band timer 3 enable + Uint16 DBT:4; // 11:8 Dead-Band timer period + Uint16 rsvd2:4; // 15:12 reserved +}; + +/* Allow access to the bit fields or entire register */ +union DBTCON_REG { + Uint16 all; + struct DBTCON_BITS bit; +}; + + +/* Capture Control register bit definitions */ +struct CAPCONA_BITS { + Uint16 rsvd1:2; // 1:0 reserved + Uint16 CAP3EDGE:2; // 3:2 Edge Detection for Unit 3 + Uint16 CAP2EDGE:2; // 5:4 Edge Detection for Unit 2 + Uint16 CAP1EDGE:2; // 7:6 Edge Detection for Unit 1 + Uint16 CAP3TOADC:1; // 8 Unit 3 starts the ADC + Uint16 CAP12TSEL:1; // 9 GP Timer selection for Units 1 and 2 + Uint16 CAP3TSEL:1; // 10 GP Timer selection for Unit 3 + Uint16 rsvd2:1; // 11 reserved + Uint16 CAP3EN:1; // 12 Capture Unit 3 enable + Uint16 CAP12EN:2; // 14:13 Capture Unit 1 and 2 enable + Uint16 CAPRES:1; // 15 Capture reset (always reads 0) +}; + +/* Allow access to the bit fields or entire register */ +union CAPCONA_REG { + Uint16 all; + struct CAPCONA_BITS bit; +}; + + +/* Control register bit definitions */ +struct CAPCONB_BITS { + Uint16 rsvd1:2; // 1:0 reserved + Uint16 CAP6EDGE:2; // 3:2 Edge Detection for Unit 6 + Uint16 CAP5EDGE:2; // 5:4 Edge Detection for Unit 5 + Uint16 CAP4EDGE:2; // 7:6 Edge Detection for Unit 4 + Uint16 CAP6TOADC:1; // 8 Unit 6 starts the ADC + Uint16 CAP45TSEL:1; // 9 GP Timer selection for Units 4 and 5 + Uint16 CAP6TSEL:1; // 10 GP Timer selection for Unit 6 + Uint16 rsvd2:1; // 11 reserved + Uint16 CAP6EN:1; // 12 Capture Unit 6 control + Uint16 CAP45EN:2; // 14:13 Capture Unit 4 and 5 control + Uint16 CAPRES:1; // 15 Capture reset (always reads 0) +}; + +/* Allow access to the bit fields or entire register */ +union CAPCONB_REG { + Uint16 all; + struct CAPCONB_BITS bit; +}; + +/* Capture FIFO Status Register bit definitions */ +struct CAPFIFOA_BITS { + Uint16 rsvd1:8; // 7:0 reserved + Uint16 CAP1FIFO:2; // 9:8 CAP1 FIFO status + Uint16 CAP2FIFO:2; // 11:10 CAP2 FIFO status + Uint16 CAP3FIFO:2; // 13:12 CAP2 FIFO status + Uint16 rsvd2:2; // 15:14 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CAPFIFOA_REG { + Uint16 all; + struct CAPFIFOA_BITS bit; +}; + +/* Capture FIFO Status Register bit definitions */ +struct CAPFIFOB_BITS { + Uint16 rsvd1:8; // 7:0 reserved + Uint16 CAP4FIFO:2; // 9:8 CAP4 FIFO status + Uint16 CAP5FIFO:2; // 11:10 CAP5 FIFO status + Uint16 CAP6FIFO:2; // 13:12 CAP6 FIFO status + Uint16 rsvd2:2; // 15:14 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CAPFIFOB_REG { + Uint16 all; + struct CAPFIFOB_BITS bit; +}; + +/* Interrupt Mask Register bit definitions */ +struct EVAIMRA_BITS { + Uint16 PDPINTA:1; // 0 Enable PDPINTA + Uint16 CMP1INT:1; // 1 Enable + Uint16 CMP2INT:1; // 2 Enable + Uint16 CMP3INT:1; // 3 Enable + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T1PINT:1; // 7 Enable + Uint16 T1CINT:1; // 8 Enable + Uint16 T1UFINT:1; // 9 Enable + Uint16 T1OFINT:1; // 10 Enable + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIMRA_REG { + Uint16 all; + struct EVAIMRA_BITS bit; +}; + +/* Interrupt Mask Register bit definitions */ +struct EVBIMRA_BITS { + Uint16 PDPINTB:1; // 0 Enable PDPINTB + Uint16 CMP4INT:1; // 1 Enable + Uint16 CMP5INT:1; // 2 Enable + Uint16 CMP6INT:1; // 3 Enable + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T3PINT:1; // 7 Enable + Uint16 T3CINT:1; // 8 Enable + Uint16 T3UFINT:1; // 9 Enable + Uint16 T3OFINT:1; // 10 Enable + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIMRA_REG { + Uint16 all; + struct EVBIMRA_BITS bit; +}; + +struct EVAIMRB_BITS { + Uint16 T2PINT:1; // 0 Enable + Uint16 T2CINT:1; // 1 Enable + Uint16 T2UFINT:1; // 2 Enable + Uint16 T2OFINT:1; // 3 Enable + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIMRB_REG { + Uint16 all; + struct EVAIMRB_BITS bit; +}; + +struct EVBIMRB_BITS { + Uint16 T4PINT:1; // 0 Enable + Uint16 T4CINT:1; // 1 Enable + Uint16 T4UFINT:1; // 2 Enable + Uint16 T4OFINT:1; // 3 Enable + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIMRB_REG { + Uint16 all; + struct EVBIMRB_BITS bit; +}; + +struct EVAIMRC_BITS { + Uint16 CAP1INT:1; // 0 Enable + Uint16 CAP2INT:1; // 1 Enable + Uint16 CAP3INT:1; // 2 Enable + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIMRC_REG { + Uint16 all; + struct EVAIMRC_BITS bit; +}; + +struct EVBIMRC_BITS { + Uint16 CAP4INT:1; // 0 Enable + Uint16 CAP5INT:1; // 1 Enable + Uint16 CAP6INT:1; // 2 Enable + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIMRC_REG { + Uint16 all; + struct EVBIMRC_BITS bit; +}; + +/* Interrupt Flag Register bit definitions */ +struct EVAIFRA_BITS { + Uint16 PDPINTA:1; // 0 Flag PDPINTA + Uint16 CMP1INT:1; // 1 Flag + Uint16 CMP2INT:1; // 2 Flag + Uint16 CMP3INT:1; // 3 Flag + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T1PINT:1; // 7 Flag + Uint16 T1CINT:1; // 8 Flag + Uint16 T1UFINT:1; // 9 Flag + Uint16 T1OFINT:1; // 10 Flag + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIFRA_REG { + Uint16 all; + struct EVAIMRA_BITS bit; +}; + +/* Interrupt Mask Register bit definitions */ +struct EVBIFRA_BITS { + Uint16 PDPINTB:1; // 0 Flag PDPINTB + Uint16 CMP4INT:1; // 1 Flag + Uint16 CMP5INT:1; // 2 Flag + Uint16 CMP6INT:1; // 3 Flag + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T3PINT:1; // 7 Flag + Uint16 T3CINT:1; // 8 Flag + Uint16 T3UFINT:1; // 9 Flag + Uint16 T3OFINT:1; // 10 Flag + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIFRA_REG { + Uint16 all; + struct EVBIFRA_BITS bit; +}; + +struct EVAIFRB_BITS { + Uint16 T2PINT:1; // 0 Flag + Uint16 T2CINT:1; // 1 Flag + Uint16 T2UFINT:1; // 2 Flag + Uint16 T2OFINT:1; // 3 Flag + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIFRB_REG { + Uint16 all; + struct EVAIFRB_BITS bit; +}; + +struct EVBIFRB_BITS { + Uint16 T4PINT:1; // 0 Flag + Uint16 T4CINT:1; // 1 Flag + Uint16 T4UFINT:1; // 2 Flag + Uint16 T4OFINT:1; // 3 Flag + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIFRB_REG { + Uint16 all; + struct EVBIFRB_BITS bit; +}; + +struct EVAIFRC_BITS { + Uint16 CAP1INT:1; // 0 Flag + Uint16 CAP2INT:1; // 1 Flag + Uint16 CAP3INT:1; // 2 Flag + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIFRC_REG { + Uint16 all; + struct EVAIFRC_BITS bit; +}; + +struct EVBIFRC_BITS { + Uint16 CAP4INT:1; // 0 Flag + Uint16 CAP5INT:1; // 1 Flag + Uint16 CAP6INT:1; // 2 Flag + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIFRC_REG { + Uint16 all; + struct EVBIFRC_BITS bit; +}; + +/* EVA Register File */ + +struct EVA_REGS { + union GPTCONA_REG GPTCONA; //0x7400 + Uint16 T1CNT; //0x7401 + Uint16 T1CMPR; //0x7402 + Uint16 T1PR; //0x7403 + union T1CON_REG T1CON; //0x7404 + Uint16 T2CNT; //0x7405 + Uint16 T2CMPR; //0x7406 + Uint16 T2PR; //0x7407 + union T2CON_REG T2CON; //0x7408 + union EXTCONA_REG EXTCONA; //0x7409 + Uint16 rsvd1[7]; //0x740A-10 + union COMCONA_REG COMCONA; //0x7411 + Uint16 rsvd2; //0x7412 + union ACTRA_REG ACTRA; //0x7413 + Uint16 rsvd3; //0x7414 + union DBTCON_REG DBTCONA; //0x7415 + Uint16 rsvd4; //0x7416 + Uint16 CMPR1; //0x7417 + Uint16 CMPR2; //0x7418 + Uint16 CMPR3; //0x7419 + Uint16 rsvd5[6]; //0x741A-F + union CAPCONA_REG CAPCONA; //0x7420 + Uint16 rsvd6; //0x7421 + union CAPFIFOA_REG CAPFIFOA; //0x7422 + Uint16 CAP1FIFO; //0x7423 + Uint16 CAP2FIFO; //0x7424 + Uint16 CAP3FIFO; //0x7425 + Uint16 rsvd7; //0x7426 + Uint16 CAP1FBOT; //0x7427 + Uint16 CAP2FBOT; //0x7428 + Uint16 CAP3FBOT; //0x7429 + Uint16 rsvd8[2]; //0x742A-B + union EVAIMRA_REG EVAIMRA; //0x742C + union EVAIMRB_REG EVAIMRB; //0x742D + union EVAIMRC_REG EVAIMRC; //0x742E + union EVAIFRA_REG EVAIFRA; //0x742F + union EVAIFRB_REG EVAIFRB; //0x7430 + union EVAIFRC_REG EVAIFRC; //0x7431 +}; + + +/* EVB Register File */ + +struct EVB_REGS { + union GPTCONB_REG GPTCONB; //0x7500 + Uint16 T3CNT; //0x7501 + Uint16 T3CMPR; //0x7502 + Uint16 T3PR; //0x7503 + union T3CON_REG T3CON; //0x7504 + Uint16 T4CNT; //0x7505 + Uint16 T4CMPR; //0x7506 + Uint16 T4PR; //0x7507 + union T4CON_REG T4CON; //0x7508 + union EXTCONB_REG EXTCONB; //0x7509 + Uint16 rsvd1[7]; //0x750A-10 + union COMCONB_REG COMCONB; //0x7511 + Uint16 rsvd2; //0x7512 + union ACTRB_REG ACTRB; //0x7513 + Uint16 rsvd3; //0x7514 + union DBTCON_REG DBTCONB; //0x7515 + Uint16 rsvd4; //0x7516 + Uint16 CMPR4; //0x7517 + Uint16 CMPR5; //0x7518 + Uint16 CMPR6; //0x7519 + Uint16 rsvd5[6]; //0x751A-F + union CAPCONB_REG CAPCONB; //0x7520 + Uint16 rsvd6; //0x7521 + union CAPFIFOB_REG CAPFIFOB; //0x7522 + Uint16 CAP4FIFO; //0x7523 + Uint16 CAP5FIFO; //0x7524 + Uint16 CAP6FIFO; //0x7525 + Uint16 rsvd7; //0x7526 + Uint16 CAP4FBOT; //0x7527 + Uint16 CAP5FBOT; //0x7528 + Uint16 CAP6FBOT; //0x7529 + Uint16 rsvd8[2]; //0x752A-B + union EVBIMRA_REG EVBIMRA; //0x752C + union EVBIMRB_REG EVBIMRB; //0x752D + union EVBIMRC_REG EVBIMRC; //0x752E + union EVBIFRA_REG EVBIFRA; //0x752F + union EVBIFRB_REG EVBIFRB; //0x7530 + union EVBIFRC_REG EVBIFRC; //0x7531 +}; + + + +//--------------------------------------------------------------------------- +// Function prototypes and external definitions: +// + +extern volatile struct EVA_REGS EvaRegs; +extern volatile struct EVB_REGS EvbRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_EV.H definition + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h new file mode 100644 index 0000000..fb3d751 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h @@ -0,0 +1,1034 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:26 $ +//########################################################################### +// +// FILE: DSP281x_Gpio.h +// +// TITLE: DSP281x General Purpose I/O Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_GPIO_H +#define DSP281x_GPIO_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//---------------------------------------------------- +// General purpose I/O (GPIO) Register Bit Definitions + +//---------------------------------------------------- +// GPIO A mux control register bit definitions */ +// +// +struct GPAMUX_BITS { // bits description + Uint16 PWM1_GPIOA0:1; // 0 + Uint16 PWM2_GPIOA1:1; // 1 + Uint16 PWM3_GPIOA2:1; // 2 + Uint16 PWM4_GPIOA3:1; // 3 + Uint16 PWM5_GPIOA4:1; // 4 + Uint16 PWM6_GPIOA5:1; // 5 + Uint16 T1PWM_GPIOA6:1; // 6 + Uint16 T2PWM_GPIOA7:1; // 7 + Uint16 CAP1Q1_GPIOA8:1; // 8 + Uint16 CAP2Q2_GPIOA9:1; // 9 + Uint16 CAP3QI1_GPIOA10:1; // 10 + Uint16 TDIRA_GPIOA11:1; // 11 + Uint16 TCLKINA_GPIOA12:1; // 12 + Uint16 C1TRIP_GPIOA13:1; // 13 + Uint16 C2TRIP_GPIOA14:1; // 14 + Uint16 C3TRIP_GPIOA15:1; // 15 + +}; + +union GPAMUX_REG { + Uint16 all; + struct GPAMUX_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO A Direction control register bit definitions +// +// +struct GPADIR_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPADIR_REG { + Uint16 all; + struct GPADIR_BITS bit; +}; + +//---------------------------------- +// GPA Qualregister bit definitions +// +// + +struct GPAQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPAQUAL_REG { + Uint16 all; + struct GPAQUAL_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO A Data register bit definitions +// +// +struct GPADAT_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPADAT_REG { + Uint16 all; + struct GPADAT_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO A Data set bit definitions +// +// +struct GPASET_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPASET_REG { + Uint16 all; + struct GPASET_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO A Data clear register bit definitions +// +// +struct GPACLEAR_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPACLEAR_REG { + Uint16 all; + struct GPACLEAR_BITS bit; +}; + +//--------------------------------------------------------------------------------------- +// GPIO A Data toggle register bit definitions +// +// +struct GPATOGGLE_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPATOGGLE_REG { + Uint16 all; + struct GPATOGGLE_BITS bit; +}; + + + +//--------------------------------------------------------------------------------- +// GPIO B mux control register bit definitions +// +// +struct GPBMUX_BITS { // bits description + Uint16 PWM7_GPIOB0:1; // 0 + Uint16 PWM8_GPIOB1:1; // 1 + Uint16 PWM9_GPIOB2:1; // 2 + Uint16 PWM10_GPIOB3:1; // 3 + Uint16 PWM11_GPIOB4:1; // 4 + Uint16 PWM12_GPIOB5:1; // 5 + Uint16 T3PWM_GPIOB6:1; // 6 + Uint16 T4PWM_GPIOB7:1; // 7 + Uint16 CAP4Q1_GPIOB8:1; // 8 + Uint16 CAP5Q2_GPIOB9:1; // 9 + Uint16 CAP6QI2_GPIOB10:1; // 10 + Uint16 TDIRB_GPIOB11:1; // 11 + Uint16 TCLKINB_GPIOB12:1; // 12 + Uint16 C4TRIP_GPIOB13:1; // 13 + Uint16 C5TRIP_GPIOB14:1; // 14 + Uint16 C6TRIP_GPIOB15:1; // 15 + +}; + +union GPBMUX_REG { + Uint16 all; + struct GPBMUX_BITS bit; +}; + +//--------------------------------------------------------------------------------------- +// GPIO B Direction control register bit definitions +// +// +struct GPBDIR_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBDIR_REG { + Uint16 all; + struct GPBDIR_BITS bit; +}; + +//----------------------------------- +// GPB Qualregister bit definitions +// +// + +struct GPBQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPBQUAL_REG { + Uint16 all; + struct GPBQUAL_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO B data register bit definitions +// +// +struct GPBDAT_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBDAT_REG { + Uint16 all; + struct GPBDAT_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO B data set register bit definitions +// +// +struct GPBSET_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + + +union GPBSET_REG { + Uint16 all; + struct GPBSET_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO B data clear register bit definitions +// +// +struct GPBCLEAR_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBCLEAR_REG { + Uint16 all; + struct GPBCLEAR_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO B data toggle register bit definitions +// +// +struct GPBTOGGLE_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBTOGGLE_REG { + Uint16 all; + struct GPBTOGGLE_BITS bit; +}; + + +//--------------------------------------------------------------------------------- +// GPIO D mux control register bit definitions +// +// +struct GPDMUX_BITS { // bits description + Uint16 T1CTRIP_PDPA_GPIOD0:1; // 0 + Uint16 T2CTRIP_SOCA_GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 T3CTRIP_PDPB_GPIOD5:1; // 5 + Uint16 T4CTRIP_SOCB_GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 + +}; + +union GPDMUX_REG { + Uint16 all; + struct GPDMUX_BITS bit; +}; + +//---------------------------------------------------- +// GPIO D Direction control register bit definitions +// +// +struct GPDDIR_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDDIR_REG { + Uint16 all; + struct GPDDIR_BITS bit; +}; + + +//---------------------------------------------------- +// GPIO D data register bit definitions +// +// +struct GPDDAT_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDDAT_REG { + Uint16 all; + struct GPDDAT_BITS bit; +}; + + +//---------------------------------------------------- +// GPIO D data set register bit definitions +// +// +struct GPDSET_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDSET_REG { + Uint16 all; + struct GPDSET_BITS bit; +}; + + +//---------------------------------------------------- +// GPIO D data clear register bit definitions +// +// +struct GPDCLEAR_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDCLEAR_REG { + Uint16 all; + struct GPDCLEAR_BITS bit; +}; + + + +//---------------------------------------------------- +// GPIO D data toggle register bit definitions +// +// +struct GPDTOGGLE_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDTOGGLE_REG { + Uint16 all; + struct GPDTOGGLE_BITS bit; +}; + + + +//---------------------------------- +// GPIOD Qualregister bit definitions +// +// +struct GPDQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPDQUAL_REG { + Uint16 all; + struct GPDQUAL_BITS bit; +}; + + +//--------------------------------------------- +// GPIO E mux control register bit definitions +// +// +struct GPEMUX_BITS { // bits description + Uint16 XINT1_XBIO_GPIOE0:1; // 0 + Uint16 XINT2_ADCSOC_GPIOE1:1; // 1 + Uint16 XNMI_XINT13_GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 + +}; + +union GPEMUX_REG { + Uint16 all; + struct GPEMUX_BITS bit; +}; + +//--------------------------------------------------- +// GPIO E Direction control register bit definitions +// +// +struct GPEDIR_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPEDIR_REG { + Uint16 all; + struct GPEDIR_BITS bit; +}; + +//--------------------------------------------------- +// GPIO E data register bit definitions +// +// +struct GPEDAT_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPEDAT_REG { + Uint16 all; + struct GPEDAT_BITS bit; +}; + + + +//--------------------------------------------------- +// GPIO E data set register bit definitions +// +// +struct GPESET_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPESET_REG { + Uint16 all; + struct GPESET_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO E data clear register bit definitions +// +// +struct GPECLEAR_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPECLEAR_REG { + Uint16 all; + struct GPECLEAR_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO E data toggle register bit definitions +// +// +struct GPETOGGLE_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPETOGGLE_REG { + Uint16 all; + struct GPETOGGLE_BITS bit; +}; + + + +//----------------------------------- +// GPIOE Qualregister bit definitions +// +// +struct GPEQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPEQUAL_REG { + Uint16 all; + struct GPEQUAL_BITS bit; +}; + + +//---------------------------------------------- +// GPIO F mux control register bit definitions +// +// +struct GPFMUX_BITS { // bits description + Uint16 SPISIMOA_GPIOF0:1; // 0 + Uint16 SPISOMIA_GPIOF1:1; // 1 + Uint16 SPICLKA_GPIOF2:1; // 2 + Uint16 SPISTEA_GPIOF3:1; // 3 + Uint16 SCITXDA_GPIOF4:1; // 4 + Uint16 SCIRXDA_GPIOF5:1; // 5 + Uint16 CANTXA_GPIOF6:1; // 6 + Uint16 CANRXA_GPIOF7:1; // 7 + Uint16 MCLKXA_GPIOF8:1; // 8 + Uint16 MCLKRA_GPIOF9:1; // 9 + Uint16 MFSXA_GPIOF10:1; // 10 + Uint16 MFSRA_GPIOF11:1; // 11 + Uint16 MDXA_GPIOF12:1; // 12 + Uint16 MDRA_GPIOF13:1; // 13 + Uint16 XF_GPIOF14:1; // 14 + Uint16 spare_GPIOF15:1; // 15 + +}; + +/* Allow access to the bit fields or entire register */ +union GPFMUX_REG { + Uint16 all; + struct GPFMUX_BITS bit; +}; + +//--------------------------------------------------- +// GPIO F Direction control register bit definitions +// +// + +struct GPFDIR_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFDIR_REG { + Uint16 all; + struct GPFDIR_BITS bit; +}; + +//--------------------------------------------------- +// GPIO F data register bit definitions +// +// + +struct GPFDAT_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFDAT_REG { + Uint16 all; + struct GPFDAT_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO F data set register bit definitions +// +// + +struct GPFSET_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFSET_REG { + Uint16 all; + struct GPFSET_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO F data clear register bit definitions +// +// + +struct GPFCLEAR_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFCLEAR_REG { + Uint16 all; + struct GPFCLEAR_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO F data toggle register bit definitions +// +// + +struct GPFTOGGLE_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFTOGGLE_REG { + Uint16 all; + struct GPFTOGGLE_BITS bit; +}; + +//---------------------------------------------- +// GPIO G mux control register bit definitions +// +// +struct GPGMUX_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 SCITXDB_GPIOG4:1; // 4 + Uint16 SCIRXDB_GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + + +/* Allow access to the bit fields or entire register */ +union GPGMUX_REG { + Uint16 all; + struct GPGMUX_BITS bit; +}; + +//--------------------------------------------------- +// GPIO G Direction control register bit definitions +// +// + +struct GPGDIR_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGDIR_REG { + Uint16 all; + struct GPGDIR_BITS bit; +}; + +//--------------------------------------------------- +// GPIO G data register bit definitions +// +// + +struct GPGDAT_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGDAT_REG { + Uint16 all; + struct GPGDAT_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO G data set register bit definitions +// +// + +struct GPGSET_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGSET_REG { + Uint16 all; + struct GPGSET_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO G data clear register bit definitions +// +// + +struct GPGCLEAR_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGCLEAR_REG { + Uint16 all; + struct GPGCLEAR_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO G data toggle register bit definitions +// +// + +struct GPGTOGGLE_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGTOGGLE_REG { + Uint16 all; + struct GPGTOGGLE_BITS bit; +}; + + +struct GPIO_MUX_REGS { + union GPAMUX_REG GPAMUX; + union GPADIR_REG GPADIR; + union GPAQUAL_REG GPAQUAL; + Uint16 rsvd1; + union GPBMUX_REG GPBMUX; + union GPBDIR_REG GPBDIR; + union GPBQUAL_REG GPBQUAL; + Uint16 rsvd2[5]; + union GPDMUX_REG GPDMUX; + union GPDDIR_REG GPDDIR; + union GPDQUAL_REG GPDQUAL; + Uint16 rsvd3; + union GPEMUX_REG GPEMUX; + union GPEDIR_REG GPEDIR; + union GPEQUAL_REG GPEQUAL; + Uint16 rsvd4; + union GPFMUX_REG GPFMUX; + union GPFDIR_REG GPFDIR; + Uint16 rsvd5[2]; + union GPGMUX_REG GPGMUX; + union GPGDIR_REG GPGDIR; + Uint16 rsvd6[6]; +}; + +struct GPIO_DATA_REGS { + union GPADAT_REG GPADAT; + union GPASET_REG GPASET; + union GPACLEAR_REG GPACLEAR; + union GPATOGGLE_REG GPATOGGLE; + union GPBDAT_REG GPBDAT; + union GPBSET_REG GPBSET; + union GPBCLEAR_REG GPBCLEAR; + union GPBTOGGLE_REG GPBTOGGLE; + Uint16 rsvd1[4]; + union GPDDAT_REG GPDDAT; + union GPDSET_REG GPDSET; + union GPDCLEAR_REG GPDCLEAR; + union GPDTOGGLE_REG GPDTOGGLE; + union GPEDAT_REG GPEDAT; + union GPESET_REG GPESET; + union GPECLEAR_REG GPECLEAR; + union GPETOGGLE_REG GPETOGGLE; + union GPFDAT_REG GPFDAT; + union GPFSET_REG GPFSET; + union GPFCLEAR_REG GPFCLEAR; + union GPFTOGGLE_REG GPFTOGGLE; + union GPGDAT_REG GPGDAT; + union GPGSET_REG GPGSET; + union GPGCLEAR_REG GPGCLEAR; + union GPGTOGGLE_REG GPGTOGGLE; + Uint16 rsvd2[4]; +}; + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +extern volatile struct GPIO_MUX_REGS GpioMuxRegs; +extern volatile struct GPIO_DATA_REGS GpioDataRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_GPIO_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h new file mode 100644 index 0000000..559d96d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h @@ -0,0 +1,777 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:24 $ +//########################################################################### +// +// FILE: DSP281x_Mcbsp.h +// +// TITLE: DSP281x Device McBSP Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_MCBSP_H +#define DSP281x_MCBSP_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// McBSP Individual Register Bit Definitions: +// +// McBSP DRR2 register bit definitions: +struct DRR2_BITS { // bit description + Uint16 HWLB:8; // 16:23 High word low byte + Uint16 HWHB:8; // 24:31 High word high byte +}; + +union DRR2_REG { + Uint16 all; + struct DRR2_BITS bit; +}; + +// McBSP DRR1 register bit definitions: +struct DRR1_BITS { // bit description + Uint16 LWLB:8; // 16:23 Low word low byte + Uint16 LWHB:8; // 24:31 low word high byte +}; + +union DRR1_REG { + Uint16 all; + struct DRR1_BITS bit; +}; + +// McBSP DXR2 register bit definitions: +struct DXR2_BITS { // bit description + Uint16 HWLB:8; // 16:23 High word low byte + Uint16 HWHB:8; // 24:31 High word high byte +}; + +union DXR2_REG { + Uint16 all; + struct DXR2_BITS bit; +}; + +// McBSP DXR1 register bit definitions: +struct DXR1_BITS { // bit description + Uint16 LWLB:8; // 16:23 Low word low byte + Uint16 LWHB:8; // 24:31 low word high byte +}; + +union DXR1_REG { + Uint16 all; + struct DXR1_BITS bit; +}; + +// SPCR2 control register bit definitions: +struct SPCR2_BITS { // bit description + Uint16 XRST:1; // 0 transmit reset + Uint16 XRDY:1; // 1 transmit ready + Uint16 XEMPTY:1; // 2 Transmit empty + Uint16 XSYNCERR:1; // 3 Transmit syn errorINT flag + Uint16 XINTM:2; // 5:4 Transmit interrupt types + Uint16 GRST:1; // 6 CLKG reset + Uint16 FRST:1; // 7 Frame sync reset + Uint16 SOFT:1; // 8 SOFT bit + Uint16 FREE:1; // 9 FREE bit + Uint16 rsvd:6; // 15:10 reserved +}; + +union SPCR2_REG { + Uint16 all; + struct SPCR2_BITS bit; +}; + +// SPCR1 control register bit definitions: +struct SPCR1_BITS { // bit description + Uint16 RRST:1; // 0 Receive reset + Uint16 RRDY:1; // 1 Receive ready + Uint16 RFULL:1; // 2 Receive full + Uint16 RSYNCERR:1; // 7 Receive syn error + Uint16 RINTM:2; // 5:4 Receive interrupt types + Uint16 ABIS:1; // 6 ABIS mode select + Uint16 DXENA:1; // 7 DX hi-z enable + Uint16 rsvd:3; // 10:8 reserved + Uint16 CLKSTP:2; // 12:11 CLKSTOP mode bit + Uint16 RJUST:2; // 13:14 Right justified + Uint16 DLB:1; // 15 Digital loop back +}; + +union SPCR1_REG { + Uint16 all; + struct SPCR1_BITS bit; +}; + +// RCR2 control register bit definitions: +struct RCR2_BITS { // bit description + Uint16 RDATDLY:2; // 1:0 Receive data delay + Uint16 RFIG:1; // 2 Receive frame sync ignore + Uint16 RCOMPAND:2; // 4:3 Receive Companding Mode selects + Uint16 RWDLEN2:3; // 7:5 Receive word length + Uint16 RFRLEN2:7; // 14:8 Receive Frame sync + Uint16 RPHASE:1; // 15 Receive Phase +}; + +union RCR2_REG { + Uint16 all; + struct RCR2_BITS bit; +}; + +// RCR1 control register bit definitions: +struct RCR1_BITS { // bit description + Uint16 rsvd1:5; // 4:0 reserved + Uint16 RWDLEN1:3; // 7:5 Receive word length + Uint16 RFRLEN1:7; // 14:8 Receive frame length + Uint16 rsvd2:1; // 15 reserved +}; + +union RCR1_REG { + Uint16 all; + struct RCR1_BITS bit; +}; + +// XCR2 control register bit definitions: + +struct XCR2_BITS { // bit description + Uint16 XDATDLY:2; // 1:0 Transmit data delay + Uint16 XFIG:1; // 2 Transmit frame sync ignore + Uint16 XCOMPAND:2; // 4:3 Transmit Companding Mode selects + Uint16 XWDLEN2:3; // 7:5 Transmit word length + Uint16 XFRLEN2:7; // 14:8 Transmit Frame sync + Uint16 XPHASE:1; // 15 Transmit Phase +}; + +union XCR2_REG { + Uint16 all; + struct XCR2_BITS bit; +}; + +// XCR1 control register bit definitions: +struct XCR1_BITS { // bit description + Uint16 rsvd1:5; // 4:0 reserved + Uint16 XWDLEN1:3; // 7:5 Transmit word length + Uint16 XFRLEN1:7; // 14:8 Transmit frame length + Uint16 rsvd2:1; // 15 reserved +}; + +union XCR1_REG { + Uint16 all; + struct XCR1_BITS bit; +}; + +// SRGR2 Sample rate generator control register bit definitions: +struct SRGR2_BITS { // bit description + Uint16 FPER:12; // 11:0 Frame period + Uint16 FSGM:1; // 12 Frame sync generator mode + Uint16 CLKSM:1; // 13 Sample rate generator mode + Uint16 rsvd:1; // 14 reserved + Uint16 GSYNC:1; // 15 CLKG sync +}; + +union SRGR2_REG { + Uint16 all; + struct SRGR2_BITS bit; +}; + +// SRGR1 control register bit definitions: +struct SRGR1_BITS { // bit description + Uint16 CLKGDV:8; // 7:0 CLKG divider + Uint16 FWID:8; // 15:8 Frame width +}; + +union SRGR1_REG { + Uint16 all; + struct SRGR1_BITS bit; +}; + +// MCR2 Multichannel control register bit definitions: +struct MCR2_BITS { // bit description + Uint16 XMCM:2; // 1:0 Transmit multichannel mode + Uint16 XCBLK:3; // 2:4 Transmit current block + Uint16 XPABLK:2; // 5:6 Transmit partition A Block + Uint16 XPBBLK:2; // 7:8 Transmit partition B Block + Uint16 XMCME:1; // 9 Transmit multi-channel enhance mode + Uint16 rsvd:6; // 15:10 reserved +}; + +union MCR2_REG { + Uint16 all; + struct MCR2_BITS bit; +}; + +// MCR1 Multichannel control register bit definitions: +struct MCR1_BITS { // bit description + Uint16 RMCM:1; // 0 Receive multichannel mode + Uint16 rsvd:1; // 1 reserved + Uint16 RCBLK:3; // 4:2 Receive current block + Uint16 RPABLK:2; // 6:5 Receive partition A Block + Uint16 RPBBLK:2; // 7:8 Receive partition B Block + Uint16 RMCME:1; // 9 Receive multi-channel enhance mode + Uint16 rsvd1:6; // 15:10 reserved +}; + +union MCR1_REG { + Uint16 all; + struct MCR1_BITS bit; +}; + +// RCERA control register bit definitions: +struct RCERA_BITS { // bit description + Uint16 RCEA0:1; // 0 Receive Channel enable bit + Uint16 RCEA1:1; // 1 Receive Channel enable bit + Uint16 RCEA2:1; // 2 Receive Channel enable bit + Uint16 RCEA3:1; // 3 Receive Channel enable bit + Uint16 RCEA4:1; // 4 Receive Channel enable bit + Uint16 RCEA5:1; // 5 Receive Channel enable bit + Uint16 RCEA6:1; // 6 Receive Channel enable bit + Uint16 RCEA7:1; // 7 Receive Channel enable bit + Uint16 RCEA8:1; // 8 Receive Channel enable bit + Uint16 RCEA9:1; // 9 Receive Channel enable bit + Uint16 RCEA10:1; // 10 Receive Channel enable bit + Uint16 RCEA11:1; // 11 Receive Channel enable bit + Uint16 RCEA12:1; // 12 Receive Channel enable bit + Uint16 RCEA13:1; // 13 Receive Channel enable bit + Uint16 RCEA14:1; // 14 Receive Channel enable bit + Uint16 RCEA15:1; // 15 Receive Channel enable bit +}; + +union RCERA_REG { + Uint16 all; + struct RCERA_BITS bit; +}; + +// RCERB control register bit definitions: +struct RCERB_BITS { // bit description + Uint16 RCEB0:1; // 0 Receive Channel enable bit + Uint16 RCEB1:1; // 1 Receive Channel enable bit + Uint16 RCEB2:1; // 2 Receive Channel enable bit + Uint16 RCEB3:1; // 3 Receive Channel enable bit + Uint16 RCEB4:1; // 4 Receive Channel enable bit + Uint16 RCEB5:1; // 5 Receive Channel enable bit + Uint16 RCEB6:1; // 6 Receive Channel enable bit + Uint16 RCEB7:1; // 7 Receive Channel enable bit + Uint16 RCEB8:1; // 8 Receive Channel enable bit + Uint16 RCEB9:1; // 9 Receive Channel enable bit + Uint16 RCEB10:1; // 10 Receive Channel enable bit + Uint16 RCEB11:1; // 11 Receive Channel enable bit + Uint16 RCEB12:1; // 12 Receive Channel enable bit + Uint16 RCEB13:1; // 13 Receive Channel enable bit + Uint16 RCEB14:1; // 14 Receive Channel enable bit + Uint16 RCEB15:1; // 15 Receive Channel enable bit +}; + +union RCERB_REG { + Uint16 all; + struct RCERB_BITS bit; +}; + +// XCERA control register bit definitions: +struct XCERA_BITS { // bit description + Uint16 XCERA0:1; // 0 Receive Channel enable bit + Uint16 XCERA1:1; // 1 Receive Channel enable bit + Uint16 XCERA2:1; // 2 Receive Channel enable bit + Uint16 XCERA3:1; // 3 Receive Channel enable bit + Uint16 XCERA4:1; // 4 Receive Channel enable bit + Uint16 XCERA5:1; // 5 Receive Channel enable bit + Uint16 XCERA6:1; // 6 Receive Channel enable bit + Uint16 XCERA7:1; // 7 Receive Channel enable bit + Uint16 XCERA8:1; // 8 Receive Channel enable bit + Uint16 XCERA9:1; // 9 Receive Channel enable bit + Uint16 XCERA10:1; // 10 Receive Channel enable bit + Uint16 XCERA11:1; // 11 Receive Channel enable bit + Uint16 XCERA12:1; // 12 Receive Channel enable bit + Uint16 XCERA13:1; // 13 Receive Channel enable bit + Uint16 XCERA14:1; // 14 Receive Channel enable bit + Uint16 XCERA15:1; // 15 Receive Channel enable bit +}; + +union XCERA_REG { + Uint16 all; + struct XCERA_BITS bit; +}; + +// XCERB control register bit definitions: +struct XCERB_BITS { // bit description + Uint16 XCERB0:1; // 0 Receive Channel enable bit + Uint16 XCERB1:1; // 1 Receive Channel enable bit + Uint16 XCERB2:1; // 2 Receive Channel enable bit + Uint16 XCERB3:1; // 3 Receive Channel enable bit + Uint16 XCERB4:1; // 4 Receive Channel enable bit + Uint16 XCERB5:1; // 5 Receive Channel enable bit + Uint16 XCERB6:1; // 6 Receive Channel enable bit + Uint16 XCERB7:1; // 7 Receive Channel enable bit + Uint16 XCERB8:1; // 8 Receive Channel enable bit + Uint16 XCERB9:1; // 9 Receive Channel enable bit + Uint16 XCERB10:1; // 10 Receive Channel enable bit + Uint16 XCERB11:1; // 11 Receive Channel enable bit + Uint16 XCERB12:1; // 12 Receive Channel enable bit + Uint16 XCERB13:1; // 13 Receive Channel enable bit + Uint16 XCERB14:1; // 14 Receive Channel enable bit + Uint16 XCERB15:1; // 15 Receive Channel enable bit +}; + +union XCERB_REG { + Uint16 all; + struct XCERB_BITS bit; +}; + +// PCR control register bit definitions: +struct PCR_BITS { // bit description + Uint16 CLKRP:1; // 0 Receive Clock polarity + Uint16 CLKXP:1; // 1 Transmit clock polarity + Uint16 FSRP:1; // 2 Receive Frame synchronization polarity + Uint16 FSXP:1; // 3 Transmit Frame synchronization polarity + Uint16 DR_STAT:1; // 4 DR pin status - reserved for this McBSP + Uint16 DX_STAT:1; // 5 DX pin status - reserved for this McBSP + Uint16 CLKS_STAT:1; // 6 CLKS pin status - reserved for 28x -McBSP + Uint16 SCLKME:1; // 7 Enhanced sample clock mode selection bit. + Uint16 CLKRM:1; // 8 Receiver Clock Mode + Uint16 CLKXM:1; // 9 Transmitter Clock Mode. + Uint16 FSRM:1; // 10 Receive Frame Synchronization Mode + Uint16 FSXM:1; // 11 Transmit Frame Synchronization Mode + Uint16 RIOEN:1; // 12 General Purpose I/O Mode - reserved in this 28x-McBSP + Uint16 XIOEN:1; // 13 General Purpose I/O Mode - reserved in this 28x-McBSP + Uint16 IDEL_EN:1; // 14 reserved in this 28x-McBSP + Uint16 rsvd:1 ; // 15 reserved +}; + +union PCR_REG { + Uint16 all; + struct PCR_BITS bit; +}; + +// RCERC control register bit definitions: +struct RCERC_BITS { // bit description + Uint16 RCEC0:1; // 0 Receive Channel enable bit + Uint16 RCEC1:1; // 1 Receive Channel enable bit + Uint16 RCEC2:1; // 2 Receive Channel enable bit + Uint16 RCEC3:1; // 3 Receive Channel enable bit + Uint16 RCEC4:1; // 4 Receive Channel enable bit + Uint16 RCEC5:1; // 5 Receive Channel enable bit + Uint16 RCEC6:1; // 6 Receive Channel enable bit + Uint16 RCEC7:1; // 7 Receive Channel enable bit + Uint16 RCEC8:1; // 8 Receive Channel enable bit + Uint16 RCEC9:1; // 9 Receive Channel enable bit + Uint16 RCEC10:1; // 10 Receive Channel enable bit + Uint16 RCEC11:1; // 11 Receive Channel enable bit + Uint16 RCEC12:1; // 12 Receive Channel enable bit + Uint16 RCEC13:1; // 13 Receive Channel enable bit + Uint16 RCEC14:1; // 14 Receive Channel enable bit + Uint16 RCEC15:1; // 15 Receive Channel enable bit +}; + +union RCERC_REG { + Uint16 all; + struct RCERC_BITS bit; +}; + +// RCERD control register bit definitions: +struct RCERD_BITS { // bit description + Uint16 RCED0:1; // 0 Receive Channel enable bit + Uint16 RCED1:1; // 1 Receive Channel enable bit + Uint16 RCED2:1; // 2 Receive Channel enable bit + Uint16 RCED3:1; // 3 Receive Channel enable bit + Uint16 RCED4:1; // 4 Receive Channel enable bit + Uint16 RCED5:1; // 5 Receive Channel enable bit + Uint16 RCED6:1; // 6 Receive Channel enable bit + Uint16 RCED7:1; // 7 Receive Channel enable bit + Uint16 RCED8:1; // 8 Receive Channel enable bit + Uint16 RCED9:1; // 9 Receive Channel enable bit + Uint16 RCED10:1; // 10 Receive Channel enable bit + Uint16 RCED11:1; // 11 Receive Channel enable bit + Uint16 RCED12:1; // 12 Receive Channel enable bit + Uint16 RCED13:1; // 13 Receive Channel enable bit + Uint16 RCED14:1; // 14 Receive Channel enable bit + Uint16 RCED15:1; // 15 Receive Channel enable bit +}; + +union RCERD_REG { + Uint16 all; + struct RCERD_BITS bit; +}; + +// XCERC control register bit definitions: +struct XCERC_BITS { // bit description + Uint16 XCERC0:1; // 0 Receive Channel enable bit + Uint16 XCERC1:1; // 1 Receive Channel enable bit + Uint16 XCERC2:1; // 2 Receive Channel enable bit + Uint16 XCERC3:1; // 3 Receive Channel enable bit + Uint16 XCERC4:1; // 4 Receive Channel enable bit + Uint16 XCERC5:1; // 5 Receive Channel enable bit + Uint16 XCERC6:1; // 6 Receive Channel enable bit + Uint16 XCERC7:1; // 7 Receive Channel enable bit + Uint16 XCERC8:1; // 8 Receive Channel enable bit + Uint16 XCERC9:1; // 9 Receive Channel enable bit + Uint16 XCERC10:1; // 10 Receive Channel enable bit + Uint16 XCERC11:1; // 11 Receive Channel enable bit + Uint16 XCERC12:1; // 12 Receive Channel enable bit + Uint16 XCERC13:1; // 13 Receive Channel enable bit + Uint16 XCERC14:1; // 14 Receive Channel enable bit + Uint16 XCERC15:1; // 15 Receive Channel enable bit +}; + +union XCERC_REG { + Uint16 all; + struct XCERC_BITS bit; +}; + +// XCERD control register bit definitions: +struct XCERD_BITS { // bit description + Uint16 XCERD0:1; // 0 Receive Channel enable bit + Uint16 XCERD1:1; // 1 Receive Channel enable bit + Uint16 XCERD2:1; // 2 Receive Channel enable bit + Uint16 XCERD3:1; // 3 Receive Channel enable bit + Uint16 XCERD4:1; // 4 Receive Channel enable bit + Uint16 XCERD5:1; // 5 Receive Channel enable bit + Uint16 XCERD6:1; // 6 Receive Channel enable bit + Uint16 XCERD7:1; // 7 Receive Channel enable bit + Uint16 XCERD8:1; // 8 Receive Channel enable bit + Uint16 XCERD9:1; // 9 Receive Channel enable bit + Uint16 XCERD10:1; // 10 Receive Channel enable bit + Uint16 XCERD11:1; // 11 Receive Channel enable bit + Uint16 XCERD12:1; // 12 Receive Channel enable bit + Uint16 XCERD13:1; // 13 Receive Channel enable bit + Uint16 XCERD14:1; // 14 Receive Channel enable bit + Uint16 XCERD15:1; // 15 Receive Channel enable bit +}; + +union XCERD_REG { + Uint16 all; + struct XCERD_BITS bit; +}; + +// RCERE control register bit definitions: +struct RCERE_BITS { // bit description + Uint16 RCEE0:1; // 0 Receive Channel enable bit + Uint16 RCEE1:1; // 1 Receive Channel enable bit + Uint16 RCEE2:1; // 2 Receive Channel enable bit + Uint16 RCEE3:1; // 3 Receive Channel enable bit + Uint16 RCEE4:1; // 4 Receive Channel enable bit + Uint16 RCEE5:1; // 5 Receive Channel enable bit + Uint16 RCEE6:1; // 6 Receive Channel enable bit + Uint16 RCEE7:1; // 7 Receive Channel enable bit + Uint16 RCEE8:1; // 8 Receive Channel enable bit + Uint16 RCEE9:1; // 9 Receive Channel enable bit + Uint16 RCEE10:1; // 10 Receive Channel enable bit + Uint16 RCEE11:1; // 11 Receive Channel enable bit + Uint16 RCEE12:1; // 12 Receive Channel enable bit + Uint16 RCEE13:1; // 13 Receive Channel enable bit + Uint16 RCEE14:1; // 14 Receive Channel enable bit + Uint16 RCEE15:1; // 15 Receive Channel enable bit +}; + +union RCERE_REG { + Uint16 all; + struct RCERE_BITS bit; +}; + +// RCERF control register bit definitions: +struct RCERF_BITS { // bit description + Uint16 RCEF0:1; // 0 Receive Channel enable bit + Uint16 RCEF1:1; // 1 Receive Channel enable bit + Uint16 RCEF2:1; // 2 Receive Channel enable bit + Uint16 RCEF3:1; // 3 Receive Channel enable bit + Uint16 RCEF4:1; // 4 Receive Channel enable bit + Uint16 RCEF5:1; // 5 Receive Channel enable bit + Uint16 RCEF6:1; // 6 Receive Channel enable bit + Uint16 RCEF7:1; // 7 Receive Channel enable bit + Uint16 RCEF8:1; // 8 Receive Channel enable bit + Uint16 RCEF9:1; // 9 Receive Channel enable bit + Uint16 RCEF10:1; // 10 Receive Channel enable bit + Uint16 RCEF11:1; // 11 Receive Channel enable bit + Uint16 RCEF12:1; // 12 Receive Channel enable bit + Uint16 RCEF13:1; // 13 Receive Channel enable bit + Uint16 RCEF14:1; // 14 Receive Channel enable bit + Uint16 RCEF15:1; // 15 Receive Channel enable bit +}; + +union RCERF_REG { + Uint16 all; + struct RCERF_BITS bit; +}; + +// XCERE control register bit definitions: +struct XCERE_BITS { // bit description + Uint16 XCERE0:1; // 0 Receive Channel enable bit + Uint16 XCERE1:1; // 1 Receive Channel enable bit + Uint16 XCERE2:1; // 2 Receive Channel enable bit + Uint16 XCERE3:1; // 3 Receive Channel enable bit + Uint16 XCERE4:1; // 4 Receive Channel enable bit + Uint16 XCERE5:1; // 5 Receive Channel enable bit + Uint16 XCERE6:1; // 6 Receive Channel enable bit + Uint16 XCERE7:1; // 7 Receive Channel enable bit + Uint16 XCERE8:1; // 8 Receive Channel enable bit + Uint16 XCERE9:1; // 9 Receive Channel enable bit + Uint16 XCERE10:1; // 10 Receive Channel enable bit + Uint16 XCERE11:1; // 11 Receive Channel enable bit + Uint16 XCERE12:1; // 12 Receive Channel enable bit + Uint16 XCERE13:1; // 13 Receive Channel enable bit + Uint16 XCERE14:1; // 14 Receive Channel enable bit + Uint16 XCERE15:1; // 15 Receive Channel enable bit +}; + +union XCERE_REG { + Uint16 all; + struct XCERE_BITS bit; +}; + +// XCERF control register bit definitions: +struct XCERF_BITS { // bit description + Uint16 XCERF0:1; // 0 Receive Channel enable bit + Uint16 XCERF1:1; // 1 Receive Channel enable bit + Uint16 XCERF2:1; // 2 Receive Channel enable bit + Uint16 XCERF3:1; // 3 Receive Channel enable bit + Uint16 XCERF4:1; // 4 Receive Channel enable bit + Uint16 XCERF5:1; // 5 Receive Channel enable bit + Uint16 XCERF6:1; // 6 Receive Channel enable bit + Uint16 XCERF7:1; // 7 Receive Channel enable bit + Uint16 XCERF8:1; // 8 Receive Channel enable bit + Uint16 XCERF9:1; // 9 Receive Channel enable bit + Uint16 XCERF10:1; // 10 Receive Channel enable bit + Uint16 XCERF11:1; // 11 Receive Channel enable bit + Uint16 XCERF12:1; // 12 Receive Channel enable bit + Uint16 XCERF13:1; // 13 Receive Channel enable bit + Uint16 XCERF14:1; // 14 Receive Channel enable bit + Uint16 XCERF15:1; // 15 Receive Channel enable bit +}; + +union XCERF_REG { + Uint16 all; + struct XCERF_BITS bit; +}; + +// RCERG control register bit definitions: +struct RCERG_BITS { // bit description + Uint16 RCEG0:1; // 0 Receive Channel enable bit + Uint16 RCEG1:1; // 1 Receive Channel enable bit + Uint16 RCEG2:1; // 2 Receive Channel enable bit + Uint16 RCEG3:1; // 3 Receive Channel enable bit + Uint16 RCEG4:1; // 4 Receive Channel enable bit + Uint16 RCEG5:1; // 5 Receive Channel enable bit + Uint16 RCEG6:1; // 6 Receive Channel enable bit + Uint16 RCEG7:1; // 7 Receive Channel enable bit + Uint16 RCEG8:1; // 8 Receive Channel enable bit + Uint16 RCEG9:1; // 9 Receive Channel enable bit + Uint16 RCEG10:1; // 10 Receive Channel enable bit + Uint16 RCEG11:1; // 11 Receive Channel enable bit + Uint16 RCEG12:1; // 12 Receive Channel enable bit + Uint16 RCEG13:1; // 13 Receive Channel enable bit + Uint16 RCEG14:1; // 14 Receive Channel enable bit + Uint16 RCEG15:1; // 15 Receive Channel enable bit +}; + +union RCERG_REG { + Uint16 all; + struct RCERG_BITS bit; +}; + +// RCERH control register bit definitions: +struct RCERH_BITS { // bit description + Uint16 RCEH0:1; // 0 Receive Channel enable bit + Uint16 RCEH1:1; // 1 Receive Channel enable bit + Uint16 RCEH2:1; // 2 Receive Channel enable bit + Uint16 RCEH3:1; // 3 Receive Channel enable bit + Uint16 RCEH4:1; // 4 Receive Channel enable bit + Uint16 RCEH5:1; // 5 Receive Channel enable bit + Uint16 RCEH6:1; // 6 Receive Channel enable bit + Uint16 RCEH7:1; // 7 Receive Channel enable bit + Uint16 RCEH8:1; // 8 Receive Channel enable bit + Uint16 RCEH9:1; // 9 Receive Channel enable bit + Uint16 RCEH10:1; // 10 Receive Channel enable bit + Uint16 RCEH11:1; // 11 Receive Channel enable bit + Uint16 RCEH12:1; // 12 Receive Channel enable bit + Uint16 RCEH13:1; // 13 Receive Channel enable bit + Uint16 RCEH14:1; // 14 Receive Channel enable bit + Uint16 RCEH15:1; // 15 Receive Channel enable bit +}; + +union RCERH_REG { + Uint16 all; + struct RCERH_BITS bit; +}; + +// XCERG control register bit definitions: +struct XCERG_BITS { // bit description + Uint16 XCERG0:1; // 0 Receive Channel enable bit + Uint16 XCERG1:1; // 1 Receive Channel enable bit + Uint16 XCERG2:1; // 2 Receive Channel enable bit + Uint16 XCERG3:1; // 3 Receive Channel enable bit + Uint16 XCERG4:1; // 4 Receive Channel enable bit + Uint16 XCERG5:1; // 5 Receive Channel enable bit + Uint16 XCERG6:1; // 6 Receive Channel enable bit + Uint16 XCERG7:1; // 7 Receive Channel enable bit + Uint16 XCERG8:1; // 8 Receive Channel enable bit + Uint16 XCERG9:1; // 9 Receive Channel enable bit + Uint16 XCERG10:1; // 10 Receive Channel enable bit + Uint16 XCERG11:1; // 11 Receive Channel enable bit + Uint16 XCERG12:1; // 12 Receive Channel enable bit + Uint16 XCERG13:1; // 13 Receive Channel enable bit + Uint16 XCERG14:1; // 14 Receive Channel enable bit + Uint16 XCERG15:1; // 15 Receive Channel enable bit +}; + +union XCERG_REG { + Uint16 all; + struct XCERG_BITS bit; +}; + +// XCERH control register bit definitions: +struct XCERH_BITS { // bit description + Uint16 XCEH0:1; // 0 Receive Channel enable bit + Uint16 XCEH1:1; // 1 Receive Channel enable bit + Uint16 XCEH2:1; // 2 Receive Channel enable bit + Uint16 XCEH3:1; // 3 Receive Channel enable bit + Uint16 XCEH4:1; // 4 Receive Channel enable bit + Uint16 XCEH5:1; // 5 Receive Channel enable bit + Uint16 XCEH6:1; // 6 Receive Channel enable bit + Uint16 XCEH7:1; // 7 Receive Channel enable bit + Uint16 XCEH8:1; // 8 Receive Channel enable bit + Uint16 XCEH9:1; // 9 Receive Channel enable bit + Uint16 XCEH10:1; // 10 Receive Channel enable bit + Uint16 XCEH11:1; // 11 Receive Channel enable bit + Uint16 XCEH12:1; // 12 Receive Channel enable bit + Uint16 XCEH13:1; // 13 Receive Channel enable bit + Uint16 XCEH14:1; // 14 Receive Channel enable bit + Uint16 XCEH15:1; // 15 Receive Channel enable bit +}; + +union XCERH_REG { + Uint16 all; + struct XCERH_BITS bit; +}; + +// McBSP FIFO Transmit register bit definitions: +struct MFFTX_BITS { // bit description + Uint16 TXFFIL:5; // 4:0 Interrupt level + Uint16 TXFFIENA:1; // 5 Interrupt enable + Uint16 TXFFINT_CLEAR:1; // 6 Clear INT flag + Uint16 TXFFINT_FLAG:1; // 7 INT flag + Uint16 TXFFST:5; // 12:8 FIFO status + Uint16 TXFIFO_RESET:1; // 13 FIFO reset + Uint16 MFFENA:1; // 14 Enhancement enable + Uint16 rsvd:1; // 15 reserved +}; + +union MFFTX_REG { + Uint16 all; + struct MFFTX_BITS bit; +}; + +// McBSP FIFO recieve register bit definitions: +struct MFFRX_BITS { // bits description + Uint16 RXFFIL:5; // 4:0 Interrupt level + Uint16 RXFFIENA:1; // 5 Interrupt enable + Uint16 RXFFINT_CLEAR:1; // 6 Clear INT flag + Uint16 RXFFINT_FLAG:1; // 7 INT flag + Uint16 RXFFST:5; // 12:8 FIFO status + Uint16 RXFIFO_RESET:1; // 13 FIFO reset + Uint16 RXFFOVF_CLEAR:1; // 14 Clear overflow + Uint16 RXFFOVF_FLAG:1; // 15 FIFO overflow +}; + +union MFFRX_REG { + Uint16 all; + struct MFFRX_BITS bit; +}; + +// McBSP FIFO control register bit definitions: +struct MFFCT_BITS { // bits description + Uint16 FFTXTXDLY:8; // 7:0 FIFO transmit delay + Uint16 rsvd:7; // 15:7 reserved + Uint16 IACKM:1; // 15 is IACK mode enable bit +}; + +union MFFCT_REG { + Uint16 all; + struct MFFCT_BITS bit; +}; + +// McBSP FIFO INTERRUPT control register bit definitions: +struct MFFINT_BITS { // bits description + Uint16 XINT:1; // 0 XINT interrupt enable + Uint16 XEVTA:1; // 1 XEVTA interrupt enable + Uint16 RINT:1; // 2 RINT interrupt enable + Uint16 REVTA:1; // 3 REVTA interrupt enable + Uint16 rsvd:12; // 15:4 reserved +}; + +union MFFINT_REG { + Uint16 all; + struct MFFINT_BITS bit; +}; + +// McBSP FIFO INTERRUPT status register bit definitions: +struct MFFST_BITS { // bits description + Uint16 EOBX:1; // 0 EOBX flag + Uint16 FSX:1; // 1 FSX flag + Uint16 EOBR:1; // 2 EOBR flag + Uint16 FSR:1; // 3 FSR flag + Uint16 rsvd:12; // 15:4 reserved +}; + +union MFFST_REG { + Uint16 all; + struct MFFST_BITS bit; +}; + + +//--------------------------------------------------------------------------- +// McBSP Register File: +// +struct MCBSP_REGS { + union DRR2_REG DRR2; // 0x7800, MCBSP Data receive register bits 31-16 + union DRR1_REG DRR1; // 0x7801, MCBSP Data receive register bits 15-0 + union DXR2_REG DXR2; // 0x7802, MCBSP Data transmit register bits 31-16 + union DXR1_REG DXR1; // 0x7803, MCBSP Data transmit register bits 15-0 + union SPCR2_REG SPCR2; // 0x7804, MCBSP control register bits 31-16 + union SPCR1_REG SPCR1; // 0x7805, MCBSP control register bits 15-0 + union RCR2_REG RCR2; // 0x7806, MCBSP receive control register bits 31-16 + union RCR1_REG RCR1; // 0x7807, MCBSP receive control register bits 15-0 + union XCR2_REG XCR2; // 0x7808, MCBSP transmit control register bits 31-16 + union XCR1_REG XCR1; // 0x7809, MCBSP transmit control register bits 15-0 + union SRGR2_REG SRGR2; // 0x7810, MCBSP sample rate gen register bits 31-16 + union SRGR1_REG SRGR1; // 0x7811, MCBSP sample rate gen register bits 15-0 + union MCR2_REG MCR2; // 0x7812, MCBSP multichannel register bits 31-16 + union MCR1_REG MCR1; // 0x7813, MCBSP multichannel register bits 15-0 + union RCERA_REG RCERA; // 0x7814, MCBSP Receive channel enable partition A + union RCERB_REG RCERB; // 0x7815, MCBSP Receive channel enable partition B + union XCERA_REG XCERA; // 0x7816, MCBSP Transmit channel enable partition A + union XCERB_REG XCERB; // 0x7817, MCBSP Transmit channel enable partition B + union PCR_REG PCR; // 0x7818, MCBSP Pin control register bits 15-0 + union RCERC_REG RCERC; // 0x7819, MCBSP Receive channel enable partition C + union RCERD_REG RCERD; // 0x7820, MCBSP Receive channel enable partition D + union XCERC_REG XCERC; // 0x7821, MCBSP Transmit channel enable partition C + union XCERD_REG XCERD; // 0x7823, MCBSP Transmit channel enable partition D + union RCERE_REG RCERE; // 0x7824, MCBSP Receive channel enable partition E + union RCERF_REG RCERF; // 0x7825, MCBSP Receive channel enable partition F + union XCERE_REG XCERE; // 0x7826, MCBSP Transmit channel enable partition E + union XCERF_REG XCERF; // 0x7827, MCBSP Transmit channel enable partition F + union RCERG_REG RCERG; // 0x7828, MCBSP Receive channel enable partition G + union RCERH_REG RCERH; // 0x7829, MCBSP Receive channel enable partition H + union XCERG_REG XCERG; // 0x7830, MCBSP Transmit channel enable partition G + union XCERH_REG XCERH; // 0x7831, MCBSP Transmit channel enable partition H + Uint16 rsvd1; // 0x7832, reserved + union MFFTX_REG MFFTX; // 0x7833, MCBSP Transmit FIFO register bits + union MFFRX_REG MFFRX; // 0x7834, MCBSP Receive FIFO register bits + union MFFCT_REG MFFCT; // 0x7835, MCBSP FIFO control register bits + union MFFINT_REG MFFINT; // 0x7836, MCBSP Interrupt register bits + union MFFST_REG MFFST; // 0x7837, MCBSP Status register bits +}; + +//--------------------------------------------------------------------------- +// McBSP External References & Function Declarations: +// +extern volatile struct MCBSP_REGS McbspaRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_MCBSP_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h new file mode 100644 index 0000000..512b29a --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h @@ -0,0 +1,153 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:22 $ +//########################################################################### +// +// FILE: DSP281x_PieCtrl.h +// +// TITLE: DSP281x Device PIE Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + + +#ifndef DSP281x_PIE_CTRL_H +#define DSP281x_PIE_CTRL_H + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// PIE Control Register Bit Definitions: +// +// PIECTRL: Register bit definitions: +struct PIECTRL_BITS { // bits description + Uint16 ENPIE:1; // 0 Enable PIE block + Uint16 PIEVECT:15; // 15:1 Fetched vector address +}; + +union PIECTRL_REG { + Uint16 all; + struct PIECTRL_BITS bit; +}; + +// PIEIER: Register bit definitions: +struct PIEIER_BITS { // bits description + Uint16 INTx1:1; // 0 INTx.1 + Uint16 INTx2:1; // 1 INTx.2 + Uint16 INTx3:1; // 2 INTx.3 + Uint16 INTx4:1; // 3 INTx.4 + Uint16 INTx5:1; // 4 INTx.5 + Uint16 INTx6:1; // 5 INTx.6 + Uint16 INTx7:1; // 6 INTx.7 + Uint16 INTx8:1; // 7 INTx.8 + Uint16 rsvd:8; // 15:8 reserved +}; + +union PIEIER_REG { + Uint16 all; + struct PIEIER_BITS bit; +}; + +// PIEIFR: Register bit definitions: +struct PIEIFR_BITS { // bits description + Uint16 INTx1:1; // 0 INTx.1 + Uint16 INTx2:1; // 1 INTx.2 + Uint16 INTx3:1; // 2 INTx.3 + Uint16 INTx4:1; // 3 INTx.4 + Uint16 INTx5:1; // 4 INTx.5 + Uint16 INTx6:1; // 5 INTx.6 + Uint16 INTx7:1; // 6 INTx.7 + Uint16 INTx8:1; // 7 INTx.8 + Uint16 rsvd:8; // 15:8 reserved +}; + +union PIEIFR_REG { + Uint16 all; + struct PIEIFR_BITS bit; +}; + +// PIEACK: Register bit definitions: +struct PIEACK_BITS { // bits description + Uint16 ACK1:1; // 0 Acknowledge PIE interrupt group 1 + Uint16 ACK2:1; // 1 Acknowledge PIE interrupt group 2 + Uint16 ACK3:1; // 2 Acknowledge PIE interrupt group 3 + Uint16 ACK4:1; // 3 Acknowledge PIE interrupt group 4 + Uint16 ACK5:1; // 4 Acknowledge PIE interrupt group 5 + Uint16 ACK6:1; // 5 Acknowledge PIE interrupt group 6 + Uint16 ACK7:1; // 6 Acknowledge PIE interrupt group 7 + Uint16 ACK8:1; // 7 Acknowledge PIE interrupt group 8 + Uint16 ACK9:1; // 8 Acknowledge PIE interrupt group 9 + Uint16 ACK10:1; // 9 Acknowledge PIE interrupt group 10 + Uint16 ACK11:1; // 10 Acknowledge PIE interrupt group 11 + Uint16 ACK12:1; // 11 Acknowledge PIE interrupt group 12 + Uint16 rsvd:4; // 15:12 reserved +}; + +union PIEACK_REG { + Uint16 all; + struct PIEACK_BITS bit; +}; + +//--------------------------------------------------------------------------- +// PIE Control Register File: +// +struct PIE_CTRL_REGS { + union PIECTRL_REG PIECRTL; // PIE control register + union PIEACK_REG PIEACK; // PIE acknowledge + union PIEIER_REG PIEIER1; // PIE INT1 IER register + union PIEIFR_REG PIEIFR1; // PIE INT1 IFR register + union PIEIER_REG PIEIER2; // PIE INT2 IER register + union PIEIFR_REG PIEIFR2; // PIE INT2 IFR register + union PIEIER_REG PIEIER3; // PIE INT3 IER register + union PIEIFR_REG PIEIFR3; // PIE INT3 IFR register + union PIEIER_REG PIEIER4; // PIE INT4 IER register + union PIEIFR_REG PIEIFR4; // PIE INT4 IFR register + union PIEIER_REG PIEIER5; // PIE INT5 IER register + union PIEIFR_REG PIEIFR5; // PIE INT5 IFR register + union PIEIER_REG PIEIER6; // PIE INT6 IER register + union PIEIFR_REG PIEIFR6; // PIE INT6 IFR register + union PIEIER_REG PIEIER7; // PIE INT7 IER register + union PIEIFR_REG PIEIFR7; // PIE INT7 IFR register + union PIEIER_REG PIEIER8; // PIE INT8 IER register + union PIEIFR_REG PIEIFR8; // PIE INT8 IFR register + union PIEIER_REG PIEIER9; // PIE INT9 IER register + union PIEIFR_REG PIEIFR9; // PIE INT9 IFR register + union PIEIER_REG PIEIER10; // PIE INT10 IER register + union PIEIFR_REG PIEIFR10; // PIE INT10 IFR register + union PIEIER_REG PIEIER11; // PIE INT11 IER register + union PIEIFR_REG PIEIFR11; // PIE INT11 IFR register + union PIEIER_REG PIEIER12; // PIE INT12 IER register + union PIEIFR_REG PIEIFR12; // PIE INT12 IFR register +}; + +#define PIEACK_GROUP1 0x0001; +#define PIEACK_GROUP2 0x0002; +#define PIEACK_GROUP3 0x0004; +#define PIEACK_GROUP4 0x0008; +#define PIEACK_GROUP5 0x0010; +#define PIEACK_GROUP6 0x0020; +#define PIEACK_GROUP7 0x0040; +#define PIEACK_GROUP8 0x0080; +#define PIEACK_GROUP9 0x0100; +#define PIEACK_GROUP10 0x0200; +#define PIEACK_GROUP11 0x0400; +#define PIEACK_GROUP12 0x0800; + +//--------------------------------------------------------------------------- +// PIE Control Registers External References & Function Declarations: +// +extern volatile struct PIE_CTRL_REGS PieCtrlRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_PIE_CTRL_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h new file mode 100644 index 0000000..ec34743 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h @@ -0,0 +1,210 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:21 $ +//########################################################################### +// +// FILE: DSP281x_PieVect.h +// +// TITLE: DSP281x Devices PIE Vector Table Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_PIE_VECT_H +#define DSP281x_PIE_VECT_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table Definition: +// +// Create a user type called PINT (pointer to interrupt): + +typedef interrupt void(*PINT)(void); + +// Define Vector Table: +struct PIE_VECT_TABLE { + +// Reset is never fetched from this table. +// It will always be fetched from 0x3FFFC0 in either +// boot ROM or XINTF Zone 7 depending on the state of +// the XMP/MC input signal. On the F2810 it is always +// fetched from boot ROM. + + PINT PIE1_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE2_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE3_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE4_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE5_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE6_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE7_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE8_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE9_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE10_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE11_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE12_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE13_RESERVED; // @suppress("Type cannot be resolved") + +// Non-Peripheral Interrupts: + PINT XINT13; // XINT13 // @suppress("Type cannot be resolved") + PINT TINT2; // CPU-Timer2 // @suppress("Type cannot be resolved") + PINT DATALOG; // Datalogging interrupt // @suppress("Type cannot be resolved") + PINT RTOSINT; // RTOS interrupt // @suppress("Type cannot be resolved") + PINT EMUINT; // Emulation interrupt // @suppress("Type cannot be resolved") + PINT XNMI; // Non-maskable interrupt // @suppress("Type cannot be resolved") + PINT ILLEGAL; // Illegal operation TRAP // @suppress("Type cannot be resolved") + PINT USER1; // User Defined trap 1 // @suppress("Type cannot be resolved") + PINT USER2; // User Defined trap 2 // @suppress("Type cannot be resolved") + PINT USER3; // User Defined trap 3 // @suppress("Type cannot be resolved") + PINT USER4; // User Defined trap 4 // @suppress("Type cannot be resolved") + PINT USER5; // User Defined trap 5 // @suppress("Type cannot be resolved") + PINT USER6; // User Defined trap 6 // @suppress("Type cannot be resolved") + PINT USER7; // User Defined trap 7 // @suppress("Type cannot be resolved") + PINT USER8; // User Defined trap 8 // @suppress("Type cannot be resolved") + PINT USER9; // User Defined trap 9 // @suppress("Type cannot be resolved") + PINT USER10; // User Defined trap 10 // @suppress("Type cannot be resolved") + PINT USER11; // User Defined trap 11 // @suppress("Type cannot be resolved") + PINT USER12; // User Defined trap 12 // @suppress("Type cannot be resolved") + +// Group 1 PIE Peripheral Vectors: + PINT PDPINTA; // EV-A // @suppress("Type cannot be resolved") + PINT PDPINTB; // EV-B // @suppress("Type cannot be resolved") + PINT rsvd1_3; // @suppress("Type cannot be resolved") + PINT XINT1; // @suppress("Type cannot be resolved") + PINT XINT2; // @suppress("Type cannot be resolved") + PINT ADCINT; // ADC // @suppress("Type cannot be resolved") + PINT TINT0; // Timer 0 // @suppress("Type cannot be resolved") + PINT WAKEINT; // WD // @suppress("Type cannot be resolved") + +// Group 2 PIE Peripheral Vectors: + PINT CMP1INT; // EV-A // @suppress("Type cannot be resolved") + PINT CMP2INT; // EV-A // @suppress("Type cannot be resolved") + PINT CMP3INT; // EV-A // @suppress("Type cannot be resolved") + PINT T1PINT; // EV-A // @suppress("Type cannot be resolved") + PINT T1CINT; // EV-A // @suppress("Type cannot be resolved") + PINT T1UFINT; // EV-A // @suppress("Type cannot be resolved") + PINT T1OFINT; // EV-A // @suppress("Type cannot be resolved") + PINT rsvd2_8; // @suppress("Type cannot be resolved") + +// Group 3 PIE Peripheral Vectors: + PINT T2PINT; // EV-A // @suppress("Type cannot be resolved") + PINT T2CINT; // EV-A // @suppress("Type cannot be resolved") + PINT T2UFINT; // EV-A // @suppress("Type cannot be resolved") + PINT T2OFINT; // EV-A // @suppress("Type cannot be resolved") + PINT CAPINT1; // EV-A // @suppress("Type cannot be resolved") + PINT CAPINT2; // EV-A // @suppress("Type cannot be resolved") + PINT CAPINT3; // EV-A // @suppress("Type cannot be resolved") + PINT rsvd3_8; // @suppress("Type cannot be resolved") + +// Group 4 PIE Peripheral Vectors: + PINT CMP4INT; // EV-B // @suppress("Type cannot be resolved") + PINT CMP5INT; // EV-B // @suppress("Type cannot be resolved") + PINT CMP6INT; // EV-B // @suppress("Type cannot be resolved") + PINT T3PINT; // EV-B // @suppress("Type cannot be resolved") + PINT T3CINT; // EV-B // @suppress("Type cannot be resolved") + PINT T3UFINT; // EV-B // @suppress("Type cannot be resolved") + PINT T3OFINT; // EV-B // @suppress("Type cannot be resolved") + PINT rsvd4_8; // @suppress("Type cannot be resolved") + +// Group 5 PIE Peripheral Vectors: + PINT T4PINT; // EV-B // @suppress("Type cannot be resolved") + PINT T4CINT; // EV-B // @suppress("Type cannot be resolved") + PINT T4UFINT; // EV-B // @suppress("Type cannot be resolved") + PINT T4OFINT; // EV-B // @suppress("Type cannot be resolved") + PINT CAPINT4; // EV-B // @suppress("Type cannot be resolved") + PINT CAPINT5; // EV-B // @suppress("Type cannot be resolved") + PINT CAPINT6; // EV-B // @suppress("Type cannot be resolved") + PINT rsvd5_8; // @suppress("Type cannot be resolved") + +// Group 6 PIE Peripheral Vectors: + PINT SPIRXINTA; // SPI-A // @suppress("Type cannot be resolved") + PINT SPITXINTA; // SPI-A // @suppress("Type cannot be resolved") + PINT rsvd6_3; // @suppress("Type cannot be resolved") + PINT rsvd6_4; // @suppress("Type cannot be resolved") + PINT MRINTA; // McBSP-A // @suppress("Type cannot be resolved") + PINT MXINTA; // McBSP-A // @suppress("Type cannot be resolved") + PINT rsvd6_7; // @suppress("Type cannot be resolved") + PINT rsvd6_8; // @suppress("Type cannot be resolved") + +// Group 7 PIE Peripheral Vectors: + PINT rsvd7_1; // @suppress("Type cannot be resolved") + PINT rsvd7_2; // @suppress("Type cannot be resolved") + PINT rsvd7_3; // @suppress("Type cannot be resolved") + PINT rsvd7_4; // @suppress("Type cannot be resolved") + PINT rsvd7_5; // @suppress("Type cannot be resolved") + PINT rsvd7_6; // @suppress("Type cannot be resolved") + PINT rsvd7_7; // @suppress("Type cannot be resolved") + PINT rsvd7_8; // @suppress("Type cannot be resolved") + +// Group 8 PIE Peripheral Vectors: + PINT rsvd8_1; // @suppress("Type cannot be resolved") + PINT rsvd8_2; // @suppress("Type cannot be resolved") + PINT rsvd8_3; // @suppress("Type cannot be resolved") + PINT rsvd8_4; // @suppress("Type cannot be resolved") + PINT rsvd8_5; // @suppress("Type cannot be resolved") + PINT rsvd8_6; // @suppress("Type cannot be resolved") + PINT rsvd8_7; // @suppress("Type cannot be resolved") + PINT rsvd8_8; // @suppress("Type cannot be resolved") + +// Group 9 PIE Peripheral Vectors: + PINT RXAINT; // SCI-A // @suppress("Type cannot be resolved") + PINT TXAINT; // SCI-A // @suppress("Type cannot be resolved") + PINT RXBINT; // SCI-B // @suppress("Type cannot be resolved") + PINT TXBINT; // SCI-B // @suppress("Type cannot be resolved") + PINT ECAN0INTA; // eCAN // @suppress("Type cannot be resolved") + PINT ECAN1INTA; // eCAN // @suppress("Type cannot be resolved") + PINT rsvd9_7; // @suppress("Type cannot be resolved") + PINT rsvd9_8; // @suppress("Type cannot be resolved") + +// Group 10 PIE Peripheral Vectors: + PINT rsvd10_1; // @suppress("Type cannot be resolved") + PINT rsvd10_2; // @suppress("Type cannot be resolved") + PINT rsvd10_3; // @suppress("Type cannot be resolved") + PINT rsvd10_4; // @suppress("Type cannot be resolved") + PINT rsvd10_5; // @suppress("Type cannot be resolved") + PINT rsvd10_6; // @suppress("Type cannot be resolved") + PINT rsvd10_7; // @suppress("Type cannot be resolved") + PINT rsvd10_8; // @suppress("Type cannot be resolved") + +// Group 11 PIE Peripheral Vectors: + PINT rsvd11_1; // @suppress("Type cannot be resolved") + PINT rsvd11_2; // @suppress("Type cannot be resolved") + PINT rsvd11_3; // @suppress("Type cannot be resolved") + PINT rsvd11_4; // @suppress("Type cannot be resolved") + PINT rsvd11_5; // @suppress("Type cannot be resolved") + PINT rsvd11_6; // @suppress("Type cannot be resolved") + PINT rsvd11_7; // @suppress("Type cannot be resolved") + PINT rsvd11_8; // @suppress("Type cannot be resolved") + +// Group 12 PIE Peripheral Vectors: + PINT rsvd12_1; // @suppress("Type cannot be resolved") + PINT rsvd12_2; // @suppress("Type cannot be resolved") + PINT rsvd12_3; // @suppress("Type cannot be resolved") + PINT rsvd12_4; // @suppress("Type cannot be resolved") + PINT rsvd12_5; // @suppress("Type cannot be resolved") + PINT rsvd12_6; // @suppress("Type cannot be resolved") + PINT rsvd12_7; // @suppress("Type cannot be resolved") + PINT rsvd12_8; // @suppress("Type cannot be resolved") +}; + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table External References & Function Declarations: +// +extern struct PIE_VECT_TABLE PieVectTable; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_PIE_VECT_H definition + +//=========================================================================== +// No more. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h new file mode 100644 index 0000000..2a86da0 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h @@ -0,0 +1,233 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:19 $ +//########################################################################### +// +// FILE: DSP281x_Sci.h +// +// TITLE: DSP281x Device SCI Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SCI_H +#define DSP281x_SCI_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// SCI Individual Register Bit Definitions + +//---------------------------------------------------------- +// SCICCR communication control register bit definitions: +// + +struct SCICCR_BITS { // bit description + Uint16 SCICHAR:3; // 2:0 Character length control + Uint16 ADDRIDLE_MODE:1; // 3 ADDR/IDLE Mode control + Uint16 LOOPBKENA:1; // 4 Loop Back enable + Uint16 PARITYENA:1; // 5 Parity enable + Uint16 PARITY:1; // 6 Even or Odd Parity + Uint16 STOPBITS:1; // 7 Number of Stop Bits + Uint16 rsvd1:8; // 15:8 reserved +}; + + +union SCICCR_REG { + Uint16 all; + struct SCICCR_BITS bit; +}; + +//------------------------------------------- +// SCICTL1 control register 1 bit definitions: +// + +struct SCICTL1_BITS { // bit description + Uint16 RXENA:1; // 0 SCI receiver enable + Uint16 TXENA:1; // 1 SCI transmitter enable + Uint16 SLEEP:1; // 2 SCI sleep + Uint16 TXWAKE:1; // 3 Transmitter wakeup method + Uint16 rsvd:1; // 4 reserved + Uint16 SWRESET:1; // 5 Software reset + Uint16 RXERRINTENA:1; // 6 Recieve interrupt enable + Uint16 rsvd1:9; // 15:7 reserved + +}; + +union SCICTL1_REG { + Uint16 all; + struct SCICTL1_BITS bit; +}; + +//--------------------------------------------- +// SCICTL2 control register 2 bit definitions: +// + +struct SCICTL2_BITS { // bit description + Uint16 TXINTENA:1; // 0 Transmit interrupt enable + Uint16 RXBKINTENA:1; // 1 Receiver-buffer break enable + Uint16 rsvd:4; // 5:2 reserved + Uint16 TXEMPTY:1; // 6 Transmitter empty flag + Uint16 TXRDY:1; // 7 Transmitter ready flag + Uint16 rsvd1:8; // 15:8 reserved + +}; + +union SCICTL2_REG { + Uint16 all; + struct SCICTL2_BITS bit; +}; + +//--------------------------------------------------- +// SCIRXST Receiver status register bit definitions: +// + +struct SCIRXST_BITS { // bit description + Uint16 rsvd:1; // 0 reserved + Uint16 RXWAKE:1; // 1 Receiver wakeup detect flag + Uint16 PE:1; // 2 Parity error flag + Uint16 OE:1; // 3 Overrun error flag + Uint16 FE:1; // 4 Framing error flag + Uint16 BRKDT:1; // 5 Break-detect flag + Uint16 RXRDY:1; // 6 Receiver ready flag + Uint16 RXERROR:1; // 7 Receiver error flag + +}; + +union SCIRXST_REG { + Uint16 all; + struct SCIRXST_BITS bit; +}; + +//---------------------------------------------------- +// SCIRXBUF Receiver Data Buffer with FIFO bit definitions: +// + +struct SCIRXBUF_BITS { // bits description + Uint16 RXDT:8; // 7:0 Receive word + Uint16 rsvd:6; // 13:8 reserved + Uint16 SCIFFPE:1; // 14 SCI PE error in FIFO mode + Uint16 SCIFFFE:1; // 15 SCI FE error in FIFO mode +}; + +union SCIRXBUF_REG { + Uint16 all; + struct SCIRXBUF_BITS bit; +}; + +//-------------------------------------------------- +// SCIPRI Priority control register bit definitions: +// +// + +struct SCIPRI_BITS { // bit description + Uint16 rsvd:3; // 2:0 reserved + Uint16 FREE:1; // 3 Free emulation suspend mode + Uint16 SOFT:1; // 4 Soft emulation suspend mode + Uint16 rsvd1:3; // 7:5 reserved +}; + +union SCIPRI_REG { + Uint16 all; + struct SCIPRI_BITS bit; +}; + +//------------------------------------------------- +// SCI FIFO Transmit register bit definitions: +// +// + +struct SCIFFTX_BITS { // bit description + Uint16 TXFFILIL:5; // 4:0 Interrupt level + Uint16 TXFFIENA:1; // 5 Interrupt enable + Uint16 TXINTCLR:1; // 6 Clear INT flag + Uint16 TXFFINT:1; // 7 INT flag + Uint16 TXFFST:5; // 12:8 FIFO status + Uint16 TXFIFOXRESET:1; // 13 FIFO reset + Uint16 SCIFFENA:1; // 14 Enhancement enable + Uint16 SCIRST:1; // 15 SCI reset rx/tx channels + +}; + +union SCIFFTX_REG { + Uint16 all; + struct SCIFFTX_BITS bit; +}; + +//------------------------------------------------ +// SCI FIFO recieve register bit definitions: +// +// + +struct SCIFFRX_BITS { // bits description + Uint16 RXFFIL:5; // 4:0 Interrupt level + Uint16 RXFFIENA:1; // 5 Interrupt enable + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + Uint16 RXFFINT:1; // 7 INT flag + Uint16 RXFIFST:5; // 12:8 FIFO status + Uint16 RXFIFORESET:1; // 13 FIFO reset + Uint16 RXFFOVRCLR:1; // 14 Clear overflow + Uint16 RXFFOVF:1; // 15 FIFO overflow + +}; + +union SCIFFRX_REG { + Uint16 all; + struct SCIFFRX_BITS bit; +}; + +// SCI FIFO control register bit definitions: +struct SCIFFCT_BITS { // bits description + Uint16 FFTXDLY:8; // 7:0 FIFO transmit delay + Uint16 rsvd:5; // 12:8 reserved + Uint16 CDC:1; // 13 Auto baud mode enable + Uint16 ABDCLR:1; // 14 Auto baud clear + Uint16 ABD:1; // 15 Auto baud detect +}; + +union SCIFFCT_REG { + Uint16 all; + struct SCIFFCT_BITS bit; +}; + +//--------------------------------------------------------------------------- +// SCI Register File: +// +struct SCI_REGS { + union SCICCR_REG SCICCR; // Communications control register + union SCICTL1_REG SCICTL1; // Control register 1 + Uint16 SCIHBAUD; // Baud rate (high) register + Uint16 SCILBAUD; // Baud rate (low) register + union SCICTL2_REG SCICTL2; // Control register 2 + union SCIRXST_REG SCIRXST; // Recieve status register + Uint16 SCIRXEMU; // Recieve emulation buffer register + union SCIRXBUF_REG SCIRXBUF; // Recieve data buffer + Uint16 rsvd1; // reserved + Uint16 SCITXBUF; // Transmit data buffer + union SCIFFTX_REG SCIFFTX; // FIFO transmit register + union SCIFFRX_REG SCIFFRX; // FIFO recieve register + union SCIFFCT_REG SCIFFCT; // FIFO control register + Uint16 rsvd2; // reserved + Uint16 rsvd3; // reserved + union SCIPRI_REG SCIPRI; // FIFO Priority control +}; + +//--------------------------------------------------------------------------- +// SCI External References & Function Declarations: +// +extern volatile struct SCI_REGS SciaRegs; +extern volatile struct SCI_REGS ScibRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_SCI_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h new file mode 100644 index 0000000..a5c29ab --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h @@ -0,0 +1,183 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:16 $ +//########################################################################### +// +// FILE: DSP281x_Spi.h +// +// TITLE: DSP281x Device SPI Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SPI_H +#define DSP281x_SPI_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// SPI Individual Register Bit Definitions: +// +// SPI FIFO Transmit register bit definitions: +struct SPIFFTX_BITS { // bit description + Uint16 TXFFIL:5; // 4:0 Interrupt level + Uint16 TXFFIENA:1; // 5 Interrupt enable + Uint16 TXFFINTCLR:1; // 6 Clear INT flag + Uint16 TXFFINT:1; // 7 INT flag + Uint16 TXFFST:5; // 12:8 FIFO status + Uint16 TXFIFO:1; // 13 FIFO reset + Uint16 SPIFFENA:1; // 14 Enhancement enable + Uint16 SPIRST:1; // 15 Reset SPI +}; + +union SPIFFTX_REG { + Uint16 all; + struct SPIFFTX_BITS bit; +}; + +//-------------------------------------------- +// SPI FIFO recieve register bit definitions: +// +// +struct SPIFFRX_BITS { // bits description + Uint16 RXFFIL:5; // 4:0 Interrupt level + Uint16 RXFFIENA:1; // 5 Interrupt enable + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + Uint16 RXFFINT:1; // 7 INT flag + Uint16 RXFFST:5; // 12:8 FIFO status + Uint16 RXFIFORESET:1; // 13 FIFO reset + Uint16 RXFFOVFCLR:1; // 14 Clear overflow + Uint16 RXFFOVF:1; // 15 FIFO overflow + +}; + +union SPIFFRX_REG { + Uint16 all; + struct SPIFFRX_BITS bit; +}; + +//-------------------------------------------- +// SPI FIFO control register bit definitions: +// +// +struct SPIFFCT_BITS { // bits description + Uint16 TXDLY:8; // 7:0 FIFO transmit delay + Uint16 rsvd:8; // 15:8 reserved +}; + +union SPIFFCT_REG { + Uint16 all; + struct SPIFFCT_BITS bit; +}; + +//--------------------------------------------- +// SPI configuration register bit definitions: +// +// +struct SPICCR_BITS { // bits description + Uint16 SPICHAR:4; // 3:0 Character length control + Uint16 SPILBK:1; // 4 Loop-back enable/disable + Uint16 rsvd1:1; // 5 reserved + Uint16 CLKPOLARITY:1; // 6 Clock polarity + Uint16 SPISWRESET:1; // 7 SPI SW Reset + Uint16 rsvd2:8; // 15:8 reserved +}; + +union SPICCR_REG { + Uint16 all; + struct SPICCR_BITS bit; +}; + +//------------------------------------------------- +// SPI operation control register bit definitions: +// +// +struct SPICTL_BITS { // bits description + Uint16 SPIINTENA:1; // 0 Interrupt enable + Uint16 TALK:1; // 1 Master/Slave transmit enable + Uint16 MASTER_SLAVE:1; // 2 Network control mode + Uint16 CLK_PHASE:1; // 3 Clock phase select + Uint16 OVERRUNINTENA:1; // 4 Overrun interrupt enable + Uint16 rsvd:11; // 15:5 reserved +}; + +union SPICTL_REG { + Uint16 all; + struct SPICTL_BITS bit; +}; + +//-------------------------------------- +// SPI status register bit definitions: +// +// +struct SPISTS_BITS { // bits description + Uint16 rsvd1:5; // 4:0 reserved + Uint16 BUFFULL_FLAG:1; // 5 SPI transmit buffer full flag + Uint16 INT_FLAG:1; // 6 SPI interrupt flag + Uint16 OVERRUN_FLAG:1; // 7 SPI reciever overrun flag + Uint16 rsvd2:8; // 15:8 reserved +}; + +union SPISTS_REG { + Uint16 all; + struct SPISTS_BITS bit; +}; + +//------------------------------------------------ +// SPI priority control register bit definitions: +// +// +struct SPIPRI_BITS { // bits description + Uint16 rsvd1:4; // 3:0 reserved + Uint16 FREE:1; // 4 Free emulation mode control + Uint16 SOFT:1; // 5 Soft emulation mode control + Uint16 PRIORITY:1; // 6 Interrupt priority select + Uint16 rsvd2:9; // 15:7 reserved +}; + +union SPIPRI_REG { + Uint16 all; + struct SPIPRI_BITS bit; +}; + +//--------------------------------------------------------------------------- +// SPI Register File: +// +struct SPI_REGS { + union SPICCR_REG SPICCR; // Configuration register + union SPICTL_REG SPICTL; // Operation control register + union SPISTS_REG SPISTS; // Status register + Uint16 rsvd1; // reserved + Uint16 SPIBRR; // Baud Rate + Uint16 rsvd2; // reserved + Uint16 SPIRXEMU; // Emulation buffer + Uint16 SPIRXBUF; // Serial input buffer + Uint16 SPITXBUF; // Serial output buffer + Uint16 SPIDAT; // Serial data + union SPIFFTX_REG SPIFFTX; // FIFO transmit register + union SPIFFRX_REG SPIFFRX; // FIFO recieve register + union SPIFFCT_REG SPIFFCT; // FIFO control register + Uint16 rsvd3[2]; // reserved + union SPIPRI_REG SPIPRI; // FIFO Priority control +}; + +//--------------------------------------------------------------------------- +// SPI External References & Function Declarations: +// +extern volatile struct SPI_REGS SpiaRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_SPI_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h new file mode 100644 index 0000000..6700f62 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h @@ -0,0 +1,325 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 16, 2007 13:58:47 $ +//########################################################################### +// +// FILE: DSP281x_SysCtrl.h +// +// TITLE: DSP281x Device System Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SYS_CTRL_H +#define DSP281x_SYS_CTRL_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// System Control Individual Register Bit Definitions: +// +// High speed peripheral clock register bit definitions: +struct HISPCP_BITS { // bits description + Uint16 HSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + Uint16 rsvd1:13; // 15:3 reserved +}; + +union HISPCP_REG { + Uint16 all; + struct HISPCP_BITS bit; +}; + +// Low speed peripheral clock register bit definitions: +struct LOSPCP_BITS { // bits description + Uint16 LSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + Uint16 rsvd1:13; // 15:3 reserved +}; + +union LOSPCP_REG { + Uint16 all; + struct LOSPCP_BITS bit; +}; + +// Peripheral clock control register bit definitions: +struct PCLKCR_BITS { // bits description + Uint16 EVAENCLK:1; // 0 Enable high speed clk to EV-A + Uint16 EVBENCLK:1; // 1 Enable high speed clk to EV-B + Uint16 rsvd1:1; // 2 + Uint16 ADCENCLK:1; // 3 Enable high speed clk to ADC + Uint16 rsvd2:4; // 7:4 reserved + Uint16 SPIENCLK:1; // 8 Enable low speed clk to SPI + Uint16 rsvd3:1; // 9 reserved + Uint16 SCIAENCLK:1; // 10 Enable low speed clk to SCI-A + Uint16 SCIBENCLK:1; // 11 Enable low speed clk to SCI-B + Uint16 MCBSPENCLK:1; // 12 Enable low speed clk to McBSP + Uint16 rsvd4:1; // 13 reserved + Uint16 ECANENCLK:1; // 14 Enable system clk to eCAN +}; + +union PCLKCR_REG { + Uint16 all; + struct PCLKCR_BITS bit; +}; + +// PLL control register bit definitions: +struct PLLCR_BITS { // bits description + Uint16 DIV:4; // 3:0 Set clock ratio for the PLL + Uint16 rsvd1:12; // 15:4 reserved +}; + +union PLLCR_REG { + Uint16 all; + struct PLLCR_BITS bit; +}; + +// Low Power Mode 0 control register bit definitions: +struct LPMCR0_BITS { // bits description + Uint16 LPM:2; // 1:0 Set the low power mode + Uint16 QUALSTDBY:6; // 7:2 Qualification + Uint16 rsvd1:8; // 15:8 reserved +}; + +union LPMCR0_REG { + Uint16 all; + struct LPMCR0_BITS bit; +}; + +// Low Power Mode 1 control register bit definitions: +struct LPMCR1_BITS { // bits description + Uint16 XINT1:1; // 0 Enable XINT1 to wake the device from standby + Uint16 XNMI:1; // 1 Enable XMNI to wake the device from standby + Uint16 WDINT:1; // 2 Enable watchdog interrupt to wake the device from standby + Uint16 T1CTRIP:1; // 3 Enable T1CTRIP to wake the device from standby + Uint16 T2CTRIP:1; // 4 Enable T2CTRIP to wake the device from standby + Uint16 T3CTRIP:1; // 5 Enable T3CTRIP to wake the device from standby + Uint16 T4CTRIP:1; // 6 Enable T4CTRIP to wake the device from standby + Uint16 C1TRIP:1; // 7 Enable C1TRIP to wake the device from standby + Uint16 C2TRIP:1; // 8 Enable C2TRIP to wake the device from standby + Uint16 C3TRIP:1; // 9 Enable C3TRIP to wake the device from standby + Uint16 C4TRIP:1; // 10 Enable C4TRIP to wake the device from standby + Uint16 C5TRIP:1; // 11 Enable C5TRIP to wake the device from standby + Uint16 C6TRIP:1; // 12 Enable C6TRIP to wake the device from standby + Uint16 SCIRXA:1; // 13 Enable SCIRXA to wake the device from standby + Uint16 SCIRXB:1; // 14 Enable SCIRXB to wake the device from standby + Uint16 CANRX:1; // 15 Enable CANRX to wake the device from standby +}; + +union LPMCR1_REG { + Uint16 all; + struct LPMCR1_BITS bit; +}; + +//--------------------------------------------------------------------------- +// System Control Register File: +// +struct SYS_CTRL_REGS { + Uint16 rsvd1[10]; // 0-9 + union HISPCP_REG HISPCP; // 10: High-speed peripheral clock pre-scaler + union LOSPCP_REG LOSPCP; // 11: Low-speed peripheral clock pre-scaler + union PCLKCR_REG PCLKCR; // 12: Peripheral clock control register + Uint16 rsvd2; // 13: reserved + union LPMCR0_REG LPMCR0; // 14: Low-power mode control register 0 + union LPMCR1_REG LPMCR1; // 15: Low-power mode control register 1 + Uint16 rsvd3; // 16: reserved + union PLLCR_REG PLLCR; // 17: PLL control register + // No bit definitions are defined for SCSR because + // a read-modify-write instruction can clear the WDOVERRIDE bit + Uint16 SCSR; // 18: System control and status register + Uint16 WDCNTR; // 19: WD counter register + Uint16 rsvd4; // 20 + Uint16 WDKEY; // 21: WD reset key register + Uint16 rsvd5[3]; // 22-24 + // No bit definitions are defined for WDCR because + // the proper value must be written to the WDCHK field + // whenever writing to this register. + Uint16 WDCR; // 25: WD timer control register + Uint16 rsvd6[6]; // 26-31 +}; + + +/* --------------------------------------------------- */ +/* CSM Registers */ +/* */ +/* ----------------------------------------------------*/ + +/* CSM Status & Control register bit definitions */ +struct CSMSCR_BITS { // bit description + Uint16 SECURE:1; // 0 Secure flag + Uint16 rsvd1:14; // 14-1 reserved + Uint16 FORCESEC:1; // 15 Force Secure control bit + +}; + +/* Allow access to the bit fields or entire register */ +union CSMSCR_REG { + Uint16 all; + struct CSMSCR_BITS bit; +}; + +/* CSM Register File */ +struct CSM_REGS { + Uint16 KEY0; // KEY reg bits 15-0 + Uint16 KEY1; // KEY reg bits 31-16 + Uint16 KEY2; // KEY reg bits 47-32 + Uint16 KEY3; // KEY reg bits 63-48 + Uint16 KEY4; // KEY reg bits 79-64 + Uint16 KEY5; // KEY reg bits 95-80 + Uint16 KEY6; // KEY reg bits 111-96 + Uint16 KEY7; // KEY reg bits 127-112 + Uint16 rsvd1; // reserved + Uint16 rsvd2; // reserved + Uint16 rsvd3; // reserved + Uint16 rsvd4; // reserved + Uint16 rsvd5; // reserved + Uint16 rsvd6; // reserved + Uint16 rsvd7; // reserved + union CSMSCR_REG CSMSCR; // CSM Status & Control register +}; + +/* Password locations */ +struct CSM_PWL { + Uint16 PSWD0; // PSWD bits 15-0 + Uint16 PSWD1; // PSWD bits 31-16 + Uint16 PSWD2; // PSWD bits 47-32 + Uint16 PSWD3; // PSWD bits 63-48 + Uint16 PSWD4; // PSWD bits 79-64 + Uint16 PSWD5; // PSWD bits 95-80 + Uint16 PSWD6; // PSWD bits 111-96 + Uint16 PSWD7; // PSWD bits 127-112 +}; + + + +/* Flash Registers */ + +#define FLASH_SLEEP 0x0000; +#define FLASH_STANDBY 0x0001; +#define FLASH_ACTIVE 0x0003; + + +/* Flash Option Register bit definitions */ +struct FOPT_BITS { // bit description + Uint16 ENPIPE:1; // 0 Enable Pipeline Mode + Uint16 rsvd:15; // 1-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FOPT_REG { + Uint16 all; + struct FOPT_BITS bit; +}; + +/* Flash Power Modes Register bit definitions */ +struct FPWR_BITS { // bit description + Uint16 PWR:2; // 0-1 Power Mode bits + Uint16 rsvd:14; // 2-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FPWR_REG { + Uint16 all; + struct FPWR_BITS bit; +}; + + +/* Flash Status Register bit definitions */ +struct FSTATUS_BITS { // bit description + Uint16 PWRS:2; // 0-1 Power Mode Status bits + Uint16 STDBYWAITS:1; // 2 Bank/Pump Sleep to Standby Wait Counter Status bits + Uint16 ACTIVEWAITS:1; // 3 Bank/Pump Standby to Active Wait Counter Status bits + Uint16 rsvd1:4; // 4-7 reserved + Uint16 V3STAT:1; // 8 VDD3V Status Latch bit + Uint16 rsvd2:7; // 9-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FSTATUS_REG { + Uint16 all; + struct FSTATUS_BITS bit; +}; + +/* Flash Sleep to Standby Wait Counter Register bit definitions */ +struct FSTDBYWAIT_BITS { // bit description + Uint16 STDBYWAIT:9; // 0-8 Bank/Pump Sleep to Standby Wait Count bits + Uint16 rsvd:7; // 9-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FSTDBYWAIT_REG { + Uint16 all; + struct FSTDBYWAIT_BITS bit; +}; + +/* Flash Standby to Active Wait Counter Register bit definitions */ +struct FACTIVEWAIT_BITS { // bit description + Uint16 ACTIVEWAIT:9; // 0-8 Bank/Pump Standby to Active Wait Count bits + Uint16 rsvd:7; // 9-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FACTIVEWAIT_REG { + Uint16 all; + struct FACTIVEWAIT_BITS bit; +}; + +/* Bank Read Access Wait State Register bit definitions */ +struct FBANKWAIT_BITS { // bit description + Uint16 RANDWAIT:4; // 0-3 Flash Random Read Wait State bits + Uint16 rsvd1:4; // 4-7 reserved + Uint16 PAGEWAIT:4; // 8-11 Flash Paged Read Wait State bits + Uint16 rsvd2:4; // 12-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FBANKWAIT_REG { + Uint16 all; + struct FBANKWAIT_BITS bit; +}; + +/* OTP Read Access Wait State Register bit definitions */ +struct FOTPWAIT_BITS { // bit description + Uint16 OTPWAIT:5; // 0-4 OTP Read Wait State bits + Uint16 rsvd:11; // 5-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FOTPWAIT_REG { + Uint16 all; + struct FOTPWAIT_BITS bit; +}; + + +struct FLASH_REGS { + union FOPT_REG FOPT; // Option Register + Uint16 rsvd1; // reserved + union FPWR_REG FPWR; // Power Modes Register + union FSTATUS_REG FSTATUS; // Status Register + union FSTDBYWAIT_REG FSTDBYWAIT; // Pump/Bank Sleep to Standby Wait State Register + union FACTIVEWAIT_REG FACTIVEWAIT; // Pump/Bank Standby to Active Wait State Register + union FBANKWAIT_REG FBANKWAIT; // Bank Read Access Wait State Register + union FOTPWAIT_REG FOTPWAIT; // OTP Read Access Wait State Register +}; + +//--------------------------------------------------------------------------- +// System Control External References & Function Declarations: +// +extern volatile struct SYS_CTRL_REGS SysCtrlRegs; +extern volatile struct CSM_REGS CsmRegs; +extern volatile struct CSM_PWL CsmPwl; +extern volatile struct FLASH_REGS FlashRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_SYS_CTRL_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h new file mode 100644 index 0000000..7cb66d7 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h @@ -0,0 +1,78 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:07 $ +//########################################################################### +// +// FILE: DSP281x_XIntrupt.h +// +// TITLE: DSP281x Device External Interrupt Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_XINTRUPT_H +#define DSP281x_XINTRUPT_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- + +struct XINTCR_BITS { + Uint16 ENABLE:1; // 0 enable/disable + Uint16 rsvd1:1; // 1 reserved + Uint16 POLARITY:1; // 2 pos/neg triggered + Uint16 rsvd2:12; // 15:3 reserved +}; + +union XINTCR_REG { + Uint16 all; + struct XINTCR_BITS bit; +}; + +struct XNMICR_BITS { + Uint16 ENABLE:1; // 0 enable/disable + Uint16 SELECT:1; // 1 Timer 1 or XNMI connected to INT13 + Uint16 POLARITY:1; // 2 pos/neg triggered + Uint16 rsvd2:12; // 15:3 reserved +}; + +union XNMICR_REG { + Uint16 all; + struct XNMICR_BITS bit; +}; + + + + +//--------------------------------------------------------------------------- +// External Interrupt Register File: +// +struct XINTRUPT_REGS { + union XINTCR_REG XINT1CR; + union XINTCR_REG XINT2CR; + Uint16 rsvd1[5]; + union XNMICR_REG XNMICR; + Uint16 XINT1CTR; + Uint16 XINT2CTR; + Uint16 rsvd[5]; + Uint16 XNMICTR; +}; + +//--------------------------------------------------------------------------- +// External Interrupt References & Function Declarations: +// +extern volatile struct XINTRUPT_REGS XIntruptRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_XINTF_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h new file mode 100644 index 0000000..b394f72 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h @@ -0,0 +1,111 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 20, 2007 16:30:14 $ +//########################################################################### +// +// FILE: DSP281x_Xintf.h +// +// TITLE: DSP281x Device External Interface Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_XINTF_H +#define DSP281x_XINTF_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +// XINTF timing register bit definitions: +struct XTIMING_BITS { // bits description + Uint16 XWRTRAIL:2; // 1:0 Write access trail timing + Uint16 XWRACTIVE:3; // 4:2 Write access active timing + Uint16 XWRLEAD:2; // 6:5 Write access lead timing + Uint16 XRDTRAIL:2; // 8:7 Read access trail timing + Uint16 XRDACTIVE:3; // 11:9 Read access active timing + Uint16 XRDLEAD:2; // 13:12 Read access lead timing + Uint16 USEREADY:1; // 14 Extend access using HW waitstates + Uint16 READYMODE:1; // 15 Ready mode + Uint16 XSIZE:2; // 17:16 XINTF bus width - must be written as 11b + Uint16 rsvd1:4; // 21:18 reserved + Uint16 X2TIMING:1; // 22 Double lead/active/trail timing + Uint16 rsvd3:9; // 31:23 reserved +}; + +union XTIMING_REG { + Uint32 all; + struct XTIMING_BITS bit; +}; + +// XINTF control register bit definitions: +struct XINTCNF2_BITS { // bits description + Uint16 WRBUFF:2; // 1:0 Write buffer depth + Uint16 CLKMODE:1; // 2 Ratio for XCLKOUT with respect to XTIMCLK + Uint16 CLKOFF:1; // 3 Disable XCLKOUT + Uint16 rsvd1:2; // 5:4 reserved + Uint16 WLEVEL:2; // 7:6 Current level of the write buffer + Uint16 MPNMC:1; // 8 Micro-processor/micro-computer mode + Uint16 HOLD:1; // 9 Hold enable/disable + Uint16 HOLDS:1; // 10 Current state of HOLDn input + Uint16 HOLDAS:1; // 11 Current state of HOLDAn output + Uint16 rsvd2:4; // 15:12 reserved + Uint16 XTIMCLK:3; // 18:16 Ratio for XTIMCLK + Uint16 rsvd3:13; // 31:19 reserved +}; + +union XINTCNF2_REG { + Uint32 all; + struct XINTCNF2_BITS bit; +}; + +// XINTF bank switching register bit definitions: +struct XBANK_BITS { // bits description + Uint16 BANK:3; // 2:0 Zone for which banking is enabled + Uint16 BCYC:3; // 5:3 XTIMCLK cycles to add + Uint16 rsvd:10; // 15:6 reserved +}; + +union XBANK_REG { + Uint16 all; + struct XBANK_BITS bit; +}; + + +//--------------------------------------------------------------------------- +// XINTF Register File: +// +struct XINTF_REGS { + union XTIMING_REG XTIMING0; + union XTIMING_REG XTIMING1; + union XTIMING_REG XTIMING2; + Uint32 rsvd1[3]; + union XTIMING_REG XTIMING6; + union XTIMING_REG XTIMING7; + Uint32 rsvd2[2]; + union XINTCNF2_REG XINTCNF2; + Uint32 rsvd3; + union XBANK_REG XBANK; + Uint16 rsvd4; + Uint16 XREVISION; + Uint16 rsvd5[5]; +}; + +//--------------------------------------------------------------------------- +// XINTF External References & Function Declarations: +// +extern volatile struct XINTF_REGS XintfRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_XINTF_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c new file mode 100644 index 0000000..63bdc48 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c @@ -0,0 +1,109 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: July 9, 2009 10:51:58 $ +//########################################################################### +// +// FILE: DSP281x_CpuTimers.c +// +// TITLE: CPU 32-bit Timers Initialization & Support Functions. +// +// NOTES: CpuTimer2 is reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use these this timer in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // Headerfile Include File +#include "DSP281x_Examples.h" // Examples Include File +#include "DSP281x_CpuTimers.h" +struct CPUTIMER_VARS CpuTimer0; + +// When using DSP BIOS & other RTOS, comment out CPU Timer 2 code. +struct CPUTIMER_VARS CpuTimer1; +struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// InitCpuTimers: +//--------------------------------------------------------------------------- +// This function initializes all three CPU timers to a known state. +// +void InitCpuTimers(void) +{ + // CPU Timer 0 + // Initialize address pointers to respective timer registers: + CpuTimer0.RegsAddr = &CpuTimer0Regs; + // Initialize timer period to maximum: + CpuTimer0Regs.PRD.all = 0xFFFFFFFF; + // Initialize pre-scale counter to divide by 1 (SYSCLKOUT): + CpuTimer0Regs.TPR.all = 0; + CpuTimer0Regs.TPRH.all = 0; + // Make sure timer is stopped: + CpuTimer0Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + CpuTimer0Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + CpuTimer0.InterruptCount = 0; + + +// CpuTimer2 is reserved for DSP BIOS & other RTOS +// Do not use this timer if you ever plan on integrating +// DSP-BIOS or another realtime OS. + + // Initialize address pointers to respective timer registers: + CpuTimer1.RegsAddr = &CpuTimer1Regs; + CpuTimer2.RegsAddr = &CpuTimer2Regs; + // Initialize timer period to maximum: + CpuTimer1Regs.PRD.all = 0xFFFFFFFF; + CpuTimer2Regs.PRD.all = 0xFFFFFFFF; + // Make sure timers are stopped: + CpuTimer1Regs.TCR.bit.TSS = 1; + CpuTimer2Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + CpuTimer1Regs.TCR.bit.TRB = 1; + CpuTimer2Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + CpuTimer1.InterruptCount = 0; + CpuTimer2.InterruptCount = 0; + +} + +//--------------------------------------------------------------------------- +// ConfigCpuTimer: +//--------------------------------------------------------------------------- +// This function initializes the selected timer to the period specified +// by the "Freq" and "Period" parameters. The "Freq" is entered as "MHz" +// and the period in "uSeconds". The timer is held in the stopped state +// after configuration. +// +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period) +{ + Uint32 temp; + + // Initialize timer period: + Timer->CPUFreqInMHz = Freq; + Timer->PeriodInUSec = Period; + temp = (long) (Freq * Period); + Timer->RegsAddr->PRD.all = temp; + + // Set pre-scale counter to divide by 1 (SYSCLKOUT): + Timer->RegsAddr->TPR.all = 0; + Timer->RegsAddr->TPRH.all = 0; + + // Initialize timer control register: + Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 = Start/Restart Timer + Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer + Timer->RegsAddr->TCR.bit.SOFT = 1; + Timer->RegsAddr->TCR.bit.FREE = 1; // Timer Free Run + Timer->RegsAddr->TCR.bit.TIE = 1; // 0 = Disable/ 1 = Enable Timer Interrupt + + // Reset interrupt counter: + Timer->InterruptCount = 0; +} + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c new file mode 100644 index 0000000..cdd93b0 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c @@ -0,0 +1,265 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: July 9, 2009 17:28:45 $ +//########################################################################### +// +// FILE: DSP281x_GlobalVariableDefs.c +// +// TITLE: DSP281x Global Variables and Data Section Pragmas. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // DSP281x Headerfile Include File + +//--------------------------------------------------------------------------- +// Define Global Peripheral Variables: +// + +#ifdef __cplusplus +#pragma DATA_SECTION("AdcRegsFile") +#else +#pragma DATA_SECTION(AdcRegs,"AdcRegsFile"); +#endif +volatile struct ADC_REGS AdcRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("CpuTimer0RegsFile") +#else +#pragma DATA_SECTION(CpuTimer0Regs,"CpuTimer0RegsFile"); +#endif +volatile struct CPUTIMER_REGS CpuTimer0Regs; +//---------------------------------------- + +#ifdef __cplusplus +#pragma DATA_SECTION("CpuTimer1RegsFile") +#else +#pragma DATA_SECTION(CpuTimer1Regs,"CpuTimer1RegsFile"); +#endif +volatile struct CPUTIMER_REGS CpuTimer1Regs; +//---------------------------------------- + +#ifdef __cplusplus +#pragma DATA_SECTION("CpuTimer2RegsFile") +#else +#pragma DATA_SECTION(CpuTimer2Regs,"CpuTimer2RegsFile"); +#endif +volatile struct CPUTIMER_REGS CpuTimer2Regs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaRegsFile") +#else +#pragma DATA_SECTION(ECanaRegs,"ECanaRegsFile"); +#endif +volatile struct ECAN_REGS ECanaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaMboxesFile") +#else +#pragma DATA_SECTION(ECanaMboxes,"ECanaMboxesFile"); +#endif +volatile struct ECAN_MBOXES ECanaMboxes; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaLAMRegsFile") +#else +#pragma DATA_SECTION(ECanaLAMRegs,"ECanaLAMRegsFile"); +#endif +volatile struct LAM_REGS ECanaLAMRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaMOTSRegsFile") +#else +#pragma DATA_SECTION(ECanaMOTSRegs,"ECanaMOTSRegsFile"); +#endif +volatile struct MOTS_REGS ECanaMOTSRegs; + + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaMOTORegsFile") +#else +#pragma DATA_SECTION(ECanaMOTORegs,"ECanaMOTORegsFile"); +#endif +volatile struct MOTO_REGS ECanaMOTORegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("EvaRegsFile") +#else +#pragma DATA_SECTION(EvaRegs,"EvaRegsFile"); +#endif +volatile struct EVA_REGS EvaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("EvbRegsFile") +#else +#pragma DATA_SECTION(EvbRegs,"EvbRegsFile"); +#endif +volatile struct EVB_REGS EvbRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("GpioDataRegsFile") +#else +#pragma DATA_SECTION(GpioDataRegs,"GpioDataRegsFile"); +#endif +volatile struct GPIO_DATA_REGS GpioDataRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("GpioMuxRegsFile") +#else +#pragma DATA_SECTION(GpioMuxRegs,"GpioMuxRegsFile"); +#endif +volatile struct GPIO_MUX_REGS GpioMuxRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("McbspaRegsFile") +#else +#pragma DATA_SECTION(McbspaRegs,"McbspaRegsFile"); +#endif +volatile struct MCBSP_REGS McbspaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("PieCtrlRegsFile") +#else +#pragma DATA_SECTION(PieCtrlRegs,"PieCtrlRegsFile"); +#endif +volatile struct PIE_CTRL_REGS PieCtrlRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("PieVectTableFile") +#else +#pragma DATA_SECTION(PieVectTable,"PieVectTableFile"); +#endif +struct PIE_VECT_TABLE PieVectTable; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("SciaRegsFile") +#else +#pragma DATA_SECTION(SciaRegs,"SciaRegsFile"); +#endif +volatile struct SCI_REGS SciaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ScibRegsFile") +#else +#pragma DATA_SECTION(ScibRegs,"ScibRegsFile"); +#endif +volatile struct SCI_REGS ScibRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("SpiaRegsFile") +#else +#pragma DATA_SECTION(SpiaRegs,"SpiaRegsFile"); +#endif +volatile struct SPI_REGS SpiaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("SysCtrlRegsFile") +#else +#pragma DATA_SECTION(SysCtrlRegs,"SysCtrlRegsFile"); +#endif +volatile struct SYS_CTRL_REGS SysCtrlRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("DevEmuRegsFile") +#else +#pragma DATA_SECTION(DevEmuRegs,"DevEmuRegsFile"); +#endif +volatile struct DEV_EMU_REGS DevEmuRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("CsmRegsFile") +#else +#pragma DATA_SECTION(CsmRegs,"CsmRegsFile"); +#endif +volatile struct CSM_REGS CsmRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("CsmPwlFile") +#else +#pragma DATA_SECTION(CsmPwl,"CsmPwlFile"); +#endif +volatile struct CSM_PWL CsmPwl; + + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("FlashRegsFile") +#else +#pragma DATA_SECTION(FlashRegs,"FlashRegsFile"); +#endif +volatile struct FLASH_REGS FlashRegs; + +#if DSP28_F2812 +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("XintfRegsFile") +#else +#pragma DATA_SECTION(XintfRegs,"XintfRegsFile"); +#endif +volatile struct XINTF_REGS XintfRegs; +#endif + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("XIntruptRegsFile") +#else +#pragma DATA_SECTION(XIntruptRegs,"XIntruptRegsFile"); +#endif +volatile struct XINTRUPT_REGS XIntruptRegs; + + + +// The following are provided to support alternate notation +// that was used in an early version of the header files + +#define ADCRegs AdcRegs +#define CPUTimer0Regs CpuTimer0Regs +#define CPUTimer1Regs CpuTimer1Regs +#define CPUTimer2Regs CpuTimer2Regs +#define ECANARegs ECanaRegs +#define ECANAMboxes ECanaMboxes +#define EVARegs EvaRegs +#define GPIODataRegs GpioDataRegs +#define GPIOMuxRegs GpioMuxRegs +#define MCBSPARegs McbspaRegs +#define PIECtrlRegs PieCtrlRegs +#define PIEVectTable PieVectTable +#define SCIARegs SciaRegs +#define SCIBRegs ScibRegs +#define SYSCtrlRegs SysCtrlRegs +#define DEVEmuRegs DevEmuRegs +#define CSMRegs CsmRegs +#define CSMPwl CsmPwl +#define FLASHRegs FlashRegs +#define XINTFRegs XintfRegs +#define XINTRUPTRegs XIntruptRegs + + + + + + + + + diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c new file mode 100644 index 0000000..8d38af6 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c @@ -0,0 +1,84 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 29, 2005 11:09:05 $ +//########################################################################### +// +// FILE: DSP281x_PieCtrl.c +// +// TITLE: DSP281x Device PIE Control Register Initialization Functions. +// + +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // DSP281x Headerfile Include File +#include "DSP281x_Examples.h" // DSP281x Examples Include File + +//--------------------------------------------------------------------------- +// InitPieCtrl: +//--------------------------------------------------------------------------- +// This function initializes the PIE control registers to a known state. +// +void InitPieCtrl(void) +{ + // Disable Interrupts at the CPU level: + DINT; + + // Disable the PIE + PieCtrlRegs.PIECRTL.bit.ENPIE = 0; + + // Clear all PIEIER registers: + PieCtrlRegs.PIEIER1.all = 0; + PieCtrlRegs.PIEIER2.all = 0; + PieCtrlRegs.PIEIER3.all = 0; + PieCtrlRegs.PIEIER4.all = 0; + PieCtrlRegs.PIEIER5.all = 0; + PieCtrlRegs.PIEIER6.all = 0; + PieCtrlRegs.PIEIER7.all = 0; + PieCtrlRegs.PIEIER8.all = 0; + PieCtrlRegs.PIEIER9.all = 0; + PieCtrlRegs.PIEIER10.all = 0; + PieCtrlRegs.PIEIER11.all = 0; + PieCtrlRegs.PIEIER12.all = 0; + + // Clear all PIEIFR registers: + PieCtrlRegs.PIEIFR1.all = 0; + PieCtrlRegs.PIEIFR2.all = 0; + PieCtrlRegs.PIEIFR3.all = 0; + PieCtrlRegs.PIEIFR4.all = 0; + PieCtrlRegs.PIEIFR5.all = 0; + PieCtrlRegs.PIEIFR6.all = 0; + PieCtrlRegs.PIEIFR7.all = 0; + PieCtrlRegs.PIEIFR8.all = 0; + PieCtrlRegs.PIEIFR9.all = 0; + PieCtrlRegs.PIEIFR10.all = 0; + PieCtrlRegs.PIEIFR11.all = 0; + PieCtrlRegs.PIEIFR12.all = 0; + + +} + +//--------------------------------------------------------------------------- +// EnableInterrupts: +//--------------------------------------------------------------------------- +// This function enables the PIE module and CPU interrupts +// +void EnableInterrupts() +{ + + // Enable the PIE + PieCtrlRegs.PIECRTL.bit.ENPIE = 1; + + // Enables PIE to drive a pulse into the CPU + PieCtrlRegs.PIEACK.all = 0xFFFF; + + // Enable Interrupts at the CPU level + EINT; + +} + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c new file mode 100644 index 0000000..9db37eb --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c @@ -0,0 +1,295 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: April 4, 2007 13:20:29 $ +//########################################################################### +// +// FILE: DSP281x_SysCtrl.c +// +// TITLE: DSP281x Device System Control Initialization & Support Functions. +// +// DESCRIPTION: +// +// Example initialization of system resources. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // DSP281x Headerfile Include File +#include "DSP281x_Examples.h" // DSP281x Examples Include File + +// Functions that will be run from RAM need to be assigned to +// a different section. This section will then be mapped to a load and +// run address using the linker cmd file. + +#pragma CODE_SECTION(InitFlash, "ramfuncs"); + +#pragma DATA_SECTION(HSPCLK,".fast_vars1"); +float SYSCLKOUT, LSPCLK, HSPCLK; + +//--------------------------------------------------------------------------- +// InitSysCtrl: +//--------------------------------------------------------------------------- +// This function initializes the System Control registers to a known state. +// - Disables the watchdog +// - Set the PLLCR for proper SYSCLKOUT frequency +// - Set the pre-scaler for the high and low frequency peripheral clocks +// - Enable the clocks to the peripherals + +void InitSysCtrl(void) +{ + +// On F2812/F2810 TMX samples prior to rev C this initialization was +// required. For Rev C and after this is no longer required +/* + EALLOW; + DevEmuRegs.M0RAMDFT = 0x0300; + DevEmuRegs.M1RAMDFT = 0x0300; + DevEmuRegs.L0RAMDFT = 0x0300; + DevEmuRegs.L1RAMDFT = 0x0300; + DevEmuRegs.H0RAMDFT = 0x0300; + EDIS; +*/ + // Disable the watchdog + DisableDog(); + + // Initialize the PLLCR to 0xA + InitPll(0xA); + + // Initialize the peripheral clocks + InitPeripheralClocks(); +} + + +//--------------------------------------------------------------------------- +// Example: InitFlash: +//--------------------------------------------------------------------------- +// This function initializes the Flash Control registers + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results + +void InitFlash(void) +{ + + + + EALLOW; + //Enable Flash Pipeline mode to improve performance + //of code executed from Flash. + FlashRegs.FOPT.bit.ENPIPE = 1; + + // CAUTION + //Minimum waitstates required for the flash operating + //at a given CPU rate must be characterized by TI. + //Refer to the datasheet for the latest information. + + //Set the Random Waitstate for the Flash + FlashRegs.FBANKWAIT.bit.RANDWAIT = 5; + + //Set the Paged Waitstate for the Flash + FlashRegs.FBANKWAIT.bit.PAGEWAIT = 5; + + // CAUTION + //Minimum cycles required to move between power states + //at a given CPU rate must be characterized by TI. + //Refer to the datasheet for the latest information. + + //For now use the default count + //Set number of cycles to transition from sleep to standby + FlashRegs.FSTDBYWAIT.bit.STDBYWAIT = 0x01FF; + + //Set number of cycles to transition from standby to active + FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT = 0x01FF; + +// new add!!! + + FlashRegs.FPWR.bit.PWR = 3; // Pump and bank set to active mode + FlashRegs.FSTATUS.bit.V3STAT = 1; // Clear the 3VSTAT bit + FlashRegs.FOTPWAIT.bit.OTPWAIT = 8; // OTP waitstates + +///////// + + EDIS; + + //Force a pipeline flush to ensure that the write to + //the last register configured occurs before returning. + + asm(" RPT #7 || NOP"); +} + + +//--------------------------------------------------------------------------- +// Example: KickDog: +//--------------------------------------------------------------------------- +// This function resets the watchdog timer. +// Enable this function for using KickDog in the application + +void KickDog(void) +{ + EALLOW; + SysCtrlRegs.WDKEY = 0x0055; + SysCtrlRegs.WDKEY = 0x00AA; + EDIS; +} + +//--------------------------------------------------------------------------- +// Example: DisableDog: +//--------------------------------------------------------------------------- +// This function disables the watchdog timer. + +void DisableDog(void) +{ + EALLOW; + SysCtrlRegs.WDCR= 0x0068; + EDIS; +} + +//--------------------------------------------------------------------------- +// Example: InitPll: +//--------------------------------------------------------------------------- +// This function initializes the PLLCR register. + +void InitPll(Uint16 val) +{ + float Val; + volatile Uint16 iVol; + + Val = (val)?val:1; + Val = XCLKIN * (Val / 2); + SYSCLKOUT = Val; + + + + if (SysCtrlRegs.PLLCR.bit.DIV != val) + { + EALLOW; + SysCtrlRegs.PLLCR.bit.DIV = val; + EDIS; + + // Optional: Wait for PLL to lock. + // During this time the CPU will switch to OSCCLK/2 until the PLL is + // stable. Once the PLL is stable the CPU will switch to the new PLL value. + // + // This switch time is 131072 CLKIN cycles as of Rev C silicon. + // + // Code is not required to sit and wait for the PLL to lock. + // However, if the code does anything that is timing critical, + // and requires the correct clock be locked, then it is best to + // wait until this switching has completed. + + // If this function is run from waitstated memory, then the loop count can + // be reduced as long as the minimum switch time is still met. + + // iVol is volatile so the compiler will not optimize this loop out + // + // The watchdog should be disabled before this loop, or fed within + // the loop. + + DisableDog(); + + // Wait lock cycles. + // Note, This loop is tuned to 0-waitstate RAM memory. If this + // function is run from wait-stated memory such as Flash or XINTF, + // then the number of times through the loop can be reduced + // accordingly. + for(iVol= 0; iVol< ( (131072/2)/12 ); iVol++) + { + + } + } +} + +//-------------------------------------------------------------------------- +// Example: InitPeripheralClocks: +//--------------------------------------------------------------------------- +// This function initializes the clocks to the peripheral modules. +// First the high and low clock prescalers are set +// Second the clocks are enabled to each peripheral. +// To reduce power, leave clocks to unused peripherals disabled +// Note: If a peripherals clock is not enabled then you cannot +// read or write to the registers for that peripheral + +void InitPeripheralClocks(void) +{ + float Val; + + EALLOW; +// HISPCP/LOSPCP prescale register settings, normally it will be set to default values + SysCtrlRegs.HISPCP.all = 0x002;//0x0002; + SysCtrlRegs.LOSPCP.all = 0x0000;//0x4 + + + Val = (SysCtrlRegs.HISPCP.all)? + SysCtrlRegs.HISPCP.all*2 : 1; + Val = SYSCLKOUT / Val; + + HSPCLK = Val; + + Val = (SysCtrlRegs.LOSPCP.all)? + SysCtrlRegs.LOSPCP.all*2 : 1; + Val = SYSCLKOUT / Val; + LSPCLK = Val; + +// Peripheral clock enables set for the selected peripherals. + SysCtrlRegs.PCLKCR.bit.EVAENCLK=1; + SysCtrlRegs.PCLKCR.bit.EVBENCLK=1; + SysCtrlRegs.PCLKCR.bit.SCIAENCLK=1; + SysCtrlRegs.PCLKCR.bit.SCIBENCLK=1; + SysCtrlRegs.PCLKCR.bit.MCBSPENCLK=1; + SysCtrlRegs.PCLKCR.bit.SPIENCLK=1; + SysCtrlRegs.PCLKCR.bit.ECANENCLK=1; + SysCtrlRegs.PCLKCR.bit.ADCENCLK=1; + EDIS; +} + +//--------------------------------------------------------------------------- +// Example: CsmUnlock: +//--------------------------------------------------------------------------- +// This function unlocks the CSM. User must replace 0xFFFF's with current +// password for the DSP. Returns 1 if unlock is successful. + +#define STATUS_FAIL 0 +#define STATUS_SUCCESS 1 + +Uint16 CsmUnlock() +{ + volatile Uint16 temp; + + // Load the key registers with the current password. The 0xFFFF's are dummy + // passwords. User should replace them with the correct password for the DSP. + + EALLOW; + CsmRegs.KEY0 = 0xFFFF; + CsmRegs.KEY1 = 0xFFFF; + CsmRegs.KEY2 = 0xFFFF; + CsmRegs.KEY3 = 0xFFFF; + CsmRegs.KEY4 = 0xFFFF; + CsmRegs.KEY5 = 0xFFFF; + CsmRegs.KEY6 = 0xFFFF; + CsmRegs.KEY7 = 0xFFFF; + EDIS; + + // Perform a dummy read of the password locations + // if they match the key values, the CSM will unlock + + temp = CsmPwl.PSWD0; + temp = CsmPwl.PSWD1; + temp = CsmPwl.PSWD2; + temp = CsmPwl.PSWD3; + temp = CsmPwl.PSWD4; + temp = CsmPwl.PSWD5; + temp = CsmPwl.PSWD6; + temp = CsmPwl.PSWD7; + + // If the CSM unlocked, return succes, otherwise return + // failure. + if (CsmRegs.CSMSCR.bit.SECURE == 0) return STATUS_SUCCESS; + else return STATUS_FAIL; + +} + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm new file mode 100644 index 0000000..e1b644e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm @@ -0,0 +1,71 @@ +;// TI File $Revision: /main/2 $ +;// Checkin $Date: April 29, 2005 11:01:42 $ +;//########################################################################### +;// +;// FILE: DSP281x_usDelay.asm +;// +;// TITLE: Simple delay function +;// +;// DESCRIPTION: +;// +;// This is a simple delay function that can be used to insert a specified +;// delay into code. +;// +;// This function is only accurate if executed from internal zero-waitstate +;// SARAM. If it is executed from waitstate memory then the delay will be +;// longer then specified. +;// +;// To use this function: +;// +;// 1 - update the CPU clock speed in the DSP281x_Examples.h +;// file. For example: +;// #define CPU_CLOCK_SPEED 6.6667L // for a 150MHz CPU clock speed +;// +;// 2 - Call this function by using the DELAY_US(A) macro +;// that is defined in the DSP28_Device.h file. This macro +;// will convert the number of microseconds specified +;// into a loop count for use with this function. +;// This count will be based on the CPU frequency you specify. +;// +;// 3 - For the most accurate delay +;// - Execute this function in 0 waitstate RAM. +;// - Disable interrupts before calling the function +;// If you do not disable interrupts, then think of +;// this as an "at least" delay function as the actual +;// delay may be longer. +;// +;// The C assembly call from the DELAY_US(time) macro will +;// look as follows: +;// +;// extern void Delay(long LoopCount); +;// +;// MOV AL,#LowLoopCount +;// MOV AH,#HighLoopCount +;// LCR _Delay +;// +;// Or as follows (if count is less then 16-bits): +;// +;// MOV ACC,#LoopCount +;// LCR _Delay +;// +;// +;//########################################################################### +;// $TI Release: DSP281x C/C++ Header Files V1.20 $ +;// $Release Date: July 27, 2009 $ +;//########################################################################### + .def _DSP28x_usDelay + .sect ".fast_run" + + .global __DSP28x_usDelay +_DSP28x_usDelay: + SUB ACC,#1 + BF _DSP28x_usDelay,GEQ ;; Loop if ACC >= 0 + LRETR + +;There is a 9/10 cycle overhead and each loop +;takes five cycles. The LoopCount is given by +;the following formula: +; DELAY_CPU_CYCLES = 9 + 5*LoopCount +; LoopCount = (DELAY_CPU_CYCLES - 9) / 5 +; The macro DELAY_US(A) performs this calculation for you +;================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd b/c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd new file mode 100644 index 0000000..d16ae33 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd @@ -0,0 +1,240 @@ +/* Поставляемое TI описание Headers_nonBIOS для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +/* +// TI File $Revision: /main/8 $ +// Checkin $Date: June 2, 2008 11:12:24 $ +//########################################################################### +// +// FILE: DSP2833x_Headers_nonBIOS.cmd +// +// TITLE: DSP2833x Peripheral registers linker command file +// +// DESCRIPTION: +// +// This file is for use in Non-BIOS applications. +// +// Linker command file to place the peripheral structures +// used within the DSP2833x headerfiles into the correct memory +// mapped locations. +// +// This version of the file includes the PieVectorTable structure. +// For BIOS applications, please use the DSP2833x_Headers_BIOS.cmd file +// which does not include the PieVectorTable structure. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### +*/ + +/* Начинает описание физических блоков памяти для линкера. */ +MEMORY +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + PAGE 0: /* Program Memory */ /* Выбирает страницу адресного пространства линкера: 0 — программа, 1 — данные. */ + + PAGE 1: /* Data Memory */ /* Выбирает страницу адресного пространства линкера: 0 — программа, 1 — данные. */ + + DEV_EMU : origin = 0x000880, length = 0x000180 /* device emulation registers */ /* Записывает origin значением 0x000880, length = 0x000180; данные origin. */ + FLASH_REGS : origin = 0x000A80, length = 0x000060 /* FLASH registers */ /* Записывает origin значением 0x000A80, length = 0x000060; данные origin. */ + CSM : origin = 0x000AE0, length = 0x000010 /* code security module registers */ /* Записывает origin значением 0x000AE0, length = 0x000010; данные origin. */ + + ADC_MIRROR : origin = 0x000B00, length = 0x000010 /* ADC Results register mirror */ /* Записывает origin значением 0x000B00, length = 0x000010; данные origin. */ + + XINTF : origin = 0x000B20, length = 0x000020 /* external interface registers */ /* Записывает origin значением 0x000B20, length = 0x000020; данные origin. */ + + CPU_TIMER0 : origin = 0x000C00, length = 0x000008 /* CPU Timer0 registers */ /* Записывает origin значением 0x000C00, length = 0x000008; данные origin. */ + CPU_TIMER1 : origin = 0x000C08, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ /* Записывает origin значением 0x000C08, length = 0x000008; данные origin. */ + CPU_TIMER2 : origin = 0x000C10, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ /* Записывает origin значением 0x000C10, length = 0x000008; данные origin. */ + + PIE_CTRL : origin = 0x000CE0, length = 0x000020 /* PIE control registers */ /* Записывает origin значением 0x000CE0, length = 0x000020; данные origin. */ + PIE_VECT : origin = 0x000D00, length = 0x000100 /* PIE Vector Table */ /* Записывает origin значением 0x000D00, length = 0x000100; данные origin. */ + + DMA : origin = 0x001000, length = 0x000200 /* DMA registers */ /* Записывает origin значением 0x001000, length = 0x000200; данные origin. */ + + MCBSPA : origin = 0x005000, length = 0x000040 /* McBSP-A registers */ /* Записывает origin значением 0x005000, length = 0x000040; данные origin. */ + MCBSPB : origin = 0x005040, length = 0x000040 /* McBSP-B registers */ /* Записывает origin значением 0x005040, length = 0x000040; данные origin. */ + + ECANA : origin = 0x006000, length = 0x000040 /* eCAN-A control and status registers */ /* Записывает origin значением 0x006000, length = 0x000040; данные origin. */ + ECANA_LAM : origin = 0x006040, length = 0x000040 /* eCAN-A local acceptance masks */ /* Записывает origin значением 0x006040, length = 0x000040; данные origin. */ + ECANA_MOTS : origin = 0x006080, length = 0x000040 /* eCAN-A message object time stamps */ /* Записывает origin значением 0x006080, length = 0x000040; данные origin. */ + ECANA_MOTO : origin = 0x0060C0, length = 0x000040 /* eCAN-A object time-out registers */ /* Записывает origin значением 0x0060C0, length = 0x000040; данные origin. */ + ECANA_MBOX : origin = 0x006100, length = 0x000100 /* eCAN-A mailboxes */ /* Записывает origin значением 0x006100, length = 0x000100; данные origin. */ + + ECANB : origin = 0x006200, length = 0x000040 /* eCAN-B control and status registers */ /* Записывает origin значением 0x006200, length = 0x000040; данные origin. */ + ECANB_LAM : origin = 0x006240, length = 0x000040 /* eCAN-B local acceptance masks */ /* Записывает origin значением 0x006240, length = 0x000040; данные origin. */ + ECANB_MOTS : origin = 0x006280, length = 0x000040 /* eCAN-B message object time stamps */ /* Записывает origin значением 0x006280, length = 0x000040; данные origin. */ + ECANB_MOTO : origin = 0x0062C0, length = 0x000040 /* eCAN-B object time-out registers */ /* Записывает origin значением 0x0062C0, length = 0x000040; данные origin. */ + ECANB_MBOX : origin = 0x006300, length = 0x000100 /* eCAN-B mailboxes */ /* Записывает origin значением 0x006300, length = 0x000100; данные origin. */ + + EPWM1 : origin = 0x006800, length = 0x000022 /* Enhanced PWM 1 registers */ /* Записывает origin значением 0x006800, length = 0x000022; данные origin. */ + EPWM2 : origin = 0x006840, length = 0x000022 /* Enhanced PWM 2 registers */ /* Записывает origin значением 0x006840, length = 0x000022; данные origin. */ + EPWM3 : origin = 0x006880, length = 0x000022 /* Enhanced PWM 3 registers */ /* Записывает origin значением 0x006880, length = 0x000022; данные origin. */ + EPWM4 : origin = 0x0068C0, length = 0x000022 /* Enhanced PWM 4 registers */ /* Записывает origin значением 0x0068C0, length = 0x000022; данные origin. */ + EPWM5 : origin = 0x006900, length = 0x000022 /* Enhanced PWM 5 registers */ /* Записывает origin значением 0x006900, length = 0x000022; данные origin. */ + EPWM6 : origin = 0x006940, length = 0x000022 /* Enhanced PWM 6 registers */ /* Записывает origin значением 0x006940, length = 0x000022; данные origin. */ + + ECAP1 : origin = 0x006A00, length = 0x000020 /* Enhanced Capture 1 registers */ /* Записывает origin значением 0x006A00, length = 0x000020; данные origin. */ + ECAP2 : origin = 0x006A20, length = 0x000020 /* Enhanced Capture 2 registers */ /* Записывает origin значением 0x006A20, length = 0x000020; данные origin. */ + ECAP3 : origin = 0x006A40, length = 0x000020 /* Enhanced Capture 3 registers */ /* Записывает origin значением 0x006A40, length = 0x000020; данные origin. */ + ECAP4 : origin = 0x006A60, length = 0x000020 /* Enhanced Capture 4 registers */ /* Записывает origin значением 0x006A60, length = 0x000020; данные origin. */ + ECAP5 : origin = 0x006A80, length = 0x000020 /* Enhanced Capture 5 registers */ /* Записывает origin значением 0x006A80, length = 0x000020; данные origin. */ + ECAP6 : origin = 0x006AA0, length = 0x000020 /* Enhanced Capture 6 registers */ /* Записывает origin значением 0x006AA0, length = 0x000020; данные origin. */ + + EQEP1 : origin = 0x006B00, length = 0x000040 /* Enhanced QEP 1 registers */ /* Записывает origin значением 0x006B00, length = 0x000040; данные origin. */ + EQEP2 : origin = 0x006B40, length = 0x000040 /* Enhanced QEP 2 registers */ /* Записывает origin значением 0x006B40, length = 0x000040; данные origin. */ + + GPIOCTRL : origin = 0x006F80, length = 0x000040 /* GPIO control registers */ /* Записывает origin значением 0x006F80, length = 0x000040; данные origin. */ + GPIODAT : origin = 0x006FC0, length = 0x000020 /* GPIO data registers */ /* Записывает origin значением 0x006FC0, length = 0x000020; данные origin. */ + GPIOINT : origin = 0x006FE0, length = 0x000020 /* GPIO interrupt/LPM registers */ /* Записывает origin значением 0x006FE0, length = 0x000020; данные origin. */ + + SYSTEM : origin = 0x007010, length = 0x000020 /* System control registers */ /* Записывает origin значением 0x007010, length = 0x000020; данные origin. */ + SPIA : origin = 0x007040, length = 0x000010 /* SPI-A registers */ /* Записывает origin значением 0x007040, length = 0x000010; данные origin. */ + SCIA : origin = 0x007050, length = 0x000010 /* SCI-A registers */ /* Записывает origin значением 0x007050, length = 0x000010; данные origin. */ + XINTRUPT : origin = 0x007070, length = 0x000010 /* external interrupt registers */ /* Записывает origin значением 0x007070, length = 0x000010; данные origin. */ + + ADC : origin = 0x007100, length = 0x000020 /* ADC registers */ /* Записывает origin значением 0x007100, length = 0x000020; данные origin. */ + + SCIB : origin = 0x007750, length = 0x000010 /* SCI-B registers */ /* Записывает origin значением 0x007750, length = 0x000010; данные origin. */ + + SCIC : origin = 0x007770, length = 0x000010 /* SCI-C registers */ /* Записывает origin значением 0x007770, length = 0x000010; данные origin. */ + + I2CA : origin = 0x007900, length = 0x000040 /* I2C-A registers */ /* Записывает origin значением 0x007900, length = 0x000040; данные origin. */ + + CSM_PWL : origin = 0x33FFF8, length = 0x000008 /* Part of FLASHA. CSM password locations. */ /* Записывает origin значением 0x33FFF8, length = 0x000008; данные origin. */ + + PARTID : origin = 0x380090, length = 0x000001 /* Part ID register location */ /* Записывает origin значением 0x380090, length = 0x000001; данные origin. */ +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +/* Начинает описание размещения секций объектных файлов для линкера. */ +SECTIONS +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Записывает PAGE значением 1; данные PAGE. */ + PieVectTableFile : > PIE_VECT, PAGE = 1 + +/*** Peripheral Frame 0 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + DevEmuRegsFile : > DEV_EMU, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + FlashRegsFile : > FLASH_REGS, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CsmRegsFile : > CSM, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + AdcMirrorFile : > ADC_MIRROR, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + XintfRegsFile : > XINTF, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + PieCtrlRegsFile : > PIE_CTRL, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + DmaRegsFile : > DMA, PAGE = 1 + +/*** Peripheral Frame 3 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + McbspaRegsFile : > MCBSPA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + McbspbRegsFile : > MCBSPB, PAGE = 1 + +/*** Peripheral Frame 1 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaRegsFile : > ECANA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaLAMRegsFile : > ECANA_LAM PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaMboxesFile : > ECANA_MBOX PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaMOTSRegsFile : > ECANA_MOTS PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaMOTORegsFile : > ECANA_MOTO PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbRegsFile : > ECANB, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbLAMRegsFile : > ECANB_LAM PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbMboxesFile : > ECANB_MBOX PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbMOTSRegsFile : > ECANB_MOTS PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbMOTORegsFile : > ECANB_MOTO PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm1RegsFile : > EPWM1 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm2RegsFile : > EPWM2 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm3RegsFile : > EPWM3 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm4RegsFile : > EPWM4 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm5RegsFile : > EPWM5 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm6RegsFile : > EPWM6 PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + ECap1RegsFile : > ECAP1 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap2RegsFile : > ECAP2 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap3RegsFile : > ECAP3 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap4RegsFile : > ECAP4 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap5RegsFile : > ECAP5 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap6RegsFile : > ECAP6 PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + EQep1RegsFile : > EQEP1 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EQep2RegsFile : > EQEP2 PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + GpioCtrlRegsFile : > GPIOCTRL PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + GpioDataRegsFile : > GPIODAT PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + GpioIntRegsFile : > GPIOINT PAGE = 1 + +/*** Peripheral Frame 2 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + SysCtrlRegsFile : > SYSTEM, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + SpiaRegsFile : > SPIA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + SciaRegsFile : > SCIA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + XIntruptRegsFile : > XINTRUPT, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + AdcRegsFile : > ADC, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ScibRegsFile : > SCIB, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ScicRegsFile : > SCIC, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + I2caRegsFile : > I2CA, PAGE = 1 + +/*** Code Security Module Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + CsmPwlFile : > CSM_PWL, PAGE = 1 + +/*** Device Part ID Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + PartIdRegsFile : > PARTID, PAGE = 1 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +/* +//=========================================================================== +// End of file. +//=========================================================================== +*/ diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h new file mode 100644 index 0000000..648872d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h @@ -0,0 +1,236 @@ +/* Поставляемое TI описание DefaultIsr для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:45:37 $ +//########################################################################### +// +// FILE: DSP2833x_DefaultIsr.h +// +// TITLE: DSP2833x Devices Default Interrupt Service Routines Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DEFAULT_ISR_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DEFAULT_ISR_H +/* Определяет защитный символ или переключатель DSP2833x_DEFAULT_ISR_H для последующей компиляции. */ +#define DSP2833x_DEFAULT_ISR_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// Default Interrupt Service Routine Declarations: +// +// The following function prototypes are for the +// default ISR routines used with the default PIE vector table. +// This default vector table is found in the DSP2833x_PieVect.h +// file. +// + +// Non-Peripheral Interrupts: +/* Объявляет обработчик INT13_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1 +/* Объявляет обработчик INT14_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void INT14_ISR(void); // CPU-Timer2 +/* Объявляет обработчик DATALOG_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DATALOG_ISR(void); // Datalogging interrupt +/* Объявляет обработчик RTOSINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void RTOSINT_ISR(void); // RTOS interrupt +/* Объявляет обработчик EMUINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EMUINT_ISR(void); // Emulation interrupt +/* Объявляет обработчик NMI_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void NMI_ISR(void); // Non-maskable interrupt +/* Объявляет обработчик ILLEGAL_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP +/* Объявляет обработчик USER1_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER1_ISR(void); // User Defined trap 1 +/* Объявляет обработчик USER2_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER2_ISR(void); // User Defined trap 2 +/* Объявляет обработчик USER3_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER3_ISR(void); // User Defined trap 3 +/* Объявляет обработчик USER4_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER4_ISR(void); // User Defined trap 4 +/* Объявляет обработчик USER5_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER5_ISR(void); // User Defined trap 5 +/* Объявляет обработчик USER6_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER6_ISR(void); // User Defined trap 6 +/* Объявляет обработчик USER7_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER7_ISR(void); // User Defined trap 7 +/* Объявляет обработчик USER8_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER8_ISR(void); // User Defined trap 8 +/* Объявляет обработчик USER9_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER9_ISR(void); // User Defined trap 9 +/* Объявляет обработчик USER10_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER10_ISR(void); // User Defined trap 10 +/* Объявляет обработчик USER11_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER11_ISR(void); // User Defined trap 11 +/* Объявляет обработчик USER12_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER12_ISR(void); // User Defined trap 12 + +// Group 1 PIE Interrupt Service Routines: +/* Объявляет обработчик SEQ1INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SEQ1INT_ISR(void); // ADC Sequencer 1 ISR +/* Объявляет обработчик SEQ2INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SEQ2INT_ISR(void); // ADC Sequencer 2 ISR +/* Объявляет обработчик XINT1_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT1_ISR(void); // External interrupt 1 +/* Объявляет обработчик XINT2_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT2_ISR(void); // External interrupt 2 +/* Объявляет обработчик ADCINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ADCINT_ISR(void); // ADC +/* Объявляет обработчик TINT0_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void TINT0_ISR(void); // Timer 0 +/* Объявляет обработчик WAKEINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void WAKEINT_ISR(void); // WD + +// Group 2 PIE Interrupt Service Routines: +/* Объявляет обработчик EPWM1_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM1_TZINT_ISR(void); // EPWM-1 +/* Объявляет обработчик EPWM2_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM2_TZINT_ISR(void); // EPWM-2 +/* Объявляет обработчик EPWM3_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM3_TZINT_ISR(void); // EPWM-3 +/* Объявляет обработчик EPWM4_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM4_TZINT_ISR(void); // EPWM-4 +/* Объявляет обработчик EPWM5_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM5_TZINT_ISR(void); // EPWM-5 +/* Объявляет обработчик EPWM6_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM6_TZINT_ISR(void); // EPWM-6 + +// Group 3 PIE Interrupt Service Routines: +/* Объявляет обработчик EPWM1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM1_INT_ISR(void); // EPWM-1 +/* Объявляет обработчик EPWM2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM2_INT_ISR(void); // EPWM-2 +/* Объявляет обработчик EPWM3_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM3_INT_ISR(void); // EPWM-3 +/* Объявляет обработчик EPWM4_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM4_INT_ISR(void); // EPWM-4 +/* Объявляет обработчик EPWM5_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM5_INT_ISR(void); // EPWM-5 +/* Объявляет обработчик EPWM6_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM6_INT_ISR(void); // EPWM-6 + +// Group 4 PIE Interrupt Service Routines: +/* Объявляет обработчик ECAP1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP1_INT_ISR(void); // ECAP-1 +/* Объявляет обработчик ECAP2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP2_INT_ISR(void); // ECAP-2 +/* Объявляет обработчик ECAP3_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP3_INT_ISR(void); // ECAP-3 +/* Объявляет обработчик ECAP4_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP4_INT_ISR(void); // ECAP-4 +/* Объявляет обработчик ECAP5_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP5_INT_ISR(void); // ECAP-5 +/* Объявляет обработчик ECAP6_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP6_INT_ISR(void); // ECAP-6 + +// Group 5 PIE Interrupt Service Routines: +/* Объявляет обработчик EQEP1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EQEP1_INT_ISR(void); // EQEP-1 +/* Объявляет обработчик EQEP2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EQEP2_INT_ISR(void); // EQEP-2 + +// Group 6 PIE Interrupt Service Routines: +/* Объявляет обработчик SPIRXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SPIRXINTA_ISR(void); // SPI-A +/* Объявляет обработчик SPITXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SPITXINTA_ISR(void); // SPI-A +/* Объявляет обработчик MRINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MRINTA_ISR(void); // McBSP-A +/* Объявляет обработчик MXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MXINTA_ISR(void); // McBSP-A +/* Объявляет обработчик MRINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MRINTB_ISR(void); // McBSP-B +/* Объявляет обработчик MXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MXINTB_ISR(void); // McBSP-B + +// Group 7 PIE Interrupt Service Routines: +/* Объявляет обработчик DINTCH1_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH1_ISR(void); // DMA-Channel 1 +/* Объявляет обработчик DINTCH2_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH2_ISR(void); // DMA-Channel 2 +/* Объявляет обработчик DINTCH3_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH3_ISR(void); // DMA-Channel 3 +/* Объявляет обработчик DINTCH4_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH4_ISR(void); // DMA-Channel 4 +/* Объявляет обработчик DINTCH5_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH5_ISR(void); // DMA-Channel 5 +/* Объявляет обработчик DINTCH6_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH6_ISR(void); // DMA-Channel 6 + +// Group 8 PIE Interrupt Service Routines: +/* Объявляет обработчик I2CINT1A_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void I2CINT1A_ISR(void); // I2C-A +/* Объявляет обработчик I2CINT2A_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void I2CINT2A_ISR(void); // I2C-A +/* Объявляет обработчик SCIRXINTC_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCIRXINTC_ISR(void); // SCI-C +/* Объявляет обработчик SCITXINTC_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCITXINTC_ISR(void); // SCI-C + +// Group 9 PIE Interrupt Service Routines: +/* Объявляет обработчик SCIRXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCIRXINTA_ISR(void); // SCI-A +/* Объявляет обработчик SCITXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCITXINTA_ISR(void); // SCI-A +/* Объявляет обработчик SCIRXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCIRXINTB_ISR(void); // SCI-B +/* Объявляет обработчик SCITXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCITXINTB_ISR(void); // SCI-B +/* Объявляет обработчик ECAN0INTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN0INTA_ISR(void); // eCAN-A +/* Объявляет обработчик ECAN1INTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN1INTA_ISR(void); // eCAN-A +/* Объявляет обработчик ECAN0INTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN0INTB_ISR(void); // eCAN-B +/* Объявляет обработчик ECAN1INTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN1INTB_ISR(void); // eCAN-B + +// Group 10 PIE Interrupt Service Routines: + +// Group 11 PIE Interrupt Service Routines: + +// Group 12 PIE Interrupt Service Routines: +/* Объявляет обработчик XINT3_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT3_ISR(void); // External interrupt 3 +/* Объявляет обработчик XINT4_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT4_ISR(void); // External interrupt 4 +/* Объявляет обработчик XINT5_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT5_ISR(void); // External interrupt 5 +/* Объявляет обработчик XINT6_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT6_ISR(void); // External interrupt 6 +/* Объявляет обработчик XINT7_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT7_ISR(void); // External interrupt 7 +/* Объявляет обработчик LVF_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void LVF_ISR(void); // Latched overflow flag +/* Объявляет обработчик LUF_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void LUF_ISR(void); // Latched underflow flag + +// Catch-all for Reserved Locations For testing purposes: +/* Объявляет интерфейс функции PIE_RESERVED; реализация вызывается через этот прототип. */ +interrupt void PIE_RESERVED(void); // Reserved for test +/* Объявляет обработчик rsvd_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void rsvd_ISR(void); // for test +/* Объявляет обработчик INT_NOTUSED_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void INT_NOTUSED_ISR(void); // for unused interrupts + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DEFAULT_ISR_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h new file mode 100644 index 0000000..a327969 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h @@ -0,0 +1,125 @@ +/* Поставляемое TI описание Dma_defines для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: August 14, 2007 16:32:29 $ +//########################################################################### +// +// FILE: DSP2833x_Dma_defines.h +// +// TITLE: #defines used in DMA examples +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DMA_DEFINES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DMA_DEFINES_H +/* Определяет защитный символ или переключатель DSP2833x_DMA_DEFINES_H для последующей компиляции. */ +#define DSP2833x_DMA_DEFINES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +// MODE +//========================== +// PERINTSEL bits +/* Задаёт DMA_SEQ1INT = 1; DMA 1 INT. */ +#define DMA_SEQ1INT 1 +/* Задаёт DMA_SEQ2INT = 2; DMA 2 INT. */ +#define DMA_SEQ2INT 2 +/* Задаёт DMA_XINT1 = 3; DMA 1. */ +#define DMA_XINT1 3 +/* Задаёт DMA_XINT2 = 4; DMA 2. */ +#define DMA_XINT2 4 +/* Задаёт DMA_XINT3 = 5; DMA 3. */ +#define DMA_XINT3 5 +/* Задаёт DMA_XINT4 = 6; DMA 4. */ +#define DMA_XINT4 6 +/* Задаёт DMA_XINT5 = 7; DMA 5. */ +#define DMA_XINT5 7 +/* Задаёт DMA_XINT6 = 8; DMA 6. */ +#define DMA_XINT6 8 +/* Задаёт DMA_XINT7 = 9; DMA 7. */ +#define DMA_XINT7 9 +/* Задаёт DMA_XINT13 = 10; DMA 13. */ +#define DMA_XINT13 10 +/* Задаёт DMA_TINT0 = 11; DMA 0. */ +#define DMA_TINT0 11 +/* Задаёт DMA_TINT1 = 12; DMA 1. */ +#define DMA_TINT1 12 +/* Задаёт DMA_TINT2 = 13; DMA 2. */ +#define DMA_TINT2 13 +/* Задаёт DMA_MXEVTA = 14; DMA MXEVTA. */ +#define DMA_MXEVTA 14 +/* Задаёт DMA_MREVTA = 15; DMA MREVTA. */ +#define DMA_MREVTA 15 +/* Задаёт DMA_MXREVTB = 16; DMA MXREVTB. */ +#define DMA_MXREVTB 16 +/* Задаёт DMA_MREVTB = 17; DMA MREVTB. */ +#define DMA_MREVTB 17 +// OVERINTE bit +/* Задаёт OVRFLOW_DISABLE = 0x0; OVRFLOW запрет. */ +#define OVRFLOW_DISABLE 0x0 +/* Задаёт OVEFLOW_ENABLE = 0x1; OVEFLOW разрешение. */ +#define OVEFLOW_ENABLE 0x1 +// PERINTE bit +/* Задаёт PERINT_DISABLE = 0x0; PERINT запрет. */ +#define PERINT_DISABLE 0x0 +/* Задаёт PERINT_ENABLE = 0x1; PERINT разрешение. */ +#define PERINT_ENABLE 0x1 +// CHINTMODE bits +/* Задаёт CHINT_BEGIN = 0x0; данные CHINT_BEGIN. */ +#define CHINT_BEGIN 0x0 +/* Задаёт CHINT_END = 0x1; данные CHINT_END. */ +#define CHINT_END 0x1 +// ONESHOT bits +/* Задаёт ONESHOT_DISABLE = 0x0; ONESHOT запрет. */ +#define ONESHOT_DISABLE 0x0 +/* Задаёт ONESHOT_ENABLE = 0x1; ONESHOT разрешение. */ +#define ONESHOT_ENABLE 0x1 +// CONTINOUS bit +/* Задаёт CONT_DISABLE = 0x0; CONT запрет. */ +#define CONT_DISABLE 0x0 +/* Задаёт CONT_ENABLE = 0x1; CONT разрешение. */ +#define CONT_ENABLE 0x1 +// SYNCE bit +/* Задаёт SYNC_DISABLE = 0x0; синхронизация запрет. */ +#define SYNC_DISABLE 0x0 +/* Задаёт SYNC_ENABLE = 0x1; синхронизация разрешение. */ +#define SYNC_ENABLE 0x1 +// SYNCSEL bit +/* Задаёт SYNC_SRC = 0x0; синхронизация SRC. */ +#define SYNC_SRC 0x0 +/* Задаёт SYNC_DST = 0x1; синхронизация DST. */ +#define SYNC_DST 0x1 +// DATASIZE bit +/* Задаёт SIXTEEN_BIT = 0x0; SIXTEEN бит. */ +#define SIXTEEN_BIT 0x0 +/* Задаёт THIRTYTWO_BIT = 0x1; THIRTYTWO бит. */ +#define THIRTYTWO_BIT 0x1 +// CHINTE bit +/* Задаёт CHINT_DISABLE = 0x0; CHINT запрет. */ +#define CHINT_DISABLE 0x0 +/* Задаёт CHINT_ENABLE = 0x1; CHINT разрешение. */ +#define CHINT_ENABLE 0x1 + + + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // - end of DSP2833x_EPWM_DEFINES_H + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h new file mode 100644 index 0000000..0084f16 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h @@ -0,0 +1,253 @@ +/* Поставляемое TI описание EPwm_defines для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:45:39 $ +//########################################################################### +// +// FILE: DSP2833x_EPwm_defines.h +// +// TITLE: #defines used in ePWM examples examples +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EPWM_DEFINES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EPWM_DEFINES_H +/* Определяет защитный символ или переключатель DSP2833x_EPWM_DEFINES_H для последующей компиляции. */ +#define DSP2833x_EPWM_DEFINES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +// TBCTL (Time-Base Control) +//========================== +// CTRMODE bits +/* Задаёт TB_COUNT_UP = 0x0; TB число UP. */ +#define TB_COUNT_UP 0x0 +/* Задаёт TB_COUNT_DOWN = 0x1; TB число DOWN. */ +#define TB_COUNT_DOWN 0x1 +/* Задаёт TB_COUNT_UPDOWN = 0x2; TB число UPDOWN. */ +#define TB_COUNT_UPDOWN 0x2 +/* Задаёт TB_FREEZE = 0x3; данные TB_FREEZE. */ +#define TB_FREEZE 0x3 +// PHSEN bit +/* Задаёт TB_DISABLE = 0x0; TB запрет. */ +#define TB_DISABLE 0x0 +/* Задаёт TB_ENABLE = 0x1; TB разрешение. */ +#define TB_ENABLE 0x1 +// PRDLD bit +/* Задаёт TB_SHADOW = 0x0; данные TB_SHADOW. */ +#define TB_SHADOW 0x0 +/* Задаёт TB_IMMEDIATE = 0x1; данные TB_IMMEDIATE. */ +#define TB_IMMEDIATE 0x1 +// SYNCOSEL bits +/* Задаёт TB_SYNC_IN = 0x0; TB синхронизация IN. */ +#define TB_SYNC_IN 0x0 +/* Задаёт TB_CTR_ZERO = 0x1; данные TB_CTR_ZERO. */ +#define TB_CTR_ZERO 0x1 +/* Задаёт TB_CTR_CMPB = 0x2; данные TB_CTR_CMPB. */ +#define TB_CTR_CMPB 0x2 +/* Задаёт TB_SYNC_DISABLE = 0x3; TB синхронизация запрет. */ +#define TB_SYNC_DISABLE 0x3 +// HSPCLKDIV and CLKDIV bits +/* Задаёт TB_DIV1 = 0x0; данные TB_DIV1. */ +#define TB_DIV1 0x0 +/* Задаёт TB_DIV2 = 0x1; данные TB_DIV2. */ +#define TB_DIV2 0x1 +/* Задаёт TB_DIV4 = 0x2; данные TB_DIV4. */ +#define TB_DIV4 0x2 +// PHSDIR bit +/* Задаёт TB_DOWN = 0x0; данные TB_DOWN. */ +#define TB_DOWN 0x0 +/* Задаёт TB_UP = 0x1; данные TB_UP. */ +#define TB_UP 0x1 + +// CMPCTL (Compare Control) +//========================== +// LOADAMODE and LOADBMODE bits +/* Задаёт CC_CTR_ZERO = 0x0; данные CC_CTR_ZERO. */ +#define CC_CTR_ZERO 0x0 +/* Задаёт CC_CTR_PRD = 0x1; данные CC_CTR_PRD. */ +#define CC_CTR_PRD 0x1 +/* Задаёт CC_CTR_ZERO_PRD = 0x2; данные CC_CTR_ZERO_PRD. */ +#define CC_CTR_ZERO_PRD 0x2 +/* Задаёт CC_LD_DISABLE = 0x3; CC LD запрет. */ +#define CC_LD_DISABLE 0x3 +// SHDWAMODE and SHDWBMODE bits +/* Задаёт CC_SHADOW = 0x0; данные CC_SHADOW. */ +#define CC_SHADOW 0x0 +/* Задаёт CC_IMMEDIATE = 0x1; данные CC_IMMEDIATE. */ +#define CC_IMMEDIATE 0x1 + +// AQCTLA and AQCTLB (Action Qualifier Control) +//============================================= +// ZRO, PRD, CAU, CAD, CBU, CBD bits +/* Задаёт AQ_NO_ACTION = 0x0; данные AQ_NO_ACTION. */ +#define AQ_NO_ACTION 0x0 +/* Задаёт AQ_CLEAR = 0x1; AQ очистка. */ +#define AQ_CLEAR 0x1 +/* Задаёт AQ_SET = 0x2; AQ установка. */ +#define AQ_SET 0x2 +/* Задаёт AQ_TOGGLE = 0x3; данные AQ_TOGGLE. */ +#define AQ_TOGGLE 0x3 + +// DBCTL (Dead-Band Control) +//========================== +// OUT MODE bits +/* Задаёт DB_DISABLE = 0x0; DB запрет. */ +#define DB_DISABLE 0x0 +/* Задаёт DBA_ENABLE = 0x1; DBA разрешение. */ +#define DBA_ENABLE 0x1 +/* Задаёт DBB_ENABLE = 0x2; DBB разрешение. */ +#define DBB_ENABLE 0x2 +/* Задаёт DB_FULL_ENABLE = 0x3; DB FULL разрешение. */ +#define DB_FULL_ENABLE 0x3 +// POLSEL bits +/* Задаёт DB_ACTV_HI = 0x0; данные DB_ACTV_HI. */ +#define DB_ACTV_HI 0x0 +/* Задаёт DB_ACTV_LOC = 0x1; данные DB_ACTV_LOC. */ +#define DB_ACTV_LOC 0x1 +/* Задаёт DB_ACTV_HIC = 0x2; данные DB_ACTV_HIC. */ +#define DB_ACTV_HIC 0x2 +/* Задаёт DB_ACTV_LO = 0x3; данные DB_ACTV_LO. */ +#define DB_ACTV_LO 0x3 +// IN MODE +/* Задаёт DBA_ALL = 0x0; данные DBA_ALL. */ +#define DBA_ALL 0x0 +/* Задаёт DBB_RED_DBA_FED = 0x1; данные DBB_RED_DBA_FED. */ +#define DBB_RED_DBA_FED 0x1 +/* Задаёт DBA_RED_DBB_FED = 0x2; данные DBA_RED_DBB_FED. */ +#define DBA_RED_DBB_FED 0x2 +/* Задаёт DBB_ALL = 0x3; данные DBB_ALL. */ +#define DBB_ALL 0x3 + +// CHPCTL (chopper control) +//========================== +// CHPEN bit +/* Задаёт CHP_DISABLE = 0x0; CHP запрет. */ +#define CHP_DISABLE 0x0 +/* Задаёт CHP_ENABLE = 0x1; CHP разрешение. */ +#define CHP_ENABLE 0x1 +// CHPFREQ bits +/* Задаёт CHP_DIV1 = 0x0; данные CHP_DIV1. */ +#define CHP_DIV1 0x0 +/* Задаёт CHP_DIV2 = 0x1; данные CHP_DIV2. */ +#define CHP_DIV2 0x1 +/* Задаёт CHP_DIV3 = 0x2; данные CHP_DIV3. */ +#define CHP_DIV3 0x2 +/* Задаёт CHP_DIV4 = 0x3; данные CHP_DIV4. */ +#define CHP_DIV4 0x3 +/* Задаёт CHP_DIV5 = 0x4; данные CHP_DIV5. */ +#define CHP_DIV5 0x4 +/* Задаёт CHP_DIV6 = 0x5; данные CHP_DIV6. */ +#define CHP_DIV6 0x5 +/* Задаёт CHP_DIV7 = 0x6; данные CHP_DIV7. */ +#define CHP_DIV7 0x6 +/* Задаёт CHP_DIV8 = 0x7; данные CHP_DIV8. */ +#define CHP_DIV8 0x7 +// CHPDUTY bits +/* Задаёт CHP1_8TH = 0x0; данные CHP1_8TH. */ +#define CHP1_8TH 0x0 +/* Задаёт CHP2_8TH = 0x1; данные CHP2_8TH. */ +#define CHP2_8TH 0x1 +/* Задаёт CHP3_8TH = 0x2; данные CHP3_8TH. */ +#define CHP3_8TH 0x2 +/* Задаёт CHP4_8TH = 0x3; данные CHP4_8TH. */ +#define CHP4_8TH 0x3 +/* Задаёт CHP5_8TH = 0x4; данные CHP5_8TH. */ +#define CHP5_8TH 0x4 +/* Задаёт CHP6_8TH = 0x5; данные CHP6_8TH. */ +#define CHP6_8TH 0x5 +/* Задаёт CHP7_8TH = 0x6; данные CHP7_8TH. */ +#define CHP7_8TH 0x6 + +// TZSEL (Trip Zone Select) +//========================== +// CBCn and OSHTn bits +/* Задаёт TZ_DISABLE = 0x0; TZ запрет. */ +#define TZ_DISABLE 0x0 +/* Задаёт TZ_ENABLE = 0x1; TZ разрешение. */ +#define TZ_ENABLE 0x1 + +// TZCTL (Trip Zone Control) +//========================== +// TZA and TZB bits +/* Задаёт TZ_HIZ = 0x0; данные TZ_HIZ. */ +#define TZ_HIZ 0x0 +/* Задаёт TZ_FORCE_HI = 0x1; TZ принудительная установка HI. */ +#define TZ_FORCE_HI 0x1 +/* Задаёт TZ_FORCE_LO = 0x2; TZ принудительная установка LO. */ +#define TZ_FORCE_LO 0x2 +/* Задаёт TZ_NO_CHANGE = 0x3; данные TZ_NO_CHANGE. */ +#define TZ_NO_CHANGE 0x3 + +// ETSEL (Event Trigger Select) +//============================= +/* Задаёт ET_CTR_ZERO = 0x1; данные ET_CTR_ZERO. */ +#define ET_CTR_ZERO 0x1 +/* Задаёт ET_CTR_PRD = 0x2; данные ET_CTR_PRD. */ +#define ET_CTR_PRD 0x2 +/* Задаёт ET_CTRU_CMPA = 0x4; данные ET_CTRU_CMPA. */ +#define ET_CTRU_CMPA 0x4 +/* Задаёт ET_CTRD_CMPA = 0x5; данные ET_CTRD_CMPA. */ +#define ET_CTRD_CMPA 0x5 +/* Задаёт ET_CTRU_CMPB = 0x6; данные ET_CTRU_CMPB. */ +#define ET_CTRU_CMPB 0x6 +/* Задаёт ET_CTRD_CMPB = 0x7; данные ET_CTRD_CMPB. */ +#define ET_CTRD_CMPB 0x7 + +// ETPS (Event Trigger Pre-scale) +//=============================== +// INTPRD, SOCAPRD, SOCBPRD bits +/* Задаёт ET_DISABLE = 0x0; ET запрет. */ +#define ET_DISABLE 0x0 +/* Задаёт ET_1ST = 0x1; данные ET_1ST. */ +#define ET_1ST 0x1 +/* Задаёт ET_2ND = 0x2; данные ET_2ND. */ +#define ET_2ND 0x2 +/* Задаёт ET_3RD = 0x3; данные ET_3RD. */ +#define ET_3RD 0x3 + + +//-------------------------------- +// HRPWM (High Resolution PWM) +//================================ +// HRCNFG +/* Задаёт HR_Disable = 0x0; HR запрет. */ +#define HR_Disable 0x0 +/* Задаёт HR_REP = 0x1; данные HR_REP. */ +#define HR_REP 0x1 +/* Задаёт HR_FEP = 0x2; данные HR_FEP. */ +#define HR_FEP 0x2 +/* Задаёт HR_BEP = 0x3; данные HR_BEP. */ +#define HR_BEP 0x3 + +/* Задаёт HR_CMP = 0x0; данные HR_CMP. */ +#define HR_CMP 0x0 +/* Задаёт HR_PHS = 0x1; данные HR_PHS. */ +#define HR_PHS 0x1 + +/* Задаёт HR_CTR_ZERO = 0x0; данные HR_CTR_ZERO. */ +#define HR_CTR_ZERO 0x0 +/* Задаёт HR_CTR_PRD = 0x1; данные HR_CTR_PRD. */ +#define HR_CTR_PRD 0x1 + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // - end of DSP2833x_EPWM_DEFINES_H + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h new file mode 100644 index 0000000..eaa6500 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h @@ -0,0 +1,176 @@ +/* Поставляемое TI описание Examples для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/9 $ +// Checkin $Date: July 2, 2008 14:31:12 $ +//########################################################################### +// +// FILE: DSP2833x_Examples.h +// +// TITLE: DSP2833x Device Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EXAMPLES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EXAMPLES_H +/* Определяет защитный символ или переключатель DSP2833x_EXAMPLES_H для последующей компиляции. */ +#define DSP2833x_EXAMPLES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +/*----------------------------------------------------------------------------- + Specify the PLL control register (PLLCR) and divide select (DIVSEL) value. +-----------------------------------------------------------------------------*/ +//#define DSP28_DIVSEL 0 // Enable /4 for SYSCLKOUT +//#define DSP28_DIVSEL 1 // Enable /4 for SYSCKOUT +/* Задаёт DSP28_DIVSEL = 2; данные DSP28_DIVSEL. */ +#define DSP28_DIVSEL 2 // Enable /2 for SYSCLKOUT +//#define DSP28_DIVSEL 3 // Enable /1 for SYSCLKOUT + +/* Задаёт DSP28_PLLCR = CLKMULT*2; данные DSP28_PLLCR. */ +#define DSP28_PLLCR CLKMULT*2 + +//#define DSP28_PLLCR 10 +//#define DSP28_PLLCR 9 +//#define DSP28_PLLCR 8 +//#define DSP28_PLLCR 7 +//#define DSP28_PLLCR 6 +//#define DSP28_PLLCR 5 +//#define DSP28_PLLCR 4 +//#define DSP28_PLLCR 3 +//#define DSP28_PLLCR 2 +//#define DSP28_PLLCR 1 +//#define DSP28_PLLCR 0 // PLL is bypassed in this mode +//---------------------------------------------------------------------------- + + +/*----------------------------------------------------------------------------- + Specify the clock rate of the CPU (SYSCLKOUT) in nS. + + Take into account the input clock frequency and the PLL multiplier + selected in step 1. + + Use one of the values provided, or define your own. + The trailing L is required tells the compiler to treat + the number as a 64-bit value. + + Only one statement should be uncommented. + + Example 1:150 MHz devices: + CLKIN is a 30MHz crystal. + + In step 1 the user specified PLLCR = 0xA for a + 150Mhz CPU clock (SYSCLKOUT = 150MHz). + + In this case, the CPU_RATE will be 6.667L + Uncomment the line: #define CPU_RATE 6.667L + + Example 2: 100 MHz devices: + CLKIN is a 20MHz crystal. + + In step 1 the user specified PLLCR = 0xA for a + 100Mhz CPU clock (SYSCLKOUT = 100MHz). + + In this case, the CPU_RATE will be 10.000L + Uncomment the line: #define CPU_RATE 10.000L +-----------------------------------------------------------------------------*/ +/* Задаёт CPU_RATE = 6.667L; данные CPU_RATE. */ +#define CPU_RATE 6.667L // for a 150MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 7.143L // for a 140MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 8.333L // for a 120MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 10.000L // for a 100MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 13.330L // for a 75MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 20.000L // for a 50MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 33.333L // for a 30MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 41.667L // for a 24MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 50.000L // for a 20MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 66.667L // for a 15MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 100.000L // for a 10MHz CPU clock speed (SYSCLKOUT) + +//---------------------------------------------------------------------------- + +/*----------------------------------------------------------------------------- + Target device (in DSP2833x_Device.h) determines CPU frequency + (for examples) - either 150 MHz (for 28335 and 28334) or 100 MHz + (for 28332). User does not have to change anything here. +-----------------------------------------------------------------------------*/ +/* Условие компиляции DSP28_28332: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28332 // DSP28_28332 device only + /* Задаёт CPU_FRQ_100MHZ = 1; данные CPU_FRQ_100MHZ. */ + #define CPU_FRQ_100MHZ 1 // 100 Mhz CPU Freq (20 MHz input freq) + /* Задаёт CPU_FRQ_150MHZ = 0; данные CPU_FRQ_150MHZ. */ + #define CPU_FRQ_150MHZ 0 +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else + /* Задаёт CPU_FRQ_100MHZ = 0; данные CPU_FRQ_100MHZ. */ + #define CPU_FRQ_100MHZ 0 // DSP28_28335||DSP28_28334 + /* Задаёт CPU_FRQ_150MHZ = 1; данные CPU_FRQ_150MHZ. */ + #define CPU_FRQ_150MHZ 1 // 150 MHz CPU Freq (30 MHz input freq) by DEFAULT +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// Include Example Header Files: +// + +/* Подключает "DSP2833x_GlobalPrototypes.h": поставляемое TI описание GlobalPrototypes для семейства C2833x. */ +#include "DSP2833x_GlobalPrototypes.h" // Prototypes for global functions within the + // .c files. + +/* Подключает "DSP2833x_ePwm_defines.h": поставляемое TI описание ePwm_defines для семейства C2833x. */ +#include "DSP2833x_ePwm_defines.h" // Macros used for PWM examples. +/* Подключает "DSP2833x_Dma_defines.h": поставляемое TI описание Dma_defines для семейства C2833x. */ +#include "DSP2833x_Dma_defines.h" // Macros used for DMA examples. +/* Подключает "DSP2833x_I2C_defines.h": поставляемое TI описание I2C_defines для семейства C2833x. */ +#include "DSP2833x_I2C_defines.h" // Macros used for I2C examples. + +/* Задаёт PARTNO_28335 = 0xEF; данные PARTNO_28335. */ +#define PARTNO_28335 0xEF +/* Задаёт PARTNO_28334 = 0xEE; данные PARTNO_28334. */ +#define PARTNO_28334 0xEE +/* Задаёт PARTNO_28332 = 0xED; данные PARTNO_28332. */ +#define PARTNO_28332 0xED +/* Задаёт PARTNO_28235 = 0xE8; данные PARTNO_28235. */ +#define PARTNO_28235 0xE8 +/* Задаёт PARTNO_28234 = 0xE7; данные PARTNO_28234. */ +#define PARTNO_28234 0xE7 +/* Задаёт PARTNO_28232 = 0xE6; данные PARTNO_28232. */ +#define PARTNO_28232 0xE6 + + +// Include files not used with DSP/BIOS +/* Начинает условие: DSP28_BIOS ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP28_BIOS +/* Подключает "DSP2833x_DefaultISR.h": поставляемое TI описание DefaultISR для семейства C2833x. */ +#include "DSP2833x_DefaultISR.h" +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +// DO NOT MODIFY THIS LINE. +/* Задаёт DELAY_US = DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L); данные DELAY_US. */ +#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L) + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_EXAMPLES_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h new file mode 100644 index 0000000..4cd293d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h @@ -0,0 +1,363 @@ +/* Поставляемое TI описание GlobalPrototypes для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/11 $ +// Checkin $Date: May 12, 2008 14:30:08 $ +//########################################################################### +// +// FILE: DSP2833x_GlobalPrototypes.h +// +// TITLE: Global prototypes for DSP2833x Examples +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_GLOBALPROTOTYPES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_GLOBALPROTOTYPES_H +/* Определяет защитный символ или переключатель DSP2833x_GLOBALPROTOTYPES_H для последующей компиляции. */ +#define DSP2833x_GLOBALPROTOTYPES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/*---- shared global function prototypes -----------------------------------*/ +/* Объявляет интерфейс функции InitAdc; реализация вызывается через этот прототип. */ +extern void InitAdc(void); + +/* Объявляет интерфейс функции DMAInitialize; реализация вызывается через этот прототип. */ +extern void DMAInitialize(void); +// DMA Channel 1 +/* Объявляет интерфейс функции DMACH1AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH1AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH1BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH1BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH1TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH1TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH1WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH1WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH1ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH1ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH1; реализация вызывается через этот прототип. */ +extern void StartDMACH1(void); +// DMA Channel 2 +/* Объявляет интерфейс функции DMACH2AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH2AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH2BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH2BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH2TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH2TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH2WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH2WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH2ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH2ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH2; реализация вызывается через этот прототип. */ +extern void StartDMACH2(void); +// DMA Channel 3 +/* Объявляет интерфейс функции DMACH3AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH3AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH3BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH3BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH3TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH3TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH3WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH3WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH3ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH3ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH3; реализация вызывается через этот прототип. */ +extern void StartDMACH3(void); +// DMA Channel 4 +/* Объявляет интерфейс функции DMACH4AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH4AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH4BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH4BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH4TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH4TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH4WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH4WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH4ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH4ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH4; реализация вызывается через этот прототип. */ +extern void StartDMACH4(void); +// DMA Channel 5 +/* Объявляет интерфейс функции DMACH5AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH5AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH5BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH5BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH5TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH5TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH5WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH5WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH5ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH5ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH5; реализация вызывается через этот прототип. */ +extern void StartDMACH5(void); +// DMA Channel 6 +/* Объявляет интерфейс функции DMACH6AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH6AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH6BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH6BurstConfig(Uint16 bsize,Uint16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH6TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH6TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH6WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH6WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH6ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH6ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH6; реализация вызывается через этот прототип. */ +extern void StartDMACH6(void); + +/* Объявляет интерфейс функции InitPeripherals; реализация вызывается через этот прототип. */ +extern void InitPeripherals(void); +/* Условие компиляции DSP28_ECANA: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECANA +/* Объявляет интерфейс функции InitECan; реализация вызывается через этот прототип. */ +extern void InitECan(void); +/* Объявляет интерфейс функции InitECana; реализация вызывается через этот прототип. */ +extern void InitECana(void); +/* Объявляет интерфейс функции InitECanGpio; реализация вызывается через этот прототип. */ +extern void InitECanGpio(void); +/* Объявляет интерфейс функции InitECanaGpio; реализация вызывается через этот прототип. */ +extern void InitECanaGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECANA +/* Условие компиляции DSP28_ECANB: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECANB +/* Объявляет интерфейс функции InitECanb; реализация вызывается через этот прототип. */ +extern void InitECanb(void); +/* Объявляет интерфейс функции InitECanbGpio; реализация вызывается через этот прототип. */ +extern void InitECanbGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECANB +/* Объявляет интерфейс функции InitECap; реализация вызывается через этот прототип. */ +extern void InitECap(void); +/* Объявляет интерфейс функции InitECapGpio; реализация вызывается через этот прототип. */ +extern void InitECapGpio(void); +/* Объявляет интерфейс функции InitECap1Gpio; реализация вызывается через этот прототип. */ +extern void InitECap1Gpio(void); +/* Объявляет интерфейс функции InitECap2Gpio; реализация вызывается через этот прототип. */ +extern void InitECap2Gpio(void); +/* Условие компиляции DSP28_ECAP3: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP3 +/* Объявляет интерфейс функции InitECap3Gpio; реализация вызывается через этот прототип. */ +extern void InitECap3Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP3 +/* Условие компиляции DSP28_ECAP4: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP4 +/* Объявляет интерфейс функции InitECap4Gpio; реализация вызывается через этот прототип. */ +extern void InitECap4Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP4 +/* Условие компиляции DSP28_ECAP5: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP5 +/* Объявляет интерфейс функции InitECap5Gpio; реализация вызывается через этот прототип. */ +extern void InitECap5Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP5 +/* Условие компиляции DSP28_ECAP6: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP6 +/* Объявляет интерфейс функции InitECap6Gpio; реализация вызывается через этот прототип. */ +extern void InitECap6Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP6 +/* Объявляет интерфейс функции InitEPwm; реализация вызывается через этот прототип. */ +extern void InitEPwm(void); +/* Объявляет интерфейс функции InitEPwmGpio; реализация вызывается через этот прототип. */ +extern void InitEPwmGpio(void); +/* Объявляет интерфейс функции InitEPwm1Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm1Gpio(void); +/* Объявляет интерфейс функции InitEPwm2Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm2Gpio(void); +/* Объявляет интерфейс функции InitEPwm3Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm3Gpio(void); +/* Условие компиляции DSP28_EPWM4: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EPWM4 +/* Объявляет интерфейс функции InitEPwm4Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm4Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EPWM4 +/* Условие компиляции DSP28_EPWM5: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EPWM5 +/* Объявляет интерфейс функции InitEPwm5Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm5Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EPWM5 +/* Условие компиляции DSP28_EPWM6: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EPWM6 +/* Объявляет интерфейс функции InitEPwm6Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm6Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EPWM6 +/* Условие компиляции DSP28_EQEP1: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EQEP1 +/* Объявляет интерфейс функции InitEQep; реализация вызывается через этот прототип. */ +extern void InitEQep(void); +/* Объявляет интерфейс функции InitEQepGpio; реализация вызывается через этот прототип. */ +extern void InitEQepGpio(void); +/* Объявляет интерфейс функции InitEQep1Gpio; реализация вызывается через этот прототип. */ +extern void InitEQep1Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // if DSP28_EQEP1 +/* Условие компиляции DSP28_EQEP2: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EQEP2 +/* Объявляет интерфейс функции InitEQep2Gpio; реализация вызывается через этот прототип. */ +extern void InitEQep2Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EQEP2 +/* Объявляет интерфейс функции InitGpio; реализация вызывается через этот прототип. */ +extern void InitGpio(void); +/* Объявляет интерфейс функции InitI2CGpio; реализация вызывается через этот прототип. */ +extern void InitI2CGpio(void); + +/* Объявляет интерфейс функции InitMcbsp; реализация вызывается через этот прототип. */ +extern void InitMcbsp(void); +/* Объявляет интерфейс функции InitMcbspa; реализация вызывается через этот прототип. */ +extern void InitMcbspa(void); +/* Объявляет интерфейс функции delay_loop; реализация вызывается через этот прототип. */ +extern void delay_loop(void); +/* Объявляет интерфейс функции InitMcbspaGpio; реализация вызывается через этот прототип. */ +extern void InitMcbspaGpio(void); +/* Объявляет интерфейс функции InitMcbspa8bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa8bit(void); +/* Объявляет интерфейс функции InitMcbspa12bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa12bit(void); +/* Объявляет интерфейс функции InitMcbspa16bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa16bit(void); +/* Объявляет интерфейс функции InitMcbspa20bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa20bit(void); +/* Объявляет интерфейс функции InitMcbspa24bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa24bit(void); +/* Объявляет интерфейс функции InitMcbspa32bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa32bit(void); +/* Условие компиляции DSP28_MCBSPB: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_MCBSPB +/* Объявляет интерфейс функции InitMcbspb; реализация вызывается через этот прототип. */ +extern void InitMcbspb(void); +/* Объявляет интерфейс функции InitMcbspbGpio; реализация вызывается через этот прототип. */ +extern void InitMcbspbGpio(void); +/* Объявляет интерфейс функции InitMcbspb8bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb8bit(void); +/* Объявляет интерфейс функции InitMcbspb12bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb12bit(void); +/* Объявляет интерфейс функции InitMcbspb16bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb16bit(void); +/* Объявляет интерфейс функции InitMcbspb20bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb20bit(void); +/* Объявляет интерфейс функции InitMcbspb24bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb24bit(void); +/* Объявляет интерфейс функции InitMcbspb32bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb32bit(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_MCBSPB + +/* Объявляет интерфейс функции InitPieCtrl; реализация вызывается через этот прототип. */ +extern void InitPieCtrl(void); +/* Объявляет интерфейс функции InitPieVectTable; реализация вызывается через этот прототип. */ +extern void InitPieVectTable(void); + +/* Объявляет интерфейс функции InitSci; реализация вызывается через этот прототип. */ +extern void InitSci(void); +/* Объявляет интерфейс функции InitSciGpio; реализация вызывается через этот прототип. */ +extern void InitSciGpio(void); +/* Объявляет интерфейс функции InitSciaGpio; реализация вызывается через этот прототип. */ +extern void InitSciaGpio(void); +/* Условие компиляции DSP28_SCIB: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_SCIB +/* Объявляет интерфейс функции InitScibGpio; реализация вызывается через этот прототип. */ +extern void InitScibGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_SCIB +/* Условие компиляции DSP28_SCIC: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_SCIC +/* Объявляет интерфейс функции InitScicGpio; реализация вызывается через этот прототип. */ +extern void InitScicGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Объявляет интерфейс функции InitSpi; реализация вызывается через этот прототип. */ +extern void InitSpi(void); +/* Объявляет интерфейс функции InitSpiGpio; реализация вызывается через этот прототип. */ +extern void InitSpiGpio(void); +/* Объявляет интерфейс функции InitSpiaGpio; реализация вызывается через этот прототип. */ +extern void InitSpiaGpio(void); +/* Объявляет интерфейс функции InitSysCtrl; реализация вызывается через этот прототип. */ +extern void InitSysCtrl(void); +/* Объявляет интерфейс функции InitTzGpio; реализация вызывается через этот прототип. */ +extern void InitTzGpio(void); +/* Объявляет интерфейс функции InitXIntrupt; реализация вызывается через этот прототип. */ +extern void InitXIntrupt(void); +/* Объявляет интерфейс функции XintfInit; реализация вызывается через этот прототип. */ +extern void XintfInit(void); +/* Объявляет интерфейс функции InitXintf16Gpio; реализация вызывается через этот прототип. */ +extern void InitXintf16Gpio(); +/* Объявляет интерфейс функции InitXintf32Gpio; реализация вызывается через этот прототип. */ +extern void InitXintf32Gpio(); +/* Объявляет интерфейс функции InitPll; реализация вызывается через этот прототип. */ +extern void InitPll(Uint16 pllcr, Uint16 clkindiv); +/* Объявляет интерфейс функции InitPeripheralClocks; реализация вызывается через этот прототип. */ +extern void InitPeripheralClocks(void); +/* Объявляет интерфейс функции EnableInterrupts; реализация вызывается через этот прототип. */ +extern void EnableInterrupts(void); +/* Объявляет интерфейс функции DSP28x_usDelay; реализация вызывается через этот прототип. */ +extern void DSP28x_usDelay(Uint32 Count); +/* Объявляет интерфейс функции ADC_cal; реализация вызывается через этот прототип. */ +extern void ADC_cal (void); +/* Задаёт KickDog = ServiceDog; данные KickDog. */ +#define KickDog ServiceDog // For compatiblity with previous versions +/* Объявляет интерфейс функции ServiceDog; реализация вызывается через этот прототип. */ +extern void ServiceDog(void); +/* Объявляет интерфейс функции DisableDog; реализация вызывается через этот прототип. */ +extern void DisableDog(void); +/* Объявляет интерфейс функции CsmUnlock; реализация вызывается через этот прототип. */ +extern Uint16 CsmUnlock(void); + +// DSP28_DBGIER.asm +/* Объявляет интерфейс функции SetDBGIER; реализация вызывается через этот прототип. */ +extern void SetDBGIER(Uint16 dbgier); + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results +/* Объявляет интерфейс функции InitFlash; реализация вызывается через этот прототип. */ +extern void InitFlash(void); + + +/* Объявляет интерфейс функции MemCopy; реализация вызывается через этот прототип. */ +void MemCopy(Uint16 *SourceAddr, Uint16* SourceEndAddr, Uint16* DestAddr); + + +//--------------------------------------------------------------------------- +// External symbols created by the linker cmd file +// DSP28 examples will use these to relocate code from one LOAD location +// in either Flash or XINTF to a different RUN location in internal +// RAM +/* Объявляет RamfuncsLoadStart — данные RamfuncsLoadStart. Память определена в другом модуле. */ +extern Uint16 RamfuncsLoadStart; +/* Объявляет RamfuncsLoadEnd — данные RamfuncsLoadEnd. Память определена в другом модуле. */ +extern Uint16 RamfuncsLoadEnd; +/* Объявляет RamfuncsRunStart — данные RamfuncsRunStart. Память определена в другом модуле. */ +extern Uint16 RamfuncsRunStart; + +/* Объявляет XintffuncsLoadStart — данные XintffuncsLoadStart. Память определена в другом модуле. */ +extern Uint16 XintffuncsLoadStart; +/* Объявляет XintffuncsLoadEnd — данные XintffuncsLoadEnd. Память определена в другом модуле. */ +extern Uint16 XintffuncsLoadEnd; +/* Объявляет XintffuncsRunStart — данные XintffuncsRunStart. Память определена в другом модуле. */ +extern Uint16 XintffuncsRunStart; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // - end of DSP2833x_GLOBALPROTOTYPES_H + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h new file mode 100644 index 0000000..6dfd58d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h @@ -0,0 +1,176 @@ +/* Поставляемое TI описание I2c_defines для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 16, 2008 17:16:47 $ +//########################################################################### +// +// FILE: DSP2833x_I2cExample.h +// +// TITLE: 2833x I2C Example Code Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_I2C_DEFINES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_I2C_DEFINES_H +/* Определяет защитный символ или переключатель DSP2833x_I2C_DEFINES_H для последующей компиляции. */ +#define DSP2833x_I2C_DEFINES_H + +//-------------------------------------------- +// Defines +//-------------------------------------------- + +// Error Messages +/* Задаёт I2C_ERROR = 0xFFFF; 2 C ошибка. */ +#define I2C_ERROR 0xFFFF +/* Задаёт I2C_ARB_LOST_ERROR = 0x0001; 2 C ARB LOST ошибка. */ +#define I2C_ARB_LOST_ERROR 0x0001 +/* Задаёт I2C_NACK_ERROR = 0x0002; 2 C NACK ошибка. */ +#define I2C_NACK_ERROR 0x0002 +/* Задаёт I2C_BUS_BUSY_ERROR = 0x1000; 2 C BUS BUSY ошибка. */ +#define I2C_BUS_BUSY_ERROR 0x1000 +/* Задаёт I2C_STP_NOT_READY_ERROR = 0x5555; 2 C STP NOT READY ошибка. */ +#define I2C_STP_NOT_READY_ERROR 0x5555 +/* Задаёт I2C_NO_FLAGS = 0xAAAA; 2 C NO флаги. */ +#define I2C_NO_FLAGS 0xAAAA +/* Задаёт I2C_SUCCESS = 0x0000; данные I2C_SUCCESS. */ +#define I2C_SUCCESS 0x0000 + +// Clear Status Flags +/* Задаёт I2C_CLR_AL_BIT = 0x0001; 2 C CLR AL бит. */ +#define I2C_CLR_AL_BIT 0x0001 +/* Задаёт I2C_CLR_NACK_BIT = 0x0002; 2 C CLR NACK бит. */ +#define I2C_CLR_NACK_BIT 0x0002 +/* Задаёт I2C_CLR_ARDY_BIT = 0x0004; 2 C CLR ARDY бит. */ +#define I2C_CLR_ARDY_BIT 0x0004 +/* Задаёт I2C_CLR_RRDY_BIT = 0x0008; 2 C CLR RRDY бит. */ +#define I2C_CLR_RRDY_BIT 0x0008 +/* Задаёт I2C_CLR_SCD_BIT = 0x0020; 2 C CLR SCD бит. */ +#define I2C_CLR_SCD_BIT 0x0020 + +// Interrupt Source Messages +/* Задаёт I2C_NO_ISRC = 0x0000; данные I2C_NO_ISRC. */ +#define I2C_NO_ISRC 0x0000 +/* Задаёт I2C_ARB_ISRC = 0x0001; данные I2C_ARB_ISRC. */ +#define I2C_ARB_ISRC 0x0001 +/* Задаёт I2C_NACK_ISRC = 0x0002; данные I2C_NACK_ISRC. */ +#define I2C_NACK_ISRC 0x0002 +/* Задаёт I2C_ARDY_ISRC = 0x0003; данные I2C_ARDY_ISRC. */ +#define I2C_ARDY_ISRC 0x0003 +/* Задаёт I2C_RX_ISRC = 0x0004; данные I2C_RX_ISRC. */ +#define I2C_RX_ISRC 0x0004 +/* Задаёт I2C_TX_ISRC = 0x0005; данные I2C_TX_ISRC. */ +#define I2C_TX_ISRC 0x0005 +/* Задаёт I2C_SCD_ISRC = 0x0006; данные I2C_SCD_ISRC. */ +#define I2C_SCD_ISRC 0x0006 +/* Задаёт I2C_AAS_ISRC = 0x0007; данные I2C_AAS_ISRC. */ +#define I2C_AAS_ISRC 0x0007 + +// I2CMSG structure defines +/* Задаёт I2C_NO_STOP = 0; данные I2C_NO_STOP. */ +#define I2C_NO_STOP 0 +/* Задаёт I2C_YES_STOP = 1; данные I2C_YES_STOP. */ +#define I2C_YES_STOP 1 +/* Задаёт I2C_RECEIVE = 0; 2 C приём. */ +#define I2C_RECEIVE 0 +/* Задаёт I2C_TRANSMIT = 1; 2 C передача. */ +#define I2C_TRANSMIT 1 +/* Задаёт I2C_MAX_BUFFER_SIZE = 16; 2 C MAX буфер размер. */ +#define I2C_MAX_BUFFER_SIZE 16 + +// I2C Slave State defines +/* Задаёт I2C_NOTSLAVE = 0; данные I2C_NOTSLAVE. */ +#define I2C_NOTSLAVE 0 +/* Задаёт I2C_ADDR_AS_SLAVE = 1; данные I2C_ADDR_AS_SLAVE. */ +#define I2C_ADDR_AS_SLAVE 1 +/* Задаёт I2C_ST_MSG_READY = 2; данные I2C_ST_MSG_READY. */ +#define I2C_ST_MSG_READY 2 + +// I2C Slave Receiver messages defines +/* Задаёт I2C_SND_MSG1 = 1; данные I2C_SND_MSG1. */ +#define I2C_SND_MSG1 1 +/* Задаёт I2C_SND_MSG2 = 2; данные I2C_SND_MSG2. */ +#define I2C_SND_MSG2 2 + +// I2C State defines +/* Задаёт I2C_IDLE = 0; данные I2C_IDLE. */ +#define I2C_IDLE 0 +/* Задаёт I2C_SLAVE_RECEIVER = 1; данные I2C_SLAVE_RECEIVER. */ +#define I2C_SLAVE_RECEIVER 1 +/* Задаёт I2C_SLAVE_TRANSMITTER = 2; данные I2C_SLAVE_TRANSMITTER. */ +#define I2C_SLAVE_TRANSMITTER 2 +/* Задаёт I2C_MASTER_RECEIVER = 3; данные I2C_MASTER_RECEIVER. */ +#define I2C_MASTER_RECEIVER 3 +/* Задаёт I2C_MASTER_TRANSMITTER = 4; данные I2C_MASTER_TRANSMITTER. */ +#define I2C_MASTER_TRANSMITTER 4 + +// I2C Message Commands for I2CMSG struct +/* Задаёт I2C_MSGSTAT_INACTIVE = 0x0000; данные I2C_MSGSTAT_INACTIVE. */ +#define I2C_MSGSTAT_INACTIVE 0x0000 +/* Задаёт I2C_MSGSTAT_SEND_WITHSTOP = 0x0010; данные I2C_MSGSTAT_SEND_WITHSTOP. */ +#define I2C_MSGSTAT_SEND_WITHSTOP 0x0010 +/* Задаёт I2C_MSGSTAT_WRITE_BUSY = 0x0011; 2 C MSGSTAT запись BUSY. */ +#define I2C_MSGSTAT_WRITE_BUSY 0x0011 +/* Задаёт I2C_MSGSTAT_SEND_NOSTOP = 0x0020; данные I2C_MSGSTAT_SEND_NOSTOP. */ +#define I2C_MSGSTAT_SEND_NOSTOP 0x0020 +/* Задаёт I2C_MSGSTAT_SEND_NOSTOP_BUSY = 0x0021; данные I2C_MSGSTAT_SEND_NOSTOP_BUSY. */ +#define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021 +/* Задаёт I2C_MSGSTAT_RESTART = 0x0022; данные I2C_MSGSTAT_RESTART. */ +#define I2C_MSGSTAT_RESTART 0x0022 +/* Задаёт I2C_MSGSTAT_READ_BUSY = 0x0023; 2 C MSGSTAT чтение BUSY. */ +#define I2C_MSGSTAT_READ_BUSY 0x0023 + +// Generic defines +/* Задаёт I2C_TRUE = 1; данные I2C_TRUE. */ +#define I2C_TRUE 1 +/* Задаёт I2C_FALSE = 0; данные I2C_FALSE. */ +#define I2C_FALSE 0 +/* Задаёт I2C_YES = 1; данные I2C_YES. */ +#define I2C_YES 1 +/* Задаёт I2C_NO = 0; данные I2C_NO. */ +#define I2C_NO 0 +/* Задаёт I2C_DUMMY_BYTE = 0; данные I2C_DUMMY_BYTE. */ +#define I2C_DUMMY_BYTE 0 + + +//-------------------------------------------- +// Structures +//-------------------------------------------- + +// I2C Message Structure +/* Описывает структуру I2CMSG; порядок полей определяет расположение данных. */ +struct I2CMSG { + /* Объявляет MsgStatus — Msg состояние. */ + Uint16 MsgStatus; // Word stating what state msg is in: + // I2C_MSGCMD_INACTIVE = do not send msg + // I2C_MSGCMD_BUSY = msg start has been sent, + // awaiting stop + // I2C_MSGCMD_SEND_WITHSTOP = command to send + // master trans msg complete with a stop bit + // I2C_MSGCMD_SEND_NOSTOP = command to send + // master trans msg without the stop bit + // I2C_MSGCMD_RESTART = command to send a restart + // as a master receiver with a stop bit + /* Объявляет SlaveAddress — Slave адрес. */ + Uint16 SlaveAddress; // I2C address of slave msg is intended for + /* Объявляет NumOfBytes — данные NumOfBytes. */ + Uint16 NumOfBytes; // Num of valid bytes in (or to be put in MsgBuffer) + /* Объявляет MemoryHighAddr — данные MemoryHighAddr. */ + Uint16 MemoryHighAddr; // EEPROM address of data associated with msg (high byte) + /* Объявляет MemoryLowAddr — данные MemoryLowAddr. */ + Uint16 MemoryLowAddr; // EEPROM address of data associated with msg (low byte) + /* Объявляет MsgBuffer — Msg буфер. */ + Uint16 MsgBuffer[I2C_MAX_BUFFER_SIZE]; // Array holding msg data - max that + // MAX_BUFFER_SIZE can be is 16 due to + // the FIFO's +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_I2C_DEFINES_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h new file mode 100644 index 0000000..67fb657 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h @@ -0,0 +1,10803 @@ +/* Поставляемое TI описание SWPrioritizedIsrLevels для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 4, 2007 14:25:21 $ +//########################################################################### +// +// FILE: DSP2833x_SWPrioritizedIsrLevels.h +// +// TITLE: DSP28 Devices Software Prioritized Interrupt Service Routine +// Level definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SW_PRIORITZIED_ISR_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SW_PRIORITZIED_ISR_H +/* Определяет защитный символ или переключатель DSP2833x_SW_PRIORITZIED_ISR_H для последующей компиляции. */ +#define DSP2833x_SW_PRIORITZIED_ISR_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//------------------------------------------------------------------------------- +// Interrupt Enable Register Allocation For 2833x Devices: +//------------------------------------------------------------------------------- +// Interrupts can be enabled/disabled using the CPU interrupt enable register +// (IER) and the PIE interrupt enable registers (PIEIER1 to PIEIER12). +//------------------------------------------------------------------------------- +//------------------------------------------------------------------------------- +// Set "Global" Interrupt Priority Level (IER register): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the CPU +// interrupts. This is termed as the "global" priority. The priority level +// must be a number between 1 (highest) to 16 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used. +// +// Note: The priority levels below are used to calculate the IER register +// interrupt masks MINT1 to MINT16. +// +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 16 = lowest priority +/* Задаёт INT1PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT1PL 2 // Group1 Interrupts (PIEIER1) +/* Задаёт INT2PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT2PL 0 // Group2 Interrupts (PIEIER2) +/* Задаёт INT3PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT3PL 4 // Group3 Interrupts (PIEIER3) +/* Задаёт INT4PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT4PL 2 // Group4 Interrupts (PIEIER4) +/* Задаёт INT5PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT5PL 2 // Group5 Interrupts (PIEIER5) +/* Задаёт INT6PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT6PL 3 // Group6 Interrupts (PIEIER6) +/* Задаёт INT7PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT7PL 0 // reserved +/* Задаёт INT8PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT8PL 0 // reserved +/* Задаёт INT9PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT9PL 1 // Group9 Interrupts (PIEIER9) +/* Задаёт INT10PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT10PL 0 // reserved +/* Задаёт INT11PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT11PL 0 // reserved +/* Задаёт INT12PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT12PL 0 // reserved +/* Задаёт INT13PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT13PL 4 // XINT13 +/* Задаёт INT14PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT14PL 4 // INT14 (TINT2) +/* Задаёт INT15PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT15PL 4 // DATALOG +/* Задаёт INT16PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT16PL 4 // RTOSINT + +//------------------------------------------------------------------------------- +// Set "Group" Interrupt Priority Level (PIEIER1 to PIEIER12 registers): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the PIE +// interrupts. This is termed as the "group" priority. The priority level +// must be a number between 1 (highest) to 8 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used: +// +// Note: The priority levels below are used to calculate the following +// PIEIER register interrupt masks: +// MG11 to MG18 +// MG21 to MG28 +// MG31 to MG38 +// MG41 to MG48 +// MG51 to MG58 +// MG61 to MG68 +// MG71 to MG78 +// MG81 to MG88 +// MG91 to MG98 +// MG101 to MG108 +// MG111 to MG118 +// MG121 to MG128 +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 8 = lowest priority +// +/* Задаёт G11PL = 7; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G11PL 7 // SEQ1INT (ADC) +/* Задаёт G12PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G12PL 6 // SEQ2INT (ADC) +/* Задаёт G13PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G13PL 0 // reserved +/* Задаёт G14PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G14PL 1 // XINT1 (External) +/* Задаёт G15PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G15PL 3 // XINT2 (External) +/* Задаёт G16PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G16PL 2 // ADCINT (ADC) +/* Задаёт G17PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G17PL 1 // TINT0 (CPU Timer 0) +/* Задаёт G18PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G18PL 5 // WAKEINT (WD/LPM) + +/* Задаёт G21PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G21PL 4 // EPWM1_TZINT (ePWM1 Trip) +/* Задаёт G22PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G22PL 3 // EPWM2_TZINT (ePWM2 Trip) +/* Задаёт G23PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G23PL 2 // EPWM3_TZINT (ePWM3 Trip) +/* Задаёт G24PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G24PL 1 // EPWM4_TZINT (ePWM4 Trip) +/* Задаёт G25PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G25PL 5 // EPWM5_TZINT (ePWM5 Trip) +/* Задаёт G26PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G26PL 6 // EPWM6_TZINT (ePWM6 Trip) +/* Задаёт G27PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G27PL 0 // reserved +/* Задаёт G28PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G28PL 0 // reserved + +/* Задаёт G31PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G31PL 4 // EPWM1_INT (ePWM1 Int) +/* Задаёт G32PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G32PL 1 // EPWM2_INT (ePWM2 Int) +/* Задаёт G33PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G33PL 1 // EPWM3_INT (ePWM3 Int) +/* Задаёт G34PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G34PL 2 // EPWM4_INT (ePWM4 Int) +/* Задаёт G35PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G35PL 2 // EPWM5_INT (ePWM5 Int) +/* Задаёт G36PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G36PL 1 // EPWM6_INT (ePWM6 Int) +/* Задаёт G37PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G37PL 0 // reserved +/* Задаёт G38PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G38PL 0 // reserved + +/* Задаёт G41PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G41PL 2 // ECAP1_INT (eCAP1 Int) +/* Задаёт G42PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G42PL 1 // ECAP2_INT (eCAP2 Int) +/* Задаёт G43PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G43PL 3 // ECAP3_INT (eCAP3 Int) +/* Задаёт G44PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G44PL 3 // ECAP4_INT (eCAP4 Int) +/* Задаёт G45PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G45PL 5 // ECAP5_INT (eCAP5 Int) +/* Задаёт G46PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G46PL 5 // ECAP6_INT (eCAP6 Int) +/* Задаёт G47PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G47PL 0 // reserved +/* Задаёт G48PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G48PL 0 // reserved + +/* Задаёт G51PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G51PL 2 // EQEP1_INT (eQEP1 Int) +/* Задаёт G52PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G52PL 1 // EQEP2_INT (eQEP2 Int) +/* Задаёт G53PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G53PL 0 // reserved +/* Задаёт G54PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G54PL 0 // reserved +/* Задаёт G55PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G55PL 0 // reserved +/* Задаёт G56PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G56PL 0 // reserved +/* Задаёт G57PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G57PL 0 // reserved +/* Задаёт G58PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G58PL 0 // reserved + +/* Задаёт G61PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G61PL 3 // SPIRXINTA (SPI-A) +/* Задаёт G62PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G62PL 1 // SPITXINTA (SPI-A) +/* Задаёт G63PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G63PL 4 // MRINTB (McBSP-B) +/* Задаёт G64PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G64PL 6 // MXINTB (McBSP-B) +/* Задаёт G65PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G65PL 2 // MRINTA (McBSP-A) +/* Задаёт G66PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G66PL 1 // MXINTA (McBSP-A) +/* Задаёт G67PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G67PL 0 // reserved +/* Задаёт G68PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G68PL 0 // reserved + +/* Задаёт G71PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G71PL 5 // DINTCH1 (DMA) +/* Задаёт G72PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G72PL 4 // DINTCH2 (DMA) +/* Задаёт G73PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G73PL 4 // DINTCH3 (DMA) +/* Задаёт G74PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G74PL 2 // DINTCH4 (DMA) +/* Задаёт G75PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G75PL 3 // DINTCH5 (DMA) +/* Задаёт G76PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G76PL 1 // DINTCH6 (DMA) +/* Задаёт G77PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G77PL 0 // reserved +/* Задаёт G78PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G78PL 0 // reserved + +/* Задаёт G81PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G81PL 1 // I2CINT1A (I2C-A) +/* Задаёт G82PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G82PL 2 // I2CINT2A (I2C-A) +/* Задаёт G83PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G83PL 0 // reserved +/* Задаёт G84PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G84PL 0 // reserved +/* Задаёт G85PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G85PL 4 // SCIRXINTC (SCI-C) +/* Задаёт G86PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G86PL 3 // SCITXINTC (SCI-C) +/* Задаёт G87PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G87PL 0 // reserved +/* Задаёт G88PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G88PL 0 // reserved + +/* Задаёт G91PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G91PL 1 // SCIRXINTA (SCI-A) +/* Задаёт G92PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G92PL 5 // SCITXINTA (SCI-A) +/* Задаёт G93PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G93PL 3 // SCIRXINTB (SCI-B) +/* Задаёт G94PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G94PL 4 // SCITXINTB (SCI-B) +/* Задаёт G95PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G95PL 1 // ECAN0INTA (ECAN-A) +/* Задаёт G96PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G96PL 1 // ECAN1INTA (ECAN-A) +/* Задаёт G97PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G97PL 2 // ECAN0INTB (ECAN-B) +/* Задаёт G98PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G98PL 4 // ECAN1INTB (ECAN-B) + +/* Задаёт G101PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G101PL 0 // reserved +/* Задаёт G102PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G102PL 0 // reserved +/* Задаёт G103PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G103PL 0 // reserved +/* Задаёт G104PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G104PL 0 // reserved +/* Задаёт G105PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G105PL 0 // reserved +/* Задаёт G106PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G106PL 0 // reserved +/* Задаёт G107PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G107PL 0 // reserved +/* Задаёт G108PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G108PL 0 // reserved + +/* Задаёт G111PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G111PL 0 // reserved +/* Задаёт G112PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G112PL 0 // reserved +/* Задаёт G113PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G113PL 0 // reserved +/* Задаёт G114PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G114PL 0 // reserved +/* Задаёт G115PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G115PL 0 // reserved +/* Задаёт G116PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G116PL 0 // reserved +/* Задаёт G117PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G117PL 0 // reserved +/* Задаёт G118PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G118PL 0 // reserved + +/* Задаёт G121PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G121PL 5 // XINT3 (External) +/* Задаёт G122PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G122PL 3 // XINT4 (External) +/* Задаёт G123PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G123PL 2 // XINT5 (External) +/* Задаёт G124PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G124PL 2 // XINT6 (External) +/* Задаёт G125PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G125PL 1 // XINT7 (External) +/* Задаёт G126PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G126PL 0 // reserved +/* Задаёт G127PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G127PL 6 // LVF (FPA32) +/* Задаёт G128PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G128PL 1 // LUF (FPA32) + + +// There should be no need to modify code below this line +//------------------------------------------------------------------------------- +// Automatically generate IER interrupt masks MINT1 to MINT16: +// + +// Beginning of MINT1: +/* Условие компиляции (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL == 0) +/* Задаёт MINT1_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 1_1PL. */ +#define MINT1_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_1PL. */ +#define MINT1_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT1PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT1PL) || (INT2PL == 0) +/* Задаёт MINT1_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 1_2PL. */ +#define MINT1_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_2PL. */ +#define MINT1_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT1PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT1PL) || (INT3PL == 0) +/* Задаёт MINT1_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 1_3PL. */ +#define MINT1_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_3PL. */ +#define MINT1_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT1PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT1PL) || (INT4PL == 0) +/* Задаёт MINT1_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 1_4PL. */ +#define MINT1_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_4PL. */ +#define MINT1_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT1PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT1PL) || (INT5PL == 0) +/* Задаёт MINT1_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 1_5PL. */ +#define MINT1_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_5PL. */ +#define MINT1_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT1PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT1PL) || (INT6PL == 0) +/* Задаёт MINT1_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 1_6PL. */ +#define MINT1_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_6PL. */ +#define MINT1_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT1PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT1PL) || (INT7PL == 0) +/* Задаёт MINT1_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 1_7PL. */ +#define MINT1_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_7PL. */ +#define MINT1_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT1PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT1PL) || (INT8PL == 0) +/* Задаёт MINT1_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 1_8PL. */ +#define MINT1_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_8PL. */ +#define MINT1_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT1PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT1PL) || (INT9PL == 0) +/* Задаёт MINT1_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 1_9PL. */ +#define MINT1_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_9PL. */ +#define MINT1_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT1PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT1PL) || (INT10PL == 0) +/* Задаёт MINT1_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 1_10PL. */ +#define MINT1_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_10PL. */ +#define MINT1_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT1PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT1PL) || (INT11PL == 0) +/* Задаёт MINT1_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 1_11PL. */ +#define MINT1_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_11PL. */ +#define MINT1_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT1PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT1PL) || (INT12PL == 0) +/* Задаёт MINT1_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 1_12PL. */ +#define MINT1_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_12PL. */ +#define MINT1_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT1PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT1PL) || (INT13PL == 0) +/* Задаёт MINT1_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 1_13PL. */ +#define MINT1_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_13PL. */ +#define MINT1_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT1PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT1PL) || (INT14PL == 0) +/* Задаёт MINT1_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 1_14PL. */ +#define MINT1_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_14PL. */ +#define MINT1_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT1PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT1PL) || (INT15PL == 0) +/* Задаёт MINT1_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 1_15PL. */ +#define MINT1_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_15PL. */ +#define MINT1_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT1PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT1PL) || (INT16PL == 0) +/* Задаёт MINT1_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 1_16PL. */ +#define MINT1_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_16PL. */ +#define MINT1_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT1 = (MINT1_1PL & MINT1_2PL & MINT1_3PL & MINT1_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 1. */ +#define MINT1 (MINT1_1PL & MINT1_2PL & MINT1_3PL & MINT1_4PL & \ + MINT1_5PL & MINT1_6PL & MINT1_7PL & MINT1_8PL & /* Продолжает список аргументов, полей или выражение MINT1_5PL & MINT1_6PL & MINT1_7PL & MINT1_8PL &; порядок элементов сохраняется. */ \ + MINT1_9PL & MINT1_10PL & MINT1_11PL & MINT1_12PL & /* Продолжает список аргументов, полей или выражение MINT1_9PL & MINT1_10PL & MINT1_11PL & MINT1_12PL &; порядок элементов сохраняется. */ \ + MINT1_13PL & MINT1_14PL & MINT1_15PL & MINT1_16PL) /* Продолжает список аргументов, полей или выражение MINT1_13PL & MINT1_14PL & MINT1_15PL & MINT1_16PL); порядок элементов сохраняется. */ +// End Of MINT1. + +// Beginning of MINT2: +/* Условие компиляции (INT1PL >= INT2PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT2PL) || (INT1PL == 0) +/* Задаёт MINT2_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 2_1PL. */ +#define MINT2_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_1PL. */ +#define MINT2_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL == 0) +/* Задаёт MINT2_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 2_2PL. */ +#define MINT2_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_2PL. */ +#define MINT2_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT2PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT2PL) || (INT3PL == 0) +/* Задаёт MINT2_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 2_3PL. */ +#define MINT2_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_3PL. */ +#define MINT2_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT2PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT2PL) || (INT4PL == 0) +/* Задаёт MINT2_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 2_4PL. */ +#define MINT2_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_4PL. */ +#define MINT2_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT2PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT2PL) || (INT5PL == 0) +/* Задаёт MINT2_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 2_5PL. */ +#define MINT2_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_5PL. */ +#define MINT2_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT2PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT2PL) || (INT6PL == 0) +/* Задаёт MINT2_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 2_6PL. */ +#define MINT2_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_6PL. */ +#define MINT2_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT2PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT2PL) || (INT7PL == 0) +/* Задаёт MINT2_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 2_7PL. */ +#define MINT2_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_7PL. */ +#define MINT2_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT2PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT2PL) || (INT8PL == 0) +/* Задаёт MINT2_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 2_8PL. */ +#define MINT2_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_8PL. */ +#define MINT2_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT2PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT2PL) || (INT9PL == 0) +/* Задаёт MINT2_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 2_9PL. */ +#define MINT2_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_9PL. */ +#define MINT2_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT2PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT2PL) || (INT10PL == 0) +/* Задаёт MINT2_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 2_10PL. */ +#define MINT2_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_10PL. */ +#define MINT2_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT2PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT2PL) || (INT11PL == 0) +/* Задаёт MINT2_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 2_11PL. */ +#define MINT2_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_11PL. */ +#define MINT2_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT2PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT2PL) || (INT12PL == 0) +/* Задаёт MINT2_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 2_12PL. */ +#define MINT2_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_12PL. */ +#define MINT2_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT2PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT2PL) || (INT13PL == 0) +/* Задаёт MINT2_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 2_13PL. */ +#define MINT2_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_13PL. */ +#define MINT2_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT2PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT2PL) || (INT14PL == 0) +/* Задаёт MINT2_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 2_14PL. */ +#define MINT2_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_14PL. */ +#define MINT2_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT2PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT2PL) || (INT15PL == 0) +/* Задаёт MINT2_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 2_15PL. */ +#define MINT2_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_15PL. */ +#define MINT2_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT2PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT2PL) || (INT16PL == 0) +/* Задаёт MINT2_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 2_16PL. */ +#define MINT2_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_16PL. */ +#define MINT2_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT2 = (MINT2_1PL & MINT2_2PL & MINT2_3PL & MINT2_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 2. */ +#define MINT2 (MINT2_1PL & MINT2_2PL & MINT2_3PL & MINT2_4PL & \ + MINT2_5PL & MINT2_6PL & MINT2_7PL & MINT2_8PL & /* Продолжает список аргументов, полей или выражение MINT2_5PL & MINT2_6PL & MINT2_7PL & MINT2_8PL &; порядок элементов сохраняется. */ \ + MINT2_9PL & MINT2_10PL & MINT2_11PL & MINT2_12PL & /* Продолжает список аргументов, полей или выражение MINT2_9PL & MINT2_10PL & MINT2_11PL & MINT2_12PL &; порядок элементов сохраняется. */ \ + MINT2_13PL & MINT2_14PL & MINT2_15PL & MINT2_16PL) /* Продолжает список аргументов, полей или выражение MINT2_13PL & MINT2_14PL & MINT2_15PL & MINT2_16PL); порядок элементов сохраняется. */ +// End Of MINT2. + +// Beginning of MINT3: +/* Условие компиляции (INT1PL >= INT3PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT3PL) || (INT1PL == 0) +/* Задаёт MINT3_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 3_1PL. */ +#define MINT3_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_1PL. */ +#define MINT3_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT3PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT3PL) || (INT2PL == 0) +/* Задаёт MINT3_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 3_2PL. */ +#define MINT3_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_2PL. */ +#define MINT3_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL == 0) +/* Задаёт MINT3_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 3_3PL. */ +#define MINT3_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_3PL. */ +#define MINT3_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT3PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT3PL) || (INT4PL == 0) +/* Задаёт MINT3_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 3_4PL. */ +#define MINT3_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_4PL. */ +#define MINT3_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT3PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT3PL) || (INT5PL == 0) +/* Задаёт MINT3_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 3_5PL. */ +#define MINT3_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_5PL. */ +#define MINT3_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT3PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT3PL) || (INT6PL == 0) +/* Задаёт MINT3_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 3_6PL. */ +#define MINT3_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_6PL. */ +#define MINT3_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT3PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT3PL) || (INT7PL == 0) +/* Задаёт MINT3_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 3_7PL. */ +#define MINT3_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_7PL. */ +#define MINT3_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT3PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT3PL) || (INT8PL == 0) +/* Задаёт MINT3_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 3_8PL. */ +#define MINT3_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_8PL. */ +#define MINT3_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT3PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT3PL) || (INT9PL == 0) +/* Задаёт MINT3_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 3_9PL. */ +#define MINT3_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_9PL. */ +#define MINT3_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT3PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT3PL) || (INT10PL == 0) +/* Задаёт MINT3_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 3_10PL. */ +#define MINT3_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_10PL. */ +#define MINT3_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT3PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT3PL) || (INT11PL == 0) +/* Задаёт MINT3_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 3_11PL. */ +#define MINT3_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_11PL. */ +#define MINT3_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT3PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT3PL) || (INT12PL == 0) +/* Задаёт MINT3_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 3_12PL. */ +#define MINT3_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_12PL. */ +#define MINT3_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT3PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT3PL) || (INT13PL == 0) +/* Задаёт MINT3_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 3_13PL. */ +#define MINT3_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_13PL. */ +#define MINT3_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT3PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT3PL) || (INT14PL == 0) +/* Задаёт MINT3_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 3_14PL. */ +#define MINT3_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_14PL. */ +#define MINT3_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT3PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT3PL) || (INT15PL == 0) +/* Задаёт MINT3_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 3_15PL. */ +#define MINT3_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_15PL. */ +#define MINT3_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT3PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT3PL) || (INT16PL == 0) +/* Задаёт MINT3_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 3_16PL. */ +#define MINT3_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_16PL. */ +#define MINT3_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT3 = (MINT3_1PL & MINT3_2PL & MINT3_3PL & MINT3_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 3. */ +#define MINT3 (MINT3_1PL & MINT3_2PL & MINT3_3PL & MINT3_4PL & \ + MINT3_5PL & MINT3_6PL & MINT3_7PL & MINT3_8PL & /* Продолжает список аргументов, полей или выражение MINT3_5PL & MINT3_6PL & MINT3_7PL & MINT3_8PL &; порядок элементов сохраняется. */ \ + MINT3_9PL & MINT3_10PL & MINT3_11PL & MINT3_12PL & /* Продолжает список аргументов, полей или выражение MINT3_9PL & MINT3_10PL & MINT3_11PL & MINT3_12PL &; порядок элементов сохраняется. */ \ + MINT3_13PL & MINT3_14PL & MINT3_15PL & MINT3_16PL) /* Продолжает список аргументов, полей или выражение MINT3_13PL & MINT3_14PL & MINT3_15PL & MINT3_16PL); порядок элементов сохраняется. */ +// End Of MINT3. + +// Beginning of MINT4: +/* Условие компиляции (INT1PL >= INT4PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT4PL) || (INT1PL == 0) +/* Задаёт MINT4_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 4_1PL. */ +#define MINT4_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_1PL. */ +#define MINT4_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT4PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT4PL) || (INT2PL == 0) +/* Задаёт MINT4_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 4_2PL. */ +#define MINT4_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_2PL. */ +#define MINT4_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT4PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT4PL) || (INT3PL == 0) +/* Задаёт MINT4_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 4_3PL. */ +#define MINT4_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_3PL. */ +#define MINT4_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL == 0) +/* Задаёт MINT4_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 4_4PL. */ +#define MINT4_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_4PL. */ +#define MINT4_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT4PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT4PL) || (INT5PL == 0) +/* Задаёт MINT4_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 4_5PL. */ +#define MINT4_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_5PL. */ +#define MINT4_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT4PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT4PL) || (INT6PL == 0) +/* Задаёт MINT4_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 4_6PL. */ +#define MINT4_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_6PL. */ +#define MINT4_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT4PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT4PL) || (INT7PL == 0) +/* Задаёт MINT4_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 4_7PL. */ +#define MINT4_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_7PL. */ +#define MINT4_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT4PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT4PL) || (INT8PL == 0) +/* Задаёт MINT4_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 4_8PL. */ +#define MINT4_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_8PL. */ +#define MINT4_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT4PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT4PL) || (INT9PL == 0) +/* Задаёт MINT4_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 4_9PL. */ +#define MINT4_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_9PL. */ +#define MINT4_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT4PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT4PL) || (INT10PL == 0) +/* Задаёт MINT4_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 4_10PL. */ +#define MINT4_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_10PL. */ +#define MINT4_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT4PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT4PL) || (INT11PL == 0) +/* Задаёт MINT4_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 4_11PL. */ +#define MINT4_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_11PL. */ +#define MINT4_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT4PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT4PL) || (INT12PL == 0) +/* Задаёт MINT4_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 4_12PL. */ +#define MINT4_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_12PL. */ +#define MINT4_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT4PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT4PL) || (INT13PL == 0) +/* Задаёт MINT4_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 4_13PL. */ +#define MINT4_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_13PL. */ +#define MINT4_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT4PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT4PL) || (INT14PL == 0) +/* Задаёт MINT4_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 4_14PL. */ +#define MINT4_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_14PL. */ +#define MINT4_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT4PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT4PL) || (INT15PL == 0) +/* Задаёт MINT4_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 4_15PL. */ +#define MINT4_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_15PL. */ +#define MINT4_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT4PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT4PL) || (INT16PL == 0) +/* Задаёт MINT4_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 4_16PL. */ +#define MINT4_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_16PL. */ +#define MINT4_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT4 = (MINT4_1PL & MINT4_2PL & MINT4_3PL & MINT4_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 4. */ +#define MINT4 (MINT4_1PL & MINT4_2PL & MINT4_3PL & MINT4_4PL & \ + MINT4_5PL & MINT4_6PL & MINT4_7PL & MINT4_8PL & /* Продолжает список аргументов, полей или выражение MINT4_5PL & MINT4_6PL & MINT4_7PL & MINT4_8PL &; порядок элементов сохраняется. */ \ + MINT4_9PL & MINT4_10PL & MINT4_11PL & MINT4_12PL & /* Продолжает список аргументов, полей или выражение MINT4_9PL & MINT4_10PL & MINT4_11PL & MINT4_12PL &; порядок элементов сохраняется. */ \ + MINT4_13PL & MINT4_14PL & MINT4_15PL & MINT4_16PL) /* Продолжает список аргументов, полей или выражение MINT4_13PL & MINT4_14PL & MINT4_15PL & MINT4_16PL); порядок элементов сохраняется. */ +// End Of MINT4. + +// Beginning of MINT5: +/* Условие компиляции (INT1PL >= INT5PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT5PL) || (INT1PL == 0) +/* Задаёт MINT5_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 5_1PL. */ +#define MINT5_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_1PL. */ +#define MINT5_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT5PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT5PL) || (INT2PL == 0) +/* Задаёт MINT5_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 5_2PL. */ +#define MINT5_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_2PL. */ +#define MINT5_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT5PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT5PL) || (INT3PL == 0) +/* Задаёт MINT5_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 5_3PL. */ +#define MINT5_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_3PL. */ +#define MINT5_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT5PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT5PL) || (INT4PL == 0) +/* Задаёт MINT5_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 5_4PL. */ +#define MINT5_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_4PL. */ +#define MINT5_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL == 0) +/* Задаёт MINT5_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 5_5PL. */ +#define MINT5_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_5PL. */ +#define MINT5_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT5PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT5PL) || (INT6PL == 0) +/* Задаёт MINT5_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 5_6PL. */ +#define MINT5_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_6PL. */ +#define MINT5_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT5PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT5PL) || (INT7PL == 0) +/* Задаёт MINT5_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 5_7PL. */ +#define MINT5_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_7PL. */ +#define MINT5_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT5PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT5PL) || (INT8PL == 0) +/* Задаёт MINT5_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 5_8PL. */ +#define MINT5_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_8PL. */ +#define MINT5_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT5PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT5PL) || (INT9PL == 0) +/* Задаёт MINT5_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 5_9PL. */ +#define MINT5_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_9PL. */ +#define MINT5_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT5PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT5PL) || (INT10PL == 0) +/* Задаёт MINT5_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 5_10PL. */ +#define MINT5_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_10PL. */ +#define MINT5_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT5PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT5PL) || (INT11PL == 0) +/* Задаёт MINT5_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 5_11PL. */ +#define MINT5_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_11PL. */ +#define MINT5_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT5PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT5PL) || (INT12PL == 0) +/* Задаёт MINT5_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 5_12PL. */ +#define MINT5_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_12PL. */ +#define MINT5_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT5PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT5PL) || (INT13PL == 0) +/* Задаёт MINT5_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 5_13PL. */ +#define MINT5_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_13PL. */ +#define MINT5_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT5PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT5PL) || (INT14PL == 0) +/* Задаёт MINT5_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 5_14PL. */ +#define MINT5_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_14PL. */ +#define MINT5_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT5PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT5PL) || (INT15PL == 0) +/* Задаёт MINT5_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 5_15PL. */ +#define MINT5_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_15PL. */ +#define MINT5_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT5PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT5PL) || (INT16PL == 0) +/* Задаёт MINT5_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 5_16PL. */ +#define MINT5_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_16PL. */ +#define MINT5_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT5 = (MINT5_1PL & MINT5_2PL & MINT5_3PL & MINT5_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 5. */ +#define MINT5 (MINT5_1PL & MINT5_2PL & MINT5_3PL & MINT5_4PL & \ + MINT5_5PL & MINT5_6PL & MINT5_7PL & MINT5_8PL & /* Продолжает список аргументов, полей или выражение MINT5_5PL & MINT5_6PL & MINT5_7PL & MINT5_8PL &; порядок элементов сохраняется. */ \ + MINT5_9PL & MINT5_10PL & MINT5_11PL & MINT5_12PL & /* Продолжает список аргументов, полей или выражение MINT5_9PL & MINT5_10PL & MINT5_11PL & MINT5_12PL &; порядок элементов сохраняется. */ \ + MINT5_13PL & MINT5_14PL & MINT5_15PL & MINT5_16PL) /* Продолжает список аргументов, полей или выражение MINT5_13PL & MINT5_14PL & MINT5_15PL & MINT5_16PL); порядок элементов сохраняется. */ +// End Of MINT5. + +// Beginning of MINT6: +/* Условие компиляции (INT1PL >= INT6PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT6PL) || (INT1PL == 0) +/* Задаёт MINT6_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 6_1PL. */ +#define MINT6_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_1PL. */ +#define MINT6_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT6PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT6PL) || (INT2PL == 0) +/* Задаёт MINT6_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 6_2PL. */ +#define MINT6_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_2PL. */ +#define MINT6_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT6PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT6PL) || (INT3PL == 0) +/* Задаёт MINT6_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 6_3PL. */ +#define MINT6_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_3PL. */ +#define MINT6_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT6PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT6PL) || (INT4PL == 0) +/* Задаёт MINT6_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 6_4PL. */ +#define MINT6_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_4PL. */ +#define MINT6_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT6PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT6PL) || (INT5PL == 0) +/* Задаёт MINT6_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 6_5PL. */ +#define MINT6_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_5PL. */ +#define MINT6_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL == 0) +/* Задаёт MINT6_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 6_6PL. */ +#define MINT6_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_6PL. */ +#define MINT6_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT6PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT6PL) || (INT7PL == 0) +/* Задаёт MINT6_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 6_7PL. */ +#define MINT6_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_7PL. */ +#define MINT6_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT6PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT6PL) || (INT8PL == 0) +/* Задаёт MINT6_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 6_8PL. */ +#define MINT6_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_8PL. */ +#define MINT6_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT6PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT6PL) || (INT9PL == 0) +/* Задаёт MINT6_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 6_9PL. */ +#define MINT6_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_9PL. */ +#define MINT6_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT6PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT6PL) || (INT10PL == 0) +/* Задаёт MINT6_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 6_10PL. */ +#define MINT6_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_10PL. */ +#define MINT6_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT6PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT6PL) || (INT11PL == 0) +/* Задаёт MINT6_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 6_11PL. */ +#define MINT6_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_11PL. */ +#define MINT6_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT6PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT6PL) || (INT12PL == 0) +/* Задаёт MINT6_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 6_12PL. */ +#define MINT6_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_12PL. */ +#define MINT6_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT6PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT6PL) || (INT13PL == 0) +/* Задаёт MINT6_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 6_13PL. */ +#define MINT6_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_13PL. */ +#define MINT6_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT6PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT6PL) || (INT14PL == 0) +/* Задаёт MINT6_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 6_14PL. */ +#define MINT6_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_14PL. */ +#define MINT6_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT6PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT6PL) || (INT15PL == 0) +/* Задаёт MINT6_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 6_15PL. */ +#define MINT6_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_15PL. */ +#define MINT6_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT6PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT6PL) || (INT16PL == 0) +/* Задаёт MINT6_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 6_16PL. */ +#define MINT6_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_16PL. */ +#define MINT6_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT6 = (MINT6_1PL & MINT6_2PL & MINT6_3PL & MINT6_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 6. */ +#define MINT6 (MINT6_1PL & MINT6_2PL & MINT6_3PL & MINT6_4PL & \ + MINT6_5PL & MINT6_6PL & MINT6_7PL & MINT6_8PL & /* Продолжает список аргументов, полей или выражение MINT6_5PL & MINT6_6PL & MINT6_7PL & MINT6_8PL &; порядок элементов сохраняется. */ \ + MINT6_9PL & MINT6_10PL & MINT6_11PL & MINT6_12PL & /* Продолжает список аргументов, полей или выражение MINT6_9PL & MINT6_10PL & MINT6_11PL & MINT6_12PL &; порядок элементов сохраняется. */ \ + MINT6_13PL & MINT6_14PL & MINT6_15PL & MINT6_16PL) /* Продолжает список аргументов, полей или выражение MINT6_13PL & MINT6_14PL & MINT6_15PL & MINT6_16PL); порядок элементов сохраняется. */ +// End Of MINT6. + +// Beginning of MINT7: +/* Условие компиляции (INT1PL >= INT7PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT7PL) || (INT1PL == 0) +/* Задаёт MINT7_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 7_1PL. */ +#define MINT7_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_1PL. */ +#define MINT7_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT7PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT7PL) || (INT2PL == 0) +/* Задаёт MINT7_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 7_2PL. */ +#define MINT7_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_2PL. */ +#define MINT7_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT7PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT7PL) || (INT3PL == 0) +/* Задаёт MINT7_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 7_3PL. */ +#define MINT7_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_3PL. */ +#define MINT7_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT7PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT7PL) || (INT4PL == 0) +/* Задаёт MINT7_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 7_4PL. */ +#define MINT7_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_4PL. */ +#define MINT7_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT7PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT7PL) || (INT5PL == 0) +/* Задаёт MINT7_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 7_5PL. */ +#define MINT7_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_5PL. */ +#define MINT7_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT7PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT7PL) || (INT6PL == 0) +/* Задаёт MINT7_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 7_6PL. */ +#define MINT7_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_6PL. */ +#define MINT7_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL == 0) +/* Задаёт MINT7_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 7_7PL. */ +#define MINT7_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_7PL. */ +#define MINT7_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT7PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT7PL) || (INT8PL == 0) +/* Задаёт MINT7_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 7_8PL. */ +#define MINT7_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_8PL. */ +#define MINT7_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT7PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT7PL) || (INT9PL == 0) +/* Задаёт MINT7_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 7_9PL. */ +#define MINT7_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_9PL. */ +#define MINT7_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT7PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT7PL) || (INT10PL == 0) +/* Задаёт MINT7_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 7_10PL. */ +#define MINT7_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_10PL. */ +#define MINT7_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT7PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT7PL) || (INT11PL == 0) +/* Задаёт MINT7_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 7_11PL. */ +#define MINT7_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_11PL. */ +#define MINT7_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT7PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT7PL) || (INT12PL == 0) +/* Задаёт MINT7_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 7_12PL. */ +#define MINT7_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_12PL. */ +#define MINT7_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT7PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT7PL) || (INT13PL == 0) +/* Задаёт MINT7_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 7_13PL. */ +#define MINT7_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_13PL. */ +#define MINT7_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT7PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT7PL) || (INT14PL == 0) +/* Задаёт MINT7_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 7_14PL. */ +#define MINT7_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_14PL. */ +#define MINT7_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT7PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT7PL) || (INT15PL == 0) +/* Задаёт MINT7_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 7_15PL. */ +#define MINT7_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_15PL. */ +#define MINT7_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT7PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT7PL) || (INT16PL == 0) +/* Задаёт MINT7_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 7_16PL. */ +#define MINT7_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_16PL. */ +#define MINT7_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT7 = (MINT7_1PL & MINT7_2PL & MINT7_3PL & MINT7_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 7. */ +#define MINT7 (MINT7_1PL & MINT7_2PL & MINT7_3PL & MINT7_4PL & \ + MINT7_5PL & MINT7_6PL & MINT7_7PL & MINT7_8PL & /* Продолжает список аргументов, полей или выражение MINT7_5PL & MINT7_6PL & MINT7_7PL & MINT7_8PL &; порядок элементов сохраняется. */ \ + MINT7_9PL & MINT7_10PL & MINT7_11PL & MINT7_12PL & /* Продолжает список аргументов, полей или выражение MINT7_9PL & MINT7_10PL & MINT7_11PL & MINT7_12PL &; порядок элементов сохраняется. */ \ + MINT7_13PL & MINT7_14PL & MINT7_15PL & MINT7_16PL) /* Продолжает список аргументов, полей или выражение MINT7_13PL & MINT7_14PL & MINT7_15PL & MINT7_16PL); порядок элементов сохраняется. */ +// End Of MINT7. + +// Beginning of MINT8: +/* Условие компиляции (INT1PL >= INT8PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT8PL) || (INT1PL == 0) +/* Задаёт MINT8_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 8_1PL. */ +#define MINT8_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_1PL. */ +#define MINT8_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT8PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT8PL) || (INT2PL == 0) +/* Задаёт MINT8_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 8_2PL. */ +#define MINT8_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_2PL. */ +#define MINT8_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT8PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT8PL) || (INT3PL == 0) +/* Задаёт MINT8_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 8_3PL. */ +#define MINT8_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_3PL. */ +#define MINT8_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT8PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT8PL) || (INT4PL == 0) +/* Задаёт MINT8_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 8_4PL. */ +#define MINT8_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_4PL. */ +#define MINT8_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT8PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT8PL) || (INT5PL == 0) +/* Задаёт MINT8_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 8_5PL. */ +#define MINT8_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_5PL. */ +#define MINT8_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT8PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT8PL) || (INT6PL == 0) +/* Задаёт MINT8_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 8_6PL. */ +#define MINT8_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_6PL. */ +#define MINT8_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT8PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT8PL) || (INT7PL == 0) +/* Задаёт MINT8_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 8_7PL. */ +#define MINT8_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_7PL. */ +#define MINT8_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL == 0) +/* Задаёт MINT8_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 8_8PL. */ +#define MINT8_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_8PL. */ +#define MINT8_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT8PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT8PL) || (INT9PL == 0) +/* Задаёт MINT8_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 8_9PL. */ +#define MINT8_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_9PL. */ +#define MINT8_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT8PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT8PL) || (INT10PL == 0) +/* Задаёт MINT8_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 8_10PL. */ +#define MINT8_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_10PL. */ +#define MINT8_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT8PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT8PL) || (INT11PL == 0) +/* Задаёт MINT8_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 8_11PL. */ +#define MINT8_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_11PL. */ +#define MINT8_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT8PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT8PL) || (INT12PL == 0) +/* Задаёт MINT8_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 8_12PL. */ +#define MINT8_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_12PL. */ +#define MINT8_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT8PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT8PL) || (INT13PL == 0) +/* Задаёт MINT8_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 8_13PL. */ +#define MINT8_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_13PL. */ +#define MINT8_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT8PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT8PL) || (INT14PL == 0) +/* Задаёт MINT8_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 8_14PL. */ +#define MINT8_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_14PL. */ +#define MINT8_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT8PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT8PL) || (INT15PL == 0) +/* Задаёт MINT8_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 8_15PL. */ +#define MINT8_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_15PL. */ +#define MINT8_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT8PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT8PL) || (INT16PL == 0) +/* Задаёт MINT8_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 8_16PL. */ +#define MINT8_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_16PL. */ +#define MINT8_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT8 = (MINT8_1PL & MINT8_2PL & MINT8_3PL & MINT8_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 8. */ +#define MINT8 (MINT8_1PL & MINT8_2PL & MINT8_3PL & MINT8_4PL & \ + MINT8_5PL & MINT8_6PL & MINT8_7PL & MINT8_8PL & /* Продолжает список аргументов, полей или выражение MINT8_5PL & MINT8_6PL & MINT8_7PL & MINT8_8PL &; порядок элементов сохраняется. */ \ + MINT8_9PL & MINT8_10PL & MINT8_11PL & MINT8_12PL & /* Продолжает список аргументов, полей или выражение MINT8_9PL & MINT8_10PL & MINT8_11PL & MINT8_12PL &; порядок элементов сохраняется. */ \ + MINT8_13PL & MINT8_14PL & MINT8_15PL & MINT8_16PL) /* Продолжает список аргументов, полей или выражение MINT8_13PL & MINT8_14PL & MINT8_15PL & MINT8_16PL); порядок элементов сохраняется. */ +// End Of MINT8. + +// Beginning of MINT9: +/* Условие компиляции (INT1PL >= INT9PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT9PL) || (INT1PL == 0) +/* Задаёт MINT9_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 9_1PL. */ +#define MINT9_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_1PL. */ +#define MINT9_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT9PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT9PL) || (INT2PL == 0) +/* Задаёт MINT9_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 9_2PL. */ +#define MINT9_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_2PL. */ +#define MINT9_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT9PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT9PL) || (INT3PL == 0) +/* Задаёт MINT9_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 9_3PL. */ +#define MINT9_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_3PL. */ +#define MINT9_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT9PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT9PL) || (INT4PL == 0) +/* Задаёт MINT9_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 9_4PL. */ +#define MINT9_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_4PL. */ +#define MINT9_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT9PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT9PL) || (INT5PL == 0) +/* Задаёт MINT9_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 9_5PL. */ +#define MINT9_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_5PL. */ +#define MINT9_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT9PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT9PL) || (INT6PL == 0) +/* Задаёт MINT9_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 9_6PL. */ +#define MINT9_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_6PL. */ +#define MINT9_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT9PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT9PL) || (INT7PL == 0) +/* Задаёт MINT9_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 9_7PL. */ +#define MINT9_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_7PL. */ +#define MINT9_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT9PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT9PL) || (INT8PL == 0) +/* Задаёт MINT9_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 9_8PL. */ +#define MINT9_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_8PL. */ +#define MINT9_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL == 0) +/* Задаёт MINT9_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 9_9PL. */ +#define MINT9_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_9PL. */ +#define MINT9_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT9PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT9PL) || (INT10PL == 0) +/* Задаёт MINT9_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 9_10PL. */ +#define MINT9_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_10PL. */ +#define MINT9_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT9PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT9PL) || (INT11PL == 0) +/* Задаёт MINT9_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 9_11PL. */ +#define MINT9_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_11PL. */ +#define MINT9_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT9PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT9PL) || (INT12PL == 0) +/* Задаёт MINT9_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 9_12PL. */ +#define MINT9_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_12PL. */ +#define MINT9_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT9PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT9PL) || (INT13PL == 0) +/* Задаёт MINT9_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 9_13PL. */ +#define MINT9_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_13PL. */ +#define MINT9_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT9PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT9PL) || (INT14PL == 0) +/* Задаёт MINT9_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 9_14PL. */ +#define MINT9_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_14PL. */ +#define MINT9_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT9PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT9PL) || (INT15PL == 0) +/* Задаёт MINT9_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 9_15PL. */ +#define MINT9_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_15PL. */ +#define MINT9_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT9PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT9PL) || (INT16PL == 0) +/* Задаёт MINT9_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 9_16PL. */ +#define MINT9_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_16PL. */ +#define MINT9_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT9 = (MINT9_1PL & MINT9_2PL & MINT9_3PL & MINT9_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 9. */ +#define MINT9 (MINT9_1PL & MINT9_2PL & MINT9_3PL & MINT9_4PL & \ + MINT9_5PL & MINT9_6PL & MINT9_7PL & MINT9_8PL & /* Продолжает список аргументов, полей или выражение MINT9_5PL & MINT9_6PL & MINT9_7PL & MINT9_8PL &; порядок элементов сохраняется. */ \ + MINT9_9PL & MINT9_10PL & MINT9_11PL & MINT9_12PL & /* Продолжает список аргументов, полей или выражение MINT9_9PL & MINT9_10PL & MINT9_11PL & MINT9_12PL &; порядок элементов сохраняется. */ \ + MINT9_13PL & MINT9_14PL & MINT9_15PL & MINT9_16PL) /* Продолжает список аргументов, полей или выражение MINT9_13PL & MINT9_14PL & MINT9_15PL & MINT9_16PL); порядок элементов сохраняется. */ +// End Of MINT9. + +// Beginning of MINT10: +/* Условие компиляции (INT1PL >= INT10PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT10PL) || (INT1PL == 0) +/* Задаёт MINT10_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 10_1PL. */ +#define MINT10_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_1PL. */ +#define MINT10_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT10PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT10PL) || (INT2PL == 0) +/* Задаёт MINT10_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 10_2PL. */ +#define MINT10_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_2PL. */ +#define MINT10_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT10PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT10PL) || (INT3PL == 0) +/* Задаёт MINT10_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 10_3PL. */ +#define MINT10_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_3PL. */ +#define MINT10_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT10PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT10PL) || (INT4PL == 0) +/* Задаёт MINT10_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 10_4PL. */ +#define MINT10_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_4PL. */ +#define MINT10_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT10PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT10PL) || (INT5PL == 0) +/* Задаёт MINT10_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 10_5PL. */ +#define MINT10_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_5PL. */ +#define MINT10_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT10PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT10PL) || (INT6PL == 0) +/* Задаёт MINT10_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 10_6PL. */ +#define MINT10_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_6PL. */ +#define MINT10_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT10PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT10PL) || (INT7PL == 0) +/* Задаёт MINT10_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 10_7PL. */ +#define MINT10_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_7PL. */ +#define MINT10_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT10PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT10PL) || (INT8PL == 0) +/* Задаёт MINT10_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 10_8PL. */ +#define MINT10_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_8PL. */ +#define MINT10_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT10PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT10PL) || (INT9PL == 0) +/* Задаёт MINT10_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 10_9PL. */ +#define MINT10_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_9PL. */ +#define MINT10_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL == 0) +/* Задаёт MINT10_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 10_10PL. */ +#define MINT10_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_10PL. */ +#define MINT10_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT10PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT10PL) || (INT11PL == 0) +/* Задаёт MINT10_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 10_11PL. */ +#define MINT10_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_11PL. */ +#define MINT10_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT10PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT10PL) || (INT12PL == 0) +/* Задаёт MINT10_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 10_12PL. */ +#define MINT10_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_12PL. */ +#define MINT10_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT10PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT10PL) || (INT13PL == 0) +/* Задаёт MINT10_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 10_13PL. */ +#define MINT10_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_13PL. */ +#define MINT10_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT10PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT10PL) || (INT14PL == 0) +/* Задаёт MINT10_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 10_14PL. */ +#define MINT10_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_14PL. */ +#define MINT10_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT10PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT10PL) || (INT15PL == 0) +/* Задаёт MINT10_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 10_15PL. */ +#define MINT10_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_15PL. */ +#define MINT10_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT10PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT10PL) || (INT16PL == 0) +/* Задаёт MINT10_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 10_16PL. */ +#define MINT10_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_16PL. */ +#define MINT10_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT10 = (MINT10_1PL & MINT10_2PL & MINT10_3PL & MINT10_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 10. */ +#define MINT10 (MINT10_1PL & MINT10_2PL & MINT10_3PL & MINT10_4PL & \ + MINT10_5PL & MINT10_6PL & MINT10_7PL & MINT10_8PL & /* Продолжает список аргументов, полей или выражение MINT10_5PL & MINT10_6PL & MINT10_7PL & MINT10_8PL &; порядок элементов сохраняется. */ \ + MINT10_9PL & MINT10_10PL & MINT10_11PL & MINT10_12PL & /* Продолжает список аргументов, полей или выражение MINT10_9PL & MINT10_10PL & MINT10_11PL & MINT10_12PL &; порядок элементов сохраняется. */ \ + MINT10_13PL & MINT10_14PL & MINT10_15PL & MINT10_16PL) /* Продолжает список аргументов, полей или выражение MINT10_13PL & MINT10_14PL & MINT10_15PL & MINT10_16PL); порядок элементов сохраняется. */ +// End Of MINT10. + +// Beginning of MINT11: +/* Условие компиляции (INT1PL >= INT11PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT11PL) || (INT1PL == 0) +/* Задаёт MINT11_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 11_1PL. */ +#define MINT11_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_1PL. */ +#define MINT11_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT11PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT11PL) || (INT2PL == 0) +/* Задаёт MINT11_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 11_2PL. */ +#define MINT11_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_2PL. */ +#define MINT11_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT11PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT11PL) || (INT3PL == 0) +/* Задаёт MINT11_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 11_3PL. */ +#define MINT11_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_3PL. */ +#define MINT11_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT11PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT11PL) || (INT4PL == 0) +/* Задаёт MINT11_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 11_4PL. */ +#define MINT11_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_4PL. */ +#define MINT11_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT11PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT11PL) || (INT5PL == 0) +/* Задаёт MINT11_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 11_5PL. */ +#define MINT11_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_5PL. */ +#define MINT11_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT11PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT11PL) || (INT6PL == 0) +/* Задаёт MINT11_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 11_6PL. */ +#define MINT11_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_6PL. */ +#define MINT11_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT11PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT11PL) || (INT7PL == 0) +/* Задаёт MINT11_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 11_7PL. */ +#define MINT11_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_7PL. */ +#define MINT11_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT11PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT11PL) || (INT8PL == 0) +/* Задаёт MINT11_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 11_8PL. */ +#define MINT11_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_8PL. */ +#define MINT11_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT11PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT11PL) || (INT9PL == 0) +/* Задаёт MINT11_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 11_9PL. */ +#define MINT11_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_9PL. */ +#define MINT11_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT11PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT11PL) || (INT10PL == 0) +/* Задаёт MINT11_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 11_10PL. */ +#define MINT11_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_10PL. */ +#define MINT11_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL == 0) +/* Задаёт MINT11_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 11_11PL. */ +#define MINT11_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_11PL. */ +#define MINT11_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT11PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT11PL) || (INT12PL == 0) +/* Задаёт MINT11_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 11_12PL. */ +#define MINT11_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_12PL. */ +#define MINT11_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT11PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT11PL) || (INT13PL == 0) +/* Задаёт MINT11_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 11_13PL. */ +#define MINT11_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_13PL. */ +#define MINT11_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT11PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT11PL) || (INT14PL == 0) +/* Задаёт MINT11_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 11_14PL. */ +#define MINT11_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_14PL. */ +#define MINT11_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT11PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT11PL) || (INT15PL == 0) +/* Задаёт MINT11_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 11_15PL. */ +#define MINT11_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_15PL. */ +#define MINT11_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT11PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT11PL) || (INT16PL == 0) +/* Задаёт MINT11_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 11_16PL. */ +#define MINT11_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_16PL. */ +#define MINT11_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT11 = (MINT11_1PL & MINT11_2PL & MINT11_3PL & MINT11_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 11. */ +#define MINT11 (MINT11_1PL & MINT11_2PL & MINT11_3PL & MINT11_4PL & \ + MINT11_5PL & MINT11_6PL & MINT11_7PL & MINT11_8PL & /* Продолжает список аргументов, полей или выражение MINT11_5PL & MINT11_6PL & MINT11_7PL & MINT11_8PL &; порядок элементов сохраняется. */ \ + MINT11_9PL & MINT11_10PL & MINT11_11PL & MINT11_12PL & /* Продолжает список аргументов, полей или выражение MINT11_9PL & MINT11_10PL & MINT11_11PL & MINT11_12PL &; порядок элементов сохраняется. */ \ + MINT11_13PL & MINT11_14PL & MINT11_15PL & MINT11_16PL) /* Продолжает список аргументов, полей или выражение MINT11_13PL & MINT11_14PL & MINT11_15PL & MINT11_16PL); порядок элементов сохраняется. */ +// End Of MINT11. + +// Beginning of MINT12: +/* Условие компиляции (INT1PL >= INT12PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT12PL) || (INT1PL == 0) +/* Задаёт MINT12_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 12_1PL. */ +#define MINT12_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_1PL. */ +#define MINT12_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT12PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT12PL) || (INT2PL == 0) +/* Задаёт MINT12_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 12_2PL. */ +#define MINT12_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_2PL. */ +#define MINT12_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT12PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT12PL) || (INT3PL == 0) +/* Задаёт MINT12_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 12_3PL. */ +#define MINT12_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_3PL. */ +#define MINT12_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT12PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT12PL) || (INT4PL == 0) +/* Задаёт MINT12_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 12_4PL. */ +#define MINT12_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_4PL. */ +#define MINT12_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT12PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT12PL) || (INT5PL == 0) +/* Задаёт MINT12_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 12_5PL. */ +#define MINT12_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_5PL. */ +#define MINT12_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT12PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT12PL) || (INT6PL == 0) +/* Задаёт MINT12_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 12_6PL. */ +#define MINT12_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_6PL. */ +#define MINT12_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT12PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT12PL) || (INT7PL == 0) +/* Задаёт MINT12_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 12_7PL. */ +#define MINT12_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_7PL. */ +#define MINT12_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT12PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT12PL) || (INT8PL == 0) +/* Задаёт MINT12_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 12_8PL. */ +#define MINT12_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_8PL. */ +#define MINT12_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT12PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT12PL) || (INT9PL == 0) +/* Задаёт MINT12_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 12_9PL. */ +#define MINT12_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_9PL. */ +#define MINT12_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT12PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT12PL) || (INT10PL == 0) +/* Задаёт MINT12_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 12_10PL. */ +#define MINT12_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_10PL. */ +#define MINT12_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT12PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT12PL) || (INT11PL == 0) +/* Задаёт MINT12_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 12_11PL. */ +#define MINT12_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_11PL. */ +#define MINT12_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL == 0) +/* Задаёт MINT12_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 12_12PL. */ +#define MINT12_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_12PL. */ +#define MINT12_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT12PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT12PL) || (INT13PL == 0) +/* Задаёт MINT12_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 12_13PL. */ +#define MINT12_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_13PL. */ +#define MINT12_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT12PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT12PL) || (INT14PL == 0) +/* Задаёт MINT12_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 12_14PL. */ +#define MINT12_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_14PL. */ +#define MINT12_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT12PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT12PL) || (INT15PL == 0) +/* Задаёт MINT12_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 12_15PL. */ +#define MINT12_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_15PL. */ +#define MINT12_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT12PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT12PL) || (INT16PL == 0) +/* Задаёт MINT12_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 12_16PL. */ +#define MINT12_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_16PL. */ +#define MINT12_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT12 = (MINT12_1PL & MINT12_2PL & MINT12_3PL & MINT12_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 12. */ +#define MINT12 (MINT12_1PL & MINT12_2PL & MINT12_3PL & MINT12_4PL & \ + MINT12_5PL & MINT12_6PL & MINT12_7PL & MINT12_8PL & /* Продолжает список аргументов, полей или выражение MINT12_5PL & MINT12_6PL & MINT12_7PL & MINT12_8PL &; порядок элементов сохраняется. */ \ + MINT12_9PL & MINT12_10PL & MINT12_11PL & MINT12_12PL & /* Продолжает список аргументов, полей или выражение MINT12_9PL & MINT12_10PL & MINT12_11PL & MINT12_12PL &; порядок элементов сохраняется. */ \ + MINT12_13PL & MINT12_14PL & MINT12_15PL & MINT12_16PL) /* Продолжает список аргументов, полей или выражение MINT12_13PL & MINT12_14PL & MINT12_15PL & MINT12_16PL); порядок элементов сохраняется. */ +// End Of MINT12. + +// Beginning of MINT13: +/* Условие компиляции (INT1PL >= INT13PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT13PL) || (INT1PL == 0) +/* Задаёт MINT13_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 13_1PL. */ +#define MINT13_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_1PL. */ +#define MINT13_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT13PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT13PL) || (INT2PL == 0) +/* Задаёт MINT13_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 13_2PL. */ +#define MINT13_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_2PL. */ +#define MINT13_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT13PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT13PL) || (INT3PL == 0) +/* Задаёт MINT13_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 13_3PL. */ +#define MINT13_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_3PL. */ +#define MINT13_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT13PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT13PL) || (INT4PL == 0) +/* Задаёт MINT13_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 13_4PL. */ +#define MINT13_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_4PL. */ +#define MINT13_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT13PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT13PL) || (INT5PL == 0) +/* Задаёт MINT13_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 13_5PL. */ +#define MINT13_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_5PL. */ +#define MINT13_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT13PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT13PL) || (INT6PL == 0) +/* Задаёт MINT13_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 13_6PL. */ +#define MINT13_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_6PL. */ +#define MINT13_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT13PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT13PL) || (INT7PL == 0) +/* Задаёт MINT13_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 13_7PL. */ +#define MINT13_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_7PL. */ +#define MINT13_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT13PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT13PL) || (INT8PL == 0) +/* Задаёт MINT13_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 13_8PL. */ +#define MINT13_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_8PL. */ +#define MINT13_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT13PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT13PL) || (INT9PL == 0) +/* Задаёт MINT13_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 13_9PL. */ +#define MINT13_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_9PL. */ +#define MINT13_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT13PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT13PL) || (INT10PL == 0) +/* Задаёт MINT13_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 13_10PL. */ +#define MINT13_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_10PL. */ +#define MINT13_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT13PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT13PL) || (INT11PL == 0) +/* Задаёт MINT13_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 13_11PL. */ +#define MINT13_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_11PL. */ +#define MINT13_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT13_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 13_12PL. */ +#define MINT13_12PL ~(1 << 11) + +/* Условие компиляции (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL == 0) +/* Задаёт MINT13_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 13_13PL. */ +#define MINT13_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_13PL. */ +#define MINT13_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT13PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT13PL) || (INT14PL == 0) +/* Задаёт MINT13_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 13_14PL. */ +#define MINT13_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_14PL. */ +#define MINT13_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT13PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT13PL) || (INT15PL == 0) +/* Задаёт MINT13_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 13_15PL. */ +#define MINT13_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_15PL. */ +#define MINT13_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT13PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT13PL) || (INT16PL == 0) +/* Задаёт MINT13_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 13_16PL. */ +#define MINT13_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_16PL. */ +#define MINT13_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT13 = (MINT13_1PL & MINT13_2PL & MINT13_3PL & MINT13_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 13. */ +#define MINT13 (MINT13_1PL & MINT13_2PL & MINT13_3PL & MINT13_4PL & \ + MINT13_5PL & MINT13_6PL & MINT13_7PL & MINT13_8PL & /* Продолжает список аргументов, полей или выражение MINT13_5PL & MINT13_6PL & MINT13_7PL & MINT13_8PL &; порядок элементов сохраняется. */ \ + MINT13_9PL & MINT13_10PL & MINT13_11PL & MINT13_12PL & /* Продолжает список аргументов, полей или выражение MINT13_9PL & MINT13_10PL & MINT13_11PL & MINT13_12PL &; порядок элементов сохраняется. */ \ + MINT13_13PL & MINT13_14PL & MINT13_15PL & MINT13_16PL) /* Продолжает список аргументов, полей или выражение MINT13_13PL & MINT13_14PL & MINT13_15PL & MINT13_16PL); порядок элементов сохраняется. */ +// End Of MINT13. + +// Beginning of MINT14: +/* Условие компиляции (INT1PL >= INT14PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT14PL) || (INT1PL == 0) +/* Задаёт MINT14_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 14_1PL. */ +#define MINT14_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_1PL. */ +#define MINT14_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT14PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT14PL) || (INT2PL == 0) +/* Задаёт MINT14_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 14_2PL. */ +#define MINT14_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_2PL. */ +#define MINT14_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT14PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT14PL) || (INT3PL == 0) +/* Задаёт MINT14_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 14_3PL. */ +#define MINT14_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_3PL. */ +#define MINT14_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT14PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT14PL) || (INT4PL == 0) +/* Задаёт MINT14_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 14_4PL. */ +#define MINT14_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_4PL. */ +#define MINT14_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT14PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT14PL) || (INT5PL == 0) +/* Задаёт MINT14_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 14_5PL. */ +#define MINT14_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_5PL. */ +#define MINT14_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT14PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT14PL) || (INT6PL == 0) +/* Задаёт MINT14_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 14_6PL. */ +#define MINT14_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_6PL. */ +#define MINT14_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT14PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT14PL) || (INT7PL == 0) +/* Задаёт MINT14_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 14_7PL. */ +#define MINT14_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_7PL. */ +#define MINT14_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT14PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT14PL) || (INT8PL == 0) +/* Задаёт MINT14_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 14_8PL. */ +#define MINT14_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_8PL. */ +#define MINT14_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT14PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT14PL) || (INT9PL == 0) +/* Задаёт MINT14_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 14_9PL. */ +#define MINT14_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_9PL. */ +#define MINT14_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT14PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT14PL) || (INT10PL == 0) +/* Задаёт MINT14_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 14_10PL. */ +#define MINT14_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_10PL. */ +#define MINT14_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT14PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT14PL) || (INT11PL == 0) +/* Задаёт MINT14_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 14_11PL. */ +#define MINT14_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_11PL. */ +#define MINT14_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT14PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT14PL) || (INT12PL == 0) +/* Задаёт MINT14_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 14_12PL. */ +#define MINT14_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_12PL. */ +#define MINT14_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT14PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT14PL) || (INT13PL == 0) +/* Задаёт MINT14_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 14_13PL. */ +#define MINT14_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_13PL. */ +#define MINT14_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT14_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 14_14PL. */ +#define MINT14_14PL ~(1 << 13) + +/* Условие компиляции (INT15PL >= INT14PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT14PL) || (INT15PL == 0) +/* Задаёт MINT14_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 14_15PL. */ +#define MINT14_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_15PL. */ +#define MINT14_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT14PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT14PL) || (INT16PL == 0) +/* Задаёт MINT14_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 14_16PL. */ +#define MINT14_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_16PL. */ +#define MINT14_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT14 = (MINT14_1PL & MINT14_2PL & MINT14_3PL & MINT14_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 14. */ +#define MINT14 (MINT14_1PL & MINT14_2PL & MINT14_3PL & MINT14_4PL & \ + MINT14_5PL & MINT14_6PL & MINT14_7PL & MINT14_8PL & /* Продолжает список аргументов, полей или выражение MINT14_5PL & MINT14_6PL & MINT14_7PL & MINT14_8PL &; порядок элементов сохраняется. */ \ + MINT14_9PL & MINT14_10PL & MINT14_11PL & MINT14_12PL & /* Продолжает список аргументов, полей или выражение MINT14_9PL & MINT14_10PL & MINT14_11PL & MINT14_12PL &; порядок элементов сохраняется. */ \ + MINT14_13PL & MINT14_14PL & MINT14_15PL & MINT14_16PL) /* Продолжает список аргументов, полей или выражение MINT14_13PL & MINT14_14PL & MINT14_15PL & MINT14_16PL); порядок элементов сохраняется. */ +// End Of MINT14. + +// Beginning of MINT15: +/* Условие компиляции (INT1PL >= INT15PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT15PL) || (INT1PL == 0) +/* Задаёт MINT15_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 15_1PL. */ +#define MINT15_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_1PL. */ +#define MINT15_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT15PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT15PL) || (INT2PL == 0) +/* Задаёт MINT15_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 15_2PL. */ +#define MINT15_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_2PL. */ +#define MINT15_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT15PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT15PL) || (INT3PL == 0) +/* Задаёт MINT15_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 15_3PL. */ +#define MINT15_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_3PL. */ +#define MINT15_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT15PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT15PL) || (INT4PL == 0) +/* Задаёт MINT15_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 15_4PL. */ +#define MINT15_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_4PL. */ +#define MINT15_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT15PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT15PL) || (INT5PL == 0) +/* Задаёт MINT15_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 15_5PL. */ +#define MINT15_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_5PL. */ +#define MINT15_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT15PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT15PL) || (INT6PL == 0) +/* Задаёт MINT15_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 15_6PL. */ +#define MINT15_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_6PL. */ +#define MINT15_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT15PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT15PL) || (INT7PL == 0) +/* Задаёт MINT15_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 15_7PL. */ +#define MINT15_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_7PL. */ +#define MINT15_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT15PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT15PL) || (INT8PL == 0) +/* Задаёт MINT15_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 15_8PL. */ +#define MINT15_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_8PL. */ +#define MINT15_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT15PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT15PL) || (INT9PL == 0) +/* Задаёт MINT15_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 15_9PL. */ +#define MINT15_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_9PL. */ +#define MINT15_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT15PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT15PL) || (INT10PL == 0) +/* Задаёт MINT15_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 15_10PL. */ +#define MINT15_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_10PL. */ +#define MINT15_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT15PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT15PL) || (INT11PL == 0) +/* Задаёт MINT15_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 15_11PL. */ +#define MINT15_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_11PL. */ +#define MINT15_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT15PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT15PL) || (INT12PL == 0) +/* Задаёт MINT15_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 15_12PL. */ +#define MINT15_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_12PL. */ +#define MINT15_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT15PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT15PL) || (INT13PL == 0) +/* Задаёт MINT15_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 15_13PL. */ +#define MINT15_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_13PL. */ +#define MINT15_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT15PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT15PL) || (INT14PL == 0) +/* Задаёт MINT15_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 15_14PL. */ +#define MINT15_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_14PL. */ +#define MINT15_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT15_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 15_15PL. */ +#define MINT15_15PL ~(1 << 14) + +/* Условие компиляции (INT16PL >= INT15PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT15PL) || (INT16PL == 0) +/* Задаёт MINT15_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 15_16PL. */ +#define MINT15_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_16PL. */ +#define MINT15_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT15 = (MINT15_1PL & MINT15_2PL & MINT15_3PL & MINT15_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 15. */ +#define MINT15 (MINT15_1PL & MINT15_2PL & MINT15_3PL & MINT15_4PL & \ + MINT15_5PL & MINT15_6PL & MINT15_7PL & MINT15_8PL & /* Продолжает список аргументов, полей или выражение MINT15_5PL & MINT15_6PL & MINT15_7PL & MINT15_8PL &; порядок элементов сохраняется. */ \ + MINT15_9PL & MINT15_10PL & MINT15_11PL & MINT15_12PL & /* Продолжает список аргументов, полей или выражение MINT15_9PL & MINT15_10PL & MINT15_11PL & MINT15_12PL &; порядок элементов сохраняется. */ \ + MINT15_13PL & MINT15_14PL & MINT15_15PL & MINT15_16PL) /* Продолжает список аргументов, полей или выражение MINT15_13PL & MINT15_14PL & MINT15_15PL & MINT15_16PL); порядок элементов сохраняется. */ +// End Of MINT15. + +// Beginning of MINT16: +/* Условие компиляции (INT1PL >= INT16PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT16PL) || (INT1PL == 0) +/* Задаёт MINT16_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 16_1PL. */ +#define MINT16_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_1PL. */ +#define MINT16_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT16PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT16PL) || (INT2PL == 0) +/* Задаёт MINT16_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 16_2PL. */ +#define MINT16_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_2PL. */ +#define MINT16_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT16PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT16PL) || (INT3PL == 0) +/* Задаёт MINT16_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 16_3PL. */ +#define MINT16_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_3PL. */ +#define MINT16_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT16PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT16PL) || (INT4PL == 0) +/* Задаёт MINT16_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 16_4PL. */ +#define MINT16_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_4PL. */ +#define MINT16_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT16PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT16PL) || (INT5PL == 0) +/* Задаёт MINT16_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 16_5PL. */ +#define MINT16_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_5PL. */ +#define MINT16_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT16PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT16PL) || (INT6PL == 0) +/* Задаёт MINT16_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 16_6PL. */ +#define MINT16_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_6PL. */ +#define MINT16_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT16PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT16PL) || (INT7PL == 0) +/* Задаёт MINT16_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 16_7PL. */ +#define MINT16_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_7PL. */ +#define MINT16_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT16PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT16PL) || (INT8PL == 0) +/* Задаёт MINT16_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 16_8PL. */ +#define MINT16_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_8PL. */ +#define MINT16_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT16PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT16PL) || (INT9PL == 0) +/* Задаёт MINT16_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 16_9PL. */ +#define MINT16_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_9PL. */ +#define MINT16_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT16PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT16PL) || (INT10PL == 0) +/* Задаёт MINT16_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 16_10PL. */ +#define MINT16_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_10PL. */ +#define MINT16_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT16PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT16PL) || (INT11PL == 0) +/* Задаёт MINT16_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 16_11PL. */ +#define MINT16_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_11PL. */ +#define MINT16_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT16PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT16PL) || (INT12PL == 0) +/* Задаёт MINT16_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 16_12PL. */ +#define MINT16_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_12PL. */ +#define MINT16_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT16PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT16PL) || (INT13PL == 0) +/* Задаёт MINT16_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 16_13PL. */ +#define MINT16_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_13PL. */ +#define MINT16_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT16PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT16PL) || (INT14PL == 0) +/* Задаёт MINT16_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 16_14PL. */ +#define MINT16_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_14PL. */ +#define MINT16_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT16PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT16PL) || (INT15PL == 0) +/* Задаёт MINT16_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 16_15PL. */ +#define MINT16_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_15PL. */ +#define MINT16_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT16_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 16_16PL. */ +#define MINT16_16PL ~(1 << 15) + +/* Задаёт MINT16 = (MINT16_1PL & MINT16_2PL & MINT16_3PL & MINT16_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 16. */ +#define MINT16 (MINT16_1PL & MINT16_2PL & MINT16_3PL & MINT16_4PL & \ + MINT16_5PL & MINT16_6PL & MINT16_7PL & MINT16_8PL & /* Продолжает список аргументов, полей или выражение MINT16_5PL & MINT16_6PL & MINT16_7PL & MINT16_8PL &; порядок элементов сохраняется. */ \ + MINT16_9PL & MINT16_10PL & MINT16_11PL & MINT16_12PL & /* Продолжает список аргументов, полей или выражение MINT16_9PL & MINT16_10PL & MINT16_11PL & MINT16_12PL &; порядок элементов сохраняется. */ \ + MINT16_13PL & MINT16_14PL & MINT16_15PL & MINT16_16PL) /* Продолжает список аргументов, полей или выражение MINT16_13PL & MINT16_14PL & MINT16_15PL & MINT16_16PL); порядок элементов сохраняется. */ +// End Of MINT16. + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG11 to MG18: + +// Beginning of MG11: +/* Условие компиляции (G12PL >= G11PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G11PL) || (G12PL == 0) +/* Задаёт MG11_12PL = ~(1 << 1); данные MG11_12PL. */ +#define MG11_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_12PL = 0xFFFF; данные MG11_12PL. */ +#define MG11_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G13PL >= G11PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G11PL) || (G13PL == 0) +/* Задаёт MG11_13PL = ~(1 << 2); данные MG11_13PL. */ +#define MG11_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_13PL = 0xFFFF; данные MG11_13PL. */ +#define MG11_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G14PL >= G11PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G11PL) || (G14PL == 0) +/* Задаёт MG11_14PL = ~(1 << 3); данные MG11_14PL. */ +#define MG11_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_14PL = 0xFFFF; данные MG11_14PL. */ +#define MG11_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G15PL >= G11PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G11PL) || (G15PL == 0) +/* Задаёт MG11_15PL = ~(1 << 4); данные MG11_15PL. */ +#define MG11_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_15PL = 0xFFFF; данные MG11_15PL. */ +#define MG11_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G16PL >= G11PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G11PL) || (G16PL == 0) +/* Задаёт MG11_16PL = ~(1 << 5); данные MG11_16PL. */ +#define MG11_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_16PL = 0xFFFF; данные MG11_16PL. */ +#define MG11_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G17PL >= G11PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G11PL) || (G17PL == 0) +/* Задаёт MG11_17PL = ~(1 << 6); данные MG11_17PL. */ +#define MG11_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_17PL = 0xFFFF; данные MG11_17PL. */ +#define MG11_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G18PL >= G11PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G11PL) || (G18PL == 0) +/* Задаёт MG11_18PL = ~(1 << 7); данные MG11_18PL. */ +#define MG11_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_18PL = 0xFFFF; данные MG11_18PL. */ +#define MG11_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MG11_11PL = 0x00FE; данные MG11_11PL. */ +#define MG11_11PL 0x00FE +/* Задаёт MG11 = (MG11_11PL & MG11_12PL & MG11_13PL & MG11_14PL &; маска разрешённых прерываний внутри группы PIE 11. */ +#define MG11 (MG11_11PL & MG11_12PL & MG11_13PL & MG11_14PL & \ + MG11_15PL & MG11_16PL & MG11_17PL & MG11_18PL) /* Продолжает список аргументов, полей или выражение MG11_15PL & MG11_16PL & MG11_17PL & MG11_18PL); порядок элементов сохраняется. */ +// End of MG11: + +// Beginning of MG12: +/* Условие компиляции (G11PL >= G12PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G12PL) || (G11PL == 0) +/* Задаёт MG12_11PL = ~(1); данные MG12_11PL. */ +#define MG12_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_11PL = 0xFFFF; данные MG12_11PL. */ +#define MG12_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G12PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G12PL) || (G13PL == 0) +/* Задаёт MG12_13PL = ~(1 << 2); данные MG12_13PL. */ +#define MG12_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_13PL = 0xFFFF; данные MG12_13PL. */ +#define MG12_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G12PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G12PL) || (G14PL == 0) +/* Задаёт MG12_14PL = ~(1 << 3); данные MG12_14PL. */ +#define MG12_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_14PL = 0xFFFF; данные MG12_14PL. */ +#define MG12_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G12PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G12PL) || (G15PL == 0) +/* Задаёт MG12_15PL = ~(1 << 4); данные MG12_15PL. */ +#define MG12_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_15PL = 0xFFFF; данные MG12_15PL. */ +#define MG12_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G12PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G12PL) || (G16PL == 0) +/* Задаёт MG12_16PL = ~(1 << 5); данные MG12_16PL. */ +#define MG12_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_16PL = 0xFFFF; данные MG12_16PL. */ +#define MG12_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G12PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G12PL) || (G17PL == 0) +/* Задаёт MG12_17PL = ~(1 << 6); данные MG12_17PL. */ +#define MG12_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_17PL = 0xFFFF; данные MG12_17PL. */ +#define MG12_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G12PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G12PL) || (G18PL == 0) +/* Задаёт MG12_18PL = ~(1 << 7); данные MG12_18PL. */ +#define MG12_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_18PL = 0xFFFF; данные MG12_18PL. */ +#define MG12_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG12_12PL = 0x00FD; данные MG12_12PL. */ +#define MG12_12PL 0x00FD +/* Задаёт MG12 = (MG12_11PL & MG12_12PL & MG12_13PL & MG12_14PL &; маска разрешённых прерываний внутри группы PIE 12. */ +#define MG12 (MG12_11PL & MG12_12PL & MG12_13PL & MG12_14PL & \ + MG12_15PL & MG12_16PL & MG12_17PL & MG12_18PL) /* Продолжает список аргументов, полей или выражение MG12_15PL & MG12_16PL & MG12_17PL & MG12_18PL); порядок элементов сохраняется. */ +// End of MG12: + +// Beginning of MG13: +/* Условие компиляции (G11PL >= G13PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G13PL) || (G11PL == 0) +/* Задаёт MG13_11PL = ~(1); данные MG13_11PL. */ +#define MG13_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_11PL = 0xFFFF; данные MG13_11PL. */ +#define MG13_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G13PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G13PL) || (G12PL == 0) +/* Задаёт MG13_12PL = ~(1 << 1); данные MG13_12PL. */ +#define MG13_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_12PL = 0xFFFF; данные MG13_12PL. */ +#define MG13_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G13PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G13PL) || (G14PL == 0) +/* Задаёт MG13_14PL = ~(1 << 3); данные MG13_14PL. */ +#define MG13_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_14PL = 0xFFFF; данные MG13_14PL. */ +#define MG13_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G13PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G13PL) || (G15PL == 0) +/* Задаёт MG13_15PL = ~(1 << 4); данные MG13_15PL. */ +#define MG13_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_15PL = 0xFFFF; данные MG13_15PL. */ +#define MG13_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G13PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G13PL) || (G16PL == 0) +/* Задаёт MG13_16PL = ~(1 << 5); данные MG13_16PL. */ +#define MG13_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_16PL = 0xFFFF; данные MG13_16PL. */ +#define MG13_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G13PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G13PL) || (G17PL == 0) +/* Задаёт MG13_17PL = ~(1 << 6); данные MG13_17PL. */ +#define MG13_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_17PL = 0xFFFF; данные MG13_17PL. */ +#define MG13_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G13PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G13PL) || (G18PL == 0) +/* Задаёт MG13_18PL = ~(1 << 7); данные MG13_18PL. */ +#define MG13_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_18PL = 0xFFFF; данные MG13_18PL. */ +#define MG13_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG13_13PL = 0x00FB; данные MG13_13PL. */ +#define MG13_13PL 0x00FB +/* Задаёт MG13 = (MG13_11PL & MG13_12PL & MG13_13PL & MG13_14PL &; маска разрешённых прерываний внутри группы PIE 13. */ +#define MG13 (MG13_11PL & MG13_12PL & MG13_13PL & MG13_14PL & \ + MG13_15PL & MG13_16PL & MG13_17PL & MG13_18PL) /* Продолжает список аргументов, полей или выражение MG13_15PL & MG13_16PL & MG13_17PL & MG13_18PL); порядок элементов сохраняется. */ +// End of MG13: + +// Beginning of MG14: +/* Условие компиляции (G11PL >= G14PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G14PL) || (G11PL == 0) +/* Задаёт MG14_11PL = ~(1); данные MG14_11PL. */ +#define MG14_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_11PL = 0xFFFF; данные MG14_11PL. */ +#define MG14_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G14PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G14PL) || (G12PL == 0) +/* Задаёт MG14_12PL = ~(1 << 1); данные MG14_12PL. */ +#define MG14_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_12PL = 0xFFFF; данные MG14_12PL. */ +#define MG14_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G14PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G14PL) || (G13PL == 0) +/* Задаёт MG14_13PL = ~(1 << 2); данные MG14_13PL. */ +#define MG14_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_13PL = 0xFFFF; данные MG14_13PL. */ +#define MG14_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G14PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G14PL) || (G15PL == 0) +/* Задаёт MG14_15PL = ~(1 << 4); данные MG14_15PL. */ +#define MG14_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_15PL = 0xFFFF; данные MG14_15PL. */ +#define MG14_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G14PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G14PL) || (G16PL == 0) +/* Задаёт MG14_16PL = ~(1 << 5); данные MG14_16PL. */ +#define MG14_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_16PL = 0xFFFF; данные MG14_16PL. */ +#define MG14_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G14PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G14PL) || (G17PL == 0) +/* Задаёт MG14_17PL = ~(1 << 6); данные MG14_17PL. */ +#define MG14_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_17PL = 0xFFFF; данные MG14_17PL. */ +#define MG14_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G14PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G14PL) || (G18PL == 0) +/* Задаёт MG14_18PL = ~(1 << 7); данные MG14_18PL. */ +#define MG14_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_18PL = 0xFFFF; данные MG14_18PL. */ +#define MG14_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG14_14PL = 0x00F7; данные MG14_14PL. */ +#define MG14_14PL 0x00F7 +/* Задаёт MG14 = (MG14_11PL & MG14_12PL & MG14_13PL & MG14_14PL &; маска разрешённых прерываний внутри группы PIE 14. */ +#define MG14 (MG14_11PL & MG14_12PL & MG14_13PL & MG14_14PL & \ + MG14_15PL & MG14_16PL & MG14_17PL & MG14_18PL) /* Продолжает список аргументов, полей или выражение MG14_15PL & MG14_16PL & MG14_17PL & MG14_18PL); порядок элементов сохраняется. */ +// End of MG14: + +// Beginning of MG15: +/* Условие компиляции (G11PL >= G15PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G15PL) || (G11PL == 0) +/* Задаёт MG15_11PL = ~(1); данные MG15_11PL. */ +#define MG15_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_11PL = 0xFFFF; данные MG15_11PL. */ +#define MG15_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G15PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G15PL) || (G12PL == 0) +/* Задаёт MG15_12PL = ~(1 << 1); данные MG15_12PL. */ +#define MG15_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_12PL = 0xFFFF; данные MG15_12PL. */ +#define MG15_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G15PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G15PL) || (G13PL == 0) +/* Задаёт MG15_13PL = ~(1 << 2); данные MG15_13PL. */ +#define MG15_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_13PL = 0xFFFF; данные MG15_13PL. */ +#define MG15_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G15PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G15PL) || (G14PL == 0) +/* Задаёт MG15_14PL = ~(1 << 3); данные MG15_14PL. */ +#define MG15_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_14PL = 0xFFFF; данные MG15_14PL. */ +#define MG15_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G15PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G15PL) || (G16PL == 0) +/* Задаёт MG15_16PL = ~(1 << 5); данные MG15_16PL. */ +#define MG15_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_16PL = 0xFFFF; данные MG15_16PL. */ +#define MG15_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G15PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G15PL) || (G17PL == 0) +/* Задаёт MG15_17PL = ~(1 << 6); данные MG15_17PL. */ +#define MG15_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_17PL = 0xFFFF; данные MG15_17PL. */ +#define MG15_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G15PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G15PL) || (G18PL == 0) +/* Задаёт MG15_18PL = ~(1 << 7); данные MG15_18PL. */ +#define MG15_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_18PL = 0xFFFF; данные MG15_18PL. */ +#define MG15_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG15_15PL = 0x00EF; данные MG15_15PL. */ +#define MG15_15PL 0x00EF +/* Задаёт MG15 = (MG15_11PL & MG15_12PL & MG15_13PL & MG15_14PL &; маска разрешённых прерываний внутри группы PIE 15. */ +#define MG15 (MG15_11PL & MG15_12PL & MG15_13PL & MG15_14PL & \ + MG15_15PL & MG15_16PL & MG15_17PL & MG15_18PL) /* Продолжает список аргументов, полей или выражение MG15_15PL & MG15_16PL & MG15_17PL & MG15_18PL); порядок элементов сохраняется. */ +// End of MG15: + +// Beginning of MG16: +/* Условие компиляции (G11PL >= G16PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G16PL) || (G11PL == 0) +/* Задаёт MG16_11PL = ~(1); данные MG16_11PL. */ +#define MG16_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_11PL = 0xFFFF; данные MG16_11PL. */ +#define MG16_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G16PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G16PL) || (G12PL == 0) +/* Задаёт MG16_12PL = ~(1 << 1); данные MG16_12PL. */ +#define MG16_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_12PL = 0xFFFF; данные MG16_12PL. */ +#define MG16_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G16PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G16PL) || (G13PL == 0) +/* Задаёт MG16_13PL = ~(1 << 2); данные MG16_13PL. */ +#define MG16_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_13PL = 0xFFFF; данные MG16_13PL. */ +#define MG16_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G16PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G16PL) || (G14PL == 0) +/* Задаёт MG16_14PL = ~(1 << 3); данные MG16_14PL. */ +#define MG16_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_14PL = 0xFFFF; данные MG16_14PL. */ +#define MG16_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G16PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G16PL) || (G15PL == 0) +/* Задаёт MG16_15PL = ~(1 << 4); данные MG16_15PL. */ +#define MG16_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_15PL = 0xFFFF; данные MG16_15PL. */ +#define MG16_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G16PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G16PL) || (G17PL == 0) +/* Задаёт MG16_17PL = ~(1 << 6); данные MG16_17PL. */ +#define MG16_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_17PL = 0xFFFF; данные MG16_17PL. */ +#define MG16_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G16PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G16PL) || (G18PL == 0) +/* Задаёт MG16_18PL = ~(1 << 7); данные MG16_18PL. */ +#define MG16_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_18PL = 0xFFFF; данные MG16_18PL. */ +#define MG16_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG16_16PL = 0x00DF; данные MG16_16PL. */ +#define MG16_16PL 0x00DF +/* Задаёт MG16 = (MG16_11PL & MG16_12PL & MG16_13PL & MG16_14PL &; маска разрешённых прерываний внутри группы PIE 16. */ +#define MG16 (MG16_11PL & MG16_12PL & MG16_13PL & MG16_14PL & \ + MG16_15PL & MG16_16PL & MG16_17PL & MG16_18PL) /* Продолжает список аргументов, полей или выражение MG16_15PL & MG16_16PL & MG16_17PL & MG16_18PL); порядок элементов сохраняется. */ +// End of MG16: + +// Beginning of MG17: +/* Условие компиляции (G11PL >= G17PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G17PL) || (G11PL == 0) +/* Задаёт MG17_11PL = ~(1); данные MG17_11PL. */ +#define MG17_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_11PL = 0xFFFF; данные MG17_11PL. */ +#define MG17_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G17PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G17PL) || (G12PL == 0) +/* Задаёт MG17_12PL = ~(1 << 1); данные MG17_12PL. */ +#define MG17_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_12PL = 0xFFFF; данные MG17_12PL. */ +#define MG17_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G17PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G17PL) || (G13PL == 0) +/* Задаёт MG17_13PL = ~(1 << 2); данные MG17_13PL. */ +#define MG17_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_13PL = 0xFFFF; данные MG17_13PL. */ +#define MG17_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G17PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G17PL) || (G14PL == 0) +/* Задаёт MG17_14PL = ~(1 << 3); данные MG17_14PL. */ +#define MG17_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_14PL = 0xFFFF; данные MG17_14PL. */ +#define MG17_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G17PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G17PL) || (G15PL == 0) +/* Задаёт MG17_15PL = ~(1 << 4); данные MG17_15PL. */ +#define MG17_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_15PL = 0xFFFF; данные MG17_15PL. */ +#define MG17_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G17PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G17PL) || (G16PL == 0) +/* Задаёт MG17_16PL = ~(1 << 5); данные MG17_16PL. */ +#define MG17_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_16PL = 0xFFFF; данные MG17_16PL. */ +#define MG17_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G17PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G17PL) || (G18PL == 0) +/* Задаёт MG17_18PL = ~(1 << 7); данные MG17_18PL. */ +#define MG17_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_18PL = 0xFFFF; данные MG17_18PL. */ +#define MG17_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG17_17PL = 0x00BF; данные MG17_17PL. */ +#define MG17_17PL 0x00BF +/* Задаёт MG17 = (MG17_11PL & MG17_12PL & MG17_13PL & MG17_14PL &; маска разрешённых прерываний внутри группы PIE 17. */ +#define MG17 (MG17_11PL & MG17_12PL & MG17_13PL & MG17_14PL & \ + MG17_15PL & MG17_16PL & MG17_17PL & MG17_18PL) /* Продолжает список аргументов, полей или выражение MG17_15PL & MG17_16PL & MG17_17PL & MG17_18PL); порядок элементов сохраняется. */ +// End of MG17: + +// Beginning of MG18: +/* Условие компиляции (G11PL >= G18PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G18PL) || (G11PL == 0) +/* Задаёт MG18_11PL = ~(1); данные MG18_11PL. */ +#define MG18_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_11PL = 0xFFFF; данные MG18_11PL. */ +#define MG18_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G18PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G18PL) || (G12PL == 0) +/* Задаёт MG18_12PL = ~(1 << 1); данные MG18_12PL. */ +#define MG18_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_12PL = 0xFFFF; данные MG18_12PL. */ +#define MG18_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G18PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G18PL) || (G13PL == 0) +/* Задаёт MG18_13PL = ~(1 << 2); данные MG18_13PL. */ +#define MG18_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_13PL = 0xFFFF; данные MG18_13PL. */ +#define MG18_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G18PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G18PL) || (G14PL == 0) +/* Задаёт MG18_14PL = ~(1 << 3); данные MG18_14PL. */ +#define MG18_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_14PL = 0xFFFF; данные MG18_14PL. */ +#define MG18_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G18PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G18PL) || (G15PL == 0) +/* Задаёт MG18_15PL = ~(1 << 4); данные MG18_15PL. */ +#define MG18_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_15PL = 0xFFFF; данные MG18_15PL. */ +#define MG18_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G18PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G18PL) || (G16PL == 0) +/* Задаёт MG18_16PL = ~(1 << 5); данные MG18_16PL. */ +#define MG18_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_16PL = 0xFFFF; данные MG18_16PL. */ +#define MG18_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G18PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G18PL) || (G17PL == 0) +/* Задаёт MG18_17PL = ~(1 << 6); данные MG18_17PL. */ +#define MG18_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_17PL = 0xFFFF; данные MG18_17PL. */ +#define MG18_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG18_18PL = 0x007F; данные MG18_18PL. */ +#define MG18_18PL 0x007F +/* Задаёт MG18 = (MG18_11PL & MG18_12PL & MG18_13PL & MG18_14PL &; маска разрешённых прерываний внутри группы PIE 18. */ +#define MG18 (MG18_11PL & MG18_12PL & MG18_13PL & MG18_14PL & \ + MG18_15PL & MG18_16PL & MG18_17PL & MG18_18PL) /* Продолжает список аргументов, полей или выражение MG18_15PL & MG18_16PL & MG18_17PL & MG18_18PL); порядок элементов сохраняется. */ +// End of MG18: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG21 to MG28: +// + +// Beginning of MG21: +/* Условие компиляции (G22PL >= G21PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G21PL) || (G22PL == 0) +/* Задаёт MG21_12PL = ~(1 << 1); данные MG21_12PL. */ +#define MG21_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_12PL = 0xFFFF; данные MG21_12PL. */ +#define MG21_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G21PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G21PL) || (G23PL == 0) +/* Задаёт MG21_13PL = ~(1 << 2); данные MG21_13PL. */ +#define MG21_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_13PL = 0xFFFF; данные MG21_13PL. */ +#define MG21_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G21PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G21PL) || (G24PL == 0) +/* Задаёт MG21_14PL = ~(1 << 3); данные MG21_14PL. */ +#define MG21_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_14PL = 0xFFFF; данные MG21_14PL. */ +#define MG21_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G21PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G21PL) || (G25PL == 0) +/* Задаёт MG21_15PL = ~(1 << 4); данные MG21_15PL. */ +#define MG21_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_15PL = 0xFFFF; данные MG21_15PL. */ +#define MG21_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G21PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G21PL) || (G26PL == 0) +/* Задаёт MG21_16PL = ~(1 << 5); данные MG21_16PL. */ +#define MG21_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_16PL = 0xFFFF; данные MG21_16PL. */ +#define MG21_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G21PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G21PL) || (G27PL == 0) +/* Задаёт MG21_17PL = ~(1 << 6); данные MG21_17PL. */ +#define MG21_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_17PL = 0xFFFF; данные MG21_17PL. */ +#define MG21_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G21PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G21PL) || (G28PL == 0) +/* Задаёт MG21_18PL = ~(1 << 7); данные MG21_18PL. */ +#define MG21_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_18PL = 0xFFFF; данные MG21_18PL. */ +#define MG21_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG21_11PL = 0x00FE; данные MG21_11PL. */ +#define MG21_11PL 0x00FE +/* Задаёт MG21 = (MG21_11PL & MG21_12PL & MG21_13PL & MG21_14PL &; маска разрешённых прерываний внутри группы PIE 21. */ +#define MG21 (MG21_11PL & MG21_12PL & MG21_13PL & MG21_14PL & \ + MG21_15PL & MG21_16PL & MG21_17PL & MG21_18PL) /* Продолжает список аргументов, полей или выражение MG21_15PL & MG21_16PL & MG21_17PL & MG21_18PL); порядок элементов сохраняется. */ +// End of MG21: + +// Beginning of MG22: +/* Условие компиляции (G21PL >= G22PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G22PL) || (G21PL == 0) +/* Задаёт MG22_11PL = ~(1); данные MG22_11PL. */ +#define MG22_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_11PL = 0xFFFF; данные MG22_11PL. */ +#define MG22_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G22PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G22PL) || (G23PL == 0) +/* Задаёт MG22_13PL = ~(1 << 2); данные MG22_13PL. */ +#define MG22_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_13PL = 0xFFFF; данные MG22_13PL. */ +#define MG22_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G22PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G22PL) || (G24PL == 0) +/* Задаёт MG22_14PL = ~(1 << 3); данные MG22_14PL. */ +#define MG22_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_14PL = 0xFFFF; данные MG22_14PL. */ +#define MG22_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G22PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G22PL) || (G25PL == 0) +/* Задаёт MG22_15PL = ~(1 << 4); данные MG22_15PL. */ +#define MG22_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_15PL = 0xFFFF; данные MG22_15PL. */ +#define MG22_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G22PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G22PL) || (G26PL == 0) +/* Задаёт MG22_16PL = ~(1 << 5); данные MG22_16PL. */ +#define MG22_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_16PL = 0xFFFF; данные MG22_16PL. */ +#define MG22_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G22PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G22PL) || (G27PL == 0) +/* Задаёт MG22_17PL = ~(1 << 6); данные MG22_17PL. */ +#define MG22_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_17PL = 0xFFFF; данные MG22_17PL. */ +#define MG22_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G22PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G22PL) || (G28PL == 0) +/* Задаёт MG22_18PL = ~(1 << 7); данные MG22_18PL. */ +#define MG22_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_18PL = 0xFFFF; данные MG22_18PL. */ +#define MG22_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG22_12PL = 0x00FD; данные MG22_12PL. */ +#define MG22_12PL 0x00FD +/* Задаёт MG22 = (MG22_11PL & MG22_12PL & MG22_13PL & MG22_14PL &; маска разрешённых прерываний внутри группы PIE 22. */ +#define MG22 (MG22_11PL & MG22_12PL & MG22_13PL & MG22_14PL & \ + MG22_15PL & MG22_16PL & MG22_17PL & MG22_18PL) /* Продолжает список аргументов, полей или выражение MG22_15PL & MG22_16PL & MG22_17PL & MG22_18PL); порядок элементов сохраняется. */ +// End of MG22: + +// Beginning of MG23: +/* Условие компиляции (G21PL >= G23PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G23PL) || (G21PL == 0) +/* Задаёт MG23_11PL = ~(1); данные MG23_11PL. */ +#define MG23_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_11PL = 0xFFFF; данные MG23_11PL. */ +#define MG23_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G23PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G23PL) || (G22PL == 0) +/* Задаёт MG23_12PL = ~(1 << 1); данные MG23_12PL. */ +#define MG23_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_12PL = 0xFFFF; данные MG23_12PL. */ +#define MG23_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G23PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G23PL) || (G24PL == 0) +/* Задаёт MG23_14PL = ~(1 << 3); данные MG23_14PL. */ +#define MG23_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_14PL = 0xFFFF; данные MG23_14PL. */ +#define MG23_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G23PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G23PL) || (G25PL == 0) +/* Задаёт MG23_15PL = ~(1 << 4); данные MG23_15PL. */ +#define MG23_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_15PL = 0xFFFF; данные MG23_15PL. */ +#define MG23_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G23PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G23PL) || (G26PL == 0) +/* Задаёт MG23_16PL = ~(1 << 5); данные MG23_16PL. */ +#define MG23_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_16PL = 0xFFFF; данные MG23_16PL. */ +#define MG23_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G23PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G23PL) || (G27PL == 0) +/* Задаёт MG23_17PL = ~(1 << 6); данные MG23_17PL. */ +#define MG23_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_17PL = 0xFFFF; данные MG23_17PL. */ +#define MG23_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G23PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G23PL) || (G28PL == 0) +/* Задаёт MG23_18PL = ~(1 << 7); данные MG23_18PL. */ +#define MG23_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_18PL = 0xFFFF; данные MG23_18PL. */ +#define MG23_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG23_13PL = 0x00FB; данные MG23_13PL. */ +#define MG23_13PL 0x00FB +/* Задаёт MG23 = (MG23_11PL & MG23_12PL & MG23_13PL & MG23_14PL &; маска разрешённых прерываний внутри группы PIE 23. */ +#define MG23 (MG23_11PL & MG23_12PL & MG23_13PL & MG23_14PL & \ + MG23_15PL & MG23_16PL & MG23_17PL & MG23_18PL) /* Продолжает список аргументов, полей или выражение MG23_15PL & MG23_16PL & MG23_17PL & MG23_18PL); порядок элементов сохраняется. */ +// End of MG23: + +// Beginning of MG24: +/* Условие компиляции (G21PL >= G24PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G24PL) || (G21PL == 0) +/* Задаёт MG24_11PL = ~(1); данные MG24_11PL. */ +#define MG24_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_11PL = 0xFFFF; данные MG24_11PL. */ +#define MG24_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G24PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G24PL) || (G22PL == 0) +/* Задаёт MG24_12PL = ~(1 << 1); данные MG24_12PL. */ +#define MG24_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_12PL = 0xFFFF; данные MG24_12PL. */ +#define MG24_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G24PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G24PL) || (G23PL == 0) +/* Задаёт MG24_13PL = ~(1 << 2); данные MG24_13PL. */ +#define MG24_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_13PL = 0xFFFF; данные MG24_13PL. */ +#define MG24_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G24PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G24PL) || (G25PL == 0) +/* Задаёт MG24_15PL = ~(1 << 4); данные MG24_15PL. */ +#define MG24_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_15PL = 0xFFFF; данные MG24_15PL. */ +#define MG24_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G24PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G24PL) || (G26PL == 0) +/* Задаёт MG24_16PL = ~(1 << 5); данные MG24_16PL. */ +#define MG24_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_16PL = 0xFFFF; данные MG24_16PL. */ +#define MG24_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G24PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G24PL) || (G27PL == 0) +/* Задаёт MG24_17PL = ~(1 << 6); данные MG24_17PL. */ +#define MG24_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_17PL = 0xFFFF; данные MG24_17PL. */ +#define MG24_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G24PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G24PL) || (G28PL == 0) +/* Задаёт MG24_18PL = ~(1 << 7); данные MG24_18PL. */ +#define MG24_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_18PL = 0xFFFF; данные MG24_18PL. */ +#define MG24_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG24_14PL = 0x00F7; данные MG24_14PL. */ +#define MG24_14PL 0x00F7 +/* Задаёт MG24 = (MG24_11PL & MG24_12PL & MG24_13PL & MG24_14PL &; маска разрешённых прерываний внутри группы PIE 24. */ +#define MG24 (MG24_11PL & MG24_12PL & MG24_13PL & MG24_14PL & \ + MG24_15PL & MG24_16PL & MG24_17PL & MG24_18PL) /* Продолжает список аргументов, полей или выражение MG24_15PL & MG24_16PL & MG24_17PL & MG24_18PL); порядок элементов сохраняется. */ +// End of MG24: + +// Beginning of MG25: +/* Условие компиляции (G21PL >= G25PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G25PL) || (G21PL == 0) +/* Задаёт MG25_11PL = ~(1); данные MG25_11PL. */ +#define MG25_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_11PL = 0xFFFF; данные MG25_11PL. */ +#define MG25_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G25PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G25PL) || (G22PL == 0) +/* Задаёт MG25_12PL = ~(1 << 1); данные MG25_12PL. */ +#define MG25_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_12PL = 0xFFFF; данные MG25_12PL. */ +#define MG25_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G25PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G25PL) || (G23PL == 0) +/* Задаёт MG25_13PL = ~(1 << 2); данные MG25_13PL. */ +#define MG25_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_13PL = 0xFFFF; данные MG25_13PL. */ +#define MG25_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G25PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G25PL) || (G24PL == 0) +/* Задаёт MG25_14PL = ~(1 << 3); данные MG25_14PL. */ +#define MG25_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_14PL = 0xFFFF; данные MG25_14PL. */ +#define MG25_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G25PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G25PL) || (G26PL == 0) +/* Задаёт MG25_16PL = ~(1 << 5); данные MG25_16PL. */ +#define MG25_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_16PL = 0xFFFF; данные MG25_16PL. */ +#define MG25_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G25PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G25PL) || (G27PL == 0) +/* Задаёт MG25_17PL = ~(1 << 6); данные MG25_17PL. */ +#define MG25_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_17PL = 0xFFFF; данные MG25_17PL. */ +#define MG25_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G25PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G25PL) || (G28PL == 0) +/* Задаёт MG25_18PL = ~(1 << 7); данные MG25_18PL. */ +#define MG25_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_18PL = 0xFFFF; данные MG25_18PL. */ +#define MG25_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG25_15PL = 0x00EF; данные MG25_15PL. */ +#define MG25_15PL 0x00EF +/* Задаёт MG25 = (MG25_11PL & MG25_12PL & MG25_13PL & MG25_14PL &; маска разрешённых прерываний внутри группы PIE 25. */ +#define MG25 (MG25_11PL & MG25_12PL & MG25_13PL & MG25_14PL & \ + MG25_15PL & MG25_16PL & MG25_17PL & MG25_18PL) /* Продолжает список аргументов, полей или выражение MG25_15PL & MG25_16PL & MG25_17PL & MG25_18PL); порядок элементов сохраняется. */ +// End of MG25: + +// Beginning of MG26: +/* Условие компиляции (G21PL >= G26PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G26PL) || (G21PL == 0) +/* Задаёт MG26_11PL = ~(1); данные MG26_11PL. */ +#define MG26_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_11PL = 0xFFFF; данные MG26_11PL. */ +#define MG26_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G26PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G26PL) || (G22PL == 0) +/* Задаёт MG26_12PL = ~(1 << 1); данные MG26_12PL. */ +#define MG26_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_12PL = 0xFFFF; данные MG26_12PL. */ +#define MG26_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G26PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G26PL) || (G23PL == 0) +/* Задаёт MG26_13PL = ~(1 << 2); данные MG26_13PL. */ +#define MG26_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_13PL = 0xFFFF; данные MG26_13PL. */ +#define MG26_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G26PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G26PL) || (G24PL == 0) +/* Задаёт MG26_14PL = ~(1 << 3); данные MG26_14PL. */ +#define MG26_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_14PL = 0xFFFF; данные MG26_14PL. */ +#define MG26_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G26PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G26PL) || (G25PL == 0) +/* Задаёт MG26_15PL = ~(1 << 4); данные MG26_15PL. */ +#define MG26_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_15PL = 0xFFFF; данные MG26_15PL. */ +#define MG26_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G26PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G26PL) || (G27PL == 0) +/* Задаёт MG26_17PL = ~(1 << 6); данные MG26_17PL. */ +#define MG26_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_17PL = 0xFFFF; данные MG26_17PL. */ +#define MG26_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G26PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G26PL) || (G28PL == 0) +/* Задаёт MG26_18PL = ~(1 << 7); данные MG26_18PL. */ +#define MG26_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_18PL = 0xFFFF; данные MG26_18PL. */ +#define MG26_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG26_16PL = 0x00DF; данные MG26_16PL. */ +#define MG26_16PL 0x00DF +/* Задаёт MG26 = (MG26_11PL & MG26_12PL & MG26_13PL & MG26_14PL &; маска разрешённых прерываний внутри группы PIE 26. */ +#define MG26 (MG26_11PL & MG26_12PL & MG26_13PL & MG26_14PL & \ + MG26_15PL & MG26_16PL & MG26_17PL & MG26_18PL) /* Продолжает список аргументов, полей или выражение MG26_15PL & MG26_16PL & MG26_17PL & MG26_18PL); порядок элементов сохраняется. */ +// End of MG26: + +// Beginning of MG27: +/* Условие компиляции (G21PL >= G27PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G27PL) || (G21PL == 0) +/* Задаёт MG27_11PL = ~(1); данные MG27_11PL. */ +#define MG27_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_11PL = 0xFFFF; данные MG27_11PL. */ +#define MG27_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G27PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G27PL) || (G22PL == 0) +/* Задаёт MG27_12PL = ~(1 << 1); данные MG27_12PL. */ +#define MG27_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_12PL = 0xFFFF; данные MG27_12PL. */ +#define MG27_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G27PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G27PL) || (G23PL == 0) +/* Задаёт MG27_13PL = ~(1 << 2); данные MG27_13PL. */ +#define MG27_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_13PL = 0xFFFF; данные MG27_13PL. */ +#define MG27_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G27PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G27PL) || (G24PL == 0) +/* Задаёт MG27_14PL = ~(1 << 3); данные MG27_14PL. */ +#define MG27_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_14PL = 0xFFFF; данные MG27_14PL. */ +#define MG27_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G27PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G27PL) || (G25PL == 0) +/* Задаёт MG27_15PL = ~(1 << 4); данные MG27_15PL. */ +#define MG27_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_15PL = 0xFFFF; данные MG27_15PL. */ +#define MG27_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G27PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G27PL) || (G26PL == 0) +/* Задаёт MG27_16PL = ~(1 << 5); данные MG27_16PL. */ +#define MG27_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_16PL = 0xFFFF; данные MG27_16PL. */ +#define MG27_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G27PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G27PL) || (G28PL == 0) +/* Задаёт MG27_18PL = ~(1 << 7); данные MG27_18PL. */ +#define MG27_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_18PL = 0xFFFF; данные MG27_18PL. */ +#define MG27_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG27_17PL = 0x00BF; данные MG27_17PL. */ +#define MG27_17PL 0x00BF +/* Задаёт MG27 = (MG27_11PL & MG27_12PL & MG27_13PL & MG27_14PL &; маска разрешённых прерываний внутри группы PIE 27. */ +#define MG27 (MG27_11PL & MG27_12PL & MG27_13PL & MG27_14PL & \ + MG27_15PL & MG27_16PL & MG27_17PL & MG27_18PL) /* Продолжает список аргументов, полей или выражение MG27_15PL & MG27_16PL & MG27_17PL & MG27_18PL); порядок элементов сохраняется. */ +// End of MG27: + +// Beginning of MG28: +/* Условие компиляции (G21PL >= G28PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G28PL) || (G21PL == 0) +/* Задаёт MG28_11PL = ~(1); данные MG28_11PL. */ +#define MG28_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_11PL = 0xFFFF; данные MG28_11PL. */ +#define MG28_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G28PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G28PL) || (G22PL == 0) +/* Задаёт MG28_12PL = ~(1 << 1); данные MG28_12PL. */ +#define MG28_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_12PL = 0xFFFF; данные MG28_12PL. */ +#define MG28_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G28PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G28PL) || (G23PL == 0) +/* Задаёт MG28_13PL = ~(1 << 2); данные MG28_13PL. */ +#define MG28_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_13PL = 0xFFFF; данные MG28_13PL. */ +#define MG28_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G28PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G28PL) || (G24PL == 0) +/* Задаёт MG28_14PL = ~(1 << 3); данные MG28_14PL. */ +#define MG28_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_14PL = 0xFFFF; данные MG28_14PL. */ +#define MG28_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G28PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G28PL) || (G25PL == 0) +/* Задаёт MG28_15PL = ~(1 << 4); данные MG28_15PL. */ +#define MG28_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_15PL = 0xFFFF; данные MG28_15PL. */ +#define MG28_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G28PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G28PL) || (G26PL == 0) +/* Задаёт MG28_16PL = ~(1 << 5); данные MG28_16PL. */ +#define MG28_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_16PL = 0xFFFF; данные MG28_16PL. */ +#define MG28_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G28PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G28PL) || (G27PL == 0) +/* Задаёт MG28_17PL = ~(1 << 6); данные MG28_17PL. */ +#define MG28_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_17PL = 0xFFFF; данные MG28_17PL. */ +#define MG28_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG28_18PL = 0x007F; данные MG28_18PL. */ +#define MG28_18PL 0x007F +/* Задаёт MG28 = (MG28_11PL & MG28_12PL & MG28_13PL & MG28_14PL &; маска разрешённых прерываний внутри группы PIE 28. */ +#define MG28 (MG28_11PL & MG28_12PL & MG28_13PL & MG28_14PL & \ + MG28_15PL & MG28_16PL & MG28_17PL & MG28_18PL) /* Продолжает список аргументов, полей или выражение MG28_15PL & MG28_16PL & MG28_17PL & MG28_18PL); порядок элементов сохраняется. */ +// End of MG28: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG31 to MG38: +// + +// Beginning of MG31: +/* Условие компиляции (G32PL >= G31PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G31PL) || (G32PL == 0) +/* Задаёт MG31_12PL = ~(1 << 1); данные MG31_12PL. */ +#define MG31_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_12PL = 0xFFFF; данные MG31_12PL. */ +#define MG31_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G31PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G31PL) || (G33PL == 0) +/* Задаёт MG31_13PL = ~(1 << 2); данные MG31_13PL. */ +#define MG31_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_13PL = 0xFFFF; данные MG31_13PL. */ +#define MG31_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G31PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G31PL) || (G34PL == 0) +/* Задаёт MG31_14PL = ~(1 << 3); данные MG31_14PL. */ +#define MG31_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_14PL = 0xFFFF; данные MG31_14PL. */ +#define MG31_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G31PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G31PL) || (G35PL == 0) +/* Задаёт MG31_15PL = ~(1 << 4); данные MG31_15PL. */ +#define MG31_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_15PL = 0xFFFF; данные MG31_15PL. */ +#define MG31_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G31PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G31PL) || (G36PL == 0) +/* Задаёт MG31_16PL = ~(1 << 5); данные MG31_16PL. */ +#define MG31_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_16PL = 0xFFFF; данные MG31_16PL. */ +#define MG31_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G31PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G31PL) || (G37PL == 0) +/* Задаёт MG31_17PL = ~(1 << 6); данные MG31_17PL. */ +#define MG31_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_17PL = 0xFFFF; данные MG31_17PL. */ +#define MG31_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G31PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G31PL) || (G38PL == 0) +/* Задаёт MG31_18PL = ~(1 << 7); данные MG31_18PL. */ +#define MG31_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_18PL = 0xFFFF; данные MG31_18PL. */ +#define MG31_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG31_11PL = 0x00FE; данные MG31_11PL. */ +#define MG31_11PL 0x00FE +/* Задаёт MG31 = (MG31_11PL & MG31_12PL & MG31_13PL & MG31_14PL &; маска разрешённых прерываний внутри группы PIE 31. */ +#define MG31 (MG31_11PL & MG31_12PL & MG31_13PL & MG31_14PL & \ + MG31_15PL & MG31_16PL & MG31_17PL & MG31_18PL) /* Продолжает список аргументов, полей или выражение MG31_15PL & MG31_16PL & MG31_17PL & MG31_18PL); порядок элементов сохраняется. */ +// End of MG31: + +// Beginning of MG32: +/* Условие компиляции (G31PL >= G32PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G32PL) || (G31PL == 0) +/* Задаёт MG32_11PL = ~(1); данные MG32_11PL. */ +#define MG32_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_11PL = 0xFFFF; данные MG32_11PL. */ +#define MG32_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G32PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G32PL) || (G33PL == 0) +/* Задаёт MG32_13PL = ~(1 << 2); данные MG32_13PL. */ +#define MG32_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_13PL = 0xFFFF; данные MG32_13PL. */ +#define MG32_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G32PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G32PL) || (G34PL == 0) +/* Задаёт MG32_14PL = ~(1 << 3); данные MG32_14PL. */ +#define MG32_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_14PL = 0xFFFF; данные MG32_14PL. */ +#define MG32_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G32PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G32PL) || (G35PL == 0) +/* Задаёт MG32_15PL = ~(1 << 4); данные MG32_15PL. */ +#define MG32_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_15PL = 0xFFFF; данные MG32_15PL. */ +#define MG32_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G32PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G32PL) || (G36PL == 0) +/* Задаёт MG32_16PL = ~(1 << 5); данные MG32_16PL. */ +#define MG32_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_16PL = 0xFFFF; данные MG32_16PL. */ +#define MG32_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G32PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G32PL) || (G37PL == 0) +/* Задаёт MG32_17PL = ~(1 << 6); данные MG32_17PL. */ +#define MG32_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_17PL = 0xFFFF; данные MG32_17PL. */ +#define MG32_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G32PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G32PL) || (G38PL == 0) +/* Задаёт MG32_18PL = ~(1 << 7); данные MG32_18PL. */ +#define MG32_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_18PL = 0xFFFF; данные MG32_18PL. */ +#define MG32_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG32_12PL = 0x00FD; данные MG32_12PL. */ +#define MG32_12PL 0x00FD +/* Задаёт MG32 = (MG32_11PL & MG32_12PL & MG32_13PL & MG32_14PL &; маска разрешённых прерываний внутри группы PIE 32. */ +#define MG32 (MG32_11PL & MG32_12PL & MG32_13PL & MG32_14PL & \ + MG32_15PL & MG32_16PL & MG32_17PL & MG32_18PL) /* Продолжает список аргументов, полей или выражение MG32_15PL & MG32_16PL & MG32_17PL & MG32_18PL); порядок элементов сохраняется. */ +// End of MG32: + +// Beginning of MG33: +/* Условие компиляции (G31PL >= G33PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G33PL) || (G31PL == 0) +/* Задаёт MG33_11PL = ~(1); данные MG33_11PL. */ +#define MG33_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_11PL = 0xFFFF; данные MG33_11PL. */ +#define MG33_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G33PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G33PL) || (G32PL == 0) +/* Задаёт MG33_12PL = ~(1 << 1); данные MG33_12PL. */ +#define MG33_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_12PL = 0xFFFF; данные MG33_12PL. */ +#define MG33_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G33PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G33PL) || (G34PL == 0) +/* Задаёт MG33_14PL = ~(1 << 3); данные MG33_14PL. */ +#define MG33_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_14PL = 0xFFFF; данные MG33_14PL. */ +#define MG33_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G33PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G33PL) || (G35PL == 0) +/* Задаёт MG33_15PL = ~(1 << 4); данные MG33_15PL. */ +#define MG33_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_15PL = 0xFFFF; данные MG33_15PL. */ +#define MG33_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G33PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G33PL) || (G36PL == 0) +/* Задаёт MG33_16PL = ~(1 << 5); данные MG33_16PL. */ +#define MG33_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_16PL = 0xFFFF; данные MG33_16PL. */ +#define MG33_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G33PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G33PL) || (G37PL == 0) +/* Задаёт MG33_17PL = ~(1 << 6); данные MG33_17PL. */ +#define MG33_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_17PL = 0xFFFF; данные MG33_17PL. */ +#define MG33_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G33PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G33PL) || (G38PL == 0) +/* Задаёт MG33_18PL = ~(1 << 7); данные MG33_18PL. */ +#define MG33_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_18PL = 0xFFFF; данные MG33_18PL. */ +#define MG33_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG33_13PL = 0x00FB; данные MG33_13PL. */ +#define MG33_13PL 0x00FB +/* Задаёт MG33 = (MG33_11PL & MG33_12PL & MG33_13PL & MG33_14PL &; маска разрешённых прерываний внутри группы PIE 33. */ +#define MG33 (MG33_11PL & MG33_12PL & MG33_13PL & MG33_14PL & \ + MG33_15PL & MG33_16PL & MG33_17PL & MG33_18PL) /* Продолжает список аргументов, полей или выражение MG33_15PL & MG33_16PL & MG33_17PL & MG33_18PL); порядок элементов сохраняется. */ +// End of MG33: + +// Beginning of MG34: +/* Условие компиляции (G31PL >= G34PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G34PL) || (G31PL == 0) +/* Задаёт MG34_11PL = ~(1); данные MG34_11PL. */ +#define MG34_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_11PL = 0xFFFF; данные MG34_11PL. */ +#define MG34_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G34PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G34PL) || (G32PL == 0) +/* Задаёт MG34_12PL = ~(1 << 1); данные MG34_12PL. */ +#define MG34_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_12PL = 0xFFFF; данные MG34_12PL. */ +#define MG34_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G34PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G34PL) || (G33PL == 0) +/* Задаёт MG34_13PL = ~(1 << 2); данные MG34_13PL. */ +#define MG34_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_13PL = 0xFFFF; данные MG34_13PL. */ +#define MG34_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G34PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G34PL) || (G35PL == 0) +/* Задаёт MG34_15PL = ~(1 << 4); данные MG34_15PL. */ +#define MG34_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_15PL = 0xFFFF; данные MG34_15PL. */ +#define MG34_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G34PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G34PL) || (G36PL == 0) +/* Задаёт MG34_16PL = ~(1 << 5); данные MG34_16PL. */ +#define MG34_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_16PL = 0xFFFF; данные MG34_16PL. */ +#define MG34_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G34PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G34PL) || (G37PL == 0) +/* Задаёт MG34_17PL = ~(1 << 6); данные MG34_17PL. */ +#define MG34_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_17PL = 0xFFFF; данные MG34_17PL. */ +#define MG34_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G34PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G34PL) || (G38PL == 0) +/* Задаёт MG34_18PL = ~(1 << 7); данные MG34_18PL. */ +#define MG34_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_18PL = 0xFFFF; данные MG34_18PL. */ +#define MG34_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG34_14PL = 0x00F7; данные MG34_14PL. */ +#define MG34_14PL 0x00F7 +/* Задаёт MG34 = (MG34_11PL & MG34_12PL & MG34_13PL & MG34_14PL &; маска разрешённых прерываний внутри группы PIE 34. */ +#define MG34 (MG34_11PL & MG34_12PL & MG34_13PL & MG34_14PL & \ + MG34_15PL & MG34_16PL & MG34_17PL & MG34_18PL) /* Продолжает список аргументов, полей или выражение MG34_15PL & MG34_16PL & MG34_17PL & MG34_18PL); порядок элементов сохраняется. */ +// End of MG34: + +// Beginning of MG35: +/* Условие компиляции (G31PL >= G35PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G35PL) || (G31PL == 0) +/* Задаёт MG35_11PL = ~(1); данные MG35_11PL. */ +#define MG35_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_11PL = 0xFFFF; данные MG35_11PL. */ +#define MG35_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G35PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G35PL) || (G32PL == 0) +/* Задаёт MG35_12PL = ~(1 << 1); данные MG35_12PL. */ +#define MG35_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_12PL = 0xFFFF; данные MG35_12PL. */ +#define MG35_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G35PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G35PL) || (G33PL == 0) +/* Задаёт MG35_13PL = ~(1 << 2); данные MG35_13PL. */ +#define MG35_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_13PL = 0xFFFF; данные MG35_13PL. */ +#define MG35_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G35PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G35PL) || (G34PL == 0) +/* Задаёт MG35_14PL = ~(1 << 3); данные MG35_14PL. */ +#define MG35_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_14PL = 0xFFFF; данные MG35_14PL. */ +#define MG35_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G35PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G35PL) || (G36PL == 0) +/* Задаёт MG35_16PL = ~(1 << 5); данные MG35_16PL. */ +#define MG35_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_16PL = 0xFFFF; данные MG35_16PL. */ +#define MG35_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G35PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G35PL) || (G37PL == 0) +/* Задаёт MG35_17PL = ~(1 << 6); данные MG35_17PL. */ +#define MG35_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_17PL = 0xFFFF; данные MG35_17PL. */ +#define MG35_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G35PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G35PL) || (G38PL == 0) +/* Задаёт MG35_18PL = ~(1 << 7); данные MG35_18PL. */ +#define MG35_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_18PL = 0xFFFF; данные MG35_18PL. */ +#define MG35_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG35_15PL = 0x00EF; данные MG35_15PL. */ +#define MG35_15PL 0x00EF +/* Задаёт MG35 = (MG35_11PL & MG35_12PL & MG35_13PL & MG35_14PL &; маска разрешённых прерываний внутри группы PIE 35. */ +#define MG35 (MG35_11PL & MG35_12PL & MG35_13PL & MG35_14PL & \ + MG35_15PL & MG35_16PL & MG35_17PL & MG35_18PL) /* Продолжает список аргументов, полей или выражение MG35_15PL & MG35_16PL & MG35_17PL & MG35_18PL); порядок элементов сохраняется. */ +// End of MG35: + +// Beginning of MG36: +/* Условие компиляции (G31PL >= G36PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G36PL) || (G31PL == 0) +/* Задаёт MG36_11PL = ~(1); данные MG36_11PL. */ +#define MG36_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_11PL = 0xFFFF; данные MG36_11PL. */ +#define MG36_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G36PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G36PL) || (G32PL == 0) +/* Задаёт MG36_12PL = ~(1 << 1); данные MG36_12PL. */ +#define MG36_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_12PL = 0xFFFF; данные MG36_12PL. */ +#define MG36_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G36PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G36PL) || (G33PL == 0) +/* Задаёт MG36_13PL = ~(1 << 2); данные MG36_13PL. */ +#define MG36_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_13PL = 0xFFFF; данные MG36_13PL. */ +#define MG36_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G36PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G36PL) || (G34PL == 0) +/* Задаёт MG36_14PL = ~(1 << 3); данные MG36_14PL. */ +#define MG36_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_14PL = 0xFFFF; данные MG36_14PL. */ +#define MG36_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G36PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G36PL) || (G35PL == 0) +/* Задаёт MG36_15PL = ~(1 << 4); данные MG36_15PL. */ +#define MG36_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_15PL = 0xFFFF; данные MG36_15PL. */ +#define MG36_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G36PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G36PL) || (G37PL == 0) +/* Задаёт MG36_17PL = ~(1 << 6); данные MG36_17PL. */ +#define MG36_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_17PL = 0xFFFF; данные MG36_17PL. */ +#define MG36_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G36PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G36PL) || (G38PL == 0) +/* Задаёт MG36_18PL = ~(1 << 7); данные MG36_18PL. */ +#define MG36_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_18PL = 0xFFFF; данные MG36_18PL. */ +#define MG36_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG36_16PL = 0x00DF; данные MG36_16PL. */ +#define MG36_16PL 0x00DF +/* Задаёт MG36 = (MG36_11PL & MG36_12PL & MG36_13PL & MG36_14PL &; маска разрешённых прерываний внутри группы PIE 36. */ +#define MG36 (MG36_11PL & MG36_12PL & MG36_13PL & MG36_14PL & \ + MG36_15PL & MG36_16PL & MG36_17PL & MG36_18PL) /* Продолжает список аргументов, полей или выражение MG36_15PL & MG36_16PL & MG36_17PL & MG36_18PL); порядок элементов сохраняется. */ +// End of MG36: + +// Beginning of MG37: +/* Условие компиляции (G31PL >= G37PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G37PL) || (G31PL == 0) +/* Задаёт MG37_11PL = ~(1); данные MG37_11PL. */ +#define MG37_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_11PL = 0xFFFF; данные MG37_11PL. */ +#define MG37_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G37PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G37PL) || (G32PL == 0) +/* Задаёт MG37_12PL = ~(1 << 1); данные MG37_12PL. */ +#define MG37_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_12PL = 0xFFFF; данные MG37_12PL. */ +#define MG37_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G37PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G37PL) || (G33PL == 0) +/* Задаёт MG37_13PL = ~(1 << 2); данные MG37_13PL. */ +#define MG37_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_13PL = 0xFFFF; данные MG37_13PL. */ +#define MG37_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G37PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G37PL) || (G34PL == 0) +/* Задаёт MG37_14PL = ~(1 << 3); данные MG37_14PL. */ +#define MG37_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_14PL = 0xFFFF; данные MG37_14PL. */ +#define MG37_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G37PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G37PL) || (G35PL == 0) +/* Задаёт MG37_15PL = ~(1 << 4); данные MG37_15PL. */ +#define MG37_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_15PL = 0xFFFF; данные MG37_15PL. */ +#define MG37_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G37PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G37PL) || (G36PL == 0) +/* Задаёт MG37_16PL = ~(1 << 5); данные MG37_16PL. */ +#define MG37_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_16PL = 0xFFFF; данные MG37_16PL. */ +#define MG37_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G37PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G37PL) || (G38PL == 0) +/* Задаёт MG37_18PL = ~(1 << 7); данные MG37_18PL. */ +#define MG37_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_18PL = 0xFFFF; данные MG37_18PL. */ +#define MG37_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG37_17PL = 0x00BF; данные MG37_17PL. */ +#define MG37_17PL 0x00BF +/* Задаёт MG37 = (MG37_11PL & MG37_12PL & MG37_13PL & MG37_14PL &; маска разрешённых прерываний внутри группы PIE 37. */ +#define MG37 (MG37_11PL & MG37_12PL & MG37_13PL & MG37_14PL & \ + MG37_15PL & MG37_16PL & MG37_17PL & MG37_18PL) /* Продолжает список аргументов, полей или выражение MG37_15PL & MG37_16PL & MG37_17PL & MG37_18PL); порядок элементов сохраняется. */ +// End of MG37: + +// Beginning of MG38: +/* Условие компиляции (G31PL >= G38PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G38PL) || (G31PL == 0) +/* Задаёт MG38_11PL = ~(1); данные MG38_11PL. */ +#define MG38_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_11PL = 0xFFFF; данные MG38_11PL. */ +#define MG38_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G38PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G38PL) || (G32PL == 0) +/* Задаёт MG38_12PL = ~(1 << 1); данные MG38_12PL. */ +#define MG38_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_12PL = 0xFFFF; данные MG38_12PL. */ +#define MG38_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G38PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G38PL) || (G33PL == 0) +/* Задаёт MG38_13PL = ~(1 << 2); данные MG38_13PL. */ +#define MG38_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_13PL = 0xFFFF; данные MG38_13PL. */ +#define MG38_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G38PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G38PL) || (G34PL == 0) +/* Задаёт MG38_14PL = ~(1 << 3); данные MG38_14PL. */ +#define MG38_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_14PL = 0xFFFF; данные MG38_14PL. */ +#define MG38_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G38PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G38PL) || (G35PL == 0) +/* Задаёт MG38_15PL = ~(1 << 4); данные MG38_15PL. */ +#define MG38_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_15PL = 0xFFFF; данные MG38_15PL. */ +#define MG38_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G38PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G38PL) || (G36PL == 0) +/* Задаёт MG38_16PL = ~(1 << 5); данные MG38_16PL. */ +#define MG38_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_16PL = 0xFFFF; данные MG38_16PL. */ +#define MG38_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G38PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G38PL) || (G37PL == 0) +/* Задаёт MG38_17PL = ~(1 << 6); данные MG38_17PL. */ +#define MG38_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_17PL = 0xFFFF; данные MG38_17PL. */ +#define MG38_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG38_18PL = 0x007F; данные MG38_18PL. */ +#define MG38_18PL 0x007F +/* Задаёт MG38 = (MG38_11PL & MG38_12PL & MG38_13PL & MG38_14PL &; маска разрешённых прерываний внутри группы PIE 38. */ +#define MG38 (MG38_11PL & MG38_12PL & MG38_13PL & MG38_14PL & \ + MG38_15PL & MG38_16PL & MG38_17PL & MG38_18PL) /* Продолжает список аргументов, полей или выражение MG38_15PL & MG38_16PL & MG38_17PL & MG38_18PL); порядок элементов сохраняется. */ +// End of MG38: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG41 to MG48: +// + +// Beginning of MG41: +/* Условие компиляции (G42PL >= G41PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G41PL) || (G42PL == 0) +/* Задаёт MG41_12PL = ~(1 << 1); данные MG41_12PL. */ +#define MG41_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_12PL = 0xFFFF; данные MG41_12PL. */ +#define MG41_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G41PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G41PL) || (G43PL == 0) +/* Задаёт MG41_13PL = ~(1 << 2); данные MG41_13PL. */ +#define MG41_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_13PL = 0xFFFF; данные MG41_13PL. */ +#define MG41_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G41PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G41PL) || (G44PL == 0) +/* Задаёт MG41_14PL = ~(1 << 3); данные MG41_14PL. */ +#define MG41_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_14PL = 0xFFFF; данные MG41_14PL. */ +#define MG41_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G41PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G41PL) || (G45PL == 0) +/* Задаёт MG41_15PL = ~(1 << 4); данные MG41_15PL. */ +#define MG41_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_15PL = 0xFFFF; данные MG41_15PL. */ +#define MG41_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G41PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G41PL) || (G46PL == 0) +/* Задаёт MG41_16PL = ~(1 << 5); данные MG41_16PL. */ +#define MG41_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_16PL = 0xFFFF; данные MG41_16PL. */ +#define MG41_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G41PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G41PL) || (G47PL == 0) +/* Задаёт MG41_17PL = ~(1 << 6); данные MG41_17PL. */ +#define MG41_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_17PL = 0xFFFF; данные MG41_17PL. */ +#define MG41_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G41PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G41PL) || (G48PL == 0) +/* Задаёт MG41_18PL = ~(1 << 7); данные MG41_18PL. */ +#define MG41_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_18PL = 0xFFFF; данные MG41_18PL. */ +#define MG41_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG41_11PL = 0x00FE; данные MG41_11PL. */ +#define MG41_11PL 0x00FE +/* Задаёт MG41 = (MG41_11PL & MG41_12PL & MG41_13PL & MG41_14PL &; маска разрешённых прерываний внутри группы PIE 41. */ +#define MG41 (MG41_11PL & MG41_12PL & MG41_13PL & MG41_14PL & \ + MG41_15PL & MG41_16PL & MG41_17PL & MG41_18PL) /* Продолжает список аргументов, полей или выражение MG41_15PL & MG41_16PL & MG41_17PL & MG41_18PL); порядок элементов сохраняется. */ +// End of MG41: + +// Beginning of MG42: +/* Условие компиляции (G41PL >= G42PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G42PL) || (G41PL == 0) +/* Задаёт MG42_11PL = ~(1); данные MG42_11PL. */ +#define MG42_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_11PL = 0xFFFF; данные MG42_11PL. */ +#define MG42_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G42PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G42PL) || (G43PL == 0) +/* Задаёт MG42_13PL = ~(1 << 2); данные MG42_13PL. */ +#define MG42_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_13PL = 0xFFFF; данные MG42_13PL. */ +#define MG42_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G42PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G42PL) || (G44PL == 0) +/* Задаёт MG42_14PL = ~(1 << 3); данные MG42_14PL. */ +#define MG42_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_14PL = 0xFFFF; данные MG42_14PL. */ +#define MG42_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G42PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G42PL) || (G45PL == 0) +/* Задаёт MG42_15PL = ~(1 << 4); данные MG42_15PL. */ +#define MG42_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_15PL = 0xFFFF; данные MG42_15PL. */ +#define MG42_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G42PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G42PL) || (G46PL == 0) +/* Задаёт MG42_16PL = ~(1 << 5); данные MG42_16PL. */ +#define MG42_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_16PL = 0xFFFF; данные MG42_16PL. */ +#define MG42_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G42PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G42PL) || (G47PL == 0) +/* Задаёт MG42_17PL = ~(1 << 6); данные MG42_17PL. */ +#define MG42_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_17PL = 0xFFFF; данные MG42_17PL. */ +#define MG42_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G42PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G42PL) || (G48PL == 0) +/* Задаёт MG42_18PL = ~(1 << 7); данные MG42_18PL. */ +#define MG42_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_18PL = 0xFFFF; данные MG42_18PL. */ +#define MG42_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG42_12PL = 0x00FD; данные MG42_12PL. */ +#define MG42_12PL 0x00FD +/* Задаёт MG42 = (MG42_11PL & MG42_12PL & MG42_13PL & MG42_14PL &; маска разрешённых прерываний внутри группы PIE 42. */ +#define MG42 (MG42_11PL & MG42_12PL & MG42_13PL & MG42_14PL & \ + MG42_15PL & MG42_16PL & MG42_17PL & MG42_18PL) /* Продолжает список аргументов, полей или выражение MG42_15PL & MG42_16PL & MG42_17PL & MG42_18PL); порядок элементов сохраняется. */ +// End of MG42: + +// Beginning of MG43: +/* Условие компиляции (G41PL >= G43PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G43PL) || (G41PL == 0) +/* Задаёт MG43_11PL = ~(1); данные MG43_11PL. */ +#define MG43_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_11PL = 0xFFFF; данные MG43_11PL. */ +#define MG43_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G43PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G43PL) || (G42PL == 0) +/* Задаёт MG43_12PL = ~(1 << 1); данные MG43_12PL. */ +#define MG43_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_12PL = 0xFFFF; данные MG43_12PL. */ +#define MG43_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G43PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G43PL) || (G44PL == 0) +/* Задаёт MG43_14PL = ~(1 << 3); данные MG43_14PL. */ +#define MG43_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_14PL = 0xFFFF; данные MG43_14PL. */ +#define MG43_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G43PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G43PL) || (G45PL == 0) +/* Задаёт MG43_15PL = ~(1 << 4); данные MG43_15PL. */ +#define MG43_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_15PL = 0xFFFF; данные MG43_15PL. */ +#define MG43_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G43PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G43PL) || (G46PL == 0) +/* Задаёт MG43_16PL = ~(1 << 5); данные MG43_16PL. */ +#define MG43_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_16PL = 0xFFFF; данные MG43_16PL. */ +#define MG43_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G43PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G43PL) || (G47PL == 0) +/* Задаёт MG43_17PL = ~(1 << 6); данные MG43_17PL. */ +#define MG43_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_17PL = 0xFFFF; данные MG43_17PL. */ +#define MG43_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G43PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G43PL) || (G48PL == 0) +/* Задаёт MG43_18PL = ~(1 << 7); данные MG43_18PL. */ +#define MG43_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_18PL = 0xFFFF; данные MG43_18PL. */ +#define MG43_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG43_13PL = 0x00FB; данные MG43_13PL. */ +#define MG43_13PL 0x00FB +/* Задаёт MG43 = (MG43_11PL & MG43_12PL & MG43_13PL & MG43_14PL &; маска разрешённых прерываний внутри группы PIE 43. */ +#define MG43 (MG43_11PL & MG43_12PL & MG43_13PL & MG43_14PL & \ + MG43_15PL & MG43_16PL & MG43_17PL & MG43_18PL) /* Продолжает список аргументов, полей или выражение MG43_15PL & MG43_16PL & MG43_17PL & MG43_18PL); порядок элементов сохраняется. */ +// End of MG43: + +// Beginning of MG44: +/* Условие компиляции (G41PL >= G44PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G44PL) || (G41PL == 0) +/* Задаёт MG44_11PL = ~(1); данные MG44_11PL. */ +#define MG44_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_11PL = 0xFFFF; данные MG44_11PL. */ +#define MG44_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G44PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G44PL) || (G42PL == 0) +/* Задаёт MG44_12PL = ~(1 << 1); данные MG44_12PL. */ +#define MG44_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_12PL = 0xFFFF; данные MG44_12PL. */ +#define MG44_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G44PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G44PL) || (G43PL == 0) +/* Задаёт MG44_13PL = ~(1 << 2); данные MG44_13PL. */ +#define MG44_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_13PL = 0xFFFF; данные MG44_13PL. */ +#define MG44_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G44PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G44PL) || (G45PL == 0) +/* Задаёт MG44_15PL = ~(1 << 4); данные MG44_15PL. */ +#define MG44_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_15PL = 0xFFFF; данные MG44_15PL. */ +#define MG44_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G44PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G44PL) || (G46PL == 0) +/* Задаёт MG44_16PL = ~(1 << 5); данные MG44_16PL. */ +#define MG44_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_16PL = 0xFFFF; данные MG44_16PL. */ +#define MG44_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G44PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G44PL) || (G47PL == 0) +/* Задаёт MG44_17PL = ~(1 << 6); данные MG44_17PL. */ +#define MG44_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_17PL = 0xFFFF; данные MG44_17PL. */ +#define MG44_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G44PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G44PL) || (G48PL == 0) +/* Задаёт MG44_18PL = ~(1 << 7); данные MG44_18PL. */ +#define MG44_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_18PL = 0xFFFF; данные MG44_18PL. */ +#define MG44_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG44_14PL = 0x00F7; данные MG44_14PL. */ +#define MG44_14PL 0x00F7 +/* Задаёт MG44 = (MG44_11PL & MG44_12PL & MG44_13PL & MG44_14PL &; маска разрешённых прерываний внутри группы PIE 44. */ +#define MG44 (MG44_11PL & MG44_12PL & MG44_13PL & MG44_14PL & \ + MG44_15PL & MG44_16PL & MG44_17PL & MG44_18PL) /* Продолжает список аргументов, полей или выражение MG44_15PL & MG44_16PL & MG44_17PL & MG44_18PL); порядок элементов сохраняется. */ +// End of MG44: + +// Beginning of MG45: +/* Условие компиляции (G41PL >= G45PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G45PL) || (G41PL == 0) +/* Задаёт MG45_11PL = ~(1); данные MG45_11PL. */ +#define MG45_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_11PL = 0xFFFF; данные MG45_11PL. */ +#define MG45_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G45PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G45PL) || (G42PL == 0) +/* Задаёт MG45_12PL = ~(1 << 1); данные MG45_12PL. */ +#define MG45_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_12PL = 0xFFFF; данные MG45_12PL. */ +#define MG45_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G45PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G45PL) || (G43PL == 0) +/* Задаёт MG45_13PL = ~(1 << 2); данные MG45_13PL. */ +#define MG45_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_13PL = 0xFFFF; данные MG45_13PL. */ +#define MG45_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G45PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G45PL) || (G44PL == 0) +/* Задаёт MG45_14PL = ~(1 << 3); данные MG45_14PL. */ +#define MG45_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_14PL = 0xFFFF; данные MG45_14PL. */ +#define MG45_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G45PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G45PL) || (G46PL == 0) +/* Задаёт MG45_16PL = ~(1 << 5); данные MG45_16PL. */ +#define MG45_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_16PL = 0xFFFF; данные MG45_16PL. */ +#define MG45_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G45PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G45PL) || (G47PL == 0) +/* Задаёт MG45_17PL = ~(1 << 6); данные MG45_17PL. */ +#define MG45_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_17PL = 0xFFFF; данные MG45_17PL. */ +#define MG45_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G45PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G45PL) || (G48PL == 0) +/* Задаёт MG45_18PL = ~(1 << 7); данные MG45_18PL. */ +#define MG45_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_18PL = 0xFFFF; данные MG45_18PL. */ +#define MG45_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG45_15PL = 0x00EF; данные MG45_15PL. */ +#define MG45_15PL 0x00EF +/* Задаёт MG45 = (MG45_11PL & MG45_12PL & MG45_13PL & MG45_14PL &; маска разрешённых прерываний внутри группы PIE 45. */ +#define MG45 (MG45_11PL & MG45_12PL & MG45_13PL & MG45_14PL & \ + MG45_15PL & MG45_16PL & MG45_17PL & MG45_18PL) /* Продолжает список аргументов, полей или выражение MG45_15PL & MG45_16PL & MG45_17PL & MG45_18PL); порядок элементов сохраняется. */ +// End of MG45: + +// Beginning of MG46: +/* Условие компиляции (G41PL >= G46PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G46PL) || (G41PL == 0) +/* Задаёт MG46_11PL = ~(1); данные MG46_11PL. */ +#define MG46_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_11PL = 0xFFFF; данные MG46_11PL. */ +#define MG46_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G46PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G46PL) || (G42PL == 0) +/* Задаёт MG46_12PL = ~(1 << 1); данные MG46_12PL. */ +#define MG46_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_12PL = 0xFFFF; данные MG46_12PL. */ +#define MG46_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G46PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G46PL) || (G43PL == 0) +/* Задаёт MG46_13PL = ~(1 << 2); данные MG46_13PL. */ +#define MG46_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_13PL = 0xFFFF; данные MG46_13PL. */ +#define MG46_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G46PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G46PL) || (G44PL == 0) +/* Задаёт MG46_14PL = ~(1 << 3); данные MG46_14PL. */ +#define MG46_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_14PL = 0xFFFF; данные MG46_14PL. */ +#define MG46_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G46PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G46PL) || (G45PL == 0) +/* Задаёт MG46_15PL = ~(1 << 4); данные MG46_15PL. */ +#define MG46_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_15PL = 0xFFFF; данные MG46_15PL. */ +#define MG46_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G46PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G46PL) || (G47PL == 0) +/* Задаёт MG46_17PL = ~(1 << 6); данные MG46_17PL. */ +#define MG46_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_17PL = 0xFFFF; данные MG46_17PL. */ +#define MG46_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G46PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G46PL) || (G48PL == 0) +/* Задаёт MG46_18PL = ~(1 << 7); данные MG46_18PL. */ +#define MG46_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_18PL = 0xFFFF; данные MG46_18PL. */ +#define MG46_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG46_16PL = 0x00DF; данные MG46_16PL. */ +#define MG46_16PL 0x00DF +/* Задаёт MG46 = (MG46_11PL & MG46_12PL & MG46_13PL & MG46_14PL &; маска разрешённых прерываний внутри группы PIE 46. */ +#define MG46 (MG46_11PL & MG46_12PL & MG46_13PL & MG46_14PL & \ + MG46_15PL & MG46_16PL & MG46_17PL & MG46_18PL) /* Продолжает список аргументов, полей или выражение MG46_15PL & MG46_16PL & MG46_17PL & MG46_18PL); порядок элементов сохраняется. */ +// End of MG46: + +// Beginning of MG47: +/* Условие компиляции (G41PL >= G47PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G47PL) || (G41PL == 0) +/* Задаёт MG47_11PL = ~(1); данные MG47_11PL. */ +#define MG47_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_11PL = 0xFFFF; данные MG47_11PL. */ +#define MG47_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G47PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G47PL) || (G42PL == 0) +/* Задаёт MG47_12PL = ~(1 << 1); данные MG47_12PL. */ +#define MG47_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_12PL = 0xFFFF; данные MG47_12PL. */ +#define MG47_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G47PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G47PL) || (G43PL == 0) +/* Задаёт MG47_13PL = ~(1 << 2); данные MG47_13PL. */ +#define MG47_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_13PL = 0xFFFF; данные MG47_13PL. */ +#define MG47_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G47PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G47PL) || (G44PL == 0) +/* Задаёт MG47_14PL = ~(1 << 3); данные MG47_14PL. */ +#define MG47_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_14PL = 0xFFFF; данные MG47_14PL. */ +#define MG47_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G47PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G47PL) || (G45PL == 0) +/* Задаёт MG47_15PL = ~(1 << 4); данные MG47_15PL. */ +#define MG47_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_15PL = 0xFFFF; данные MG47_15PL. */ +#define MG47_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G47PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G47PL) || (G46PL == 0) +/* Задаёт MG47_16PL = ~(1 << 5); данные MG47_16PL. */ +#define MG47_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_16PL = 0xFFFF; данные MG47_16PL. */ +#define MG47_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G47PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G47PL) || (G48PL == 0) +/* Задаёт MG47_18PL = ~(1 << 7); данные MG47_18PL. */ +#define MG47_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_18PL = 0xFFFF; данные MG47_18PL. */ +#define MG47_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG47_17PL = 0x00BF; данные MG47_17PL. */ +#define MG47_17PL 0x00BF +/* Задаёт MG47 = (MG47_11PL & MG47_12PL & MG47_13PL & MG47_14PL &; маска разрешённых прерываний внутри группы PIE 47. */ +#define MG47 (MG47_11PL & MG47_12PL & MG47_13PL & MG47_14PL & \ + MG47_15PL & MG47_16PL & MG47_17PL & MG47_18PL) /* Продолжает список аргументов, полей или выражение MG47_15PL & MG47_16PL & MG47_17PL & MG47_18PL); порядок элементов сохраняется. */ +// End of MG47: + +// Beginning of MG48: +/* Условие компиляции (G41PL >= G48PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G48PL) || (G41PL == 0) +/* Задаёт MG48_11PL = ~(1); данные MG48_11PL. */ +#define MG48_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_11PL = 0xFFFF; данные MG48_11PL. */ +#define MG48_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G48PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G48PL) || (G42PL == 0) +/* Задаёт MG48_12PL = ~(1 << 1); данные MG48_12PL. */ +#define MG48_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_12PL = 0xFFFF; данные MG48_12PL. */ +#define MG48_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G48PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G48PL) || (G43PL == 0) +/* Задаёт MG48_13PL = ~(1 << 2); данные MG48_13PL. */ +#define MG48_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_13PL = 0xFFFF; данные MG48_13PL. */ +#define MG48_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G48PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G48PL) || (G44PL == 0) +/* Задаёт MG48_14PL = ~(1 << 3); данные MG48_14PL. */ +#define MG48_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_14PL = 0xFFFF; данные MG48_14PL. */ +#define MG48_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G48PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G48PL) || (G45PL == 0) +/* Задаёт MG48_15PL = ~(1 << 4); данные MG48_15PL. */ +#define MG48_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_15PL = 0xFFFF; данные MG48_15PL. */ +#define MG48_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G48PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G48PL) || (G46PL == 0) +/* Задаёт MG48_16PL = ~(1 << 5); данные MG48_16PL. */ +#define MG48_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_16PL = 0xFFFF; данные MG48_16PL. */ +#define MG48_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G48PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G48PL) || (G47PL == 0) +/* Задаёт MG48_17PL = ~(1 << 6); данные MG48_17PL. */ +#define MG48_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_17PL = 0xFFFF; данные MG48_17PL. */ +#define MG48_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG48_18PL = 0x007F; данные MG48_18PL. */ +#define MG48_18PL 0x007F +/* Задаёт MG48 = (MG48_11PL & MG48_12PL & MG48_13PL & MG48_14PL &; маска разрешённых прерываний внутри группы PIE 48. */ +#define MG48 (MG48_11PL & MG48_12PL & MG48_13PL & MG48_14PL & \ + MG48_15PL & MG48_16PL & MG48_17PL & MG48_18PL) /* Продолжает список аргументов, полей или выражение MG48_15PL & MG48_16PL & MG48_17PL & MG48_18PL); порядок элементов сохраняется. */ +// End of MG48: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG51 to MG58: +// + +// Beginning of MG51: +/* Условие компиляции (G52PL >= G51PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G51PL) || (G52PL == 0) +/* Задаёт MG51_12PL = ~(1 << 1); данные MG51_12PL. */ +#define MG51_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_12PL = 0xFFFF; данные MG51_12PL. */ +#define MG51_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G51PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G51PL) || (G53PL == 0) +/* Задаёт MG51_13PL = ~(1 << 2); данные MG51_13PL. */ +#define MG51_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_13PL = 0xFFFF; данные MG51_13PL. */ +#define MG51_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G51PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G51PL) || (G54PL == 0) +/* Задаёт MG51_14PL = ~(1 << 3); данные MG51_14PL. */ +#define MG51_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_14PL = 0xFFFF; данные MG51_14PL. */ +#define MG51_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G51PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G51PL) || (G55PL == 0) +/* Задаёт MG51_15PL = ~(1 << 4); данные MG51_15PL. */ +#define MG51_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_15PL = 0xFFFF; данные MG51_15PL. */ +#define MG51_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G51PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G51PL) || (G56PL == 0) +/* Задаёт MG51_16PL = ~(1 << 5); данные MG51_16PL. */ +#define MG51_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_16PL = 0xFFFF; данные MG51_16PL. */ +#define MG51_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G51PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G51PL) || (G57PL == 0) +/* Задаёт MG51_17PL = ~(1 << 6); данные MG51_17PL. */ +#define MG51_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_17PL = 0xFFFF; данные MG51_17PL. */ +#define MG51_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G51PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G51PL) || (G58PL == 0) +/* Задаёт MG51_18PL = ~(1 << 7); данные MG51_18PL. */ +#define MG51_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_18PL = 0xFFFF; данные MG51_18PL. */ +#define MG51_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG51_11PL = 0x00FE; данные MG51_11PL. */ +#define MG51_11PL 0x00FE +/* Задаёт MG51 = (MG51_11PL & MG51_12PL & MG51_13PL & MG51_14PL &; маска разрешённых прерываний внутри группы PIE 51. */ +#define MG51 (MG51_11PL & MG51_12PL & MG51_13PL & MG51_14PL & \ + MG51_15PL & MG51_16PL & MG51_17PL & MG51_18PL) /* Продолжает список аргументов, полей или выражение MG51_15PL & MG51_16PL & MG51_17PL & MG51_18PL); порядок элементов сохраняется. */ +// End of MG51: + +// Beginning of MG52: +/* Условие компиляции (G51PL >= G52PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G52PL) || (G51PL == 0) +/* Задаёт MG52_11PL = ~(1); данные MG52_11PL. */ +#define MG52_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_11PL = 0xFFFF; данные MG52_11PL. */ +#define MG52_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G52PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G52PL) || (G53PL == 0) +/* Задаёт MG52_13PL = ~(1 << 2); данные MG52_13PL. */ +#define MG52_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_13PL = 0xFFFF; данные MG52_13PL. */ +#define MG52_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G52PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G52PL) || (G54PL == 0) +/* Задаёт MG52_14PL = ~(1 << 3); данные MG52_14PL. */ +#define MG52_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_14PL = 0xFFFF; данные MG52_14PL. */ +#define MG52_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G52PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G52PL) || (G55PL == 0) +/* Задаёт MG52_15PL = ~(1 << 4); данные MG52_15PL. */ +#define MG52_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_15PL = 0xFFFF; данные MG52_15PL. */ +#define MG52_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G52PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G52PL) || (G56PL == 0) +/* Задаёт MG52_16PL = ~(1 << 5); данные MG52_16PL. */ +#define MG52_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_16PL = 0xFFFF; данные MG52_16PL. */ +#define MG52_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G52PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G52PL) || (G57PL == 0) +/* Задаёт MG52_17PL = ~(1 << 6); данные MG52_17PL. */ +#define MG52_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_17PL = 0xFFFF; данные MG52_17PL. */ +#define MG52_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G52PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G52PL) || (G58PL == 0) +/* Задаёт MG52_18PL = ~(1 << 7); данные MG52_18PL. */ +#define MG52_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_18PL = 0xFFFF; данные MG52_18PL. */ +#define MG52_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG52_12PL = 0x00FD; данные MG52_12PL. */ +#define MG52_12PL 0x00FD +/* Задаёт MG52 = (MG52_11PL & MG52_12PL & MG52_13PL & MG52_14PL &; маска разрешённых прерываний внутри группы PIE 52. */ +#define MG52 (MG52_11PL & MG52_12PL & MG52_13PL & MG52_14PL & \ + MG52_15PL & MG52_16PL & MG52_17PL & MG52_18PL) /* Продолжает список аргументов, полей или выражение MG52_15PL & MG52_16PL & MG52_17PL & MG52_18PL); порядок элементов сохраняется. */ +// End of MG52: + +// Beginning of MG53: +/* Условие компиляции (G51PL >= G53PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G53PL) || (G51PL == 0) +/* Задаёт MG53_11PL = ~(1); данные MG53_11PL. */ +#define MG53_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_11PL = 0xFFFF; данные MG53_11PL. */ +#define MG53_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G53PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G53PL) || (G52PL == 0) +/* Задаёт MG53_12PL = ~(1 << 1); данные MG53_12PL. */ +#define MG53_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_12PL = 0xFFFF; данные MG53_12PL. */ +#define MG53_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G53PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G53PL) || (G54PL == 0) +/* Задаёт MG53_14PL = ~(1 << 3); данные MG53_14PL. */ +#define MG53_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_14PL = 0xFFFF; данные MG53_14PL. */ +#define MG53_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G53PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G53PL) || (G55PL == 0) +/* Задаёт MG53_15PL = ~(1 << 4); данные MG53_15PL. */ +#define MG53_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_15PL = 0xFFFF; данные MG53_15PL. */ +#define MG53_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G53PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G53PL) || (G56PL == 0) +/* Задаёт MG53_16PL = ~(1 << 5); данные MG53_16PL. */ +#define MG53_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_16PL = 0xFFFF; данные MG53_16PL. */ +#define MG53_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G53PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G53PL) || (G57PL == 0) +/* Задаёт MG53_17PL = ~(1 << 6); данные MG53_17PL. */ +#define MG53_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_17PL = 0xFFFF; данные MG53_17PL. */ +#define MG53_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G53PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G53PL) || (G58PL == 0) +/* Задаёт MG53_18PL = ~(1 << 7); данные MG53_18PL. */ +#define MG53_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_18PL = 0xFFFF; данные MG53_18PL. */ +#define MG53_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG53_13PL = 0x00FB; данные MG53_13PL. */ +#define MG53_13PL 0x00FB +/* Задаёт MG53 = (MG53_11PL & MG53_12PL & MG53_13PL & MG53_14PL &; маска разрешённых прерываний внутри группы PIE 53. */ +#define MG53 (MG53_11PL & MG53_12PL & MG53_13PL & MG53_14PL & \ + MG53_15PL & MG53_16PL & MG53_17PL & MG53_18PL) /* Продолжает список аргументов, полей или выражение MG53_15PL & MG53_16PL & MG53_17PL & MG53_18PL); порядок элементов сохраняется. */ +// End of MG53: + +// Beginning of MG54: +/* Условие компиляции (G51PL >= G54PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G54PL) || (G51PL == 0) +/* Задаёт MG54_11PL = ~(1); данные MG54_11PL. */ +#define MG54_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_11PL = 0xFFFF; данные MG54_11PL. */ +#define MG54_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G54PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G54PL) || (G52PL == 0) +/* Задаёт MG54_12PL = ~(1 << 1); данные MG54_12PL. */ +#define MG54_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_12PL = 0xFFFF; данные MG54_12PL. */ +#define MG54_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G54PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G54PL) || (G53PL == 0) +/* Задаёт MG54_13PL = ~(1 << 2); данные MG54_13PL. */ +#define MG54_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_13PL = 0xFFFF; данные MG54_13PL. */ +#define MG54_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G54PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G54PL) || (G55PL == 0) +/* Задаёт MG54_15PL = ~(1 << 4); данные MG54_15PL. */ +#define MG54_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_15PL = 0xFFFF; данные MG54_15PL. */ +#define MG54_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G54PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G54PL) || (G56PL == 0) +/* Задаёт MG54_16PL = ~(1 << 5); данные MG54_16PL. */ +#define MG54_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_16PL = 0xFFFF; данные MG54_16PL. */ +#define MG54_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G54PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G54PL) || (G57PL == 0) +/* Задаёт MG54_17PL = ~(1 << 6); данные MG54_17PL. */ +#define MG54_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_17PL = 0xFFFF; данные MG54_17PL. */ +#define MG54_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G54PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G54PL) || (G58PL == 0) +/* Задаёт MG54_18PL = ~(1 << 7); данные MG54_18PL. */ +#define MG54_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_18PL = 0xFFFF; данные MG54_18PL. */ +#define MG54_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG54_14PL = 0x00F7; данные MG54_14PL. */ +#define MG54_14PL 0x00F7 +/* Задаёт MG54 = (MG54_11PL & MG54_12PL & MG54_13PL & MG54_14PL &; маска разрешённых прерываний внутри группы PIE 54. */ +#define MG54 (MG54_11PL & MG54_12PL & MG54_13PL & MG54_14PL & \ + MG54_15PL & MG54_16PL & MG54_17PL & MG54_18PL) /* Продолжает список аргументов, полей или выражение MG54_15PL & MG54_16PL & MG54_17PL & MG54_18PL); порядок элементов сохраняется. */ +// End of MG54: + +// Beginning of MG55: +/* Условие компиляции (G51PL >= G55PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G55PL) || (G51PL == 0) +/* Задаёт MG55_11PL = ~(1); данные MG55_11PL. */ +#define MG55_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_11PL = 0xFFFF; данные MG55_11PL. */ +#define MG55_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G55PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G55PL) || (G52PL == 0) +/* Задаёт MG55_12PL = ~(1 << 1); данные MG55_12PL. */ +#define MG55_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_12PL = 0xFFFF; данные MG55_12PL. */ +#define MG55_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G55PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G55PL) || (G53PL == 0) +/* Задаёт MG55_13PL = ~(1 << 2); данные MG55_13PL. */ +#define MG55_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_13PL = 0xFFFF; данные MG55_13PL. */ +#define MG55_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G55PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G55PL) || (G54PL == 0) +/* Задаёт MG55_14PL = ~(1 << 3); данные MG55_14PL. */ +#define MG55_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_14PL = 0xFFFF; данные MG55_14PL. */ +#define MG55_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G55PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G55PL) || (G56PL == 0) +/* Задаёт MG55_16PL = ~(1 << 5); данные MG55_16PL. */ +#define MG55_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_16PL = 0xFFFF; данные MG55_16PL. */ +#define MG55_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G55PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G55PL) || (G57PL == 0) +/* Задаёт MG55_17PL = ~(1 << 6); данные MG55_17PL. */ +#define MG55_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_17PL = 0xFFFF; данные MG55_17PL. */ +#define MG55_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G55PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G55PL) || (G58PL == 0) +/* Задаёт MG55_18PL = ~(1 << 7); данные MG55_18PL. */ +#define MG55_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_18PL = 0xFFFF; данные MG55_18PL. */ +#define MG55_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG55_15PL = 0x00EF; данные MG55_15PL. */ +#define MG55_15PL 0x00EF +/* Задаёт MG55 = (MG55_11PL & MG55_12PL & MG55_13PL & MG55_14PL &; маска разрешённых прерываний внутри группы PIE 55. */ +#define MG55 (MG55_11PL & MG55_12PL & MG55_13PL & MG55_14PL & \ + MG55_15PL & MG55_16PL & MG55_17PL & MG55_18PL) /* Продолжает список аргументов, полей или выражение MG55_15PL & MG55_16PL & MG55_17PL & MG55_18PL); порядок элементов сохраняется. */ +// End of MG55: + +// Beginning of MG56: +/* Условие компиляции (G51PL >= G56PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G56PL) || (G51PL == 0) +/* Задаёт MG56_11PL = ~(1); данные MG56_11PL. */ +#define MG56_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_11PL = 0xFFFF; данные MG56_11PL. */ +#define MG56_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G56PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G56PL) || (G52PL == 0) +/* Задаёт MG56_12PL = ~(1 << 1); данные MG56_12PL. */ +#define MG56_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_12PL = 0xFFFF; данные MG56_12PL. */ +#define MG56_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G56PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G56PL) || (G53PL == 0) +/* Задаёт MG56_13PL = ~(1 << 2); данные MG56_13PL. */ +#define MG56_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_13PL = 0xFFFF; данные MG56_13PL. */ +#define MG56_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G56PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G56PL) || (G54PL == 0) +/* Задаёт MG56_14PL = ~(1 << 3); данные MG56_14PL. */ +#define MG56_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_14PL = 0xFFFF; данные MG56_14PL. */ +#define MG56_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G56PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G56PL) || (G55PL == 0) +/* Задаёт MG56_15PL = ~(1 << 4); данные MG56_15PL. */ +#define MG56_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_15PL = 0xFFFF; данные MG56_15PL. */ +#define MG56_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G56PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G56PL) || (G57PL == 0) +/* Задаёт MG56_17PL = ~(1 << 6); данные MG56_17PL. */ +#define MG56_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_17PL = 0xFFFF; данные MG56_17PL. */ +#define MG56_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G56PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G56PL) || (G58PL == 0) +/* Задаёт MG56_18PL = ~(1 << 7); данные MG56_18PL. */ +#define MG56_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_18PL = 0xFFFF; данные MG56_18PL. */ +#define MG56_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG56_16PL = 0x00DF; данные MG56_16PL. */ +#define MG56_16PL 0x00DF +/* Задаёт MG56 = (MG56_11PL & MG56_12PL & MG56_13PL & MG56_14PL &; маска разрешённых прерываний внутри группы PIE 56. */ +#define MG56 (MG56_11PL & MG56_12PL & MG56_13PL & MG56_14PL & \ + MG56_15PL & MG56_16PL & MG56_17PL & MG56_18PL) /* Продолжает список аргументов, полей или выражение MG56_15PL & MG56_16PL & MG56_17PL & MG56_18PL); порядок элементов сохраняется. */ +// End of MG56: + +// Beginning of MG57: +/* Условие компиляции (G51PL >= G57PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G57PL) || (G51PL == 0) +/* Задаёт MG57_11PL = ~(1); данные MG57_11PL. */ +#define MG57_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_11PL = 0xFFFF; данные MG57_11PL. */ +#define MG57_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G57PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G57PL) || (G52PL == 0) +/* Задаёт MG57_12PL = ~(1 << 1); данные MG57_12PL. */ +#define MG57_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_12PL = 0xFFFF; данные MG57_12PL. */ +#define MG57_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G57PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G57PL) || (G53PL == 0) +/* Задаёт MG57_13PL = ~(1 << 2); данные MG57_13PL. */ +#define MG57_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_13PL = 0xFFFF; данные MG57_13PL. */ +#define MG57_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G57PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G57PL) || (G54PL == 0) +/* Задаёт MG57_14PL = ~(1 << 3); данные MG57_14PL. */ +#define MG57_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_14PL = 0xFFFF; данные MG57_14PL. */ +#define MG57_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G57PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G57PL) || (G55PL == 0) +/* Задаёт MG57_15PL = ~(1 << 4); данные MG57_15PL. */ +#define MG57_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_15PL = 0xFFFF; данные MG57_15PL. */ +#define MG57_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G57PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G57PL) || (G56PL == 0) +/* Задаёт MG57_16PL = ~(1 << 5); данные MG57_16PL. */ +#define MG57_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_16PL = 0xFFFF; данные MG57_16PL. */ +#define MG57_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G57PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G57PL) || (G58PL == 0) +/* Задаёт MG57_18PL = ~(1 << 7); данные MG57_18PL. */ +#define MG57_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_18PL = 0xFFFF; данные MG57_18PL. */ +#define MG57_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG57_17PL = 0x00BF; данные MG57_17PL. */ +#define MG57_17PL 0x00BF +/* Задаёт MG57 = (MG57_11PL & MG57_12PL & MG57_13PL & MG57_14PL &; маска разрешённых прерываний внутри группы PIE 57. */ +#define MG57 (MG57_11PL & MG57_12PL & MG57_13PL & MG57_14PL & \ + MG57_15PL & MG57_16PL & MG57_17PL & MG57_18PL) /* Продолжает список аргументов, полей или выражение MG57_15PL & MG57_16PL & MG57_17PL & MG57_18PL); порядок элементов сохраняется. */ +// End of MG57: + +// Beginning of MG58: +/* Условие компиляции (G51PL >= G58PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G58PL) || (G51PL == 0) +/* Задаёт MG58_11PL = ~(1); данные MG58_11PL. */ +#define MG58_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_11PL = 0xFFFF; данные MG58_11PL. */ +#define MG58_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G58PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G58PL) || (G52PL == 0) +/* Задаёт MG58_12PL = ~(1 << 1); данные MG58_12PL. */ +#define MG58_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_12PL = 0xFFFF; данные MG58_12PL. */ +#define MG58_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G58PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G58PL) || (G53PL == 0) +/* Задаёт MG58_13PL = ~(1 << 2); данные MG58_13PL. */ +#define MG58_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_13PL = 0xFFFF; данные MG58_13PL. */ +#define MG58_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G58PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G58PL) || (G54PL == 0) +/* Задаёт MG58_14PL = ~(1 << 3); данные MG58_14PL. */ +#define MG58_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_14PL = 0xFFFF; данные MG58_14PL. */ +#define MG58_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G58PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G58PL) || (G55PL == 0) +/* Задаёт MG58_15PL = ~(1 << 4); данные MG58_15PL. */ +#define MG58_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_15PL = 0xFFFF; данные MG58_15PL. */ +#define MG58_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G58PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G58PL) || (G56PL == 0) +/* Задаёт MG58_16PL = ~(1 << 5); данные MG58_16PL. */ +#define MG58_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_16PL = 0xFFFF; данные MG58_16PL. */ +#define MG58_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G58PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G58PL) || (G57PL == 0) +/* Задаёт MG58_17PL = ~(1 << 6); данные MG58_17PL. */ +#define MG58_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_17PL = 0xFFFF; данные MG58_17PL. */ +#define MG58_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG58_18PL = 0x007F; данные MG58_18PL. */ +#define MG58_18PL 0x007F +/* Задаёт MG58 = (MG58_11PL & MG58_12PL & MG58_13PL & MG58_14PL &; маска разрешённых прерываний внутри группы PIE 58. */ +#define MG58 (MG58_11PL & MG58_12PL & MG58_13PL & MG58_14PL & \ + MG58_15PL & MG58_16PL & MG58_17PL & MG58_18PL) /* Продолжает список аргументов, полей или выражение MG58_15PL & MG58_16PL & MG58_17PL & MG58_18PL); порядок элементов сохраняется. */ +// End of MG58: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG61 to MG68: +// + +// Beginning of MG61: +/* Условие компиляции (G62PL >= G61PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G61PL) || (G62PL == 0) +/* Задаёт MG61_12PL = ~(1 << 1); данные MG61_12PL. */ +#define MG61_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_12PL = 0xFFFF; данные MG61_12PL. */ +#define MG61_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G61PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G61PL) || (G63PL == 0) +/* Задаёт MG61_13PL = ~(1 << 2); данные MG61_13PL. */ +#define MG61_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_13PL = 0xFFFF; данные MG61_13PL. */ +#define MG61_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G61PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G61PL) || (G64PL == 0) +/* Задаёт MG61_14PL = ~(1 << 3); данные MG61_14PL. */ +#define MG61_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_14PL = 0xFFFF; данные MG61_14PL. */ +#define MG61_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G61PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G61PL) || (G65PL == 0) +/* Задаёт MG61_15PL = ~(1 << 4); данные MG61_15PL. */ +#define MG61_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_15PL = 0xFFFF; данные MG61_15PL. */ +#define MG61_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G61PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G61PL) || (G66PL == 0) +/* Задаёт MG61_16PL = ~(1 << 5); данные MG61_16PL. */ +#define MG61_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_16PL = 0xFFFF; данные MG61_16PL. */ +#define MG61_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G61PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G61PL) || (G67PL == 0) +/* Задаёт MG61_17PL = ~(1 << 6); данные MG61_17PL. */ +#define MG61_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_17PL = 0xFFFF; данные MG61_17PL. */ +#define MG61_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G61PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G61PL) || (G68PL == 0) +/* Задаёт MG61_18PL = ~(1 << 7); данные MG61_18PL. */ +#define MG61_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_18PL = 0xFFFF; данные MG61_18PL. */ +#define MG61_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG61_11PL = 0x00FE; данные MG61_11PL. */ +#define MG61_11PL 0x00FE +/* Задаёт MG61 = (MG61_11PL & MG61_12PL & MG61_13PL & MG61_14PL &; маска разрешённых прерываний внутри группы PIE 61. */ +#define MG61 (MG61_11PL & MG61_12PL & MG61_13PL & MG61_14PL & \ + MG61_15PL & MG61_16PL & MG61_17PL & MG61_18PL) /* Продолжает список аргументов, полей или выражение MG61_15PL & MG61_16PL & MG61_17PL & MG61_18PL); порядок элементов сохраняется. */ +// End of MG61: + +// Beginning of MG62: +/* Условие компиляции (G61PL >= G62PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G62PL) || (G61PL == 0) +/* Задаёт MG62_11PL = ~(1); данные MG62_11PL. */ +#define MG62_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_11PL = 0xFFFF; данные MG62_11PL. */ +#define MG62_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G62PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G62PL) || (G63PL == 0) +/* Задаёт MG62_13PL = ~(1 << 2); данные MG62_13PL. */ +#define MG62_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_13PL = 0xFFFF; данные MG62_13PL. */ +#define MG62_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G62PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G62PL) || (G64PL == 0) +/* Задаёт MG62_14PL = ~(1 << 3); данные MG62_14PL. */ +#define MG62_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_14PL = 0xFFFF; данные MG62_14PL. */ +#define MG62_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G62PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G62PL) || (G65PL == 0) +/* Задаёт MG62_15PL = ~(1 << 4); данные MG62_15PL. */ +#define MG62_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_15PL = 0xFFFF; данные MG62_15PL. */ +#define MG62_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G62PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G62PL) || (G66PL == 0) +/* Задаёт MG62_16PL = ~(1 << 5); данные MG62_16PL. */ +#define MG62_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_16PL = 0xFFFF; данные MG62_16PL. */ +#define MG62_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G62PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G62PL) || (G67PL == 0) +/* Задаёт MG62_17PL = ~(1 << 6); данные MG62_17PL. */ +#define MG62_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_17PL = 0xFFFF; данные MG62_17PL. */ +#define MG62_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G62PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G62PL) || (G68PL == 0) +/* Задаёт MG62_18PL = ~(1 << 7); данные MG62_18PL. */ +#define MG62_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_18PL = 0xFFFF; данные MG62_18PL. */ +#define MG62_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG62_12PL = 0x00FD; данные MG62_12PL. */ +#define MG62_12PL 0x00FD +/* Задаёт MG62 = (MG62_11PL & MG62_12PL & MG62_13PL & MG62_14PL &; маска разрешённых прерываний внутри группы PIE 62. */ +#define MG62 (MG62_11PL & MG62_12PL & MG62_13PL & MG62_14PL & \ + MG62_15PL & MG62_16PL & MG62_17PL & MG62_18PL) /* Продолжает список аргументов, полей или выражение MG62_15PL & MG62_16PL & MG62_17PL & MG62_18PL); порядок элементов сохраняется. */ +// End of MG62: + +// Beginning of MG63: +/* Условие компиляции (G61PL >= G63PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G63PL) || (G61PL == 0) +/* Задаёт MG63_11PL = ~(1); данные MG63_11PL. */ +#define MG63_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_11PL = 0xFFFF; данные MG63_11PL. */ +#define MG63_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G63PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G63PL) || (G62PL == 0) +/* Задаёт MG63_12PL = ~(1 << 1); данные MG63_12PL. */ +#define MG63_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_12PL = 0xFFFF; данные MG63_12PL. */ +#define MG63_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G63PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G63PL) || (G64PL == 0) +/* Задаёт MG63_14PL = ~(1 << 3); данные MG63_14PL. */ +#define MG63_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_14PL = 0xFFFF; данные MG63_14PL. */ +#define MG63_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G63PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G63PL) || (G65PL == 0) +/* Задаёт MG63_15PL = ~(1 << 4); данные MG63_15PL. */ +#define MG63_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_15PL = 0xFFFF; данные MG63_15PL. */ +#define MG63_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G63PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G63PL) || (G66PL == 0) +/* Задаёт MG63_16PL = ~(1 << 5); данные MG63_16PL. */ +#define MG63_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_16PL = 0xFFFF; данные MG63_16PL. */ +#define MG63_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G63PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G63PL) || (G67PL == 0) +/* Задаёт MG63_17PL = ~(1 << 6); данные MG63_17PL. */ +#define MG63_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_17PL = 0xFFFF; данные MG63_17PL. */ +#define MG63_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G63PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G63PL) || (G68PL == 0) +/* Задаёт MG63_18PL = ~(1 << 7); данные MG63_18PL. */ +#define MG63_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_18PL = 0xFFFF; данные MG63_18PL. */ +#define MG63_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG63_13PL = 0x00FB; данные MG63_13PL. */ +#define MG63_13PL 0x00FB +/* Задаёт MG63 = (MG63_11PL & MG63_12PL & MG63_13PL & MG63_14PL &; маска разрешённых прерываний внутри группы PIE 63. */ +#define MG63 (MG63_11PL & MG63_12PL & MG63_13PL & MG63_14PL & \ + MG63_15PL & MG63_16PL & MG63_17PL & MG63_18PL) /* Продолжает список аргументов, полей или выражение MG63_15PL & MG63_16PL & MG63_17PL & MG63_18PL); порядок элементов сохраняется. */ +// End of MG63: + +// Beginning of MG64: +/* Условие компиляции (G61PL >= G64PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G64PL) || (G61PL == 0) +/* Задаёт MG64_11PL = ~(1); данные MG64_11PL. */ +#define MG64_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_11PL = 0xFFFF; данные MG64_11PL. */ +#define MG64_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G64PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G64PL) || (G62PL == 0) +/* Задаёт MG64_12PL = ~(1 << 1); данные MG64_12PL. */ +#define MG64_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_12PL = 0xFFFF; данные MG64_12PL. */ +#define MG64_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G64PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G64PL) || (G63PL == 0) +/* Задаёт MG64_13PL = ~(1 << 2); данные MG64_13PL. */ +#define MG64_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_13PL = 0xFFFF; данные MG64_13PL. */ +#define MG64_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G64PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G64PL) || (G65PL == 0) +/* Задаёт MG64_15PL = ~(1 << 4); данные MG64_15PL. */ +#define MG64_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_15PL = 0xFFFF; данные MG64_15PL. */ +#define MG64_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G64PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G64PL) || (G66PL == 0) +/* Задаёт MG64_16PL = ~(1 << 5); данные MG64_16PL. */ +#define MG64_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_16PL = 0xFFFF; данные MG64_16PL. */ +#define MG64_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G64PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G64PL) || (G67PL == 0) +/* Задаёт MG64_17PL = ~(1 << 6); данные MG64_17PL. */ +#define MG64_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_17PL = 0xFFFF; данные MG64_17PL. */ +#define MG64_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G64PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G64PL) || (G68PL == 0) +/* Задаёт MG64_18PL = ~(1 << 7); данные MG64_18PL. */ +#define MG64_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_18PL = 0xFFFF; данные MG64_18PL. */ +#define MG64_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG64_14PL = 0x00F7; данные MG64_14PL. */ +#define MG64_14PL 0x00F7 +/* Задаёт MG64 = (MG64_11PL & MG64_12PL & MG64_13PL & MG64_14PL &; маска разрешённых прерываний внутри группы PIE 64. */ +#define MG64 (MG64_11PL & MG64_12PL & MG64_13PL & MG64_14PL & \ + MG64_15PL & MG64_16PL & MG64_17PL & MG64_18PL) /* Продолжает список аргументов, полей или выражение MG64_15PL & MG64_16PL & MG64_17PL & MG64_18PL); порядок элементов сохраняется. */ +// End of MG64: + +// Beginning of MG65: +/* Условие компиляции (G61PL >= G65PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G65PL) || (G61PL == 0) +/* Задаёт MG65_11PL = ~(1); данные MG65_11PL. */ +#define MG65_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_11PL = 0xFFFF; данные MG65_11PL. */ +#define MG65_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G65PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G65PL) || (G62PL == 0) +/* Задаёт MG65_12PL = ~(1 << 1); данные MG65_12PL. */ +#define MG65_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_12PL = 0xFFFF; данные MG65_12PL. */ +#define MG65_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G65PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G65PL) || (G63PL == 0) +/* Задаёт MG65_13PL = ~(1 << 2); данные MG65_13PL. */ +#define MG65_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_13PL = 0xFFFF; данные MG65_13PL. */ +#define MG65_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G65PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G65PL) || (G64PL == 0) +/* Задаёт MG65_14PL = ~(1 << 3); данные MG65_14PL. */ +#define MG65_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_14PL = 0xFFFF; данные MG65_14PL. */ +#define MG65_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G65PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G65PL) || (G66PL == 0) +/* Задаёт MG65_16PL = ~(1 << 5); данные MG65_16PL. */ +#define MG65_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_16PL = 0xFFFF; данные MG65_16PL. */ +#define MG65_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G65PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G65PL) || (G67PL == 0) +/* Задаёт MG65_17PL = ~(1 << 6); данные MG65_17PL. */ +#define MG65_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_17PL = 0xFFFF; данные MG65_17PL. */ +#define MG65_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G65PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G65PL) || (G68PL == 0) +/* Задаёт MG65_18PL = ~(1 << 7); данные MG65_18PL. */ +#define MG65_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_18PL = 0xFFFF; данные MG65_18PL. */ +#define MG65_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG65_15PL = 0x00EF; данные MG65_15PL. */ +#define MG65_15PL 0x00EF +/* Задаёт MG65 = (MG65_11PL & MG65_12PL & MG65_13PL & MG65_14PL &; маска разрешённых прерываний внутри группы PIE 65. */ +#define MG65 (MG65_11PL & MG65_12PL & MG65_13PL & MG65_14PL & \ + MG65_15PL & MG65_16PL & MG65_17PL & MG65_18PL) /* Продолжает список аргументов, полей или выражение MG65_15PL & MG65_16PL & MG65_17PL & MG65_18PL); порядок элементов сохраняется. */ +// End of MG65: + +// Beginning of MG66: +/* Условие компиляции (G61PL >= G66PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G66PL) || (G61PL == 0) +/* Задаёт MG66_11PL = ~(1); данные MG66_11PL. */ +#define MG66_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_11PL = 0xFFFF; данные MG66_11PL. */ +#define MG66_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G66PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G66PL) || (G62PL == 0) +/* Задаёт MG66_12PL = ~(1 << 1); данные MG66_12PL. */ +#define MG66_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_12PL = 0xFFFF; данные MG66_12PL. */ +#define MG66_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G66PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G66PL) || (G63PL == 0) +/* Задаёт MG66_13PL = ~(1 << 2); данные MG66_13PL. */ +#define MG66_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_13PL = 0xFFFF; данные MG66_13PL. */ +#define MG66_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G66PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G66PL) || (G64PL == 0) +/* Задаёт MG66_14PL = ~(1 << 3); данные MG66_14PL. */ +#define MG66_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_14PL = 0xFFFF; данные MG66_14PL. */ +#define MG66_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G66PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G66PL) || (G65PL == 0) +/* Задаёт MG66_15PL = ~(1 << 4); данные MG66_15PL. */ +#define MG66_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_15PL = 0xFFFF; данные MG66_15PL. */ +#define MG66_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G66PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G66PL) || (G67PL == 0) +/* Задаёт MG66_17PL = ~(1 << 6); данные MG66_17PL. */ +#define MG66_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_17PL = 0xFFFF; данные MG66_17PL. */ +#define MG66_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G66PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G66PL) || (G68PL == 0) +/* Задаёт MG66_18PL = ~(1 << 7); данные MG66_18PL. */ +#define MG66_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_18PL = 0xFFFF; данные MG66_18PL. */ +#define MG66_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG66_16PL = 0x00DF; данные MG66_16PL. */ +#define MG66_16PL 0x00DF +/* Задаёт MG66 = (MG66_11PL & MG66_12PL & MG66_13PL & MG66_14PL &; маска разрешённых прерываний внутри группы PIE 66. */ +#define MG66 (MG66_11PL & MG66_12PL & MG66_13PL & MG66_14PL & \ + MG66_15PL & MG66_16PL & MG66_17PL & MG66_18PL) /* Продолжает список аргументов, полей или выражение MG66_15PL & MG66_16PL & MG66_17PL & MG66_18PL); порядок элементов сохраняется. */ +// End of MG66: + +// Beginning of MG67: +/* Условие компиляции (G61PL >= G67PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G67PL) || (G61PL == 0) +/* Задаёт MG67_11PL = ~(1); данные MG67_11PL. */ +#define MG67_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_11PL = 0xFFFF; данные MG67_11PL. */ +#define MG67_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G67PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G67PL) || (G62PL == 0) +/* Задаёт MG67_12PL = ~(1 << 1); данные MG67_12PL. */ +#define MG67_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_12PL = 0xFFFF; данные MG67_12PL. */ +#define MG67_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G67PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G67PL) || (G63PL == 0) +/* Задаёт MG67_13PL = ~(1 << 2); данные MG67_13PL. */ +#define MG67_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_13PL = 0xFFFF; данные MG67_13PL. */ +#define MG67_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G67PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G67PL) || (G64PL == 0) +/* Задаёт MG67_14PL = ~(1 << 3); данные MG67_14PL. */ +#define MG67_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_14PL = 0xFFFF; данные MG67_14PL. */ +#define MG67_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G67PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G67PL) || (G65PL == 0) +/* Задаёт MG67_15PL = ~(1 << 4); данные MG67_15PL. */ +#define MG67_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_15PL = 0xFFFF; данные MG67_15PL. */ +#define MG67_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G67PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G67PL) || (G66PL == 0) +/* Задаёт MG67_16PL = ~(1 << 5); данные MG67_16PL. */ +#define MG67_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_16PL = 0xFFFF; данные MG67_16PL. */ +#define MG67_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G67PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G67PL) || (G68PL == 0) +/* Задаёт MG67_18PL = ~(1 << 7); данные MG67_18PL. */ +#define MG67_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_18PL = 0xFFFF; данные MG67_18PL. */ +#define MG67_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG67_17PL = 0x00BF; данные MG67_17PL. */ +#define MG67_17PL 0x00BF +/* Задаёт MG67 = (MG67_11PL & MG67_12PL & MG67_13PL & MG67_14PL &; маска разрешённых прерываний внутри группы PIE 67. */ +#define MG67 (MG67_11PL & MG67_12PL & MG67_13PL & MG67_14PL & \ + MG67_15PL & MG67_16PL & MG67_17PL & MG67_18PL) /* Продолжает список аргументов, полей или выражение MG67_15PL & MG67_16PL & MG67_17PL & MG67_18PL); порядок элементов сохраняется. */ +// End of MG67: + +// Beginning of MG68: +/* Условие компиляции (G61PL >= G68PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G68PL) || (G61PL == 0) +/* Задаёт MG68_11PL = ~(1); данные MG68_11PL. */ +#define MG68_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_11PL = 0xFFFF; данные MG68_11PL. */ +#define MG68_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G68PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G68PL) || (G62PL == 0) +/* Задаёт MG68_12PL = ~(1 << 1); данные MG68_12PL. */ +#define MG68_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_12PL = 0xFFFF; данные MG68_12PL. */ +#define MG68_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G68PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G68PL) || (G63PL == 0) +/* Задаёт MG68_13PL = ~(1 << 2); данные MG68_13PL. */ +#define MG68_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_13PL = 0xFFFF; данные MG68_13PL. */ +#define MG68_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G68PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G68PL) || (G64PL == 0) +/* Задаёт MG68_14PL = ~(1 << 3); данные MG68_14PL. */ +#define MG68_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_14PL = 0xFFFF; данные MG68_14PL. */ +#define MG68_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G68PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G68PL) || (G65PL == 0) +/* Задаёт MG68_15PL = ~(1 << 4); данные MG68_15PL. */ +#define MG68_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_15PL = 0xFFFF; данные MG68_15PL. */ +#define MG68_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G68PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G68PL) || (G66PL == 0) +/* Задаёт MG68_16PL = ~(1 << 5); данные MG68_16PL. */ +#define MG68_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_16PL = 0xFFFF; данные MG68_16PL. */ +#define MG68_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G68PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G68PL) || (G67PL == 0) +/* Задаёт MG68_17PL = ~(1 << 6); данные MG68_17PL. */ +#define MG68_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_17PL = 0xFFFF; данные MG68_17PL. */ +#define MG68_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG68_18PL = 0x007F; данные MG68_18PL. */ +#define MG68_18PL 0x007F +/* Задаёт MG68 = (MG68_11PL & MG68_12PL & MG68_13PL & MG68_14PL &; маска разрешённых прерываний внутри группы PIE 68. */ +#define MG68 (MG68_11PL & MG68_12PL & MG68_13PL & MG68_14PL & \ + MG68_15PL & MG68_16PL & MG68_17PL & MG68_18PL) /* Продолжает список аргументов, полей или выражение MG68_15PL & MG68_16PL & MG68_17PL & MG68_18PL); порядок элементов сохраняется. */ +// End of MG68: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG71 to MG78: +// + +// Beginning of MG71: +/* Условие компиляции (G72PL >= G71PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G71PL) || (G72PL == 0) +/* Задаёт MG71_12PL = ~(1 << 1); данные MG71_12PL. */ +#define MG71_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_12PL = 0xFFFF; данные MG71_12PL. */ +#define MG71_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G71PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G71PL) || (G73PL == 0) +/* Задаёт MG71_13PL = ~(1 << 2); данные MG71_13PL. */ +#define MG71_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_13PL = 0xFFFF; данные MG71_13PL. */ +#define MG71_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G71PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G71PL) || (G74PL == 0) +/* Задаёт MG71_14PL = ~(1 << 3); данные MG71_14PL. */ +#define MG71_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_14PL = 0xFFFF; данные MG71_14PL. */ +#define MG71_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G71PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G71PL) || (G75PL == 0) +/* Задаёт MG71_15PL = ~(1 << 4); данные MG71_15PL. */ +#define MG71_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_15PL = 0xFFFF; данные MG71_15PL. */ +#define MG71_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G71PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G71PL) || (G76PL == 0) +/* Задаёт MG71_16PL = ~(1 << 5); данные MG71_16PL. */ +#define MG71_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_16PL = 0xFFFF; данные MG71_16PL. */ +#define MG71_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G71PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G71PL) || (G77PL == 0) +/* Задаёт MG71_17PL = ~(1 << 6); данные MG71_17PL. */ +#define MG71_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_17PL = 0xFFFF; данные MG71_17PL. */ +#define MG71_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G71PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G71PL) || (G78PL == 0) +/* Задаёт MG71_18PL = ~(1 << 7); данные MG71_18PL. */ +#define MG71_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_18PL = 0xFFFF; данные MG71_18PL. */ +#define MG71_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG71_11PL = 0x00FE; данные MG71_11PL. */ +#define MG71_11PL 0x00FE +/* Задаёт MG71 = (MG71_11PL & MG71_12PL & MG71_13PL & MG71_14PL &; маска разрешённых прерываний внутри группы PIE 71. */ +#define MG71 (MG71_11PL & MG71_12PL & MG71_13PL & MG71_14PL & \ + MG71_15PL & MG71_16PL & MG71_17PL & MG71_18PL) /* Продолжает список аргументов, полей или выражение MG71_15PL & MG71_16PL & MG71_17PL & MG71_18PL); порядок элементов сохраняется. */ +// End of MG71: + +// Beginning of MG72: +/* Условие компиляции (G71PL >= G72PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G72PL) || (G71PL == 0) +/* Задаёт MG72_11PL = ~(1); данные MG72_11PL. */ +#define MG72_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_11PL = 0xFFFF; данные MG72_11PL. */ +#define MG72_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G72PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G72PL) || (G73PL == 0) +/* Задаёт MG72_13PL = ~(1 << 2); данные MG72_13PL. */ +#define MG72_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_13PL = 0xFFFF; данные MG72_13PL. */ +#define MG72_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G72PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G72PL) || (G74PL == 0) +/* Задаёт MG72_14PL = ~(1 << 3); данные MG72_14PL. */ +#define MG72_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_14PL = 0xFFFF; данные MG72_14PL. */ +#define MG72_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G72PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G72PL) || (G75PL == 0) +/* Задаёт MG72_15PL = ~(1 << 4); данные MG72_15PL. */ +#define MG72_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_15PL = 0xFFFF; данные MG72_15PL. */ +#define MG72_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G72PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G72PL) || (G76PL == 0) +/* Задаёт MG72_16PL = ~(1 << 5); данные MG72_16PL. */ +#define MG72_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_16PL = 0xFFFF; данные MG72_16PL. */ +#define MG72_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G72PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G72PL) || (G77PL == 0) +/* Задаёт MG72_17PL = ~(1 << 6); данные MG72_17PL. */ +#define MG72_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_17PL = 0xFFFF; данные MG72_17PL. */ +#define MG72_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G72PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G72PL) || (G78PL == 0) +/* Задаёт MG72_18PL = ~(1 << 7); данные MG72_18PL. */ +#define MG72_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_18PL = 0xFFFF; данные MG72_18PL. */ +#define MG72_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG72_12PL = 0x00FD; данные MG72_12PL. */ +#define MG72_12PL 0x00FD +/* Задаёт MG72 = (MG72_11PL & MG72_12PL & MG72_13PL & MG72_14PL &; маска разрешённых прерываний внутри группы PIE 72. */ +#define MG72 (MG72_11PL & MG72_12PL & MG72_13PL & MG72_14PL & \ + MG72_15PL & MG72_16PL & MG72_17PL & MG72_18PL) /* Продолжает список аргументов, полей или выражение MG72_15PL & MG72_16PL & MG72_17PL & MG72_18PL); порядок элементов сохраняется. */ +// End of MG72: + +// Beginning of MG73: +/* Условие компиляции (G71PL >= G73PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G73PL) || (G71PL == 0) +/* Задаёт MG73_11PL = ~(1); данные MG73_11PL. */ +#define MG73_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_11PL = 0xFFFF; данные MG73_11PL. */ +#define MG73_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G73PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G73PL) || (G72PL == 0) +/* Задаёт MG73_12PL = ~(1 << 1); данные MG73_12PL. */ +#define MG73_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_12PL = 0xFFFF; данные MG73_12PL. */ +#define MG73_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G73PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G73PL) || (G74PL == 0) +/* Задаёт MG73_14PL = ~(1 << 3); данные MG73_14PL. */ +#define MG73_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_14PL = 0xFFFF; данные MG73_14PL. */ +#define MG73_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G73PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G73PL) || (G75PL == 0) +/* Задаёт MG73_15PL = ~(1 << 4); данные MG73_15PL. */ +#define MG73_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_15PL = 0xFFFF; данные MG73_15PL. */ +#define MG73_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G73PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G73PL) || (G76PL == 0) +/* Задаёт MG73_16PL = ~(1 << 5); данные MG73_16PL. */ +#define MG73_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_16PL = 0xFFFF; данные MG73_16PL. */ +#define MG73_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G73PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G73PL) || (G77PL == 0) +/* Задаёт MG73_17PL = ~(1 << 6); данные MG73_17PL. */ +#define MG73_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_17PL = 0xFFFF; данные MG73_17PL. */ +#define MG73_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G73PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G73PL) || (G78PL == 0) +/* Задаёт MG73_18PL = ~(1 << 7); данные MG73_18PL. */ +#define MG73_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_18PL = 0xFFFF; данные MG73_18PL. */ +#define MG73_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG73_13PL = 0x00FB; данные MG73_13PL. */ +#define MG73_13PL 0x00FB +/* Задаёт MG73 = (MG73_11PL & MG73_12PL & MG73_13PL & MG73_14PL &; маска разрешённых прерываний внутри группы PIE 73. */ +#define MG73 (MG73_11PL & MG73_12PL & MG73_13PL & MG73_14PL & \ + MG73_15PL & MG73_16PL & MG73_17PL & MG73_18PL) /* Продолжает список аргументов, полей или выражение MG73_15PL & MG73_16PL & MG73_17PL & MG73_18PL); порядок элементов сохраняется. */ +// End of MG73: + +// Beginning of MG74: +/* Условие компиляции (G71PL >= G74PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G74PL) || (G71PL == 0) +/* Задаёт MG74_11PL = ~(1); данные MG74_11PL. */ +#define MG74_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_11PL = 0xFFFF; данные MG74_11PL. */ +#define MG74_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G74PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G74PL) || (G72PL == 0) +/* Задаёт MG74_12PL = ~(1 << 1); данные MG74_12PL. */ +#define MG74_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_12PL = 0xFFFF; данные MG74_12PL. */ +#define MG74_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G74PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G74PL) || (G73PL == 0) +/* Задаёт MG74_13PL = ~(1 << 2); данные MG74_13PL. */ +#define MG74_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_13PL = 0xFFFF; данные MG74_13PL. */ +#define MG74_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G74PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G74PL) || (G75PL == 0) +/* Задаёт MG74_15PL = ~(1 << 4); данные MG74_15PL. */ +#define MG74_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_15PL = 0xFFFF; данные MG74_15PL. */ +#define MG74_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G74PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G74PL) || (G76PL == 0) +/* Задаёт MG74_16PL = ~(1 << 5); данные MG74_16PL. */ +#define MG74_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_16PL = 0xFFFF; данные MG74_16PL. */ +#define MG74_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G74PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G74PL) || (G77PL == 0) +/* Задаёт MG74_17PL = ~(1 << 6); данные MG74_17PL. */ +#define MG74_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_17PL = 0xFFFF; данные MG74_17PL. */ +#define MG74_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G74PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G74PL) || (G78PL == 0) +/* Задаёт MG74_18PL = ~(1 << 7); данные MG74_18PL. */ +#define MG74_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_18PL = 0xFFFF; данные MG74_18PL. */ +#define MG74_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG74_14PL = 0x00F7; данные MG74_14PL. */ +#define MG74_14PL 0x00F7 +/* Задаёт MG74 = (MG74_11PL & MG74_12PL & MG74_13PL & MG74_14PL &; маска разрешённых прерываний внутри группы PIE 74. */ +#define MG74 (MG74_11PL & MG74_12PL & MG74_13PL & MG74_14PL & \ + MG74_15PL & MG74_16PL & MG74_17PL & MG74_18PL) /* Продолжает список аргументов, полей или выражение MG74_15PL & MG74_16PL & MG74_17PL & MG74_18PL); порядок элементов сохраняется. */ +// End of MG74: + +// Beginning of MG75: +/* Условие компиляции (G71PL >= G75PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G75PL) || (G71PL == 0) +/* Задаёт MG75_11PL = ~(1); данные MG75_11PL. */ +#define MG75_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_11PL = 0xFFFF; данные MG75_11PL. */ +#define MG75_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G75PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G75PL) || (G72PL == 0) +/* Задаёт MG75_12PL = ~(1 << 1); данные MG75_12PL. */ +#define MG75_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_12PL = 0xFFFF; данные MG75_12PL. */ +#define MG75_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G75PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G75PL) || (G73PL == 0) +/* Задаёт MG75_13PL = ~(1 << 2); данные MG75_13PL. */ +#define MG75_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_13PL = 0xFFFF; данные MG75_13PL. */ +#define MG75_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G75PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G75PL) || (G74PL == 0) +/* Задаёт MG75_14PL = ~(1 << 3); данные MG75_14PL. */ +#define MG75_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_14PL = 0xFFFF; данные MG75_14PL. */ +#define MG75_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G75PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G75PL) || (G76PL == 0) +/* Задаёт MG75_16PL = ~(1 << 5); данные MG75_16PL. */ +#define MG75_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_16PL = 0xFFFF; данные MG75_16PL. */ +#define MG75_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G75PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G75PL) || (G77PL == 0) +/* Задаёт MG75_17PL = ~(1 << 6); данные MG75_17PL. */ +#define MG75_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_17PL = 0xFFFF; данные MG75_17PL. */ +#define MG75_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G75PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G75PL) || (G78PL == 0) +/* Задаёт MG75_18PL = ~(1 << 7); данные MG75_18PL. */ +#define MG75_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_18PL = 0xFFFF; данные MG75_18PL. */ +#define MG75_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG75_15PL = 0x00EF; данные MG75_15PL. */ +#define MG75_15PL 0x00EF +/* Задаёт MG75 = (MG75_11PL & MG75_12PL & MG75_13PL & MG75_14PL &; маска разрешённых прерываний внутри группы PIE 75. */ +#define MG75 (MG75_11PL & MG75_12PL & MG75_13PL & MG75_14PL & \ + MG75_15PL & MG75_16PL & MG75_17PL & MG75_18PL) /* Продолжает список аргументов, полей или выражение MG75_15PL & MG75_16PL & MG75_17PL & MG75_18PL); порядок элементов сохраняется. */ +// End of MG75: + +// Beginning of MG76: +/* Условие компиляции (G71PL >= G76PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G76PL) || (G71PL == 0) +/* Задаёт MG76_11PL = ~(1); данные MG76_11PL. */ +#define MG76_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_11PL = 0xFFFF; данные MG76_11PL. */ +#define MG76_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G76PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G76PL) || (G72PL == 0) +/* Задаёт MG76_12PL = ~(1 << 1); данные MG76_12PL. */ +#define MG76_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_12PL = 0xFFFF; данные MG76_12PL. */ +#define MG76_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G76PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G76PL) || (G73PL == 0) +/* Задаёт MG76_13PL = ~(1 << 2); данные MG76_13PL. */ +#define MG76_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_13PL = 0xFFFF; данные MG76_13PL. */ +#define MG76_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G76PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G76PL) || (G74PL == 0) +/* Задаёт MG76_14PL = ~(1 << 3); данные MG76_14PL. */ +#define MG76_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_14PL = 0xFFFF; данные MG76_14PL. */ +#define MG76_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G76PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G76PL) || (G75PL == 0) +/* Задаёт MG76_15PL = ~(1 << 4); данные MG76_15PL. */ +#define MG76_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_15PL = 0xFFFF; данные MG76_15PL. */ +#define MG76_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G76PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G76PL) || (G77PL == 0) +/* Задаёт MG76_17PL = ~(1 << 6); данные MG76_17PL. */ +#define MG76_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_17PL = 0xFFFF; данные MG76_17PL. */ +#define MG76_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G76PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G76PL) || (G78PL == 0) +/* Задаёт MG76_18PL = ~(1 << 7); данные MG76_18PL. */ +#define MG76_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_18PL = 0xFFFF; данные MG76_18PL. */ +#define MG76_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG76_16PL = 0x00DF; данные MG76_16PL. */ +#define MG76_16PL 0x00DF +/* Задаёт MG76 = (MG76_11PL & MG76_12PL & MG76_13PL & MG76_14PL &; маска разрешённых прерываний внутри группы PIE 76. */ +#define MG76 (MG76_11PL & MG76_12PL & MG76_13PL & MG76_14PL & \ + MG76_15PL & MG76_16PL & MG76_17PL & MG76_18PL) /* Продолжает список аргументов, полей или выражение MG76_15PL & MG76_16PL & MG76_17PL & MG76_18PL); порядок элементов сохраняется. */ +// End of MG76: + +// Beginning of MG77: +/* Условие компиляции (G71PL >= G77PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G77PL) || (G71PL == 0) +/* Задаёт MG77_11PL = ~(1); данные MG77_11PL. */ +#define MG77_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_11PL = 0xFFFF; данные MG77_11PL. */ +#define MG77_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G77PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G77PL) || (G72PL == 0) +/* Задаёт MG77_12PL = ~(1 << 1); данные MG77_12PL. */ +#define MG77_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_12PL = 0xFFFF; данные MG77_12PL. */ +#define MG77_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G77PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G77PL) || (G73PL == 0) +/* Задаёт MG77_13PL = ~(1 << 2); данные MG77_13PL. */ +#define MG77_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_13PL = 0xFFFF; данные MG77_13PL. */ +#define MG77_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G77PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G77PL) || (G74PL == 0) +/* Задаёт MG77_14PL = ~(1 << 3); данные MG77_14PL. */ +#define MG77_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_14PL = 0xFFFF; данные MG77_14PL. */ +#define MG77_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G77PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G77PL) || (G75PL == 0) +/* Задаёт MG77_15PL = ~(1 << 4); данные MG77_15PL. */ +#define MG77_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_15PL = 0xFFFF; данные MG77_15PL. */ +#define MG77_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G77PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G77PL) || (G76PL == 0) +/* Задаёт MG77_16PL = ~(1 << 5); данные MG77_16PL. */ +#define MG77_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_16PL = 0xFFFF; данные MG77_16PL. */ +#define MG77_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G77PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G77PL) || (G78PL == 0) +/* Задаёт MG77_18PL = ~(1 << 7); данные MG77_18PL. */ +#define MG77_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_18PL = 0xFFFF; данные MG77_18PL. */ +#define MG77_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG77_17PL = 0x00BF; данные MG77_17PL. */ +#define MG77_17PL 0x00BF +/* Задаёт MG77 = (MG77_11PL & MG77_12PL & MG77_13PL & MG77_14PL &; маска разрешённых прерываний внутри группы PIE 77. */ +#define MG77 (MG77_11PL & MG77_12PL & MG77_13PL & MG77_14PL & \ + MG77_15PL & MG77_16PL & MG77_17PL & MG77_18PL) /* Продолжает список аргументов, полей или выражение MG77_15PL & MG77_16PL & MG77_17PL & MG77_18PL); порядок элементов сохраняется. */ +// End of MG77: + +// Beginning of MG78: +/* Условие компиляции (G71PL >= G78PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G78PL) || (G71PL == 0) +/* Задаёт MG78_11PL = ~(1); данные MG78_11PL. */ +#define MG78_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_11PL = 0xFFFF; данные MG78_11PL. */ +#define MG78_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G78PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G78PL) || (G72PL == 0) +/* Задаёт MG78_12PL = ~(1 << 1); данные MG78_12PL. */ +#define MG78_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_12PL = 0xFFFF; данные MG78_12PL. */ +#define MG78_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G78PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G78PL) || (G73PL == 0) +/* Задаёт MG78_13PL = ~(1 << 2); данные MG78_13PL. */ +#define MG78_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_13PL = 0xFFFF; данные MG78_13PL. */ +#define MG78_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G78PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G78PL) || (G74PL == 0) +/* Задаёт MG78_14PL = ~(1 << 3); данные MG78_14PL. */ +#define MG78_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_14PL = 0xFFFF; данные MG78_14PL. */ +#define MG78_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G78PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G78PL) || (G75PL == 0) +/* Задаёт MG78_15PL = ~(1 << 4); данные MG78_15PL. */ +#define MG78_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_15PL = 0xFFFF; данные MG78_15PL. */ +#define MG78_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G78PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G78PL) || (G76PL == 0) +/* Задаёт MG78_16PL = ~(1 << 5); данные MG78_16PL. */ +#define MG78_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_16PL = 0xFFFF; данные MG78_16PL. */ +#define MG78_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G78PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G78PL) || (G77PL == 0) +/* Задаёт MG78_17PL = ~(1 << 6); данные MG78_17PL. */ +#define MG78_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_17PL = 0xFFFF; данные MG78_17PL. */ +#define MG78_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG78_18PL = 0x007F; данные MG78_18PL. */ +#define MG78_18PL 0x007F +/* Задаёт MG78 = (MG78_11PL & MG78_12PL & MG78_13PL & MG78_14PL &; маска разрешённых прерываний внутри группы PIE 78. */ +#define MG78 (MG78_11PL & MG78_12PL & MG78_13PL & MG78_14PL & \ + MG78_15PL & MG78_16PL & MG78_17PL & MG78_18PL) /* Продолжает список аргументов, полей или выражение MG78_15PL & MG78_16PL & MG78_17PL & MG78_18PL); порядок элементов сохраняется. */ +// End of MG78: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG81 to MG88: +// + +// Beginning of MG81: +/* Условие компиляции (G82PL >= G81PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G81PL) || (G82PL == 0) +/* Задаёт MG81_12PL = ~(1 << 1); данные MG81_12PL. */ +#define MG81_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_12PL = 0xFFFF; данные MG81_12PL. */ +#define MG81_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G81PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G81PL) || (G83PL == 0) +/* Задаёт MG81_13PL = ~(1 << 2); данные MG81_13PL. */ +#define MG81_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_13PL = 0xFFFF; данные MG81_13PL. */ +#define MG81_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G81PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G81PL) || (G84PL == 0) +/* Задаёт MG81_14PL = ~(1 << 3); данные MG81_14PL. */ +#define MG81_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_14PL = 0xFFFF; данные MG81_14PL. */ +#define MG81_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G81PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G81PL) || (G85PL == 0) +/* Задаёт MG81_15PL = ~(1 << 4); данные MG81_15PL. */ +#define MG81_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_15PL = 0xFFFF; данные MG81_15PL. */ +#define MG81_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G81PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G81PL) || (G86PL == 0) +/* Задаёт MG81_16PL = ~(1 << 5); данные MG81_16PL. */ +#define MG81_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_16PL = 0xFFFF; данные MG81_16PL. */ +#define MG81_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G81PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G81PL) || (G87PL == 0) +/* Задаёт MG81_17PL = ~(1 << 6); данные MG81_17PL. */ +#define MG81_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_17PL = 0xFFFF; данные MG81_17PL. */ +#define MG81_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G81PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G81PL) || (G88PL == 0) +/* Задаёт MG81_18PL = ~(1 << 7); данные MG81_18PL. */ +#define MG81_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_18PL = 0xFFFF; данные MG81_18PL. */ +#define MG81_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG81_11PL = 0x00FE; данные MG81_11PL. */ +#define MG81_11PL 0x00FE +/* Задаёт MG81 = (MG81_11PL & MG81_12PL & MG81_13PL & MG81_14PL &; маска разрешённых прерываний внутри группы PIE 81. */ +#define MG81 (MG81_11PL & MG81_12PL & MG81_13PL & MG81_14PL & \ + MG81_15PL & MG81_16PL & MG81_17PL & MG81_18PL) /* Продолжает список аргументов, полей или выражение MG81_15PL & MG81_16PL & MG81_17PL & MG81_18PL); порядок элементов сохраняется. */ +// End of MG81: + +// Beginning of MG82: +/* Условие компиляции (G81PL >= G82PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G82PL) || (G81PL == 0) +/* Задаёт MG82_11PL = ~(1); данные MG82_11PL. */ +#define MG82_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_11PL = 0xFFFF; данные MG82_11PL. */ +#define MG82_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G82PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G82PL) || (G83PL == 0) +/* Задаёт MG82_13PL = ~(1 << 2); данные MG82_13PL. */ +#define MG82_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_13PL = 0xFFFF; данные MG82_13PL. */ +#define MG82_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G82PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G82PL) || (G84PL == 0) +/* Задаёт MG82_14PL = ~(1 << 3); данные MG82_14PL. */ +#define MG82_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_14PL = 0xFFFF; данные MG82_14PL. */ +#define MG82_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G82PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G82PL) || (G85PL == 0) +/* Задаёт MG82_15PL = ~(1 << 4); данные MG82_15PL. */ +#define MG82_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_15PL = 0xFFFF; данные MG82_15PL. */ +#define MG82_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G82PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G82PL) || (G86PL == 0) +/* Задаёт MG82_16PL = ~(1 << 5); данные MG82_16PL. */ +#define MG82_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_16PL = 0xFFFF; данные MG82_16PL. */ +#define MG82_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G82PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G82PL) || (G87PL == 0) +/* Задаёт MG82_17PL = ~(1 << 6); данные MG82_17PL. */ +#define MG82_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_17PL = 0xFFFF; данные MG82_17PL. */ +#define MG82_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G82PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G82PL) || (G88PL == 0) +/* Задаёт MG82_18PL = ~(1 << 7); данные MG82_18PL. */ +#define MG82_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_18PL = 0xFFFF; данные MG82_18PL. */ +#define MG82_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG82_12PL = 0x00FD; данные MG82_12PL. */ +#define MG82_12PL 0x00FD +/* Задаёт MG82 = (MG82_11PL & MG82_12PL & MG82_13PL & MG82_14PL &; маска разрешённых прерываний внутри группы PIE 82. */ +#define MG82 (MG82_11PL & MG82_12PL & MG82_13PL & MG82_14PL & \ + MG82_15PL & MG82_16PL & MG82_17PL & MG82_18PL) /* Продолжает список аргументов, полей или выражение MG82_15PL & MG82_16PL & MG82_17PL & MG82_18PL); порядок элементов сохраняется. */ +// End of MG82: + +// Beginning of MG83: +/* Условие компиляции (G81PL >= G83PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G83PL) || (G81PL == 0) +/* Задаёт MG83_11PL = ~(1); данные MG83_11PL. */ +#define MG83_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_11PL = 0xFFFF; данные MG83_11PL. */ +#define MG83_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G83PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G83PL) || (G82PL == 0) +/* Задаёт MG83_12PL = ~(1 << 1); данные MG83_12PL. */ +#define MG83_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_12PL = 0xFFFF; данные MG83_12PL. */ +#define MG83_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G83PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G83PL) || (G84PL == 0) +/* Задаёт MG83_14PL = ~(1 << 3); данные MG83_14PL. */ +#define MG83_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_14PL = 0xFFFF; данные MG83_14PL. */ +#define MG83_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G83PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G83PL) || (G85PL == 0) +/* Задаёт MG83_15PL = ~(1 << 4); данные MG83_15PL. */ +#define MG83_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_15PL = 0xFFFF; данные MG83_15PL. */ +#define MG83_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G83PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G83PL) || (G86PL == 0) +/* Задаёт MG83_16PL = ~(1 << 5); данные MG83_16PL. */ +#define MG83_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_16PL = 0xFFFF; данные MG83_16PL. */ +#define MG83_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G83PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G83PL) || (G87PL == 0) +/* Задаёт MG83_17PL = ~(1 << 6); данные MG83_17PL. */ +#define MG83_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_17PL = 0xFFFF; данные MG83_17PL. */ +#define MG83_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G83PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G83PL) || (G88PL == 0) +/* Задаёт MG83_18PL = ~(1 << 7); данные MG83_18PL. */ +#define MG83_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_18PL = 0xFFFF; данные MG83_18PL. */ +#define MG83_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG83_13PL = 0x00FB; данные MG83_13PL. */ +#define MG83_13PL 0x00FB +/* Задаёт MG83 = (MG83_11PL & MG83_12PL & MG83_13PL & MG83_14PL &; маска разрешённых прерываний внутри группы PIE 83. */ +#define MG83 (MG83_11PL & MG83_12PL & MG83_13PL & MG83_14PL & \ + MG83_15PL & MG83_16PL & MG83_17PL & MG83_18PL) /* Продолжает список аргументов, полей или выражение MG83_15PL & MG83_16PL & MG83_17PL & MG83_18PL); порядок элементов сохраняется. */ +// End of MG83: + +// Beginning of MG84: +/* Условие компиляции (G81PL >= G84PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G84PL) || (G81PL == 0) +/* Задаёт MG84_11PL = ~(1); данные MG84_11PL. */ +#define MG84_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_11PL = 0xFFFF; данные MG84_11PL. */ +#define MG84_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G84PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G84PL) || (G82PL == 0) +/* Задаёт MG84_12PL = ~(1 << 1); данные MG84_12PL. */ +#define MG84_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_12PL = 0xFFFF; данные MG84_12PL. */ +#define MG84_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G84PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G84PL) || (G83PL == 0) +/* Задаёт MG84_13PL = ~(1 << 2); данные MG84_13PL. */ +#define MG84_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_13PL = 0xFFFF; данные MG84_13PL. */ +#define MG84_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G84PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G84PL) || (G85PL == 0) +/* Задаёт MG84_15PL = ~(1 << 4); данные MG84_15PL. */ +#define MG84_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_15PL = 0xFFFF; данные MG84_15PL. */ +#define MG84_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G84PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G84PL) || (G86PL == 0) +/* Задаёт MG84_16PL = ~(1 << 5); данные MG84_16PL. */ +#define MG84_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_16PL = 0xFFFF; данные MG84_16PL. */ +#define MG84_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G84PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G84PL) || (G87PL == 0) +/* Задаёт MG84_17PL = ~(1 << 6); данные MG84_17PL. */ +#define MG84_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_17PL = 0xFFFF; данные MG84_17PL. */ +#define MG84_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G84PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G84PL) || (G88PL == 0) +/* Задаёт MG84_18PL = ~(1 << 7); данные MG84_18PL. */ +#define MG84_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_18PL = 0xFFFF; данные MG84_18PL. */ +#define MG84_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG84_14PL = 0x00F7; данные MG84_14PL. */ +#define MG84_14PL 0x00F7 +/* Задаёт MG84 = (MG84_11PL & MG84_12PL & MG84_13PL & MG84_14PL &; маска разрешённых прерываний внутри группы PIE 84. */ +#define MG84 (MG84_11PL & MG84_12PL & MG84_13PL & MG84_14PL & \ + MG84_15PL & MG84_16PL & MG84_17PL & MG84_18PL) /* Продолжает список аргументов, полей или выражение MG84_15PL & MG84_16PL & MG84_17PL & MG84_18PL); порядок элементов сохраняется. */ +// End of MG84: + +// Beginning of MG85: +/* Условие компиляции (G81PL >= G85PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G85PL) || (G81PL == 0) +/* Задаёт MG85_11PL = ~(1); данные MG85_11PL. */ +#define MG85_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_11PL = 0xFFFF; данные MG85_11PL. */ +#define MG85_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G85PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G85PL) || (G82PL == 0) +/* Задаёт MG85_12PL = ~(1 << 1); данные MG85_12PL. */ +#define MG85_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_12PL = 0xFFFF; данные MG85_12PL. */ +#define MG85_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G85PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G85PL) || (G83PL == 0) +/* Задаёт MG85_13PL = ~(1 << 2); данные MG85_13PL. */ +#define MG85_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_13PL = 0xFFFF; данные MG85_13PL. */ +#define MG85_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G85PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G85PL) || (G84PL == 0) +/* Задаёт MG85_14PL = ~(1 << 3); данные MG85_14PL. */ +#define MG85_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_14PL = 0xFFFF; данные MG85_14PL. */ +#define MG85_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G85PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G85PL) || (G86PL == 0) +/* Задаёт MG85_16PL = ~(1 << 5); данные MG85_16PL. */ +#define MG85_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_16PL = 0xFFFF; данные MG85_16PL. */ +#define MG85_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G85PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G85PL) || (G87PL == 0) +/* Задаёт MG85_17PL = ~(1 << 6); данные MG85_17PL. */ +#define MG85_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_17PL = 0xFFFF; данные MG85_17PL. */ +#define MG85_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G85PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G85PL) || (G88PL == 0) +/* Задаёт MG85_18PL = ~(1 << 7); данные MG85_18PL. */ +#define MG85_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_18PL = 0xFFFF; данные MG85_18PL. */ +#define MG85_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG85_15PL = 0x00EF; данные MG85_15PL. */ +#define MG85_15PL 0x00EF +/* Задаёт MG85 = (MG85_11PL & MG85_12PL & MG85_13PL & MG85_14PL &; маска разрешённых прерываний внутри группы PIE 85. */ +#define MG85 (MG85_11PL & MG85_12PL & MG85_13PL & MG85_14PL & \ + MG85_15PL & MG85_16PL & MG85_17PL & MG85_18PL) /* Продолжает список аргументов, полей или выражение MG85_15PL & MG85_16PL & MG85_17PL & MG85_18PL); порядок элементов сохраняется. */ +// End of MG85: + +// Beginning of MG86: +/* Условие компиляции (G81PL >= G86PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G86PL) || (G81PL == 0) +/* Задаёт MG86_11PL = ~(1); данные MG86_11PL. */ +#define MG86_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_11PL = 0xFFFF; данные MG86_11PL. */ +#define MG86_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G86PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G86PL) || (G82PL == 0) +/* Задаёт MG86_12PL = ~(1 << 1); данные MG86_12PL. */ +#define MG86_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_12PL = 0xFFFF; данные MG86_12PL. */ +#define MG86_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G86PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G86PL) || (G83PL == 0) +/* Задаёт MG86_13PL = ~(1 << 2); данные MG86_13PL. */ +#define MG86_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_13PL = 0xFFFF; данные MG86_13PL. */ +#define MG86_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G86PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G86PL) || (G84PL == 0) +/* Задаёт MG86_14PL = ~(1 << 3); данные MG86_14PL. */ +#define MG86_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_14PL = 0xFFFF; данные MG86_14PL. */ +#define MG86_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G86PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G86PL) || (G85PL == 0) +/* Задаёт MG86_15PL = ~(1 << 4); данные MG86_15PL. */ +#define MG86_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_15PL = 0xFFFF; данные MG86_15PL. */ +#define MG86_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G86PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G86PL) || (G87PL == 0) +/* Задаёт MG86_17PL = ~(1 << 6); данные MG86_17PL. */ +#define MG86_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_17PL = 0xFFFF; данные MG86_17PL. */ +#define MG86_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G86PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G86PL) || (G88PL == 0) +/* Задаёт MG86_18PL = ~(1 << 7); данные MG86_18PL. */ +#define MG86_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_18PL = 0xFFFF; данные MG86_18PL. */ +#define MG86_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG86_16PL = 0x00DF; данные MG86_16PL. */ +#define MG86_16PL 0x00DF +/* Задаёт MG86 = (MG86_11PL & MG86_12PL & MG86_13PL & MG86_14PL &; маска разрешённых прерываний внутри группы PIE 86. */ +#define MG86 (MG86_11PL & MG86_12PL & MG86_13PL & MG86_14PL & \ + MG86_15PL & MG86_16PL & MG86_17PL & MG86_18PL) /* Продолжает список аргументов, полей или выражение MG86_15PL & MG86_16PL & MG86_17PL & MG86_18PL); порядок элементов сохраняется. */ +// End of MG86: + +// Beginning of MG87: +/* Условие компиляции (G81PL >= G87PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G87PL) || (G81PL == 0) +/* Задаёт MG87_11PL = ~(1); данные MG87_11PL. */ +#define MG87_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_11PL = 0xFFFF; данные MG87_11PL. */ +#define MG87_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G87PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G87PL) || (G82PL == 0) +/* Задаёт MG87_12PL = ~(1 << 1); данные MG87_12PL. */ +#define MG87_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_12PL = 0xFFFF; данные MG87_12PL. */ +#define MG87_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G87PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G87PL) || (G83PL == 0) +/* Задаёт MG87_13PL = ~(1 << 2); данные MG87_13PL. */ +#define MG87_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_13PL = 0xFFFF; данные MG87_13PL. */ +#define MG87_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G87PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G87PL) || (G84PL == 0) +/* Задаёт MG87_14PL = ~(1 << 3); данные MG87_14PL. */ +#define MG87_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_14PL = 0xFFFF; данные MG87_14PL. */ +#define MG87_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G87PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G87PL) || (G85PL == 0) +/* Задаёт MG87_15PL = ~(1 << 4); данные MG87_15PL. */ +#define MG87_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_15PL = 0xFFFF; данные MG87_15PL. */ +#define MG87_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G87PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G87PL) || (G86PL == 0) +/* Задаёт MG87_16PL = ~(1 << 5); данные MG87_16PL. */ +#define MG87_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_16PL = 0xFFFF; данные MG87_16PL. */ +#define MG87_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G87PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G87PL) || (G88PL == 0) +/* Задаёт MG87_18PL = ~(1 << 7); данные MG87_18PL. */ +#define MG87_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_18PL = 0xFFFF; данные MG87_18PL. */ +#define MG87_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG87_17PL = 0x00BF; данные MG87_17PL. */ +#define MG87_17PL 0x00BF +/* Задаёт MG87 = (MG87_11PL & MG87_12PL & MG87_13PL & MG87_14PL &; маска разрешённых прерываний внутри группы PIE 87. */ +#define MG87 (MG87_11PL & MG87_12PL & MG87_13PL & MG87_14PL & \ + MG87_15PL & MG87_16PL & MG87_17PL & MG87_18PL) /* Продолжает список аргументов, полей или выражение MG87_15PL & MG87_16PL & MG87_17PL & MG87_18PL); порядок элементов сохраняется. */ +// End of MG87: + +// Beginning of MG88: +/* Условие компиляции (G81PL >= G88PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G88PL) || (G81PL == 0) +/* Задаёт MG88_11PL = ~(1); данные MG88_11PL. */ +#define MG88_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_11PL = 0xFFFF; данные MG88_11PL. */ +#define MG88_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G88PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G88PL) || (G82PL == 0) +/* Задаёт MG88_12PL = ~(1 << 1); данные MG88_12PL. */ +#define MG88_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_12PL = 0xFFFF; данные MG88_12PL. */ +#define MG88_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G88PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G88PL) || (G83PL == 0) +/* Задаёт MG88_13PL = ~(1 << 2); данные MG88_13PL. */ +#define MG88_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_13PL = 0xFFFF; данные MG88_13PL. */ +#define MG88_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G88PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G88PL) || (G84PL == 0) +/* Задаёт MG88_14PL = ~(1 << 3); данные MG88_14PL. */ +#define MG88_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_14PL = 0xFFFF; данные MG88_14PL. */ +#define MG88_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G88PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G88PL) || (G85PL == 0) +/* Задаёт MG88_15PL = ~(1 << 4); данные MG88_15PL. */ +#define MG88_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_15PL = 0xFFFF; данные MG88_15PL. */ +#define MG88_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G88PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G88PL) || (G86PL == 0) +/* Задаёт MG88_16PL = ~(1 << 5); данные MG88_16PL. */ +#define MG88_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_16PL = 0xFFFF; данные MG88_16PL. */ +#define MG88_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G88PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G88PL) || (G87PL == 0) +/* Задаёт MG88_17PL = ~(1 << 6); данные MG88_17PL. */ +#define MG88_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_17PL = 0xFFFF; данные MG88_17PL. */ +#define MG88_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG88_18PL = 0x007F; данные MG88_18PL. */ +#define MG88_18PL 0x007F +/* Задаёт MG88 = (MG88_11PL & MG88_12PL & MG88_13PL & MG88_14PL &; маска разрешённых прерываний внутри группы PIE 88. */ +#define MG88 (MG88_11PL & MG88_12PL & MG88_13PL & MG88_14PL & \ + MG88_15PL & MG88_16PL & MG88_17PL & MG88_18PL) /* Продолжает список аргументов, полей или выражение MG88_15PL & MG88_16PL & MG88_17PL & MG88_18PL); порядок элементов сохраняется. */ +// End of MG88: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG91 to MG98: +// + +// Beginning of MG91: +/* Условие компиляции (G92PL >= G91PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G91PL) || (G92PL == 0) +/* Задаёт MG91_12PL = ~(1 << 1); данные MG91_12PL. */ +#define MG91_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_12PL = 0xFFFF; данные MG91_12PL. */ +#define MG91_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G91PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G91PL) || (G93PL == 0) +/* Задаёт MG91_13PL = ~(1 << 2); данные MG91_13PL. */ +#define MG91_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_13PL = 0xFFFF; данные MG91_13PL. */ +#define MG91_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G91PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G91PL) || (G94PL == 0) +/* Задаёт MG91_14PL = ~(1 << 3); данные MG91_14PL. */ +#define MG91_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_14PL = 0xFFFF; данные MG91_14PL. */ +#define MG91_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G91PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G91PL) || (G95PL == 0) +/* Задаёт MG91_15PL = ~(1 << 4); данные MG91_15PL. */ +#define MG91_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_15PL = 0xFFFF; данные MG91_15PL. */ +#define MG91_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G91PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G91PL) || (G96PL == 0) +/* Задаёт MG91_16PL = ~(1 << 5); данные MG91_16PL. */ +#define MG91_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_16PL = 0xFFFF; данные MG91_16PL. */ +#define MG91_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G91PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G91PL) || (G97PL == 0) +/* Задаёт MG91_17PL = ~(1 << 6); данные MG91_17PL. */ +#define MG91_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_17PL = 0xFFFF; данные MG91_17PL. */ +#define MG91_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G91PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G91PL) || (G98PL == 0) +/* Задаёт MG91_18PL = ~(1 << 7); данные MG91_18PL. */ +#define MG91_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_18PL = 0xFFFF; данные MG91_18PL. */ +#define MG91_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG91_11PL = 0x00FE; данные MG91_11PL. */ +#define MG91_11PL 0x00FE +/* Задаёт MG91 = (MG91_11PL & MG91_12PL & MG91_13PL & MG91_14PL &; маска разрешённых прерываний внутри группы PIE 91. */ +#define MG91 (MG91_11PL & MG91_12PL & MG91_13PL & MG91_14PL & \ + MG91_15PL & MG91_16PL & MG91_17PL & MG91_18PL) /* Продолжает список аргументов, полей или выражение MG91_15PL & MG91_16PL & MG91_17PL & MG91_18PL); порядок элементов сохраняется. */ +// End of MG91: + +// Beginning of MG92: +/* Условие компиляции (G91PL >= G92PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G92PL) || (G91PL == 0) +/* Задаёт MG92_11PL = ~(1); данные MG92_11PL. */ +#define MG92_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_11PL = 0xFFFF; данные MG92_11PL. */ +#define MG92_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G92PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G92PL) || (G93PL == 0) +/* Задаёт MG92_13PL = ~(1 << 2); данные MG92_13PL. */ +#define MG92_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_13PL = 0xFFFF; данные MG92_13PL. */ +#define MG92_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G92PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G92PL) || (G94PL == 0) +/* Задаёт MG92_14PL = ~(1 << 3); данные MG92_14PL. */ +#define MG92_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_14PL = 0xFFFF; данные MG92_14PL. */ +#define MG92_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G92PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G92PL) || (G95PL == 0) +/* Задаёт MG92_15PL = ~(1 << 4); данные MG92_15PL. */ +#define MG92_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_15PL = 0xFFFF; данные MG92_15PL. */ +#define MG92_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G92PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G92PL) || (G96PL == 0) +/* Задаёт MG92_16PL = ~(1 << 5); данные MG92_16PL. */ +#define MG92_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_16PL = 0xFFFF; данные MG92_16PL. */ +#define MG92_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G92PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G92PL) || (G97PL == 0) +/* Задаёт MG92_17PL = ~(1 << 6); данные MG92_17PL. */ +#define MG92_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_17PL = 0xFFFF; данные MG92_17PL. */ +#define MG92_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G92PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G92PL) || (G98PL == 0) +/* Задаёт MG92_18PL = ~(1 << 7); данные MG92_18PL. */ +#define MG92_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_18PL = 0xFFFF; данные MG92_18PL. */ +#define MG92_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG92_12PL = 0x00FD; данные MG92_12PL. */ +#define MG92_12PL 0x00FD +/* Задаёт MG92 = (MG92_11PL & MG92_12PL & MG92_13PL & MG92_14PL &; маска разрешённых прерываний внутри группы PIE 92. */ +#define MG92 (MG92_11PL & MG92_12PL & MG92_13PL & MG92_14PL & \ + MG92_15PL & MG92_16PL & MG92_17PL & MG92_18PL) /* Продолжает список аргументов, полей или выражение MG92_15PL & MG92_16PL & MG92_17PL & MG92_18PL); порядок элементов сохраняется. */ +// End of MG92: + +// Beginning of MG93: +/* Условие компиляции (G91PL >= G93PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G93PL) || (G91PL == 0) +/* Задаёт MG93_11PL = ~(1); данные MG93_11PL. */ +#define MG93_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_11PL = 0xFFFF; данные MG93_11PL. */ +#define MG93_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G93PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G93PL) || (G92PL == 0) +/* Задаёт MG93_12PL = ~(1 << 1); данные MG93_12PL. */ +#define MG93_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_12PL = 0xFFFF; данные MG93_12PL. */ +#define MG93_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G93PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G93PL) || (G94PL == 0) +/* Задаёт MG93_14PL = ~(1 << 3); данные MG93_14PL. */ +#define MG93_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_14PL = 0xFFFF; данные MG93_14PL. */ +#define MG93_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G93PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G93PL) || (G95PL == 0) +/* Задаёт MG93_15PL = ~(1 << 4); данные MG93_15PL. */ +#define MG93_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_15PL = 0xFFFF; данные MG93_15PL. */ +#define MG93_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G93PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G93PL) || (G96PL == 0) +/* Задаёт MG93_16PL = ~(1 << 5); данные MG93_16PL. */ +#define MG93_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_16PL = 0xFFFF; данные MG93_16PL. */ +#define MG93_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G93PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G93PL) || (G97PL == 0) +/* Задаёт MG93_17PL = ~(1 << 6); данные MG93_17PL. */ +#define MG93_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_17PL = 0xFFFF; данные MG93_17PL. */ +#define MG93_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G93PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G93PL) || (G98PL == 0) +/* Задаёт MG93_18PL = ~(1 << 7); данные MG93_18PL. */ +#define MG93_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_18PL = 0xFFFF; данные MG93_18PL. */ +#define MG93_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG93_13PL = 0x00FB; данные MG93_13PL. */ +#define MG93_13PL 0x00FB +/* Задаёт MG93 = (MG93_11PL & MG93_12PL & MG93_13PL & MG93_14PL &; маска разрешённых прерываний внутри группы PIE 93. */ +#define MG93 (MG93_11PL & MG93_12PL & MG93_13PL & MG93_14PL & \ + MG93_15PL & MG93_16PL & MG93_17PL & MG93_18PL) /* Продолжает список аргументов, полей или выражение MG93_15PL & MG93_16PL & MG93_17PL & MG93_18PL); порядок элементов сохраняется. */ +// End of MG93: + +// Beginning of MG94: +/* Условие компиляции (G91PL >= G94PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G94PL) || (G91PL == 0) +/* Задаёт MG94_11PL = ~(1); данные MG94_11PL. */ +#define MG94_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_11PL = 0xFFFF; данные MG94_11PL. */ +#define MG94_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G94PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G94PL) || (G92PL == 0) +/* Задаёт MG94_12PL = ~(1 << 1); данные MG94_12PL. */ +#define MG94_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_12PL = 0xFFFF; данные MG94_12PL. */ +#define MG94_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G94PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G94PL) || (G93PL == 0) +/* Задаёт MG94_13PL = ~(1 << 2); данные MG94_13PL. */ +#define MG94_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_13PL = 0xFFFF; данные MG94_13PL. */ +#define MG94_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G94PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G94PL) || (G95PL == 0) +/* Задаёт MG94_15PL = ~(1 << 4); данные MG94_15PL. */ +#define MG94_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_15PL = 0xFFFF; данные MG94_15PL. */ +#define MG94_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G94PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G94PL) || (G96PL == 0) +/* Задаёт MG94_16PL = ~(1 << 5); данные MG94_16PL. */ +#define MG94_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_16PL = 0xFFFF; данные MG94_16PL. */ +#define MG94_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G94PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G94PL) || (G97PL == 0) +/* Задаёт MG94_17PL = ~(1 << 6); данные MG94_17PL. */ +#define MG94_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_17PL = 0xFFFF; данные MG94_17PL. */ +#define MG94_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G94PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G94PL) || (G98PL == 0) +/* Задаёт MG94_18PL = ~(1 << 7); данные MG94_18PL. */ +#define MG94_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_18PL = 0xFFFF; данные MG94_18PL. */ +#define MG94_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG94_14PL = 0x00F7; данные MG94_14PL. */ +#define MG94_14PL 0x00F7 +/* Задаёт MG94 = (MG94_11PL & MG94_12PL & MG94_13PL & MG94_14PL &; маска разрешённых прерываний внутри группы PIE 94. */ +#define MG94 (MG94_11PL & MG94_12PL & MG94_13PL & MG94_14PL & \ + MG94_15PL & MG94_16PL & MG94_17PL & MG94_18PL) /* Продолжает список аргументов, полей или выражение MG94_15PL & MG94_16PL & MG94_17PL & MG94_18PL); порядок элементов сохраняется. */ +// End of MG94: + +// Beginning of MG95: +/* Условие компиляции (G91PL >= G95PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G95PL) || (G91PL == 0) +/* Задаёт MG95_11PL = ~(1); данные MG95_11PL. */ +#define MG95_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_11PL = 0xFFFF; данные MG95_11PL. */ +#define MG95_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G95PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G95PL) || (G92PL == 0) +/* Задаёт MG95_12PL = ~(1 << 1); данные MG95_12PL. */ +#define MG95_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_12PL = 0xFFFF; данные MG95_12PL. */ +#define MG95_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G95PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G95PL) || (G93PL == 0) +/* Задаёт MG95_13PL = ~(1 << 2); данные MG95_13PL. */ +#define MG95_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_13PL = 0xFFFF; данные MG95_13PL. */ +#define MG95_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G95PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G95PL) || (G94PL == 0) +/* Задаёт MG95_14PL = ~(1 << 3); данные MG95_14PL. */ +#define MG95_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_14PL = 0xFFFF; данные MG95_14PL. */ +#define MG95_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G95PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G95PL) || (G96PL == 0) +/* Задаёт MG95_16PL = ~(1 << 5); данные MG95_16PL. */ +#define MG95_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_16PL = 0xFFFF; данные MG95_16PL. */ +#define MG95_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G95PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G95PL) || (G97PL == 0) +/* Задаёт MG95_17PL = ~(1 << 6); данные MG95_17PL. */ +#define MG95_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_17PL = 0xFFFF; данные MG95_17PL. */ +#define MG95_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G95PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G95PL) || (G98PL == 0) +/* Задаёт MG95_18PL = ~(1 << 7); данные MG95_18PL. */ +#define MG95_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_18PL = 0xFFFF; данные MG95_18PL. */ +#define MG95_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG95_15PL = 0x00EF; данные MG95_15PL. */ +#define MG95_15PL 0x00EF +/* Задаёт MG95 = (MG95_11PL & MG95_12PL & MG95_13PL & MG95_14PL &; маска разрешённых прерываний внутри группы PIE 95. */ +#define MG95 (MG95_11PL & MG95_12PL & MG95_13PL & MG95_14PL & \ + MG95_15PL & MG95_16PL & MG95_17PL & MG95_18PL) /* Продолжает список аргументов, полей или выражение MG95_15PL & MG95_16PL & MG95_17PL & MG95_18PL); порядок элементов сохраняется. */ +// End of MG95: + +// Beginning of MG96: +/* Условие компиляции (G91PL >= G96PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G96PL) || (G91PL == 0) +/* Задаёт MG96_11PL = ~(1); данные MG96_11PL. */ +#define MG96_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_11PL = 0xFFFF; данные MG96_11PL. */ +#define MG96_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G96PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G96PL) || (G92PL == 0) +/* Задаёт MG96_12PL = ~(1 << 1); данные MG96_12PL. */ +#define MG96_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_12PL = 0xFFFF; данные MG96_12PL. */ +#define MG96_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G96PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G96PL) || (G93PL == 0) +/* Задаёт MG96_13PL = ~(1 << 2); данные MG96_13PL. */ +#define MG96_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_13PL = 0xFFFF; данные MG96_13PL. */ +#define MG96_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G96PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G96PL) || (G94PL == 0) +/* Задаёт MG96_14PL = ~(1 << 3); данные MG96_14PL. */ +#define MG96_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_14PL = 0xFFFF; данные MG96_14PL. */ +#define MG96_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G96PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G96PL) || (G95PL == 0) +/* Задаёт MG96_15PL = ~(1 << 4); данные MG96_15PL. */ +#define MG96_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_15PL = 0xFFFF; данные MG96_15PL. */ +#define MG96_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G96PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G96PL) || (G97PL == 0) +/* Задаёт MG96_17PL = ~(1 << 6); данные MG96_17PL. */ +#define MG96_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_17PL = 0xFFFF; данные MG96_17PL. */ +#define MG96_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G96PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G96PL) || (G98PL == 0) +/* Задаёт MG96_18PL = ~(1 << 7); данные MG96_18PL. */ +#define MG96_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_18PL = 0xFFFF; данные MG96_18PL. */ +#define MG96_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG96_16PL = 0x00DF; данные MG96_16PL. */ +#define MG96_16PL 0x00DF +/* Задаёт MG96 = (MG96_11PL & MG96_12PL & MG96_13PL & MG96_14PL &; маска разрешённых прерываний внутри группы PIE 96. */ +#define MG96 (MG96_11PL & MG96_12PL & MG96_13PL & MG96_14PL & \ + MG96_15PL & MG96_16PL & MG96_17PL & MG96_18PL) /* Продолжает список аргументов, полей или выражение MG96_15PL & MG96_16PL & MG96_17PL & MG96_18PL); порядок элементов сохраняется. */ +// End of MG96: + +// Beginning of MG97: +/* Условие компиляции (G91PL >= G97PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G97PL) || (G91PL == 0) +/* Задаёт MG97_11PL = ~(1); данные MG97_11PL. */ +#define MG97_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_11PL = 0xFFFF; данные MG97_11PL. */ +#define MG97_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G97PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G97PL) || (G92PL == 0) +/* Задаёт MG97_12PL = ~(1 << 1); данные MG97_12PL. */ +#define MG97_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_12PL = 0xFFFF; данные MG97_12PL. */ +#define MG97_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G97PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G97PL) || (G93PL == 0) +/* Задаёт MG97_13PL = ~(1 << 2); данные MG97_13PL. */ +#define MG97_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_13PL = 0xFFFF; данные MG97_13PL. */ +#define MG97_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G97PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G97PL) || (G94PL == 0) +/* Задаёт MG97_14PL = ~(1 << 3); данные MG97_14PL. */ +#define MG97_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_14PL = 0xFFFF; данные MG97_14PL. */ +#define MG97_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G97PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G97PL) || (G95PL == 0) +/* Задаёт MG97_15PL = ~(1 << 4); данные MG97_15PL. */ +#define MG97_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_15PL = 0xFFFF; данные MG97_15PL. */ +#define MG97_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G97PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G97PL) || (G96PL == 0) +/* Задаёт MG97_16PL = ~(1 << 5); данные MG97_16PL. */ +#define MG97_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_16PL = 0xFFFF; данные MG97_16PL. */ +#define MG97_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G97PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G97PL) || (G98PL == 0) +/* Задаёт MG97_18PL = ~(1 << 7); данные MG97_18PL. */ +#define MG97_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_18PL = 0xFFFF; данные MG97_18PL. */ +#define MG97_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG97_17PL = 0x00BF; данные MG97_17PL. */ +#define MG97_17PL 0x00BF +/* Задаёт MG97 = (MG97_11PL & MG97_12PL & MG97_13PL & MG97_14PL &; маска разрешённых прерываний внутри группы PIE 97. */ +#define MG97 (MG97_11PL & MG97_12PL & MG97_13PL & MG97_14PL & \ + MG97_15PL & MG97_16PL & MG97_17PL & MG97_18PL) /* Продолжает список аргументов, полей или выражение MG97_15PL & MG97_16PL & MG97_17PL & MG97_18PL); порядок элементов сохраняется. */ +// End of MG97: + +// Beginning of MG98: +/* Условие компиляции (G91PL >= G98PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G98PL) || (G91PL == 0) +/* Задаёт MG98_11PL = ~(1); данные MG98_11PL. */ +#define MG98_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_11PL = 0xFFFF; данные MG98_11PL. */ +#define MG98_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G98PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G98PL) || (G92PL == 0) +/* Задаёт MG98_12PL = ~(1 << 1); данные MG98_12PL. */ +#define MG98_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_12PL = 0xFFFF; данные MG98_12PL. */ +#define MG98_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G98PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G98PL) || (G93PL == 0) +/* Задаёт MG98_13PL = ~(1 << 2); данные MG98_13PL. */ +#define MG98_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_13PL = 0xFFFF; данные MG98_13PL. */ +#define MG98_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G98PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G98PL) || (G94PL == 0) +/* Задаёт MG98_14PL = ~(1 << 3); данные MG98_14PL. */ +#define MG98_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_14PL = 0xFFFF; данные MG98_14PL. */ +#define MG98_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G98PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G98PL) || (G95PL == 0) +/* Задаёт MG98_15PL = ~(1 << 4); данные MG98_15PL. */ +#define MG98_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_15PL = 0xFFFF; данные MG98_15PL. */ +#define MG98_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G98PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G98PL) || (G96PL == 0) +/* Задаёт MG98_16PL = ~(1 << 5); данные MG98_16PL. */ +#define MG98_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_16PL = 0xFFFF; данные MG98_16PL. */ +#define MG98_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G98PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G98PL) || (G97PL == 0) +/* Задаёт MG98_17PL = ~(1 << 6); данные MG98_17PL. */ +#define MG98_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_17PL = 0xFFFF; данные MG98_17PL. */ +#define MG98_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG98_18PL = 0x007F; данные MG98_18PL. */ +#define MG98_18PL 0x007F +/* Задаёт MG98 = (MG98_11PL & MG98_12PL & MG98_13PL & MG98_14PL &; маска разрешённых прерываний внутри группы PIE 98. */ +#define MG98 (MG98_11PL & MG98_12PL & MG98_13PL & MG98_14PL & \ + MG98_15PL & MG98_16PL & MG98_17PL & MG98_18PL) /* Продолжает список аргументов, полей или выражение MG98_15PL & MG98_16PL & MG98_17PL & MG98_18PL); порядок элементов сохраняется. */ +// End of MG98: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG101 to MG108: +// + +// Beginning of MG101: +/* Условие компиляции (G102PL >= G101PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G101PL) || (G102PL == 0) +/* Задаёт MG101_12PL = ~(1 << 1); данные MG101_12PL. */ +#define MG101_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_12PL = 0xFFFF; данные MG101_12PL. */ +#define MG101_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G101PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G101PL) || (G103PL == 0) +/* Задаёт MG101_13PL = ~(1 << 2); данные MG101_13PL. */ +#define MG101_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_13PL = 0xFFFF; данные MG101_13PL. */ +#define MG101_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G101PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G101PL) || (G104PL == 0) +/* Задаёт MG101_14PL = ~(1 << 3); данные MG101_14PL. */ +#define MG101_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_14PL = 0xFFFF; данные MG101_14PL. */ +#define MG101_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G101PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G101PL) || (G105PL == 0) +/* Задаёт MG101_15PL = ~(1 << 4); данные MG101_15PL. */ +#define MG101_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_15PL = 0xFFFF; данные MG101_15PL. */ +#define MG101_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G101PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G101PL) || (G106PL == 0) +/* Задаёт MG101_16PL = ~(1 << 5); данные MG101_16PL. */ +#define MG101_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_16PL = 0xFFFF; данные MG101_16PL. */ +#define MG101_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G101PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G101PL) || (G107PL == 0) +/* Задаёт MG101_17PL = ~(1 << 6); данные MG101_17PL. */ +#define MG101_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_17PL = 0xFFFF; данные MG101_17PL. */ +#define MG101_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G101PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G101PL) || (G108PL == 0) +/* Задаёт MG101_18PL = ~(1 << 7); данные MG101_18PL. */ +#define MG101_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_18PL = 0xFFFF; данные MG101_18PL. */ +#define MG101_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG101_11PL = 0x00FE; данные MG101_11PL. */ +#define MG101_11PL 0x00FE +/* Задаёт MG101 = (MG101_11PL & MG101_12PL & MG101_13PL & MG101_14PL &; маска разрешённых прерываний внутри группы PIE 101. */ +#define MG101 (MG101_11PL & MG101_12PL & MG101_13PL & MG101_14PL & \ + MG101_15PL & MG101_16PL & MG101_17PL & MG101_18PL) /* Продолжает список аргументов, полей или выражение MG101_15PL & MG101_16PL & MG101_17PL & MG101_18PL); порядок элементов сохраняется. */ +// End of MG101: + +// Beginning of MG102: +/* Условие компиляции (G101PL >= G102PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G102PL) || (G101PL == 0) +/* Задаёт MG102_11PL = ~(1); данные MG102_11PL. */ +#define MG102_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_11PL = 0xFFFF; данные MG102_11PL. */ +#define MG102_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G102PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G102PL) || (G103PL == 0) +/* Задаёт MG102_13PL = ~(1 << 2); данные MG102_13PL. */ +#define MG102_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_13PL = 0xFFFF; данные MG102_13PL. */ +#define MG102_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G102PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G102PL) || (G104PL == 0) +/* Задаёт MG102_14PL = ~(1 << 3); данные MG102_14PL. */ +#define MG102_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_14PL = 0xFFFF; данные MG102_14PL. */ +#define MG102_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G102PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G102PL) || (G105PL == 0) +/* Задаёт MG102_15PL = ~(1 << 4); данные MG102_15PL. */ +#define MG102_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_15PL = 0xFFFF; данные MG102_15PL. */ +#define MG102_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G102PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G102PL) || (G106PL == 0) +/* Задаёт MG102_16PL = ~(1 << 5); данные MG102_16PL. */ +#define MG102_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_16PL = 0xFFFF; данные MG102_16PL. */ +#define MG102_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G102PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G102PL) || (G107PL == 0) +/* Задаёт MG102_17PL = ~(1 << 6); данные MG102_17PL. */ +#define MG102_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_17PL = 0xFFFF; данные MG102_17PL. */ +#define MG102_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G102PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G102PL) || (G108PL == 0) +/* Задаёт MG102_18PL = ~(1 << 7); данные MG102_18PL. */ +#define MG102_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_18PL = 0xFFFF; данные MG102_18PL. */ +#define MG102_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG102_12PL = 0x00FD; данные MG102_12PL. */ +#define MG102_12PL 0x00FD +/* Задаёт MG102 = (MG102_11PL & MG102_12PL & MG102_13PL & MG102_14PL &; маска разрешённых прерываний внутри группы PIE 102. */ +#define MG102 (MG102_11PL & MG102_12PL & MG102_13PL & MG102_14PL & \ + MG102_15PL & MG102_16PL & MG102_17PL & MG102_18PL) /* Продолжает список аргументов, полей или выражение MG102_15PL & MG102_16PL & MG102_17PL & MG102_18PL); порядок элементов сохраняется. */ +// End of MG102: + +// Beginning of MG103: +/* Условие компиляции (G101PL >= G103PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G103PL) || (G101PL == 0) +/* Задаёт MG103_11PL = ~(1); данные MG103_11PL. */ +#define MG103_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_11PL = 0xFFFF; данные MG103_11PL. */ +#define MG103_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G103PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G103PL) || (G102PL == 0) +/* Задаёт MG103_12PL = ~(1 << 1); данные MG103_12PL. */ +#define MG103_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_12PL = 0xFFFF; данные MG103_12PL. */ +#define MG103_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G103PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G103PL) || (G104PL == 0) +/* Задаёт MG103_14PL = ~(1 << 3); данные MG103_14PL. */ +#define MG103_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_14PL = 0xFFFF; данные MG103_14PL. */ +#define MG103_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G103PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G103PL) || (G105PL == 0) +/* Задаёт MG103_15PL = ~(1 << 4); данные MG103_15PL. */ +#define MG103_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_15PL = 0xFFFF; данные MG103_15PL. */ +#define MG103_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G103PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G103PL) || (G106PL == 0) +/* Задаёт MG103_16PL = ~(1 << 5); данные MG103_16PL. */ +#define MG103_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_16PL = 0xFFFF; данные MG103_16PL. */ +#define MG103_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G103PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G103PL) || (G107PL == 0) +/* Задаёт MG103_17PL = ~(1 << 6); данные MG103_17PL. */ +#define MG103_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_17PL = 0xFFFF; данные MG103_17PL. */ +#define MG103_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G103PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G103PL) || (G108PL == 0) +/* Задаёт MG103_18PL = ~(1 << 7); данные MG103_18PL. */ +#define MG103_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_18PL = 0xFFFF; данные MG103_18PL. */ +#define MG103_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG103_13PL = 0x00FB; данные MG103_13PL. */ +#define MG103_13PL 0x00FB +/* Задаёт MG103 = (MG103_11PL & MG103_12PL & MG103_13PL & MG103_14PL &; маска разрешённых прерываний внутри группы PIE 103. */ +#define MG103 (MG103_11PL & MG103_12PL & MG103_13PL & MG103_14PL & \ + MG103_15PL & MG103_16PL & MG103_17PL & MG103_18PL) /* Продолжает список аргументов, полей или выражение MG103_15PL & MG103_16PL & MG103_17PL & MG103_18PL); порядок элементов сохраняется. */ +// End of MG103: + +// Beginning of MG104: +/* Условие компиляции (G101PL >= G104PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G104PL) || (G101PL == 0) +/* Задаёт MG104_11PL = ~(1); данные MG104_11PL. */ +#define MG104_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_11PL = 0xFFFF; данные MG104_11PL. */ +#define MG104_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G104PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G104PL) || (G102PL == 0) +/* Задаёт MG104_12PL = ~(1 << 1); данные MG104_12PL. */ +#define MG104_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_12PL = 0xFFFF; данные MG104_12PL. */ +#define MG104_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G104PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G104PL) || (G103PL == 0) +/* Задаёт MG104_13PL = ~(1 << 2); данные MG104_13PL. */ +#define MG104_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_13PL = 0xFFFF; данные MG104_13PL. */ +#define MG104_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G104PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G104PL) || (G105PL == 0) +/* Задаёт MG104_15PL = ~(1 << 4); данные MG104_15PL. */ +#define MG104_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_15PL = 0xFFFF; данные MG104_15PL. */ +#define MG104_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G104PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G104PL) || (G106PL == 0) +/* Задаёт MG104_16PL = ~(1 << 5); данные MG104_16PL. */ +#define MG104_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_16PL = 0xFFFF; данные MG104_16PL. */ +#define MG104_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G104PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G104PL) || (G107PL == 0) +/* Задаёт MG104_17PL = ~(1 << 6); данные MG104_17PL. */ +#define MG104_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_17PL = 0xFFFF; данные MG104_17PL. */ +#define MG104_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G104PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G104PL) || (G108PL == 0) +/* Задаёт MG104_18PL = ~(1 << 7); данные MG104_18PL. */ +#define MG104_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_18PL = 0xFFFF; данные MG104_18PL. */ +#define MG104_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG104_14PL = 0x00F7; данные MG104_14PL. */ +#define MG104_14PL 0x00F7 +/* Задаёт MG104 = (MG104_11PL & MG104_12PL & MG104_13PL & MG104_14PL &; маска разрешённых прерываний внутри группы PIE 104. */ +#define MG104 (MG104_11PL & MG104_12PL & MG104_13PL & MG104_14PL & \ + MG104_15PL & MG104_16PL & MG104_17PL & MG104_18PL) /* Продолжает список аргументов, полей или выражение MG104_15PL & MG104_16PL & MG104_17PL & MG104_18PL); порядок элементов сохраняется. */ +// End of MG104: + +// Beginning of MG105: +/* Условие компиляции (G101PL >= G105PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G105PL) || (G101PL == 0) +/* Задаёт MG105_11PL = ~(1); данные MG105_11PL. */ +#define MG105_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_11PL = 0xFFFF; данные MG105_11PL. */ +#define MG105_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G105PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G105PL) || (G102PL == 0) +/* Задаёт MG105_12PL = ~(1 << 1); данные MG105_12PL. */ +#define MG105_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_12PL = 0xFFFF; данные MG105_12PL. */ +#define MG105_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G105PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G105PL) || (G103PL == 0) +/* Задаёт MG105_13PL = ~(1 << 2); данные MG105_13PL. */ +#define MG105_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_13PL = 0xFFFF; данные MG105_13PL. */ +#define MG105_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G105PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G105PL) || (G104PL == 0) +/* Задаёт MG105_14PL = ~(1 << 3); данные MG105_14PL. */ +#define MG105_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_14PL = 0xFFFF; данные MG105_14PL. */ +#define MG105_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G105PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G105PL) || (G106PL == 0) +/* Задаёт MG105_16PL = ~(1 << 5); данные MG105_16PL. */ +#define MG105_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_16PL = 0xFFFF; данные MG105_16PL. */ +#define MG105_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G105PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G105PL) || (G107PL == 0) +/* Задаёт MG105_17PL = ~(1 << 6); данные MG105_17PL. */ +#define MG105_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_17PL = 0xFFFF; данные MG105_17PL. */ +#define MG105_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G105PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G105PL) || (G108PL == 0) +/* Задаёт MG105_18PL = ~(1 << 7); данные MG105_18PL. */ +#define MG105_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_18PL = 0xFFFF; данные MG105_18PL. */ +#define MG105_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG105_15PL = 0x00EF; данные MG105_15PL. */ +#define MG105_15PL 0x00EF +/* Задаёт MG105 = (MG105_11PL & MG105_12PL & MG105_13PL & MG105_14PL &; маска разрешённых прерываний внутри группы PIE 105. */ +#define MG105 (MG105_11PL & MG105_12PL & MG105_13PL & MG105_14PL & \ + MG105_15PL & MG105_16PL & MG105_17PL & MG105_18PL) /* Продолжает список аргументов, полей или выражение MG105_15PL & MG105_16PL & MG105_17PL & MG105_18PL); порядок элементов сохраняется. */ +// End of MG105: + +// Beginning of MG106: +/* Условие компиляции (G101PL >= G106PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G106PL) || (G101PL == 0) +/* Задаёт MG106_11PL = ~(1); данные MG106_11PL. */ +#define MG106_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_11PL = 0xFFFF; данные MG106_11PL. */ +#define MG106_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G106PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G106PL) || (G102PL == 0) +/* Задаёт MG106_12PL = ~(1 << 1); данные MG106_12PL. */ +#define MG106_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_12PL = 0xFFFF; данные MG106_12PL. */ +#define MG106_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G106PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G106PL) || (G103PL == 0) +/* Задаёт MG106_13PL = ~(1 << 2); данные MG106_13PL. */ +#define MG106_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_13PL = 0xFFFF; данные MG106_13PL. */ +#define MG106_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G106PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G106PL) || (G104PL == 0) +/* Задаёт MG106_14PL = ~(1 << 3); данные MG106_14PL. */ +#define MG106_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_14PL = 0xFFFF; данные MG106_14PL. */ +#define MG106_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G106PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G106PL) || (G105PL == 0) +/* Задаёт MG106_15PL = ~(1 << 4); данные MG106_15PL. */ +#define MG106_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_15PL = 0xFFFF; данные MG106_15PL. */ +#define MG106_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G106PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G106PL) || (G107PL == 0) +/* Задаёт MG106_17PL = ~(1 << 6); данные MG106_17PL. */ +#define MG106_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_17PL = 0xFFFF; данные MG106_17PL. */ +#define MG106_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G106PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G106PL) || (G108PL == 0) +/* Задаёт MG106_18PL = ~(1 << 7); данные MG106_18PL. */ +#define MG106_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_18PL = 0xFFFF; данные MG106_18PL. */ +#define MG106_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG106_16PL = 0x00DF; данные MG106_16PL. */ +#define MG106_16PL 0x00DF +/* Задаёт MG106 = (MG106_11PL & MG106_12PL & MG106_13PL & MG106_14PL &; маска разрешённых прерываний внутри группы PIE 106. */ +#define MG106 (MG106_11PL & MG106_12PL & MG106_13PL & MG106_14PL & \ + MG106_15PL & MG106_16PL & MG106_17PL & MG106_18PL) /* Продолжает список аргументов, полей или выражение MG106_15PL & MG106_16PL & MG106_17PL & MG106_18PL); порядок элементов сохраняется. */ +// End of MG106: + +// Beginning of MG107: +/* Условие компиляции (G101PL >= G107PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G107PL) || (G101PL == 0) +/* Задаёт MG107_11PL = ~(1); данные MG107_11PL. */ +#define MG107_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_11PL = 0xFFFF; данные MG107_11PL. */ +#define MG107_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G107PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G107PL) || (G102PL == 0) +/* Задаёт MG107_12PL = ~(1 << 1); данные MG107_12PL. */ +#define MG107_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_12PL = 0xFFFF; данные MG107_12PL. */ +#define MG107_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G107PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G107PL) || (G103PL == 0) +/* Задаёт MG107_13PL = ~(1 << 2); данные MG107_13PL. */ +#define MG107_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_13PL = 0xFFFF; данные MG107_13PL. */ +#define MG107_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G107PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G107PL) || (G104PL == 0) +/* Задаёт MG107_14PL = ~(1 << 3); данные MG107_14PL. */ +#define MG107_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_14PL = 0xFFFF; данные MG107_14PL. */ +#define MG107_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G107PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G107PL) || (G105PL == 0) +/* Задаёт MG107_15PL = ~(1 << 4); данные MG107_15PL. */ +#define MG107_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_15PL = 0xFFFF; данные MG107_15PL. */ +#define MG107_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G107PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G107PL) || (G106PL == 0) +/* Задаёт MG107_16PL = ~(1 << 5); данные MG107_16PL. */ +#define MG107_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_16PL = 0xFFFF; данные MG107_16PL. */ +#define MG107_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G107PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G107PL) || (G108PL == 0) +/* Задаёт MG107_18PL = ~(1 << 7); данные MG107_18PL. */ +#define MG107_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_18PL = 0xFFFF; данные MG107_18PL. */ +#define MG107_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG107_17PL = 0x00BF; данные MG107_17PL. */ +#define MG107_17PL 0x00BF +/* Задаёт MG107 = (MG107_11PL & MG107_12PL & MG107_13PL & MG107_14PL &; маска разрешённых прерываний внутри группы PIE 107. */ +#define MG107 (MG107_11PL & MG107_12PL & MG107_13PL & MG107_14PL & \ + MG107_15PL & MG107_16PL & MG107_17PL & MG107_18PL) /* Продолжает список аргументов, полей или выражение MG107_15PL & MG107_16PL & MG107_17PL & MG107_18PL); порядок элементов сохраняется. */ +// End of MG107: + +// Beginning of MG108: +/* Условие компиляции (G101PL >= G108PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G108PL) || (G101PL == 0) +/* Задаёт MG108_11PL = ~(1); данные MG108_11PL. */ +#define MG108_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_11PL = 0xFFFF; данные MG108_11PL. */ +#define MG108_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G108PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G108PL) || (G102PL == 0) +/* Задаёт MG108_12PL = ~(1 << 1); данные MG108_12PL. */ +#define MG108_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_12PL = 0xFFFF; данные MG108_12PL. */ +#define MG108_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G108PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G108PL) || (G103PL == 0) +/* Задаёт MG108_13PL = ~(1 << 2); данные MG108_13PL. */ +#define MG108_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_13PL = 0xFFFF; данные MG108_13PL. */ +#define MG108_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G108PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G108PL) || (G104PL == 0) +/* Задаёт MG108_14PL = ~(1 << 3); данные MG108_14PL. */ +#define MG108_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_14PL = 0xFFFF; данные MG108_14PL. */ +#define MG108_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G108PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G108PL) || (G105PL == 0) +/* Задаёт MG108_15PL = ~(1 << 4); данные MG108_15PL. */ +#define MG108_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_15PL = 0xFFFF; данные MG108_15PL. */ +#define MG108_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G108PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G108PL) || (G106PL == 0) +/* Задаёт MG108_16PL = ~(1 << 5); данные MG108_16PL. */ +#define MG108_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_16PL = 0xFFFF; данные MG108_16PL. */ +#define MG108_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G108PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G108PL) || (G107PL == 0) +/* Задаёт MG108_17PL = ~(1 << 6); данные MG108_17PL. */ +#define MG108_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_17PL = 0xFFFF; данные MG108_17PL. */ +#define MG108_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG108_18PL = 0x007F; данные MG108_18PL. */ +#define MG108_18PL 0x007F +/* Задаёт MG108 = (MG108_11PL & MG108_12PL & MG108_13PL & MG108_14PL &; маска разрешённых прерываний внутри группы PIE 108. */ +#define MG108 (MG108_11PL & MG108_12PL & MG108_13PL & MG108_14PL & \ + MG108_15PL & MG108_16PL & MG108_17PL & MG108_18PL) /* Продолжает список аргументов, полей или выражение MG108_15PL & MG108_16PL & MG108_17PL & MG108_18PL); порядок элементов сохраняется. */ +// End of MG108: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG111 to MG118: +// + +// Beginning of MG111: +/* Условие компиляции (G112PL >= G111PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G111PL) || (G112PL == 0) +/* Задаёт MG111_12PL = ~(1 << 1); данные MG111_12PL. */ +#define MG111_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_12PL = 0xFFFF; данные MG111_12PL. */ +#define MG111_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G111PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G111PL) || (G113PL == 0) +/* Задаёт MG111_13PL = ~(1 << 2); данные MG111_13PL. */ +#define MG111_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_13PL = 0xFFFF; данные MG111_13PL. */ +#define MG111_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G111PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G111PL) || (G114PL == 0) +/* Задаёт MG111_14PL = ~(1 << 3); данные MG111_14PL. */ +#define MG111_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_14PL = 0xFFFF; данные MG111_14PL. */ +#define MG111_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G111PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G111PL) || (G115PL == 0) +/* Задаёт MG111_15PL = ~(1 << 4); данные MG111_15PL. */ +#define MG111_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_15PL = 0xFFFF; данные MG111_15PL. */ +#define MG111_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G111PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G111PL) || (G116PL == 0) +/* Задаёт MG111_16PL = ~(1 << 5); данные MG111_16PL. */ +#define MG111_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_16PL = 0xFFFF; данные MG111_16PL. */ +#define MG111_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G111PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G111PL) || (G117PL == 0) +/* Задаёт MG111_17PL = ~(1 << 6); данные MG111_17PL. */ +#define MG111_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_17PL = 0xFFFF; данные MG111_17PL. */ +#define MG111_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G111PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G111PL) || (G118PL == 0) +/* Задаёт MG111_18PL = ~(1 << 7); данные MG111_18PL. */ +#define MG111_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_18PL = 0xFFFF; данные MG111_18PL. */ +#define MG111_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG111_11PL = 0x00FE; данные MG111_11PL. */ +#define MG111_11PL 0x00FE +/* Задаёт MG111 = (MG111_11PL & MG111_12PL & MG111_13PL & MG111_14PL &; маска разрешённых прерываний внутри группы PIE 111. */ +#define MG111 (MG111_11PL & MG111_12PL & MG111_13PL & MG111_14PL & \ + MG111_15PL & MG111_16PL & MG111_17PL & MG111_18PL) /* Продолжает список аргументов, полей или выражение MG111_15PL & MG111_16PL & MG111_17PL & MG111_18PL); порядок элементов сохраняется. */ +// End of MG111: + +// Beginning of MG112: +/* Условие компиляции (G111PL >= G112PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G112PL) || (G111PL == 0) +/* Задаёт MG112_11PL = ~(1); данные MG112_11PL. */ +#define MG112_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_11PL = 0xFFFF; данные MG112_11PL. */ +#define MG112_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G112PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G112PL) || (G113PL == 0) +/* Задаёт MG112_13PL = ~(1 << 2); данные MG112_13PL. */ +#define MG112_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_13PL = 0xFFFF; данные MG112_13PL. */ +#define MG112_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G112PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G112PL) || (G114PL == 0) +/* Задаёт MG112_14PL = ~(1 << 3); данные MG112_14PL. */ +#define MG112_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_14PL = 0xFFFF; данные MG112_14PL. */ +#define MG112_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G112PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G112PL) || (G115PL == 0) +/* Задаёт MG112_15PL = ~(1 << 4); данные MG112_15PL. */ +#define MG112_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_15PL = 0xFFFF; данные MG112_15PL. */ +#define MG112_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G112PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G112PL) || (G116PL == 0) +/* Задаёт MG112_16PL = ~(1 << 5); данные MG112_16PL. */ +#define MG112_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_16PL = 0xFFFF; данные MG112_16PL. */ +#define MG112_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G112PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G112PL) || (G117PL == 0) +/* Задаёт MG112_17PL = ~(1 << 6); данные MG112_17PL. */ +#define MG112_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_17PL = 0xFFFF; данные MG112_17PL. */ +#define MG112_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G112PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G112PL) || (G118PL == 0) +/* Задаёт MG112_18PL = ~(1 << 7); данные MG112_18PL. */ +#define MG112_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_18PL = 0xFFFF; данные MG112_18PL. */ +#define MG112_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG112_12PL = 0x00FD; данные MG112_12PL. */ +#define MG112_12PL 0x00FD +/* Задаёт MG112 = (MG112_11PL & MG112_12PL & MG112_13PL & MG112_14PL &; маска разрешённых прерываний внутри группы PIE 112. */ +#define MG112 (MG112_11PL & MG112_12PL & MG112_13PL & MG112_14PL & \ + MG112_15PL & MG112_16PL & MG112_17PL & MG112_18PL) /* Продолжает список аргументов, полей или выражение MG112_15PL & MG112_16PL & MG112_17PL & MG112_18PL); порядок элементов сохраняется. */ +// End of MG112: + +// Beginning of MG113: +/* Условие компиляции (G111PL >= G113PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G113PL) || (G111PL == 0) +/* Задаёт MG113_11PL = ~(1); данные MG113_11PL. */ +#define MG113_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_11PL = 0xFFFF; данные MG113_11PL. */ +#define MG113_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G113PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G113PL) || (G112PL == 0) +/* Задаёт MG113_12PL = ~(1 << 1); данные MG113_12PL. */ +#define MG113_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_12PL = 0xFFFF; данные MG113_12PL. */ +#define MG113_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G113PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G113PL) || (G114PL == 0) +/* Задаёт MG113_14PL = ~(1 << 3); данные MG113_14PL. */ +#define MG113_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_14PL = 0xFFFF; данные MG113_14PL. */ +#define MG113_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G113PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G113PL) || (G115PL == 0) +/* Задаёт MG113_15PL = ~(1 << 4); данные MG113_15PL. */ +#define MG113_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_15PL = 0xFFFF; данные MG113_15PL. */ +#define MG113_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G113PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G113PL) || (G116PL == 0) +/* Задаёт MG113_16PL = ~(1 << 5); данные MG113_16PL. */ +#define MG113_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_16PL = 0xFFFF; данные MG113_16PL. */ +#define MG113_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G113PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G113PL) || (G117PL == 0) +/* Задаёт MG113_17PL = ~(1 << 6); данные MG113_17PL. */ +#define MG113_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_17PL = 0xFFFF; данные MG113_17PL. */ +#define MG113_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G113PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G113PL) || (G118PL == 0) +/* Задаёт MG113_18PL = ~(1 << 7); данные MG113_18PL. */ +#define MG113_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_18PL = 0xFFFF; данные MG113_18PL. */ +#define MG113_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG113_13PL = 0x00FB; данные MG113_13PL. */ +#define MG113_13PL 0x00FB +/* Задаёт MG113 = (MG113_11PL & MG113_12PL & MG113_13PL & MG113_14PL &; маска разрешённых прерываний внутри группы PIE 113. */ +#define MG113 (MG113_11PL & MG113_12PL & MG113_13PL & MG113_14PL & \ + MG113_15PL & MG113_16PL & MG113_17PL & MG113_18PL) /* Продолжает список аргументов, полей или выражение MG113_15PL & MG113_16PL & MG113_17PL & MG113_18PL); порядок элементов сохраняется. */ +// End of MG113: + +// Beginning of MG114: +/* Условие компиляции (G111PL >= G114PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G114PL) || (G111PL == 0) +/* Задаёт MG114_11PL = ~(1); данные MG114_11PL. */ +#define MG114_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_11PL = 0xFFFF; данные MG114_11PL. */ +#define MG114_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G114PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G114PL) || (G112PL == 0) +/* Задаёт MG114_12PL = ~(1 << 1); данные MG114_12PL. */ +#define MG114_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_12PL = 0xFFFF; данные MG114_12PL. */ +#define MG114_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G114PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G114PL) || (G113PL == 0) +/* Задаёт MG114_13PL = ~(1 << 2); данные MG114_13PL. */ +#define MG114_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_13PL = 0xFFFF; данные MG114_13PL. */ +#define MG114_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G114PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G114PL) || (G115PL == 0) +/* Задаёт MG114_15PL = ~(1 << 4); данные MG114_15PL. */ +#define MG114_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_15PL = 0xFFFF; данные MG114_15PL. */ +#define MG114_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G114PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G114PL) || (G116PL == 0) +/* Задаёт MG114_16PL = ~(1 << 5); данные MG114_16PL. */ +#define MG114_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_16PL = 0xFFFF; данные MG114_16PL. */ +#define MG114_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G114PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G114PL) || (G117PL == 0) +/* Задаёт MG114_17PL = ~(1 << 6); данные MG114_17PL. */ +#define MG114_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_17PL = 0xFFFF; данные MG114_17PL. */ +#define MG114_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G114PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G114PL) || (G118PL == 0) +/* Задаёт MG114_18PL = ~(1 << 7); данные MG114_18PL. */ +#define MG114_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_18PL = 0xFFFF; данные MG114_18PL. */ +#define MG114_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG114_14PL = 0x00F7; данные MG114_14PL. */ +#define MG114_14PL 0x00F7 +/* Задаёт MG114 = (MG114_11PL & MG114_12PL & MG114_13PL & MG114_14PL &; маска разрешённых прерываний внутри группы PIE 114. */ +#define MG114 (MG114_11PL & MG114_12PL & MG114_13PL & MG114_14PL & \ + MG114_15PL & MG114_16PL & MG114_17PL & MG114_18PL) /* Продолжает список аргументов, полей или выражение MG114_15PL & MG114_16PL & MG114_17PL & MG114_18PL); порядок элементов сохраняется. */ +// End of MG114: + +// Beginning of MG115: +/* Условие компиляции (G111PL >= G115PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G115PL) || (G111PL == 0) +/* Задаёт MG115_11PL = ~(1); данные MG115_11PL. */ +#define MG115_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_11PL = 0xFFFF; данные MG115_11PL. */ +#define MG115_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G115PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G115PL) || (G112PL == 0) +/* Задаёт MG115_12PL = ~(1 << 1); данные MG115_12PL. */ +#define MG115_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_12PL = 0xFFFF; данные MG115_12PL. */ +#define MG115_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G115PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G115PL) || (G113PL == 0) +/* Задаёт MG115_13PL = ~(1 << 2); данные MG115_13PL. */ +#define MG115_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_13PL = 0xFFFF; данные MG115_13PL. */ +#define MG115_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G115PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G115PL) || (G114PL == 0) +/* Задаёт MG115_14PL = ~(1 << 3); данные MG115_14PL. */ +#define MG115_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_14PL = 0xFFFF; данные MG115_14PL. */ +#define MG115_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G115PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G115PL) || (G116PL == 0) +/* Задаёт MG115_16PL = ~(1 << 5); данные MG115_16PL. */ +#define MG115_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_16PL = 0xFFFF; данные MG115_16PL. */ +#define MG115_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G115PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G115PL) || (G117PL == 0) +/* Задаёт MG115_17PL = ~(1 << 6); данные MG115_17PL. */ +#define MG115_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_17PL = 0xFFFF; данные MG115_17PL. */ +#define MG115_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G115PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G115PL) || (G118PL == 0) +/* Задаёт MG115_18PL = ~(1 << 7); данные MG115_18PL. */ +#define MG115_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_18PL = 0xFFFF; данные MG115_18PL. */ +#define MG115_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG115_15PL = 0x00EF; данные MG115_15PL. */ +#define MG115_15PL 0x00EF +/* Задаёт MG115 = (MG115_11PL & MG115_12PL & MG115_13PL & MG115_14PL &; маска разрешённых прерываний внутри группы PIE 115. */ +#define MG115 (MG115_11PL & MG115_12PL & MG115_13PL & MG115_14PL & \ + MG115_15PL & MG115_16PL & MG115_17PL & MG115_18PL) /* Продолжает список аргументов, полей или выражение MG115_15PL & MG115_16PL & MG115_17PL & MG115_18PL); порядок элементов сохраняется. */ +// End of MG115: + +// Beginning of MG116: +/* Условие компиляции (G111PL >= G116PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G116PL) || (G111PL == 0) +/* Задаёт MG116_11PL = ~(1); данные MG116_11PL. */ +#define MG116_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_11PL = 0xFFFF; данные MG116_11PL. */ +#define MG116_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G116PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G116PL) || (G112PL == 0) +/* Задаёт MG116_12PL = ~(1 << 1); данные MG116_12PL. */ +#define MG116_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_12PL = 0xFFFF; данные MG116_12PL. */ +#define MG116_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G116PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G116PL) || (G113PL == 0) +/* Задаёт MG116_13PL = ~(1 << 2); данные MG116_13PL. */ +#define MG116_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_13PL = 0xFFFF; данные MG116_13PL. */ +#define MG116_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G116PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G116PL) || (G114PL == 0) +/* Задаёт MG116_14PL = ~(1 << 3); данные MG116_14PL. */ +#define MG116_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_14PL = 0xFFFF; данные MG116_14PL. */ +#define MG116_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G116PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G116PL) || (G115PL == 0) +/* Задаёт MG116_15PL = ~(1 << 4); данные MG116_15PL. */ +#define MG116_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_15PL = 0xFFFF; данные MG116_15PL. */ +#define MG116_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G116PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G116PL) || (G117PL == 0) +/* Задаёт MG116_17PL = ~(1 << 6); данные MG116_17PL. */ +#define MG116_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_17PL = 0xFFFF; данные MG116_17PL. */ +#define MG116_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G116PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G116PL) || (G118PL == 0) +/* Задаёт MG116_18PL = ~(1 << 7); данные MG116_18PL. */ +#define MG116_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_18PL = 0xFFFF; данные MG116_18PL. */ +#define MG116_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG116_16PL = 0x00DF; данные MG116_16PL. */ +#define MG116_16PL 0x00DF +/* Задаёт MG116 = (MG116_11PL & MG116_12PL & MG116_13PL & MG116_14PL &; маска разрешённых прерываний внутри группы PIE 116. */ +#define MG116 (MG116_11PL & MG116_12PL & MG116_13PL & MG116_14PL & \ + MG116_15PL & MG116_16PL & MG116_17PL & MG116_18PL) /* Продолжает список аргументов, полей или выражение MG116_15PL & MG116_16PL & MG116_17PL & MG116_18PL); порядок элементов сохраняется. */ +// End of MG116: + +// Beginning of MG117: +/* Условие компиляции (G111PL >= G117PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G117PL) || (G111PL == 0) +/* Задаёт MG117_11PL = ~(1); данные MG117_11PL. */ +#define MG117_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_11PL = 0xFFFF; данные MG117_11PL. */ +#define MG117_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G117PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G117PL) || (G112PL == 0) +/* Задаёт MG117_12PL = ~(1 << 1); данные MG117_12PL. */ +#define MG117_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_12PL = 0xFFFF; данные MG117_12PL. */ +#define MG117_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G117PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G117PL) || (G113PL == 0) +/* Задаёт MG117_13PL = ~(1 << 2); данные MG117_13PL. */ +#define MG117_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_13PL = 0xFFFF; данные MG117_13PL. */ +#define MG117_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G117PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G117PL) || (G114PL == 0) +/* Задаёт MG117_14PL = ~(1 << 3); данные MG117_14PL. */ +#define MG117_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_14PL = 0xFFFF; данные MG117_14PL. */ +#define MG117_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G117PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G117PL) || (G115PL == 0) +/* Задаёт MG117_15PL = ~(1 << 4); данные MG117_15PL. */ +#define MG117_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_15PL = 0xFFFF; данные MG117_15PL. */ +#define MG117_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G117PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G117PL) || (G116PL == 0) +/* Задаёт MG117_16PL = ~(1 << 5); данные MG117_16PL. */ +#define MG117_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_16PL = 0xFFFF; данные MG117_16PL. */ +#define MG117_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G117PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G117PL) || (G118PL == 0) +/* Задаёт MG117_18PL = ~(1 << 7); данные MG117_18PL. */ +#define MG117_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_18PL = 0xFFFF; данные MG117_18PL. */ +#define MG117_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG117_17PL = 0x00BF; данные MG117_17PL. */ +#define MG117_17PL 0x00BF +/* Задаёт MG117 = (MG117_11PL & MG117_12PL & MG117_13PL & MG117_14PL &; маска разрешённых прерываний внутри группы PIE 117. */ +#define MG117 (MG117_11PL & MG117_12PL & MG117_13PL & MG117_14PL & \ + MG117_15PL & MG117_16PL & MG117_17PL & MG117_18PL) /* Продолжает список аргументов, полей или выражение MG117_15PL & MG117_16PL & MG117_17PL & MG117_18PL); порядок элементов сохраняется. */ +// End of MG117: + +// Beginning of MG118: +/* Условие компиляции (G111PL >= G118PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G118PL) || (G111PL == 0) +/* Задаёт MG118_11PL = ~(1); данные MG118_11PL. */ +#define MG118_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_11PL = 0xFFFF; данные MG118_11PL. */ +#define MG118_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G118PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G118PL) || (G112PL == 0) +/* Задаёт MG118_12PL = ~(1 << 1); данные MG118_12PL. */ +#define MG118_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_12PL = 0xFFFF; данные MG118_12PL. */ +#define MG118_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G118PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G118PL) || (G113PL == 0) +/* Задаёт MG118_13PL = ~(1 << 2); данные MG118_13PL. */ +#define MG118_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_13PL = 0xFFFF; данные MG118_13PL. */ +#define MG118_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G118PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G118PL) || (G114PL == 0) +/* Задаёт MG118_14PL = ~(1 << 3); данные MG118_14PL. */ +#define MG118_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_14PL = 0xFFFF; данные MG118_14PL. */ +#define MG118_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G118PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G118PL) || (G115PL == 0) +/* Задаёт MG118_15PL = ~(1 << 4); данные MG118_15PL. */ +#define MG118_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_15PL = 0xFFFF; данные MG118_15PL. */ +#define MG118_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G118PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G118PL) || (G116PL == 0) +/* Задаёт MG118_16PL = ~(1 << 5); данные MG118_16PL. */ +#define MG118_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_16PL = 0xFFFF; данные MG118_16PL. */ +#define MG118_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G118PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G118PL) || (G117PL == 0) +/* Задаёт MG118_17PL = ~(1 << 6); данные MG118_17PL. */ +#define MG118_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_17PL = 0xFFFF; данные MG118_17PL. */ +#define MG118_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG118_18PL = 0x007F; данные MG118_18PL. */ +#define MG118_18PL 0x007F +/* Задаёт MG118 = (MG118_11PL & MG118_12PL & MG118_13PL & MG118_14PL &; маска разрешённых прерываний внутри группы PIE 118. */ +#define MG118 (MG118_11PL & MG118_12PL & MG118_13PL & MG118_14PL & \ + MG118_15PL & MG118_16PL & MG118_17PL & MG118_18PL) /* Продолжает список аргументов, полей или выражение MG118_15PL & MG118_16PL & MG118_17PL & MG118_18PL); порядок элементов сохраняется. */ +// End of MG118: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG121 to MG128: +// + +// Beginning of MG121: +/* Условие компиляции (G122PL >= G121PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G121PL) || (G122PL == 0) +/* Задаёт MG121_12PL = ~(1 << 1); данные MG121_12PL. */ +#define MG121_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_12PL = 0xFFFF; данные MG121_12PL. */ +#define MG121_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G121PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G121PL) || (G123PL == 0) +/* Задаёт MG121_13PL = ~(1 << 2); данные MG121_13PL. */ +#define MG121_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_13PL = 0xFFFF; данные MG121_13PL. */ +#define MG121_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G121PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G121PL) || (G124PL == 0) +/* Задаёт MG121_14PL = ~(1 << 3); данные MG121_14PL. */ +#define MG121_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_14PL = 0xFFFF; данные MG121_14PL. */ +#define MG121_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G121PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G121PL) || (G125PL == 0) +/* Задаёт MG121_15PL = ~(1 << 4); данные MG121_15PL. */ +#define MG121_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_15PL = 0xFFFF; данные MG121_15PL. */ +#define MG121_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G121PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G121PL) || (G126PL == 0) +/* Задаёт MG121_16PL = ~(1 << 5); данные MG121_16PL. */ +#define MG121_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_16PL = 0xFFFF; данные MG121_16PL. */ +#define MG121_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G121PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G121PL) || (G127PL == 0) +/* Задаёт MG121_17PL = ~(1 << 6); данные MG121_17PL. */ +#define MG121_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_17PL = 0xFFFF; данные MG121_17PL. */ +#define MG121_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G121PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G121PL) || (G128PL == 0) +/* Задаёт MG121_18PL = ~(1 << 7); данные MG121_18PL. */ +#define MG121_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_18PL = 0xFFFF; данные MG121_18PL. */ +#define MG121_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG121_11PL = 0x00FE; данные MG121_11PL. */ +#define MG121_11PL 0x00FE +/* Задаёт MG121 = (MG121_11PL & MG121_12PL & MG121_13PL & MG121_14PL &; маска разрешённых прерываний внутри группы PIE 121. */ +#define MG121 (MG121_11PL & MG121_12PL & MG121_13PL & MG121_14PL & \ + MG121_15PL & MG121_16PL & MG121_17PL & MG121_18PL) /* Продолжает список аргументов, полей или выражение MG121_15PL & MG121_16PL & MG121_17PL & MG121_18PL); порядок элементов сохраняется. */ +// End of MG121: + +// Beginning of MG121: +/* Условие компиляции (G121PL >= G122PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G122PL) || (G121PL == 0) +/* Задаёт MG122_11PL = ~(1); данные MG122_11PL. */ +#define MG122_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_11PL = 0xFFFF; данные MG122_11PL. */ +#define MG122_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G122PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G122PL) || (G123PL == 0) +/* Задаёт MG122_13PL = ~(1 << 2); данные MG122_13PL. */ +#define MG122_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_13PL = 0xFFFF; данные MG122_13PL. */ +#define MG122_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G122PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G122PL) || (G124PL == 0) +/* Задаёт MG122_14PL = ~(1 << 3); данные MG122_14PL. */ +#define MG122_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_14PL = 0xFFFF; данные MG122_14PL. */ +#define MG122_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G122PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G122PL) || (G125PL == 0) +/* Задаёт MG122_15PL = ~(1 << 4); данные MG122_15PL. */ +#define MG122_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_15PL = 0xFFFF; данные MG122_15PL. */ +#define MG122_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G122PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G122PL) || (G126PL == 0) +/* Задаёт MG122_16PL = ~(1 << 5); данные MG122_16PL. */ +#define MG122_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_16PL = 0xFFFF; данные MG122_16PL. */ +#define MG122_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G122PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G122PL) || (G127PL == 0) +/* Задаёт MG122_17PL = ~(1 << 6); данные MG122_17PL. */ +#define MG122_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_17PL = 0xFFFF; данные MG122_17PL. */ +#define MG122_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G122PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G122PL) || (G128PL == 0) +/* Задаёт MG122_18PL = ~(1 << 7); данные MG122_18PL. */ +#define MG122_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_18PL = 0xFFFF; данные MG122_18PL. */ +#define MG122_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG122_12PL = 0x00FD; данные MG122_12PL. */ +#define MG122_12PL 0x00FD +/* Задаёт MG122 = (MG122_11PL & MG122_12PL & MG122_13PL & MG122_14PL &; маска разрешённых прерываний внутри группы PIE 122. */ +#define MG122 (MG122_11PL & MG122_12PL & MG122_13PL & MG122_14PL & \ + MG122_15PL & MG122_16PL & MG122_17PL & MG122_18PL) /* Продолжает список аргументов, полей или выражение MG122_15PL & MG122_16PL & MG122_17PL & MG122_18PL); порядок элементов сохраняется. */ +// End of MG122: + +// Beginning of MG123: +/* Условие компиляции (G121PL >= G123PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G123PL) || (G121PL == 0) +/* Задаёт MG123_11PL = ~(1); данные MG123_11PL. */ +#define MG123_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_11PL = 0xFFFF; данные MG123_11PL. */ +#define MG123_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G123PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G123PL) || (G122PL == 0) +/* Задаёт MG123_12PL = ~(1 << 1); данные MG123_12PL. */ +#define MG123_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_12PL = 0xFFFF; данные MG123_12PL. */ +#define MG123_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G123PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G123PL) || (G124PL == 0) +/* Задаёт MG123_14PL = ~(1 << 3); данные MG123_14PL. */ +#define MG123_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_14PL = 0xFFFF; данные MG123_14PL. */ +#define MG123_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G123PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G123PL) || (G125PL == 0) +/* Задаёт MG123_15PL = ~(1 << 4); данные MG123_15PL. */ +#define MG123_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_15PL = 0xFFFF; данные MG123_15PL. */ +#define MG123_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G123PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G123PL) || (G126PL == 0) +/* Задаёт MG123_16PL = ~(1 << 5); данные MG123_16PL. */ +#define MG123_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_16PL = 0xFFFF; данные MG123_16PL. */ +#define MG123_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G123PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G123PL) || (G127PL == 0) +/* Задаёт MG123_17PL = ~(1 << 6); данные MG123_17PL. */ +#define MG123_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_17PL = 0xFFFF; данные MG123_17PL. */ +#define MG123_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G123PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G123PL) || (G128PL == 0) +/* Задаёт MG123_18PL = ~(1 << 7); данные MG123_18PL. */ +#define MG123_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_18PL = 0xFFFF; данные MG123_18PL. */ +#define MG123_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG123_13PL = 0x00FB; данные MG123_13PL. */ +#define MG123_13PL 0x00FB +/* Задаёт MG123 = (MG123_11PL & MG123_12PL & MG123_13PL & MG123_14PL &; маска разрешённых прерываний внутри группы PIE 123. */ +#define MG123 (MG123_11PL & MG123_12PL & MG123_13PL & MG123_14PL & \ + MG123_15PL & MG123_16PL & MG123_17PL & MG123_18PL) /* Продолжает список аргументов, полей или выражение MG123_15PL & MG123_16PL & MG123_17PL & MG123_18PL); порядок элементов сохраняется. */ +// End of MG123: + +// Beginning of MG124: +/* Условие компиляции (G121PL >= G124PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G124PL) || (G121PL == 0) +/* Задаёт MG124_11PL = ~(1); данные MG124_11PL. */ +#define MG124_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_11PL = 0xFFFF; данные MG124_11PL. */ +#define MG124_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G124PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G124PL) || (G122PL == 0) +/* Задаёт MG124_12PL = ~(1 << 1); данные MG124_12PL. */ +#define MG124_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_12PL = 0xFFFF; данные MG124_12PL. */ +#define MG124_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G124PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G124PL) || (G123PL == 0) +/* Задаёт MG124_13PL = ~(1 << 2); данные MG124_13PL. */ +#define MG124_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_13PL = 0xFFFF; данные MG124_13PL. */ +#define MG124_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G124PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G124PL) || (G125PL == 0) +/* Задаёт MG124_15PL = ~(1 << 4); данные MG124_15PL. */ +#define MG124_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_15PL = 0xFFFF; данные MG124_15PL. */ +#define MG124_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G124PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G124PL) || (G126PL == 0) +/* Задаёт MG124_16PL = ~(1 << 5); данные MG124_16PL. */ +#define MG124_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_16PL = 0xFFFF; данные MG124_16PL. */ +#define MG124_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G124PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G124PL) || (G127PL == 0) +/* Задаёт MG124_17PL = ~(1 << 6); данные MG124_17PL. */ +#define MG124_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_17PL = 0xFFFF; данные MG124_17PL. */ +#define MG124_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G124PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G124PL) || (G128PL == 0) +/* Задаёт MG124_18PL = ~(1 << 7); данные MG124_18PL. */ +#define MG124_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_18PL = 0xFFFF; данные MG124_18PL. */ +#define MG124_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG124_14PL = 0x00F7; данные MG124_14PL. */ +#define MG124_14PL 0x00F7 +/* Задаёт MG124 = (MG124_11PL & MG124_12PL & MG124_13PL & MG124_14PL &; маска разрешённых прерываний внутри группы PIE 124. */ +#define MG124 (MG124_11PL & MG124_12PL & MG124_13PL & MG124_14PL & \ + MG124_15PL & MG124_16PL & MG124_17PL & MG124_18PL) /* Продолжает список аргументов, полей или выражение MG124_15PL & MG124_16PL & MG124_17PL & MG124_18PL); порядок элементов сохраняется. */ +// End of MG124: + +// Beginning of MG125: +/* Условие компиляции (G121PL >= G125PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G125PL) || (G121PL == 0) +/* Задаёт MG125_11PL = ~(1); данные MG125_11PL. */ +#define MG125_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_11PL = 0xFFFF; данные MG125_11PL. */ +#define MG125_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G125PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G125PL) || (G122PL == 0) +/* Задаёт MG125_12PL = ~(1 << 1); данные MG125_12PL. */ +#define MG125_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_12PL = 0xFFFF; данные MG125_12PL. */ +#define MG125_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G125PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G125PL) || (G123PL == 0) +/* Задаёт MG125_13PL = ~(1 << 2); данные MG125_13PL. */ +#define MG125_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_13PL = 0xFFFF; данные MG125_13PL. */ +#define MG125_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G125PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G125PL) || (G124PL == 0) +/* Задаёт MG125_14PL = ~(1 << 3); данные MG125_14PL. */ +#define MG125_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_14PL = 0xFFFF; данные MG125_14PL. */ +#define MG125_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G125PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G125PL) || (G126PL == 0) +/* Задаёт MG125_16PL = ~(1 << 5); данные MG125_16PL. */ +#define MG125_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_16PL = 0xFFFF; данные MG125_16PL. */ +#define MG125_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G125PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G125PL) || (G127PL == 0) +/* Задаёт MG125_17PL = ~(1 << 6); данные MG125_17PL. */ +#define MG125_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_17PL = 0xFFFF; данные MG125_17PL. */ +#define MG125_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G125PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G125PL) || (G128PL == 0) +/* Задаёт MG125_18PL = ~(1 << 7); данные MG125_18PL. */ +#define MG125_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_18PL = 0xFFFF; данные MG125_18PL. */ +#define MG125_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG125_15PL = 0x00EF; данные MG125_15PL. */ +#define MG125_15PL 0x00EF +/* Задаёт MG125 = (MG125_11PL & MG125_12PL & MG125_13PL & MG125_14PL &; маска разрешённых прерываний внутри группы PIE 125. */ +#define MG125 (MG125_11PL & MG125_12PL & MG125_13PL & MG125_14PL & \ + MG125_15PL & MG125_16PL & MG125_17PL & MG125_18PL) /* Продолжает список аргументов, полей или выражение MG125_15PL & MG125_16PL & MG125_17PL & MG125_18PL); порядок элементов сохраняется. */ +// End of MG125: + +// Beginning of MG126: +/* Условие компиляции (G121PL >= G126PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G126PL) || (G121PL == 0) +/* Задаёт MG126_11PL = ~(1); данные MG126_11PL. */ +#define MG126_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_11PL = 0xFFFF; данные MG126_11PL. */ +#define MG126_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G126PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G126PL) || (G122PL == 0) +/* Задаёт MG126_12PL = ~(1 << 1); данные MG126_12PL. */ +#define MG126_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_12PL = 0xFFFF; данные MG126_12PL. */ +#define MG126_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G126PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G126PL) || (G123PL == 0) +/* Задаёт MG126_13PL = ~(1 << 2); данные MG126_13PL. */ +#define MG126_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_13PL = 0xFFFF; данные MG126_13PL. */ +#define MG126_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G126PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G126PL) || (G124PL == 0) +/* Задаёт MG126_14PL = ~(1 << 3); данные MG126_14PL. */ +#define MG126_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_14PL = 0xFFFF; данные MG126_14PL. */ +#define MG126_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G126PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G126PL) || (G125PL == 0) +/* Задаёт MG126_15PL = ~(1 << 4); данные MG126_15PL. */ +#define MG126_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_15PL = 0xFFFF; данные MG126_15PL. */ +#define MG126_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G126PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G126PL) || (G127PL == 0) +/* Задаёт MG126_17PL = ~(1 << 6); данные MG126_17PL. */ +#define MG126_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_17PL = 0xFFFF; данные MG126_17PL. */ +#define MG126_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G126PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G126PL) || (G128PL == 0) +/* Задаёт MG126_18PL = ~(1 << 7); данные MG126_18PL. */ +#define MG126_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_18PL = 0xFFFF; данные MG126_18PL. */ +#define MG126_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG126_16PL = 0x00DF; данные MG126_16PL. */ +#define MG126_16PL 0x00DF +/* Задаёт MG126 = (MG126_11PL & MG126_12PL & MG126_13PL & MG126_14PL &; маска разрешённых прерываний внутри группы PIE 126. */ +#define MG126 (MG126_11PL & MG126_12PL & MG126_13PL & MG126_14PL & \ + MG126_15PL & MG126_16PL & MG126_17PL & MG126_18PL) /* Продолжает список аргументов, полей или выражение MG126_15PL & MG126_16PL & MG126_17PL & MG126_18PL); порядок элементов сохраняется. */ +// End of MG126: + +// Beginning of MG127: +/* Условие компиляции (G121PL >= G127PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G127PL) || (G121PL == 0) +/* Задаёт MG127_11PL = ~(1); данные MG127_11PL. */ +#define MG127_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_11PL = 0xFFFF; данные MG127_11PL. */ +#define MG127_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G127PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G127PL) || (G122PL == 0) +/* Задаёт MG127_12PL = ~(1 << 1); данные MG127_12PL. */ +#define MG127_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_12PL = 0xFFFF; данные MG127_12PL. */ +#define MG127_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G127PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G127PL) || (G123PL == 0) +/* Задаёт MG127_13PL = ~(1 << 2); данные MG127_13PL. */ +#define MG127_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_13PL = 0xFFFF; данные MG127_13PL. */ +#define MG127_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G127PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G127PL) || (G124PL == 0) +/* Задаёт MG127_14PL = ~(1 << 3); данные MG127_14PL. */ +#define MG127_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_14PL = 0xFFFF; данные MG127_14PL. */ +#define MG127_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G127PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G127PL) || (G125PL == 0) +/* Задаёт MG127_15PL = ~(1 << 4); данные MG127_15PL. */ +#define MG127_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_15PL = 0xFFFF; данные MG127_15PL. */ +#define MG127_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G127PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G127PL) || (G126PL == 0) +/* Задаёт MG127_16PL = ~(1 << 5); данные MG127_16PL. */ +#define MG127_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_16PL = 0xFFFF; данные MG127_16PL. */ +#define MG127_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G127PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G127PL) || (G128PL == 0) +/* Задаёт MG127_18PL = ~(1 << 7); данные MG127_18PL. */ +#define MG127_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_18PL = 0xFFFF; данные MG127_18PL. */ +#define MG127_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG127_17PL = 0x00BF; данные MG127_17PL. */ +#define MG127_17PL 0x00BF +/* Задаёт MG127 = (MG127_11PL & MG127_12PL & MG127_13PL & MG127_14PL &; маска разрешённых прерываний внутри группы PIE 127. */ +#define MG127 (MG127_11PL & MG127_12PL & MG127_13PL & MG127_14PL & \ + MG127_15PL & MG127_16PL & MG127_17PL & MG127_18PL) /* Продолжает список аргументов, полей или выражение MG127_15PL & MG127_16PL & MG127_17PL & MG127_18PL); порядок элементов сохраняется. */ +// End of MG127: + +// Beginning of MG128: +/* Условие компиляции (G121PL >= G128PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G128PL) || (G121PL == 0) +/* Задаёт MG128_11PL = ~(1); данные MG128_11PL. */ +#define MG128_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_11PL = 0xFFFF; данные MG128_11PL. */ +#define MG128_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G128PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G128PL) || (G122PL == 0) +/* Задаёт MG128_12PL = ~(1 << 1); данные MG128_12PL. */ +#define MG128_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_12PL = 0xFFFF; данные MG128_12PL. */ +#define MG128_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G128PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G128PL) || (G123PL == 0) +/* Задаёт MG128_13PL = ~(1 << 2); данные MG128_13PL. */ +#define MG128_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_13PL = 0xFFFF; данные MG128_13PL. */ +#define MG128_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G128PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G128PL) || (G124PL == 0) +/* Задаёт MG128_14PL = ~(1 << 3); данные MG128_14PL. */ +#define MG128_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_14PL = 0xFFFF; данные MG128_14PL. */ +#define MG128_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G128PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G128PL) || (G125PL == 0) +/* Задаёт MG128_15PL = ~(1 << 4); данные MG128_15PL. */ +#define MG128_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_15PL = 0xFFFF; данные MG128_15PL. */ +#define MG128_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G128PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G128PL) || (G126PL == 0) +/* Задаёт MG128_16PL = ~(1 << 5); данные MG128_16PL. */ +#define MG128_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_16PL = 0xFFFF; данные MG128_16PL. */ +#define MG128_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G128PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G128PL) || (G127PL == 0) +/* Задаёт MG128_17PL = ~(1 << 6); данные MG128_17PL. */ +#define MG128_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_17PL = 0xFFFF; данные MG128_17PL. */ +#define MG128_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG128_18PL = 0x007F; данные MG128_18PL. */ +#define MG128_18PL 0x007F +/* Задаёт MG128 = (MG128_11PL & MG128_12PL & MG128_13PL & MG128_14PL &; маска разрешённых прерываний внутри группы PIE 128. */ +#define MG128 (MG128_11PL & MG128_12PL & MG128_13PL & MG128_14PL & \ + MG128_15PL & MG128_16PL & MG128_17PL & MG128_18PL) /* Продолжает список аргументов, полей или выражение MG128_15PL & MG128_16PL & MG128_17PL & MG128_18PL); порядок элементов сохраняется. */ +// End of MG128: + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // eof + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h new file mode 100644 index 0000000..d94194a --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h @@ -0,0 +1,28 @@ +/* Настройки и интерфейс DSP28x_Project. Русские пояснения сохранены в UTF-8. */ + +// TI File $Revision: /main/1 $ +// Checkin $Date: April 22, 2008 14:35:56 $ +//########################################################################### +// +// FILE: DSP28x_Project.h +// +// TITLE: DSP28x Project Headerfile and Examples Include File +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP28x_PROJECT_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP28x_PROJECT_H +/* Определяет защитный символ или переключатель DSP28x_PROJECT_H для последующей компиляции. */ +#define DSP28x_PROJECT_H + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // DSP2833x Examples Include File + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP28x_PROJECT_H definition + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h new file mode 100644 index 0000000..289dea6 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h @@ -0,0 +1,465 @@ +/* Поставляемое TI описание Adc для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:51:50 $ +//########################################################################### +// +// FILE: DSP2833x_Adc.h +// +// TITLE: DSP2833x Device ADC Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_ADC_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_ADC_H +/* Определяет защитный символ или переключатель DSP2833x_ADC_H для последующей компиляции. */ +#define DSP2833x_ADC_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// ADC Individual Register Bit Definitions: + +/* Описывает структуру ADCTRL1_BITS; порядок полей определяет расположение данных. */ +struct ADCTRL1_BITS { // bits description + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 3:0 reserved + /* Битовое поле SEQ_CASC, ширина 1 бит; данные SEQ_CASC. */ + Uint16 SEQ_CASC:1; // 4 Cascaded sequencer mode + /* Битовое поле SEQ_OVRD, ширина 1 бит; данные SEQ_OVRD. */ + Uint16 SEQ_OVRD:1; // 5 Sequencer override + /* Битовое поле CONT_RUN, ширина 1 бит; данные CONT_RUN. */ + Uint16 CONT_RUN:1; // 6 Continuous run + /* Битовое поле CPS, ширина 1 бит; данные CPS. */ + Uint16 CPS:1; // 7 ADC core clock pre-scalar + /* Битовое поле ACQ_PS, ширина 4 бит; данные ACQ_PS. */ + Uint16 ACQ_PS:4; // 11:8 Acquisition window size + /* Битовое поле SUSMOD, ширина 2 бит; данные SUSMOD. */ + Uint16 SUSMOD:2; // 13:12 Emulation suspend mode + /* Битовое поле RESET, ширина 1 бит; сброс. */ + Uint16 RESET:1; // 14 ADC reset + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ADCTRL1_REG в одной области памяти. */ +union ADCTRL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCTRL1_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCTRL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCTRL2_BITS; порядок полей определяет расположение данных. */ +struct ADCTRL2_BITS { // bits description + /* Битовое поле EPWM_SOCB_SEQ2, ширина 1 бит; данные EPWM_SOCB_SEQ2. */ + Uint16 EPWM_SOCB_SEQ2:1; // 0 EPWM compare B SOC mask for SEQ2 + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле INT_MOD_SEQ2, ширина 1 бит; данные INT_MOD_SEQ2. */ + Uint16 INT_MOD_SEQ2:1; // 2 SEQ2 Interrupt mode + /* Битовое поле INT_ENA_SEQ2, ширина 1 бит; данные INT_ENA_SEQ2. */ + Uint16 INT_ENA_SEQ2:1; // 3 SEQ2 Interrupt enable + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 4 reserved + /* Битовое поле SOC_SEQ2, ширина 1 бит; данные SOC_SEQ2. */ + Uint16 SOC_SEQ2:1; // 5 Start of conversion for SEQ2 + /* Битовое поле RST_SEQ2, ширина 1 бит; данные RST_SEQ2. */ + Uint16 RST_SEQ2:1; // 6 Reset SEQ2 + /* Битовое поле EXT_SOC_SEQ1, ширина 1 бит; данные EXT_SOC_SEQ1. */ + Uint16 EXT_SOC_SEQ1:1; // 7 External start of conversion for SEQ1 + /* Битовое поле EPWM_SOCA_SEQ1, ширина 1 бит; данные EPWM_SOCA_SEQ1. */ + Uint16 EPWM_SOCA_SEQ1:1; // 8 EPWM compare B SOC mask for SEQ1 + /* Битовое поле rsvd3, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:1; // 9 reserved + /* Битовое поле INT_MOD_SEQ1, ширина 1 бит; данные INT_MOD_SEQ1. */ + Uint16 INT_MOD_SEQ1:1; // 10 SEQ1 Interrupt mode + /* Битовое поле INT_ENA_SEQ1, ширина 1 бит; данные INT_ENA_SEQ1. */ + Uint16 INT_ENA_SEQ1:1; // 11 SEQ1 Interrupt enable + /* Битовое поле rsvd4, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4:1; // 12 reserved + /* Битовое поле SOC_SEQ1, ширина 1 бит; данные SOC_SEQ1. */ + Uint16 SOC_SEQ1:1; // 13 Start of conversion trigger for SEQ1 + /* Битовое поле RST_SEQ1, ширина 1 бит; данные RST_SEQ1. */ + Uint16 RST_SEQ1:1; // 14 Restart sequencer 1 + /* Битовое поле EPWM_SOCB_SEQ, ширина 1 бит; данные EPWM_SOCB_SEQ. */ + Uint16 EPWM_SOCB_SEQ:1; // 15 EPWM compare B SOC enable +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ADCTRL2_REG в одной области памяти. */ +union ADCTRL2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCTRL2_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCTRL2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCASEQSR_BITS; порядок полей определяет расположение данных. */ +struct ADCASEQSR_BITS { // bits description + /* Битовое поле SEQ1_STATE, ширина 4 бит; данные SEQ1_STATE. */ + Uint16 SEQ1_STATE:4; // 3:0 SEQ1 state + /* Битовое поле SEQ2_STATE, ширина 3 бит; данные SEQ2_STATE. */ + Uint16 SEQ2_STATE:3; // 6:4 SEQ2 state + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 7 reserved + /* Битовое поле SEQ_CNTR, ширина 4 бит; данные SEQ_CNTR. */ + Uint16 SEQ_CNTR:4; // 11:8 Sequencing counter status + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCASEQSR_REG в одной области памяти. */ +union ADCASEQSR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCASEQSR_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCASEQSR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCMAXCONV_BITS; порядок полей определяет расположение данных. */ +struct ADCMAXCONV_BITS { // bits description + /* Битовое поле MAX_CONV1, ширина 4 бит; данные MAX_CONV1. */ + Uint16 MAX_CONV1:4; // 3:0 Max number of conversions + /* Битовое поле MAX_CONV2, ширина 3 бит; данные MAX_CONV2. */ + Uint16 MAX_CONV2:3; // 6:4 Max number of conversions + /* Битовое поле rsvd1, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:9; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCMAXCONV_REG в одной области памяти. */ +union ADCMAXCONV_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCMAXCONV_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCMAXCONV_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCCHSELSEQ1_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ1_BITS { // bits description + /* Битовое поле CONV00, ширина 4 бит; данные CONV00. */ + Uint16 CONV00:4; // 3:0 Conversion selection 00 + /* Битовое поле CONV01, ширина 4 бит; данные CONV01. */ + Uint16 CONV01:4; // 7:4 Conversion selection 01 + /* Битовое поле CONV02, ширина 4 бит; данные CONV02. */ + Uint16 CONV02:4; // 11:8 Conversion selection 02 + /* Битовое поле CONV03, ширина 4 бит; данные CONV03. */ + Uint16 CONV03:4; // 15:12 Conversion selection 03 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ1_REG в одной области памяти. */ +union ADCCHSELSEQ1_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ1_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCCHSELSEQ2_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ2_BITS { // bits description + /* Битовое поле CONV04, ширина 4 бит; данные CONV04. */ + Uint16 CONV04:4; // 3:0 Conversion selection 04 + /* Битовое поле CONV05, ширина 4 бит; данные CONV05. */ + Uint16 CONV05:4; // 7:4 Conversion selection 05 + /* Битовое поле CONV06, ширина 4 бит; данные CONV06. */ + Uint16 CONV06:4; // 11:8 Conversion selection 06 + /* Битовое поле CONV07, ширина 4 бит; данные CONV07. */ + Uint16 CONV07:4; // 15:12 Conversion selection 07 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ2_REG в одной области памяти. */ +union ADCCHSELSEQ2_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ2_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCCHSELSEQ3_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ3_BITS { // bits description + /* Битовое поле CONV08, ширина 4 бит; данные CONV08. */ + Uint16 CONV08:4; // 3:0 Conversion selection 08 + /* Битовое поле CONV09, ширина 4 бит; данные CONV09. */ + Uint16 CONV09:4; // 7:4 Conversion selection 09 + /* Битовое поле CONV10, ширина 4 бит; данные CONV10. */ + Uint16 CONV10:4; // 11:8 Conversion selection 10 + /* Битовое поле CONV11, ширина 4 бит; данные CONV11. */ + Uint16 CONV11:4; // 15:12 Conversion selection 11 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ3_REG в одной области памяти. */ +union ADCCHSELSEQ3_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ3_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ3_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCCHSELSEQ4_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ4_BITS { // bits description + /* Битовое поле CONV12, ширина 4 бит; данные CONV12. */ + Uint16 CONV12:4; // 3:0 Conversion selection 12 + /* Битовое поле CONV13, ширина 4 бит; данные CONV13. */ + Uint16 CONV13:4; // 7:4 Conversion selection 13 + /* Битовое поле CONV14, ширина 4 бит; данные CONV14. */ + Uint16 CONV14:4; // 11:8 Conversion selection 14 + /* Битовое поле CONV15, ширина 4 бит; данные CONV15. */ + Uint16 CONV15:4; // 15:12 Conversion selection 15 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ4_REG в одной области памяти. */ +union ADCCHSELSEQ4_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ4_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ4_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCTRL3_BITS; порядок полей определяет расположение данных. */ +struct ADCTRL3_BITS { // bits description + /* Битовое поле SMODE_SEL, ширина 1 бит; данные SMODE_SEL. */ + Uint16 SMODE_SEL:1; // 0 Sampling mode select + /* Битовое поле ADCCLKPS, ширина 4 бит; данные ADCCLKPS. */ + Uint16 ADCCLKPS:4; // 4:1 ADC core clock divider + /* Битовое поле ADCPWDN, ширина 1 бит; данные ADCPWDN. */ + Uint16 ADCPWDN:1; // 5 ADC powerdown + /* Битовое поле ADCBGRFDN, ширина 2 бит; данные ADCBGRFDN. */ + Uint16 ADCBGRFDN:2; // 7:6 ADC bandgap/ref power down + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCTRL3_REG в одной области памяти. */ +union ADCTRL3_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCTRL3_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCTRL3_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCST_BITS; порядок полей определяет расположение данных. */ +struct ADCST_BITS { // bits description + /* Битовое поле INT_SEQ1, ширина 1 бит; данные INT_SEQ1. */ + Uint16 INT_SEQ1:1; // 0 SEQ1 Interrupt flag + /* Битовое поле INT_SEQ2, ширина 1 бит; данные INT_SEQ2. */ + Uint16 INT_SEQ2:1; // 1 SEQ2 Interrupt flag + /* Битовое поле SEQ1_BSY, ширина 1 бит; данные SEQ1_BSY. */ + Uint16 SEQ1_BSY:1; // 2 SEQ1 busy status + /* Битовое поле SEQ2_BSY, ширина 1 бит; данные SEQ2_BSY. */ + Uint16 SEQ2_BSY:1; // 3 SEQ2 busy status + /* Битовое поле INT_SEQ1_CLR, ширина 1 бит; данные INT_SEQ1_CLR. */ + Uint16 INT_SEQ1_CLR:1; // 4 SEQ1 Interrupt clear + /* Битовое поле INT_SEQ2_CLR, ширина 1 бит; данные INT_SEQ2_CLR. */ + Uint16 INT_SEQ2_CLR:1; // 5 SEQ2 Interrupt clear + /* Битовое поле EOS_BUF1, ширина 1 бит; данные EOS_BUF1. */ + Uint16 EOS_BUF1:1; // 6 End of sequence buffer1 + /* Битовое поле EOS_BUF2, ширина 1 бит; данные EOS_BUF2. */ + Uint16 EOS_BUF2:1; // 7 End of sequence buffer2 + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ADCST_REG в одной области памяти. */ +union ADCST_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCST_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCST_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCREFSEL_BITS; порядок полей определяет расположение данных. */ +struct ADCREFSEL_BITS { // bits description + /* Битовое поле rsvd1, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:14; // 13:0 reserved + /* Битовое поле REF_SEL, ширина 2 бит; данные REF_SEL. */ + Uint16 REF_SEL:2; // 15:14 Reference select +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; +/* Объединяет несколько представлений ADCREFSEL_REG в одной области памяти. */ +union ADCREFSEL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCREFSEL_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCREFSEL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCOFFTRIM_BITS; порядок полей определяет расположение данных. */ +struct ADCOFFTRIM_BITS{ // bits description + /* Продолжает список аргументов, полей или выражение int16 OFFSET_TRIM:9;; порядок элементов сохраняется. */ + int16 OFFSET_TRIM:9; // 8:0 Offset Trim + /* Битовое поле rsvd1, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:7; // 15:9 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCOFFTRIM_REG в одной области памяти. */ +union ADCOFFTRIM_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCOFFTRIM_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCOFFTRIM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; +/* Описывает структуру ADC_REGS; порядок полей определяет расположение данных. */ +struct ADC_REGS { + /* Объединяет несколько представлений ADCTRL1_REG ADCTRL1; в одной области памяти. */ + union ADCTRL1_REG ADCTRL1; // ADC Control 1 + /* Объединяет несколько представлений ADCTRL2_REG ADCTRL2; в одной области памяти. */ + union ADCTRL2_REG ADCTRL2; // ADC Control 2 + /* Объединяет несколько представлений ADCMAXCONV_REG ADCMAXCONV; в одной области памяти. */ + union ADCMAXCONV_REG ADCMAXCONV; // Max conversions + /* Объединяет несколько представлений ADCCHSELSEQ1_REG ADCCHSELSEQ1; в одной области памяти. */ + union ADCCHSELSEQ1_REG ADCCHSELSEQ1; // Channel select sequencing control 1 + /* Объединяет несколько представлений ADCCHSELSEQ2_REG ADCCHSELSEQ2; в одной области памяти. */ + union ADCCHSELSEQ2_REG ADCCHSELSEQ2; // Channel select sequencing control 2 + /* Объединяет несколько представлений ADCCHSELSEQ3_REG ADCCHSELSEQ3; в одной области памяти. */ + union ADCCHSELSEQ3_REG ADCCHSELSEQ3; // Channel select sequencing control 3 + /* Объединяет несколько представлений ADCCHSELSEQ4_REG ADCCHSELSEQ4; в одной области памяти. */ + union ADCCHSELSEQ4_REG ADCCHSELSEQ4; // Channel select sequencing control 4 + /* Объединяет несколько представлений ADCASEQSR_REG ADCASEQSR; в одной области памяти. */ + union ADCASEQSR_REG ADCASEQSR; // Autosequence status register + /* Объявляет ADCRESULT0 — данные ADCRESULT0. */ + Uint16 ADCRESULT0; // Conversion Result Buffer 0 + /* Объявляет ADCRESULT1 — данные ADCRESULT1. */ + Uint16 ADCRESULT1; // Conversion Result Buffer 1 + /* Объявляет ADCRESULT2 — данные ADCRESULT2. */ + Uint16 ADCRESULT2; // Conversion Result Buffer 2 + /* Объявляет ADCRESULT3 — данные ADCRESULT3. */ + Uint16 ADCRESULT3; // Conversion Result Buffer 3 + /* Объявляет ADCRESULT4 — данные ADCRESULT4. */ + Uint16 ADCRESULT4; // Conversion Result Buffer 4 + /* Объявляет ADCRESULT5 — данные ADCRESULT5. */ + Uint16 ADCRESULT5; // Conversion Result Buffer 5 + /* Объявляет ADCRESULT6 — данные ADCRESULT6. */ + Uint16 ADCRESULT6; // Conversion Result Buffer 6 + /* Объявляет ADCRESULT7 — данные ADCRESULT7. */ + Uint16 ADCRESULT7; // Conversion Result Buffer 7 + /* Объявляет ADCRESULT8 — данные ADCRESULT8. */ + Uint16 ADCRESULT8; // Conversion Result Buffer 8 + /* Объявляет ADCRESULT9 — данные ADCRESULT9. */ + Uint16 ADCRESULT9; // Conversion Result Buffer 9 + /* Объявляет ADCRESULT10 — данные ADCRESULT10. */ + Uint16 ADCRESULT10; // Conversion Result Buffer 10 + /* Объявляет ADCRESULT11 — данные ADCRESULT11. */ + Uint16 ADCRESULT11; // Conversion Result Buffer 11 + /* Объявляет ADCRESULT12 — данные ADCRESULT12. */ + Uint16 ADCRESULT12; // Conversion Result Buffer 12 + /* Объявляет ADCRESULT13 — данные ADCRESULT13. */ + Uint16 ADCRESULT13; // Conversion Result Buffer 13 + /* Объявляет ADCRESULT14 — данные ADCRESULT14. */ + Uint16 ADCRESULT14; // Conversion Result Buffer 14 + /* Объявляет ADCRESULT15 — данные ADCRESULT15. */ + Uint16 ADCRESULT15; // Conversion Result Buffer 15 + /* Объединяет несколько представлений ADCTRL3_REG ADCTRL3; в одной области памяти. */ + union ADCTRL3_REG ADCTRL3; // ADC Control 3 + /* Объединяет несколько представлений ADCST_REG ADCST; в одной области памяти. */ + union ADCST_REG ADCST; // ADC Status Register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; + /* Объединяет несколько представлений ADCREFSEL_REG ADCREFSEL; в одной области памяти. */ + union ADCREFSEL_REG ADCREFSEL; // Reference Select Register + /* Объединяет несколько представлений ADCOFFTRIM_REG ADCOFFTRIM; в одной области памяти. */ + union ADCOFFTRIM_REG ADCOFFTRIM; // Offset Trim Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADC_RESULT_MIRROR_REGS; порядок полей определяет расположение данных. */ +struct ADC_RESULT_MIRROR_REGS +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет ADCRESULT0 — данные ADCRESULT0. */ + Uint16 ADCRESULT0; // Conversion Result Buffer 0 + /* Объявляет ADCRESULT1 — данные ADCRESULT1. */ + Uint16 ADCRESULT1; // Conversion Result Buffer 1 + /* Объявляет ADCRESULT2 — данные ADCRESULT2. */ + Uint16 ADCRESULT2; // Conversion Result Buffer 2 + /* Объявляет ADCRESULT3 — данные ADCRESULT3. */ + Uint16 ADCRESULT3; // Conversion Result Buffer 3 + /* Объявляет ADCRESULT4 — данные ADCRESULT4. */ + Uint16 ADCRESULT4; // Conversion Result Buffer 4 + /* Объявляет ADCRESULT5 — данные ADCRESULT5. */ + Uint16 ADCRESULT5; // Conversion Result Buffer 5 + /* Объявляет ADCRESULT6 — данные ADCRESULT6. */ + Uint16 ADCRESULT6; // Conversion Result Buffer 6 + /* Объявляет ADCRESULT7 — данные ADCRESULT7. */ + Uint16 ADCRESULT7; // Conversion Result Buffer 7 + /* Объявляет ADCRESULT8 — данные ADCRESULT8. */ + Uint16 ADCRESULT8; // Conversion Result Buffer 8 + /* Объявляет ADCRESULT9 — данные ADCRESULT9. */ + Uint16 ADCRESULT9; // Conversion Result Buffer 9 + /* Объявляет ADCRESULT10 — данные ADCRESULT10. */ + Uint16 ADCRESULT10; // Conversion Result Buffer 10 + /* Объявляет ADCRESULT11 — данные ADCRESULT11. */ + Uint16 ADCRESULT11; // Conversion Result Buffer 11 + /* Объявляет ADCRESULT12 — данные ADCRESULT12. */ + Uint16 ADCRESULT12; // Conversion Result Buffer 12 + /* Объявляет ADCRESULT13 — данные ADCRESULT13. */ + Uint16 ADCRESULT13; // Conversion Result Buffer 13 + /* Объявляет ADCRESULT14 — данные ADCRESULT14. */ + Uint16 ADCRESULT14; // Conversion Result Buffer 14 + /* Объявляет ADCRESULT15 — данные ADCRESULT15. */ + Uint16 ADCRESULT15; // Conversion Result Buffer 15 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// ADC External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct ADC_REGS AdcRegs;; порядок элементов сохраняется. */ +extern volatile struct ADC_REGS AdcRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ADC_RESULT_MIRROR_REGS AdcMirror;; порядок элементов сохраняется. */ +extern volatile struct ADC_RESULT_MIRROR_REGS AdcMirror; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_ADC_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h new file mode 100644 index 0000000..a3383fc --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h @@ -0,0 +1,283 @@ +/* Поставляемое TI описание CpuTimers для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/4 $ +// Checkin $Date: March 20, 2007 15:33:42 $ +//########################################################################### +// +// FILE: DSP2833x_CpuTimers.h +// +// TITLE: DSP2833x CPU 32-bit Timers Register Definitions. +// +// NOTES: CpuTimer1 and CpuTimer2 are reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use these two timers in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +// For this reason, comment out the code to manipulate these two timers +// if using DSP-BIOS or another realtime OS. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_CPU_TIMERS_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_CPU_TIMERS_H +/* Определяет защитный символ или переключатель DSP2833x_CPU_TIMERS_H для последующей компиляции. */ +#define DSP2833x_CPU_TIMERS_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// CPU Timer Register Bit Definitions: +// +// +// TCR: Control register bit definitions: +/* Описывает структуру TCR_BITS; порядок полей определяет расположение данных. */ +struct TCR_BITS { // bits description + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 3:0 reserved + /* Битовое поле TSS, ширина 1 бит; данные TSS. */ + Uint16 TSS:1; // 4 Timer Start/Stop + /* Битовое поле TRB, ширина 1 бит; данные TRB. */ + Uint16 TRB:1; // 5 Timer reload + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 9:6 reserved + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 10 Emulation modes + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 11 + /* Битовое поле rsvd3, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:2; // 12:13 reserved + /* Битовое поле TIE, ширина 1 бит; данные TIE. */ + Uint16 TIE:1; // 14 Output enable + /* Битовое поле TIF, ширина 1 бит; данные TIF. */ + Uint16 TIF:1; // 15 Interrupt flag +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TCR_REG в одной области памяти. */ +union TCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TCR_BITS bit;; порядок полей определяет расположение данных. */ + struct TCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// TPR: Pre-scale low bit definitions: +/* Описывает структуру TPR_BITS; порядок полей определяет расположение данных. */ +struct TPR_BITS { // bits description + /* Битовое поле TDDR, ширина 8 бит; данные TDDR. */ + Uint16 TDDR:8; // 7:0 Divide-down low + /* Битовое поле PSC, ширина 8 бит; данные PSC. */ + Uint16 PSC:8; // 15:8 Prescale counter low +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TPR_REG в одной области памяти. */ +union TPR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TPR_BITS bit;; порядок полей определяет расположение данных. */ + struct TPR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// TPRH: Pre-scale high bit definitions: +/* Описывает структуру TPRH_BITS; порядок полей определяет расположение данных. */ +struct TPRH_BITS { // bits description + /* Битовое поле TDDRH, ширина 8 бит; данные TDDRH. */ + Uint16 TDDRH:8; // 7:0 Divide-down high + /* Битовое поле PSCH, ширина 8 бит; данные PSCH. */ + Uint16 PSCH:8; // 15:8 Prescale counter high +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TPRH_REG в одной области памяти. */ +union TPRH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TPRH_BITS bit;; порядок полей определяет расположение данных. */ + struct TPRH_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// TIM, TIMH: Timer register definitions: +/* Описывает структуру TIM_REG; порядок полей определяет расположение данных. */ +struct TIM_REG { + /* Объявляет LSW — данные LSW. */ + Uint16 LSW; + /* Объявляет MSW — данные MSW. */ + Uint16 MSW; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TIM_GROUP в одной области памяти. */ +union TIM_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру TIM_REG half;; порядок полей определяет расположение данных. */ + struct TIM_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PRD, PRDH: Period register definitions: +/* Описывает структуру PRD_REG; порядок полей определяет расположение данных. */ +struct PRD_REG { + /* Объявляет LSW — данные LSW. */ + Uint16 LSW; + /* Объявляет MSW — данные MSW. */ + Uint16 MSW; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PRD_GROUP в одной области памяти. */ +union PRD_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру PRD_REG half;; порядок полей определяет расположение данных. */ + struct PRD_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// CPU Timer Register File: +// +/* Описывает структуру CPUTIMER_REGS; порядок полей определяет расположение данных. */ +struct CPUTIMER_REGS { + /* Объединяет несколько представлений TIM_GROUP TIM; в одной области памяти. */ + union TIM_GROUP TIM; // Timer counter register + /* Объединяет несколько представлений PRD_GROUP PRD; в одной области памяти. */ + union PRD_GROUP PRD; // Period register + /* Объединяет несколько представлений TCR_REG TCR; в одной области памяти. */ + union TCR_REG TCR; // Timer control register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объединяет несколько представлений TPR_REG TPR; в одной области памяти. */ + union TPR_REG TPR; // Timer pre-scale low + /* Объединяет несколько представлений TPRH_REG TPRH; в одной области памяти. */ + union TPRH_REG TPRH; // Timer pre-scale high +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// CPU Timer Support Variables: +// +/* Описывает структуру CPUTIMER_VARS; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS { + /* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS *RegsAddr;; порядок элементов сохраняется. */ + volatile struct CPUTIMER_REGS *RegsAddr; + /* Объявляет InterruptCount — прерывание число. */ + Uint32 InterruptCount; + /* Объявляет CPUFreqInMHz — данные CPUFreqInMHz. */ + float CPUFreqInMHz; + /* Объявляет PeriodInUSec — период In U Sec. */ + float PeriodInUSec; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// Function prototypes and external definitions: +// +/* Объявляет интерфейс функции InitCpuTimers; реализация вызывается через этот прототип. */ +void InitCpuTimers(void); +/* Объявляет интерфейс функции ConfigCpuTimer; реализация вызывается через этот прототип. */ +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period); + +/* Продолжает список аргументов, полей или выражение extern volatile struct CPUTIMER_REGS CpuTimer0Regs;; порядок элементов сохраняется. */ +extern volatile struct CPUTIMER_REGS CpuTimer0Regs; +/* Продолжает список аргументов, полей или выражение extern struct CPUTIMER_VARS CpuTimer0;; порядок элементов сохраняется. */ +extern struct CPUTIMER_VARS CpuTimer0; + +// CpuTimer 1 and CpuTimer2 are reserved for DSP BIOS & other RTOS. Comment out CpuTimer1 and CpuTimer2 if using DSP BIOS or other RTOS +/* Продолжает список аргументов, полей или выражение extern volatile struct CPUTIMER_REGS CpuTimer1Regs;; порядок элементов сохраняется. */ +extern volatile struct CPUTIMER_REGS CpuTimer1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct CPUTIMER_REGS CpuTimer2Regs;; порядок элементов сохраняется. */ +extern volatile struct CPUTIMER_REGS CpuTimer2Regs; + +/* Продолжает список аргументов, полей или выражение extern struct CPUTIMER_VARS CpuTimer1;; порядок элементов сохраняется. */ +extern struct CPUTIMER_VARS CpuTimer1; +/* Продолжает список аргументов, полей или выражение extern struct CPUTIMER_VARS CpuTimer2;; порядок элементов сохраняется. */ +extern struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// Usefull Timer Operations: +// +// Start Timer: +/* Задаёт StartCpuTimer0 = CpuTimer0Regs.TCR.bit.TSS = 0; Start Cpu таймер 0. */ +#define StartCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 0 + +// Stop Timer: +/* Задаёт StopCpuTimer0 = CpuTimer0Regs.TCR.bit.TSS = 1; Stop Cpu таймер 0. */ +#define StopCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +/* Задаёт ReloadCpuTimer0 = CpuTimer0Regs.TCR.bit.TRB = 1; Reload Cpu таймер 0. */ +#define ReloadCpuTimer0() CpuTimer0Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +/* Задаёт ReadCpuTimer0Counter = CpuTimer0Regs.TIM.all; чтение Cpu таймер 0 счётчик. */ +#define ReadCpuTimer0Counter() CpuTimer0Regs.TIM.all + +// Read 32-Bit Period Value: +/* Задаёт ReadCpuTimer0Period = CpuTimer0Regs.PRD.all; чтение Cpu таймер 0 период. */ +#define ReadCpuTimer0Period() CpuTimer0Regs.PRD.all + +// CpuTimer 1 and CpuTimer2 are reserved for DSP BIOS & other RTOS +// Do not use these two timers if you ever plan on integrating +// DSP-BIOS or another realtime OS. +// +// For this reason, comment out the code to manipulate these two timers +// if using DSP-BIOS or another realtime OS. + +// Start Timer: +/* Задаёт StartCpuTimer1 = CpuTimer1Regs.TCR.bit.TSS = 0; Start Cpu таймер 1. */ +#define StartCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 0 +/* Задаёт StartCpuTimer2 = CpuTimer2Regs.TCR.bit.TSS = 0; Start Cpu таймер 2. */ +#define StartCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 0 + + +// Stop Timer: +/* Задаёт StopCpuTimer1 = CpuTimer1Regs.TCR.bit.TSS = 1; Stop Cpu таймер 1. */ +#define StopCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 1 +/* Задаёт StopCpuTimer2 = CpuTimer2Regs.TCR.bit.TSS = 1; Stop Cpu таймер 2. */ +#define StopCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +/* Задаёт ReloadCpuTimer1 = CpuTimer1Regs.TCR.bit.TRB = 1; Reload Cpu таймер 1. */ +#define ReloadCpuTimer1() CpuTimer1Regs.TCR.bit.TRB = 1 +/* Задаёт ReloadCpuTimer2 = CpuTimer2Regs.TCR.bit.TRB = 1; Reload Cpu таймер 2. */ +#define ReloadCpuTimer2() CpuTimer2Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +/* Задаёт ReadCpuTimer1Counter = CpuTimer1Regs.TIM.all; чтение Cpu таймер 1 счётчик. */ +#define ReadCpuTimer1Counter() CpuTimer1Regs.TIM.all +/* Задаёт ReadCpuTimer2Counter = CpuTimer2Regs.TIM.all; чтение Cpu таймер 2 счётчик. */ +#define ReadCpuTimer2Counter() CpuTimer2Regs.TIM.all + +// Read 32-Bit Period Value: +/* Задаёт ReadCpuTimer1Period = CpuTimer1Regs.PRD.all; чтение Cpu таймер 1 период. */ +#define ReadCpuTimer1Period() CpuTimer1Regs.PRD.all +/* Задаёт ReadCpuTimer2Period = CpuTimer2Regs.PRD.all; чтение Cpu таймер 2 период. */ +#define ReadCpuTimer2Period() CpuTimer2Regs.PRD.all + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_CPU_TIMERS_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h new file mode 100644 index 0000000..5508e70 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h @@ -0,0 +1,437 @@ +/* Поставляемое TI описание DMA для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/11 $ +// Checkin $Date: June 23, 2008 11:34:15 $ +//########################################################################### +// +// FILE: DSP2833x_DMA.h +// +// TITLE: DSP2833x DMA Module Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DMA_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DMA_H +/* Определяет защитный символ или переключатель DSP2833x_DMA_H для последующей компиляции. */ +#define DSP2833x_DMA_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Channel MODE register bit definitions: +/* Описывает структуру MODE_BITS; порядок полей определяет расположение данных. */ +struct MODE_BITS { // bits description + /* Битовое поле PERINTSEL, ширина 5 бит; данные PERINTSEL. */ + Uint16 PERINTSEL:5; // 4:0 Peripheral Interrupt and Sync Select Bits (R/W): + // 0 no interrupt + // 1 SEQ1INT & ADCSYNC + // 2 SEQ2INT + // 3 XINT1 + // 4 XINT2 + // 5 XINT3 + // 6 XINT4 + // 7 XINT5 + // 8 XINT6 + // 9 XINT7 + // 10 XINT13 + // 11 TINT0 + // 12 TINT1 + // 13 TINT2 + // 14 MXEVTA & MXSYNCA + // 15 MREVTA & MRSYNCA + // 16 MXEVTB & MXSYNCB + // 17 MREVTB & MRSYNCB + // 18 ePWM1SOCA + // 19 ePWM1SOCB + // 20 ePWM2SOCA + // 21 ePWM2SOCB + // 22 ePWM3SOCA + // 23 ePWM3SOCB + // 24 ePWM4SOCA + // 25 ePWM4SOCB + // 26 ePWM5SOCA + // 27 ePWM5SOCB + // 28 ePWM6SOCA + // 29 ePWM6SOCB + // 30:31 no interrupt + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 6:5 (R=0:0) + /* Битовое поле OVRINTE, ширина 1 бит; данные OVRINTE. */ + Uint16 OVRINTE:1; // 7 Overflow Interrupt Enable (R/W): + // 0 overflow interrupt disabled + // 1 overflow interrupt enabled + /* Битовое поле PERINTE, ширина 1 бит; данные PERINTE. */ + Uint16 PERINTE:1; // 8 Peripheral Interrupt Enable Bit (R/W): + // 0 peripheral interrupt disabled + // 1 peripheral interrupt enabled + /* Битовое поле CHINTMODE, ширина 1 бит; данные CHINTMODE. */ + Uint16 CHINTMODE:1; // 9 Channel Interrupt Mode Bit (R/W): + // 0 generate interrupt at beginning of new transfer + // 1 generate interrupt at end of transfer + /* Битовое поле ONESHOT, ширина 1 бит; данные ONESHOT. */ + Uint16 ONESHOT:1; // 10 One Shot Mode Bit (R/W): + // 0 only interrupt event triggers single burst transfer + // 1 first interrupt triggers burst, continue until transfer count is zero + /* Битовое поле CONTINUOUS, ширина 1 бит; данные CONTINUOUS. */ + Uint16 CONTINUOUS:1; // 11 Continous Mode Bit (R/W): + // 0 stop when transfer count is zero + // 1 re-initialize when transfer count is zero + /* Битовое поле SYNCE, ширина 1 бит; данные SYNCE. */ + Uint16 SYNCE:1; // 12 Sync Enable Bit (R/W): + // 0 ignore selected interrupt sync signal + // 1 enable selected interrupt sync signal + /* Битовое поле SYNCSEL, ширина 1 бит; данные SYNCSEL. */ + Uint16 SYNCSEL:1; // 13 Sync Select Bit (R/W): + // 0 sync signal controls source wrap counter + // 1 sync signal controls destination wrap counter + /* Битовое поле DATASIZE, ширина 1 бит; данные DATASIZE. */ + Uint16 DATASIZE:1; // 14 Data Size Mode Bit (R/W): + // 0 16-bit data transfer size + // 1 32-bit data transfer size + /* Битовое поле CHINTE, ширина 1 бит; данные CHINTE. */ + Uint16 CHINTE:1; // 15 Channel Interrupt Enable Bit (R/W): + // 0 channel interrupt disabled + // 1 channel interrupt enabled +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MODE_REG в одной области памяти. */ +union MODE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MODE_BITS bit;; порядок полей определяет расположение данных. */ + struct MODE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Channel CONTROL register bit definitions: +/* Описывает структуру CONTROL_BITS; порядок полей определяет расположение данных. */ +struct CONTROL_BITS { // bits description + /* Битовое поле RUN, ширина 1 бит; данные RUN. */ + Uint16 RUN:1; // 0 Run Bit (R=0/W=1) + /* Битовое поле HALT, ширина 1 бит; данные HALT. */ + Uint16 HALT:1; // 1 Halt Bit (R=0/W=1) + /* Битовое поле SOFTRESET, ширина 1 бит; данные SOFTRESET. */ + Uint16 SOFTRESET:1; // 2 Soft Reset Bit (R=0/W=1) + /* Битовое поле PERINTFRC, ширина 1 бит; данные PERINTFRC. */ + Uint16 PERINTFRC:1; // 3 Interrupt Force Bit (R=0/W=1) + /* Битовое поле PERINTCLR, ширина 1 бит; данные PERINTCLR. */ + Uint16 PERINTCLR:1; // 4 Interrupt Clear Bit (R=0/W=1) + /* Битовое поле SYNCFRC, ширина 1 бит; данные SYNCFRC. */ + Uint16 SYNCFRC:1; // 5 Sync Force Bit (R=0/W=1) + /* Битовое поле SYNCCLR, ширина 1 бит; данные SYNCCLR. */ + Uint16 SYNCCLR:1; // 6 Sync Clear Bit (R=0/W=1) + /* Битовое поле ERRCLR, ширина 1 бит; данные ERRCLR. */ + Uint16 ERRCLR:1; // 7 Error Clear Bit (R=0/W=1) + /* Битовое поле PERINTFLG, ширина 1 бит; данные PERINTFLG. */ + Uint16 PERINTFLG:1; // 8 Interrupt Flag Bit (R): + // 0 no interrupt pending + // 1 interrupt pending + /* Битовое поле SYNCFLG, ширина 1 бит; данные SYNCFLG. */ + Uint16 SYNCFLG:1; // 9 Sync Flag Bit (R): + // 0 no sync pending + // 1 sync pending + /* Битовое поле SYNCERR, ширина 1 бит; данные SYNCERR. */ + Uint16 SYNCERR:1; // 10 Sync Error Flag Bit (R): + // 0 no sync error + // 1 sync error detected + /* Битовое поле TRANSFERSTS, ширина 1 бит; данные TRANSFERSTS. */ + Uint16 TRANSFERSTS:1; // 11 Transfer Status Bit (R): + // 0 no transfer in progress or pending + // 1 transfer in progress or pending + /* Битовое поле BURSTSTS, ширина 1 бит; данные BURSTSTS. */ + Uint16 BURSTSTS:1; // 12 Burst Status Bit (R): + // 0 no burst in progress or pending + // 1 burst in progress or pending + /* Битовое поле RUNSTS, ширина 1 бит; данные RUNSTS. */ + Uint16 RUNSTS:1; // 13 Run Status Bit (R): + // 0 channel not running or halted + // 1 channel running + /* Битовое поле OVRFLG, ширина 1 бит; данные OVRFLG. */ + Uint16 OVRFLG:1; // 14 Overflow Flag Bit(R) + // 0 no overflow event + // 1 overflow event + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 15 (R=0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений CONTROL_REG в одной области памяти. */ +union CONTROL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CONTROL_BITS bit;; порядок полей определяет расположение данных. */ + struct CONTROL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// DMACTRL register bit definitions: +/* Описывает структуру DMACTRL_BITS; порядок полей определяет расположение данных. */ +struct DMACTRL_BITS { // bits description + /* Битовое поле HARDRESET, ширина 1 бит; данные HARDRESET. */ + Uint16 HARDRESET:1; // 0 Hard Reset Bit (R=0/W=1) + /* Битовое поле PRIORITYRESET, ширина 1 бит; данные PRIORITYRESET. */ + Uint16 PRIORITYRESET:1; // 1 Priority Reset Bit (R=0/W=1) + /* Битовое поле rsvd1, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:14; // 15:2 (R=0:0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DMACTRL_REG в одной области памяти. */ +union DMACTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DMACTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct DMACTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// DEBUGCTRL register bit definitions: +/* Описывает структуру DEBUGCTRL_BITS; порядок полей определяет расположение данных. */ +struct DEBUGCTRL_BITS { // bits description + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; // 14:0 (R=0:0) + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 15 Debug Mode Bit (R/W): + // 0 halt after current read-write operation + // 1 continue running +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DEBUGCTRL_REG в одной области памяти. */ +union DEBUGCTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DEBUGCTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct DEBUGCTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// PRIORITYCTRL1 register bit definitions: +/* Описывает структуру PRIORITYCTRL1_BITS; порядок полей определяет расположение данных. */ +struct PRIORITYCTRL1_BITS { // bits description + /* Битовое поле CH1PRIORITY, ширина 1 бит; 1 приоритет. */ + Uint16 CH1PRIORITY:1; // 0 Ch1 Priority Bit (R/W): + // 0 same priority as all other channels + // 1 highest priority channel + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; // 15:1 (R=0:0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PRIORITYCTRL1_REG в одной области памяти. */ +union PRIORITYCTRL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PRIORITYCTRL1_BITS bit;; порядок полей определяет расположение данных. */ + struct PRIORITYCTRL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// PRIORITYSTAT register bit definitions: +/* Описывает структуру PRIORITYSTAT_BITS; порядок полей определяет расположение данных. */ +struct PRIORITYSTAT_BITS { // bits description + /* Битовое поле ACTIVESTS, ширина 3 бит; данные ACTIVESTS. */ + Uint16 ACTIVESTS:3; // 2:0 Active Channel Status Bits (R): + // 0,0,0 no channel active + // 0,0,1 Ch1 channel active + // 0,1,0 Ch2 channel active + // 0,1,1 Ch3 channel active + // 1,0,0 Ch4 channel active + // 1,0,1 Ch5 channel active + // 1,1,0 Ch6 channel active + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 3 (R=0) + /* Битовое поле ACTIVESTS_SHADOW, ширина 3 бит; данные ACTIVESTS_SHADOW. */ + Uint16 ACTIVESTS_SHADOW:3; // 6:4 Active Channel Status Shadow Bits (R): + // 0,0,0 no channel active and interrupted by Ch1 + // 0,0,1 cannot occur + // 0,1,0 Ch2 was active and interrupted by Ch1 + // 0,1,1 Ch3 was active and interrupted by Ch1 + // 1,0,0 Ch4 was active and interrupted by Ch1 + // 1,0,1 Ch5 was active and interrupted by Ch1 + // 1,1,0 Ch6 was active and interrupted by Ch1 + /* Битовое поле rsvd2, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:9; // 15:7 (R=0:0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PRIORITYSTAT_REG в одной области памяти. */ +union PRIORITYSTAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PRIORITYSTAT_BITS bit;; порядок полей определяет расположение данных. */ + struct PRIORITYSTAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Burst Size +/* Описывает структуру BURST_SIZE_BITS; порядок полей определяет расположение данных. */ +struct BURST_SIZE_BITS { // bits description + /* Битовое поле BURSTSIZE, ширина 5 бит; данные BURSTSIZE. */ + Uint16 BURSTSIZE:5; // 4:0 Burst transfer size + /* Битовое поле rsvd1, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений BURST_SIZE_REG в одной области памяти. */ +union BURST_SIZE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру BURST_SIZE_BITS bit;; порядок полей определяет расположение данных. */ + struct BURST_SIZE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Burst Count +/* Описывает структуру BURST_COUNT_BITS; порядок полей определяет расположение данных. */ +struct BURST_COUNT_BITS { // bits description + /* Битовое поле BURSTCOUNT, ширина 5 бит; данные BURSTCOUNT. */ + Uint16 BURSTCOUNT:5; // 4:0 Burst transfer size + /* Битовое поле rsvd1, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений BURST_COUNT_REG в одной области памяти. */ +union BURST_COUNT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру BURST_COUNT_BITS bit;; порядок полей определяет расположение данных. */ + struct BURST_COUNT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//---------------------------------------------------- +// DMA Channel Registers: +/* Описывает структуру CH_REGS; порядок полей определяет расположение данных. */ +struct CH_REGS { + /* Объединяет несколько представлений MODE_REG MODE; в одной области памяти. */ + union MODE_REG MODE; // Mode Register + /* Объединяет несколько представлений CONTROL_REG CONTROL; в одной области памяти. */ + union CONTROL_REG CONTROL; // Control Register + + /* Объединяет несколько представлений BURST_SIZE_REG BURST_SIZE; в одной области памяти. */ + union BURST_SIZE_REG BURST_SIZE; // Burst Size Register + /* Объединяет несколько представлений BURST_COUNT_REG BURST_COUNT; в одной области памяти. */ + union BURST_COUNT_REG BURST_COUNT; // Burst Count Register + /* Продолжает список аргументов, полей или выражение int16 SRC_BURST_STEP;; порядок элементов сохраняется. */ + int16 SRC_BURST_STEP; // Source Burst Step Register + /* Продолжает список аргументов, полей или выражение int16 DST_BURST_STEP;; порядок элементов сохраняется. */ + int16 DST_BURST_STEP; // Destination Burst Step Register + + /* Объявляет TRANSFER_SIZE — TRANSFER размер. */ + Uint16 TRANSFER_SIZE; // Transfer Size Register + /* Объявляет TRANSFER_COUNT — TRANSFER число. */ + Uint16 TRANSFER_COUNT; // Transfer Count Register + /* Продолжает список аргументов, полей или выражение int16 SRC_TRANSFER_STEP;; порядок элементов сохраняется. */ + int16 SRC_TRANSFER_STEP; // Source Transfer Step Register + /* Продолжает список аргументов, полей или выражение int16 DST_TRANSFER_STEP;; порядок элементов сохраняется. */ + int16 DST_TRANSFER_STEP; // Destination Transfer Step Register + + /* Объявляет SRC_WRAP_SIZE — SRC WRAP размер. */ + Uint16 SRC_WRAP_SIZE; // Source Wrap Size Register + /* Объявляет SRC_WRAP_COUNT — SRC WRAP число. */ + Uint16 SRC_WRAP_COUNT; // Source Wrap Count Register + /* Продолжает список аргументов, полей или выражение int16 SRC_WRAP_STEP;; порядок элементов сохраняется. */ + int16 SRC_WRAP_STEP; // Source Wrap Step Register + + /* Объявляет DST_WRAP_SIZE — DST WRAP размер. */ + Uint16 DST_WRAP_SIZE; // Destination Wrap Size Register + /* Объявляет DST_WRAP_COUNT — DST WRAP число. */ + Uint16 DST_WRAP_COUNT; // Destination Wrap Count Register + /* Продолжает список аргументов, полей или выражение int16 DST_WRAP_STEP;; порядок элементов сохраняется. */ + int16 DST_WRAP_STEP; // Destination Wrap Step Register + + /* Объявляет SRC_BEG_ADDR_SHADOW — данные SRC_BEG_ADDR_SHADOW. */ + Uint32 SRC_BEG_ADDR_SHADOW; // Source Begin Address Shadow Register + /* Объявляет SRC_ADDR_SHADOW — данные SRC_ADDR_SHADOW. */ + Uint32 SRC_ADDR_SHADOW; // Source Address Shadow Register + /* Объявляет SRC_BEG_ADDR_ACTIVE — данные SRC_BEG_ADDR_ACTIVE. */ + Uint32 SRC_BEG_ADDR_ACTIVE; // Source Begin Address Active Register + /* Объявляет SRC_ADDR_ACTIVE — данные SRC_ADDR_ACTIVE. */ + Uint32 SRC_ADDR_ACTIVE; // Source Address Active Register + + /* Объявляет DST_BEG_ADDR_SHADOW — данные DST_BEG_ADDR_SHADOW. */ + Uint32 DST_BEG_ADDR_SHADOW; // Destination Begin Address Shadow Register + /* Объявляет DST_ADDR_SHADOW — данные DST_ADDR_SHADOW. */ + Uint32 DST_ADDR_SHADOW; // Destination Address Shadow Register + /* Объявляет DST_BEG_ADDR_ACTIVE — данные DST_BEG_ADDR_ACTIVE. */ + Uint32 DST_BEG_ADDR_ACTIVE; // Destination Begin Address Active Register + /* Объявляет DST_ADDR_ACTIVE — данные DST_ADDR_ACTIVE. */ + Uint32 DST_ADDR_ACTIVE; // Destination Address Active Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// DMA Registers: +/* Описывает структуру DMA_REGS; порядок полей определяет расположение данных. */ +struct DMA_REGS { + /* Объединяет несколько представлений DMACTRL_REG DMACTRL; в одной области памяти. */ + union DMACTRL_REG DMACTRL; // DMA Control Register + /* Объединяет несколько представлений DEBUGCTRL_REG DEBUGCTRL; в одной области памяти. */ + union DEBUGCTRL_REG DEBUGCTRL; // Debug Control Register + /* Объявляет rsvd0 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd0; // reserved + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // + /* Объединяет несколько представлений PRIORITYCTRL1_REG PRIORITYCTRL1; в одной области памяти. */ + union PRIORITYCTRL1_REG PRIORITYCTRL1; // Priority Control 1 Register + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // + /* Объединяет несколько представлений PRIORITYSTAT_REG PRIORITYSTAT; в одной области памяти. */ + union PRIORITYSTAT_REG PRIORITYSTAT; // Priority Status Register + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3[25]; // + /* Описывает структуру CH_REGS CH1;; порядок полей определяет расположение данных. */ + struct CH_REGS CH1; // DMA Channel 1 Registers + /* Описывает структуру CH_REGS CH2;; порядок полей определяет расположение данных. */ + struct CH_REGS CH2; // DMA Channel 2 Registers + /* Описывает структуру CH_REGS CH3;; порядок полей определяет расположение данных. */ + struct CH_REGS CH3; // DMA Channel 3 Registers + /* Описывает структуру CH_REGS CH4;; порядок полей определяет расположение данных. */ + struct CH_REGS CH4; // DMA Channel 4 Registers + /* Описывает структуру CH_REGS CH5;; порядок полей определяет расположение данных. */ + struct CH_REGS CH5; // DMA Channel 5 Registers + /* Описывает структуру CH_REGS CH6;; порядок полей определяет расположение данных. */ + struct CH_REGS CH6; // DMA Channel 6 Registers +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct DMA_REGS DmaRegs;; порядок элементов сохраняется. */ +extern volatile struct DMA_REGS DmaRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DMA_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h new file mode 100644 index 0000000..b821aa7 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h @@ -0,0 +1,154 @@ +/* Поставляемое TI описание DevEmu для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: June 2, 2008 11:12:30 $ +//########################################################################### +// +// FILE: DSP2833x_DevEmu.h +// +// TITLE: DSP2833x Device Emulation Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DEV_EMU_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DEV_EMU_H +/* Определяет защитный символ или переключатель DSP2833x_DEV_EMU_H для последующей компиляции. */ +#define DSP2833x_DEV_EMU_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// Device Emulation Register Bit Definitions: +// +// Device Configuration Register Bit Definitions +/* Описывает структуру DEVICECNF_BITS; порядок полей определяет расположение данных. */ +struct DEVICECNF_BITS { // bits description + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 2:0 reserved + /* Битовое поле VMAPS, ширина 1 бит; данные VMAPS. */ + Uint16 VMAPS:1; // 3 VMAP Status + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 4 reserved + /* Битовое поле XRSn, ширина 1 бит; данные XRSn. */ + Uint16 XRSn:1; // 5 XRSn Signal Status + /* Битовое поле rsvd3, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:10; // 15:6 + /* Битовое поле rsvd4, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4:3; // 18:16 + /* Битовое поле ENPROT, ширина 1 бит; данные ENPROT. */ + Uint16 ENPROT:1; // 19 Enable/Disable pipeline protection + /* Битовое поле MONPRIV, ширина 1 бит; данные MONPRIV. */ + Uint16 MONPRIV:1; // 20 MONPRIV enable bit + /* Битовое поле rsvd5, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5:1; // 21 reserved + /* Битовое поле EMU0SEL, ширина 2 бит; данные EMU0SEL. */ + Uint16 EMU0SEL:2; // 23,22 EMU0 Mux select + /* Битовое поле EMU1SEL, ширина 2 бит; данные EMU1SEL. */ + Uint16 EMU1SEL:2; // 25,24 EMU1 Mux select + /* Битовое поле MCBSPCON, ширина 1 бит; данные MCBSPCON. */ + Uint16 MCBSPCON:1; // 26 McBSP-B to EMU0/EMU1 pins control + /* Битовое поле rsvd6, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd6:5; // 31:27 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DEVICECNF_REG в одной области памяти. */ +union DEVICECNF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру DEVICECNF_BITS bit;; порядок полей определяет расположение данных. */ + struct DEVICECNF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// CLASSID +/* Описывает структуру CLASSID_BITS; порядок полей определяет расположение данных. */ +struct CLASSID_BITS { // bits description + /* Битовое поле CLASSNO, ширина 8 бит; данные CLASSNO. */ + Uint16 CLASSNO:8; // 7:0 Class Number + /* Битовое поле PARTTYPE, ширина 8 бит; данные PARTTYPE. */ + Uint16 PARTTYPE:8; // 15:8 Part Type +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений CLASSID_REG в одной области памяти. */ +union CLASSID_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CLASSID_BITS bit;; порядок полей определяет расположение данных. */ + struct CLASSID_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру DEV_EMU_REGS; порядок полей определяет расположение данных. */ +struct DEV_EMU_REGS { + /* Объединяет несколько представлений DEVICECNF_REG DEVICECNF; в одной области памяти. */ + union DEVICECNF_REG DEVICECNF; // device configuration + /* Объединяет несколько представлений CLASSID_REG CLASSID; в одной области памяти. */ + union CLASSID_REG CLASSID; // Class ID + /* Объявляет REVID — данные REVID. */ + Uint16 REVID; // Device ID + /* Объявляет PROTSTART — данные PROTSTART. */ + Uint16 PROTSTART; // Write-Read protection start + /* Объявляет PROTRANGE — данные PROTRANGE. */ + Uint16 PROTRANGE; // Write-Read protection range + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[202]; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PARTID +/* Описывает структуру PARTID_BITS; порядок полей определяет расположение данных. */ +struct PARTID_BITS { // bits description + /* Битовое поле PARTNO, ширина 8 бит; данные PARTNO. */ + Uint16 PARTNO:8; // 7:0 Part Number + /* Битовое поле PARTTYPE, ширина 8 бит; данные PARTTYPE. */ + Uint16 PARTTYPE:8; // 15:8 Part Type +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PARTID_REG в одной области памяти. */ +union PARTID_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PARTID_BITS bit;; порядок полей определяет расположение данных. */ + struct PARTID_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру PARTID_REGS; порядок полей определяет расположение данных. */ +struct PARTID_REGS { + /* Объединяет несколько представлений PARTID_REG PARTID; в одной области памяти. */ + union PARTID_REG PARTID; // Part ID +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//--------------------------------------------------------------------------- +// Device Emulation Register References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct DEV_EMU_REGS DevEmuRegs;; порядок элементов сохраняется. */ +extern volatile struct DEV_EMU_REGS DevEmuRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct PARTID_REGS PartIdRegs;; порядок элементов сохраняется. */ +extern volatile struct PARTID_REGS PartIdRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DEV_EMU_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h new file mode 100644 index 0000000..138d251 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h @@ -0,0 +1,655 @@ +/* Поставляемое TI описание Device для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/5 $ +// Checkin $Date: January 22, 2008 16:55:35 $ +//########################################################################### +// +// FILE: DSP2833x_Device.h +// +// TITLE: DSP2833x Device Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DEVICE_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DEVICE_H +/* Определяет защитный символ или переключатель DSP2833x_DEVICE_H для последующей компиляции. */ +#define DSP2833x_DEVICE_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +/* Задаёт TARGET = 1; данные TARGET. */ +#define TARGET 1 +//--------------------------------------------------------------------------- +// User To Select Target Device: + +/* Задаёт DSP28_28335 = TARGET; данные DSP28_28335. */ +#define DSP28_28335 TARGET // Selects '28335/'28235 +/* Задаёт DSP28_28334 = 0; данные DSP28_28334. */ +#define DSP28_28334 0 // Selects '28334/'28234 +/* Задаёт DSP28_28332 = 0; данные DSP28_28332. */ +#define DSP28_28332 0 // Selects '28332/'28232 + + +//--------------------------------------------------------------------------- +// Common CPU Definitions: +// + +/* Продолжает список аргументов, полей или выражение extern cregister volatile unsigned int IFR;; порядок элементов сохраняется. */ +extern cregister volatile unsigned int IFR; +/* Продолжает список аргументов, полей или выражение extern cregister volatile unsigned int IER;; порядок элементов сохраняется. */ +extern cregister volatile unsigned int IER; + +/* Задаёт EINT = asm(" clrc INTM"); разрешение маскируемых прерываний ядра. */ +#define EINT asm(" clrc INTM") +/* Задаёт DINT = asm(" setc INTM"); запрет маскируемых прерываний ядра. */ +#define DINT asm(" setc INTM") +/* Задаёт ERTM = asm(" clrc DBGM"); данные ERTM. */ +#define ERTM asm(" clrc DBGM") +/* Задаёт DRTM = asm(" setc DBGM"); данные DRTM. */ +#define DRTM asm(" setc DBGM") +/* Задаёт EALLOW = asm(" EALLOW"); разрешение записи в защищённые регистры периферии. */ +#define EALLOW asm(" EALLOW") +/* Задаёт EDIS = asm(" EDIS"); закрытие доступа к защищённым регистрам периферии. */ +#define EDIS asm(" EDIS") +/* Задаёт ESTOP0 = asm(" ESTOP0"); данные ESTOP0. */ +#define ESTOP0 asm(" ESTOP0") + +/* Задаёт M_INT1 = 0x0001; данные M_INT1. */ +#define M_INT1 0x0001 +/* Задаёт M_INT2 = 0x0002; данные M_INT2. */ +#define M_INT2 0x0002 +/* Задаёт M_INT3 = 0x0004; данные M_INT3. */ +#define M_INT3 0x0004 +/* Задаёт M_INT4 = 0x0008; данные M_INT4. */ +#define M_INT4 0x0008 +/* Задаёт M_INT5 = 0x0010; данные M_INT5. */ +#define M_INT5 0x0010 +/* Задаёт M_INT6 = 0x0020; данные M_INT6. */ +#define M_INT6 0x0020 +/* Задаёт M_INT7 = 0x0040; данные M_INT7. */ +#define M_INT7 0x0040 +/* Задаёт M_INT8 = 0x0080; данные M_INT8. */ +#define M_INT8 0x0080 +/* Задаёт M_INT9 = 0x0100; данные M_INT9. */ +#define M_INT9 0x0100 +/* Задаёт M_INT10 = 0x0200; данные M_INT10. */ +#define M_INT10 0x0200 +/* Задаёт M_INT11 = 0x0400; данные M_INT11. */ +#define M_INT11 0x0400 +/* Задаёт M_INT12 = 0x0800; данные M_INT12. */ +#define M_INT12 0x0800 +/* Задаёт M_INT13 = 0x1000; данные M_INT13. */ +#define M_INT13 0x1000 +/* Задаёт M_INT14 = 0x2000; данные M_INT14. */ +#define M_INT14 0x2000 +/* Задаёт M_DLOG = 0x4000; данные M_DLOG. */ +#define M_DLOG 0x4000 +/* Задаёт M_RTOS = 0x8000; данные M_RTOS. */ +#define M_RTOS 0x8000 + +/* Задаёт BIT0 = 0x0001; данные BIT0. */ +#define BIT0 0x0001 +/* Задаёт BIT1 = 0x0002; данные BIT1. */ +#define BIT1 0x0002 +/* Задаёт BIT2 = 0x0004; данные BIT2. */ +#define BIT2 0x0004 +/* Задаёт BIT3 = 0x0008; данные BIT3. */ +#define BIT3 0x0008 +/* Задаёт BIT4 = 0x0010; данные BIT4. */ +#define BIT4 0x0010 +/* Задаёт BIT5 = 0x0020; данные BIT5. */ +#define BIT5 0x0020 +/* Задаёт BIT6 = 0x0040; данные BIT6. */ +#define BIT6 0x0040 +/* Задаёт BIT7 = 0x0080; данные BIT7. */ +#define BIT7 0x0080 +/* Задаёт BIT8 = 0x0100; данные BIT8. */ +#define BIT8 0x0100 +/* Задаёт BIT9 = 0x0200; данные BIT9. */ +#define BIT9 0x0200 +/* Задаёт BIT10 = 0x0400; данные BIT10. */ +#define BIT10 0x0400 +/* Задаёт BIT11 = 0x0800; данные BIT11. */ +#define BIT11 0x0800 +/* Задаёт BIT12 = 0x1000; данные BIT12. */ +#define BIT12 0x1000 +/* Задаёт BIT13 = 0x2000; данные BIT13. */ +#define BIT13 0x2000 +/* Задаёт BIT14 = 0x4000; данные BIT14. */ +#define BIT14 0x4000 +/* Задаёт BIT15 = 0x8000; данные BIT15. */ +#define BIT15 0x8000 + + + +//--------------------------------------------------------------------------- +// For Portability, User Is Recommended To Use Following Data Type Size +// Definitions For 16-bit and 32-Bit Signed/Unsigned Integers: +// + +/* Начинает условие: DSP28_DATA_TYPES ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP28_DATA_TYPES +/* Определяет защитный символ или переключатель DSP28_DATA_TYPES для последующей компиляции. */ +#define DSP28_DATA_TYPES +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef int int16; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef long int32; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef long long int64; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef unsigned int Uint16; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef unsigned long Uint32; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef unsigned long long Uint64; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef float float32; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef long double float64; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef union +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле bit0, ширина 1 бит; бит 0. */ + unsigned int bit0: 1; + /* Битовое поле bit1, ширина 1 бит; бит 1. */ + unsigned int bit1: 1; + /* Битовое поле bit2, ширина 1 бит; бит 2. */ + unsigned int bit2: 1; + /* Битовое поле bit3, ширина 1 бит; бит 3. */ + unsigned int bit3: 1; + /* Битовое поле bit4, ширина 1 бит; бит 4. */ + unsigned int bit4: 1; + /* Битовое поле bit5, ширина 1 бит; бит 5. */ + unsigned int bit5: 1; + /* Битовое поле bit6, ширина 1 бит; бит 6. */ + unsigned int bit6: 1; + /* Битовое поле bit7, ширина 1 бит; бит 7. */ + unsigned int bit7: 1; + + /* Продолжает список аргументов, полей или выражение } bit;; порядок элементов сохраняется. */ + } bit; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле quad_0, ширина 4 бит; данные quad_0. */ + unsigned int quad_0 :4; + /* Битовое поле quad_1, ширина 4 бит; данные quad_1. */ + unsigned int quad_1 :4; + + /* Продолжает список аргументов, полей или выражение } qua;; порядок элементов сохраняется. */ + } qua; + + /* Продолжает список аргументов, полей или выражение unsigned short all;; порядок элементов сохраняется. */ + unsigned short all; + +/* Продолжает список аргументов, полей или выражение } BAITE;; порядок элементов сохраняется. */ +} BAITE; + +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef union +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле bit0, ширина 1 бит; бит 0. */ + unsigned int bit0: 1; + /* Битовое поле bit1, ширина 1 бит; бит 1. */ + unsigned int bit1: 1; + /* Битовое поле bit2, ширина 1 бит; бит 2. */ + unsigned int bit2: 1; + /* Битовое поле bit3, ширина 1 бит; бит 3. */ + unsigned int bit3: 1; + /* Битовое поле bit4, ширина 1 бит; бит 4. */ + unsigned int bit4: 1; + /* Битовое поле bit5, ширина 1 бит; бит 5. */ + unsigned int bit5: 1; + /* Битовое поле bit6, ширина 1 бит; бит 6. */ + unsigned int bit6: 1; + /* Битовое поле bit7, ширина 1 бит; бит 7. */ + unsigned int bit7: 1; + /* Битовое поле bit8, ширина 1 бит; бит 8. */ + unsigned int bit8: 1; + /* Битовое поле bit9, ширина 1 бит; бит 9. */ + unsigned int bit9: 1; + /* Битовое поле bitA, ширина 1 бит; бит A. */ + unsigned int bitA: 1; + /* Битовое поле bitB, ширина 1 бит; бит B. */ + unsigned int bitB: 1; + /* Битовое поле bitC, ширина 1 бит; бит C. */ + unsigned int bitC: 1; + /* Битовое поле bitD, ширина 1 бит; бит D. */ + unsigned int bitD: 1; + /* Битовое поле bitE, ширина 1 бит; бит E. */ + unsigned int bitE: 1; + /* Битовое поле bitF, ширина 1 бит; бит F. */ + unsigned int bitF: 1; + + /* Продолжает список аргументов, полей или выражение } bit;; порядок элементов сохраняется. */ + } bit; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле quad_0, ширина 4 бит; данные quad_0. */ + unsigned int quad_0 :4; + /* Битовое поле quad_1, ширина 4 бит; данные quad_1. */ + unsigned int quad_1 :4; + /* Битовое поле quad_2, ширина 4 бит; данные quad_2. */ + unsigned int quad_2 :4; + /* Битовое поле quad_3, ширина 4 бит; данные quad_3. */ + unsigned int quad_3 :4; + + /* Продолжает список аргументов, полей или выражение } qua;; порядок элементов сохраняется. */ + } qua; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле byte_0, ширина 8 бит; данные byte_0. */ + unsigned int byte_0 :8; + /* Битовое поле byte_1, ширина 8 бит; данные byte_1. */ + unsigned int byte_1 :8; + + /* Продолжает список аргументов, полей или выражение } byt;; порядок элементов сохраняется. */ + } byt; + + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + int all; + +/* Продолжает список аргументов, полей или выражение } WORDE;; порядок элементов сохраняется. */ +} WORDE; + +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef union +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле bit00, ширина 1 бит; бит 00. */ + unsigned int bit00: 1; + /* Битовое поле bit01, ширина 1 бит; бит 01. */ + unsigned int bit01: 1; + /* Битовое поле bit02, ширина 1 бит; бит 02. */ + unsigned int bit02: 1; + /* Битовое поле bit03, ширина 1 бит; бит 03. */ + unsigned int bit03: 1; + /* Битовое поле bit04, ширина 1 бит; бит 04. */ + unsigned int bit04: 1; + /* Битовое поле bit05, ширина 1 бит; бит 05. */ + unsigned int bit05: 1; + /* Битовое поле bit06, ширина 1 бит; бит 06. */ + unsigned int bit06: 1; + /* Битовое поле bit07, ширина 1 бит; бит 07. */ + unsigned int bit07: 1; + /* Битовое поле bit08, ширина 1 бит; бит 08. */ + unsigned int bit08: 1; + /* Битовое поле bit09, ширина 1 бит; бит 09. */ + unsigned int bit09: 1; + /* Битовое поле bit0A, ширина 1 бит; бит 0 A. */ + unsigned int bit0A: 1; + /* Битовое поле bit0B, ширина 1 бит; бит 0 B. */ + unsigned int bit0B: 1; + /* Битовое поле bit0C, ширина 1 бит; бит 0 C. */ + unsigned int bit0C: 1; + /* Битовое поле bit0D, ширина 1 бит; бит 0 D. */ + unsigned int bit0D: 1; + /* Битовое поле bit0E, ширина 1 бит; бит 0 E. */ + unsigned int bit0E: 1; + /* Битовое поле bit0F, ширина 1 бит; бит 0 F. */ + unsigned int bit0F: 1; + /* Битовое поле bit10, ширина 1 бит; бит 10. */ + unsigned int bit10: 1; + /* Битовое поле bit11, ширина 1 бит; бит 11. */ + unsigned int bit11: 1; + /* Битовое поле bit12, ширина 1 бит; бит 12. */ + unsigned int bit12: 1; + /* Битовое поле bit13, ширина 1 бит; бит 13. */ + unsigned int bit13: 1; + /* Битовое поле bit14, ширина 1 бит; бит 14. */ + unsigned int bit14: 1; + /* Битовое поле bit15, ширина 1 бит; бит 15. */ + unsigned int bit15: 1; + /* Битовое поле bit16, ширина 1 бит; бит 16. */ + unsigned int bit16: 1; + /* Битовое поле bit17, ширина 1 бит; бит 17. */ + unsigned int bit17: 1; + /* Битовое поле bit18, ширина 1 бит; бит 18. */ + unsigned int bit18: 1; + /* Битовое поле bit19, ширина 1 бит; бит 19. */ + unsigned int bit19: 1; + /* Битовое поле bit1A, ширина 1 бит; бит 1 A. */ + unsigned int bit1A: 1; + /* Битовое поле bit1B, ширина 1 бит; бит 1 B. */ + unsigned int bit1B: 1; + /* Битовое поле bit1C, ширина 1 бит; бит 1 C. */ + unsigned int bit1C: 1; + /* Битовое поле bit1D, ширина 1 бит; бит 1 D. */ + unsigned int bit1D: 1; + /* Битовое поле bit1E, ширина 1 бит; бит 1 E. */ + unsigned int bit1E: 1; + /* Битовое поле bit1F, ширина 1 бит; бит 1 F. */ + unsigned int bit1F: 1; + + /* Продолжает список аргументов, полей или выражение } bit;; порядок элементов сохраняется. */ + } bit; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле quad_0, ширина 4 бит; данные quad_0. */ + unsigned int quad_0 :4; + /* Битовое поле quad_1, ширина 4 бит; данные quad_1. */ + unsigned int quad_1 :4; + /* Битовое поле quad_2, ширина 4 бит; данные quad_2. */ + unsigned int quad_2 :4; + /* Битовое поле quad_3, ширина 4 бит; данные quad_3. */ + unsigned int quad_3 :4; + /* Битовое поле quad_4, ширина 4 бит; данные quad_4. */ + unsigned int quad_4 :4; + /* Битовое поле quad_5, ширина 4 бит; данные quad_5. */ + unsigned int quad_5 :4; + /* Битовое поле quad_6, ширина 4 бит; данные quad_6. */ + unsigned int quad_6 :4; + /* Битовое поле quad_7, ширина 4 бит; данные quad_7. */ + unsigned int quad_7 :4; + + /* Продолжает список аргументов, полей или выражение } qua;; порядок элементов сохраняется. */ + } qua; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле byte_0, ширина 8 бит; данные byte_0. */ + unsigned int byte_0 :8; + /* Битовое поле byte_1, ширина 8 бит; данные byte_1. */ + unsigned int byte_1 :8; + /* Битовое поле byte_2, ширина 8 бит; данные byte_2. */ + unsigned int byte_2 :8; + /* Битовое поле byte_3, ширина 8 бит; данные byte_3. */ + unsigned int byte_3 :8; + + /* Продолжает список аргументов, полей или выражение } byt;; порядок элементов сохраняется. */ + } byt; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле word_0, ширина 16 бит; слово 0. */ + unsigned int word_0 :16; + /* Битовое поле word_1, ширина 16 бит; слово 1. */ + unsigned int word_1 :16; + + /* Продолжает список аргументов, полей или выражение } wrd;; порядок элементов сохраняется. */ + } wrd; + + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + unsigned long all; + +/* Продолжает список аргументов, полей или выражение } LONGE;; порядок элементов сохраняется. */ +} LONGE; + +/* Задаёт XCLKIN = 30000000; данные XCLKIN. */ +#define XCLKIN 30000000 // external oscillator frequency +/* Объявляет SYSCLKOUT — данные SYSCLKOUT; LSPCLK — данные LSPCLK; HSPCLK — данные HSPCLK. Память определена в другом модуле. */ +extern long SYSCLKOUT, LSPCLK, HSPCLK; + +/* Задаёт CLKMULT = 2L; данные CLKMULT. */ +#define CLKMULT 2L // 1 to 5 + +/* Задаёт LOWORD = int)( (long int)(l) &0xFFFF)); данные LOWORD. */ +#define LOWORD(l)((short int)( (long int)(l) &0xFFFF)) +/* Задаёт HIWORD = int)(((long int)(l)>>16)&0xFFFF)); данные HIWORD. */ +#define HIWORD(l)((short int)(((long int)(l)>>16)&0xFFFF)) + +/* Задаёт LOBYTE = (short int)(w) &0xFF)); данные LOBYTE. */ +#define LOBYTE(w)((char)( (short int)(w) &0xFF)) +/* Задаёт HIBYTE = int)(w)>>8)&0xFF)); данные HIBYTE. */ +#define HIBYTE(w)((char)(((short int)(w)>>8)&0xFF)) + +/* Задаёт BYTE3 = int)(l)>>24)&0xFF)); данные BYTE3. */ +#define BYTE3(l)((char)(((long int)(l)>>24)&0xFF)) +/* Задаёт BYTE2 = int)(l)>>16)&0xFF)); данные BYTE2. */ +#define BYTE2(l)((char)(((long int)(l)>>16)&0xFF)) +/* Задаёт BYTE1 = int)(l)>> 8)&0xFF)); данные BYTE1. */ +#define BYTE1(l)((char)(((long int)(l)>> 8)&0xFF)) +/* Задаёт BYTE0 = (long int)(l) &0xFF)); данные BYTE0. */ +#define BYTE0(l)((char)( (long int)(l) &0xFF)) + +//--------------------------------------------------------------------------- +// Include All Peripheral Header Files: +// +/* Подключает "DSP2833x_Adc.h": поставляемое TI описание Adc для семейства C2833x. */ +#include "DSP2833x_Adc.h" // ADC Registers +/* Подключает "DSP2833x_DevEmu.h": поставляемое TI описание DevEmu для семейства C2833x. */ +#include "DSP2833x_DevEmu.h" // Device Emulation Registers +/* Подключает "DSP2833x_CpuTimers.h": поставляемое TI описание CpuTimers для семейства C2833x. */ +#include "DSP2833x_CpuTimers.h" // 32-bit CPU Timers +/* Подключает "DSP2833x_ECan.h": поставляемое TI описание ECan для семейства C2833x. */ +#include "DSP2833x_ECan.h" // Enhanced eCAN Registers +/* Подключает "DSP2833x_ECap.h": поставляемое TI описание ECap для семейства C2833x. */ +#include "DSP2833x_ECap.h" // Enhanced Capture +/* Подключает "DSP2833x_DMA.h": поставляемое TI описание DMA для семейства C2833x. */ +#include "DSP2833x_DMA.h" // DMA Registers +/* Подключает "DSP2833x_EPwm.h": поставляемое TI описание EPwm для семейства C2833x. */ +#include "DSP2833x_EPwm.h" // Enhanced PWM +/* Подключает "DSP2833x_EQep.h": поставляемое TI описание EQep для семейства C2833x. */ +#include "DSP2833x_EQep.h" // Enhanced QEP +/* Подключает "DSP2833x_Gpio.h": поставляемое TI описание Gpio для семейства C2833x. */ +#include "DSP2833x_Gpio.h" // General Purpose I/O Registers +/* Подключает "DSP2833x_I2c.h": поставляемое TI описание I2c для семейства C2833x. */ +#include "DSP2833x_I2c.h" // I2C Registers +/* Подключает "DSP2833x_McBSP.h": поставляемое TI описание McBSP для семейства C2833x. */ +#include "DSP2833x_McBSP.h" // McBSP +/* Подключает "DSP2833x_PieCtrl.h": поставляемое TI описание PieCtrl для семейства C2833x. */ +#include "DSP2833x_PieCtrl.h" // PIE Control Registers +/* Подключает "DSP2833x_PieVect.h": поставляемое TI описание PieVect для семейства C2833x. */ +#include "DSP2833x_PieVect.h" // PIE Vector Table +/* Подключает "DSP2833x_Spi.h": поставляемое TI описание Spi для семейства C2833x. */ +#include "DSP2833x_Spi.h" // SPI Registers +/* Подключает "DSP2833x_Sci.h": поставляемое TI описание Sci для семейства C2833x. */ +#include "DSP2833x_Sci.h" // SCI Registers +/* Подключает "DSP2833x_SysCtrl.h": поставляемое TI описание SysCtrl для семейства C2833x. */ +#include "DSP2833x_SysCtrl.h" // System Control/Power Modes +/* Подключает "DSP2833x_XIntrupt.h": поставляемое TI описание XIntrupt для семейства C2833x. */ +#include "DSP2833x_XIntrupt.h" // External Interrupts +/* Подключает "DSP2833x_Xintf.h": поставляемое TI описание Xintf для семейства C2833x. */ +#include "DSP2833x_Xintf.h" // XINTF External Interface + +/* Подключает "DSP2833x_GlobalPrototypes.h": поставляемое TI описание GlobalPrototypes для семейства C2833x. */ +#include "DSP2833x_GlobalPrototypes.h" // Prototypes for global functions within the + +/* Условие компиляции DSP28_28335: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28335 +/* Задаёт DSP28_EPWM1 = 1; данные DSP28_EPWM1. */ +#define DSP28_EPWM1 1 +/* Задаёт DSP28_EPWM2 = 1; данные DSP28_EPWM2. */ +#define DSP28_EPWM2 1 +/* Задаёт DSP28_EPWM3 = 1; данные DSP28_EPWM3. */ +#define DSP28_EPWM3 1 +/* Задаёт DSP28_EPWM4 = 1; данные DSP28_EPWM4. */ +#define DSP28_EPWM4 1 +/* Задаёт DSP28_EPWM5 = 1; данные DSP28_EPWM5. */ +#define DSP28_EPWM5 1 +/* Задаёт DSP28_EPWM6 = 1; данные DSP28_EPWM6. */ +#define DSP28_EPWM6 1 +/* Задаёт DSP28_ECAP1 = 1; данные DSP28_ECAP1. */ +#define DSP28_ECAP1 1 +/* Задаёт DSP28_ECAP2 = 1; данные DSP28_ECAP2. */ +#define DSP28_ECAP2 1 +/* Задаёт DSP28_ECAP3 = 1; данные DSP28_ECAP3. */ +#define DSP28_ECAP3 1 +/* Задаёт DSP28_ECAP4 = 1; данные DSP28_ECAP4. */ +#define DSP28_ECAP4 1 +/* Задаёт DSP28_ECAP5 = 1; данные DSP28_ECAP5. */ +#define DSP28_ECAP5 1 +/* Задаёт DSP28_ECAP6 = 1; данные DSP28_ECAP6. */ +#define DSP28_ECAP6 1 +/* Задаёт DSP28_EQEP1 = 1; данные DSP28_EQEP1. */ +#define DSP28_EQEP1 1 +/* Задаёт DSP28_EQEP2 = 1; данные DSP28_EQEP2. */ +#define DSP28_EQEP2 1 +/* Задаёт DSP28_ECANA = 1; данные DSP28_ECANA. */ +#define DSP28_ECANA 1 +/* Задаёт DSP28_ECANB = 1; данные DSP28_ECANB. */ +#define DSP28_ECANB 1 +/* Задаёт DSP28_MCBSPA = 1; данные DSP28_MCBSPA. */ +#define DSP28_MCBSPA 1 +/* Задаёт DSP28_MCBSPB = 1; данные DSP28_MCBSPB. */ +#define DSP28_MCBSPB 1 +/* Задаёт DSP28_SPIA = 1; данные DSP28_SPIA. */ +#define DSP28_SPIA 1 +/* Задаёт DSP28_SCIA = 1; данные DSP28_SCIA. */ +#define DSP28_SCIA 1 +/* Задаёт DSP28_SCIB = 1; данные DSP28_SCIB. */ +#define DSP28_SCIB 1 +/* Задаёт DSP28_SCIC = 1; данные DSP28_SCIC. */ +#define DSP28_SCIC 1 +/* Задаёт DSP28_I2CA = 1; данные DSP28_I2CA. */ +#define DSP28_I2CA 1 +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end DSP28_28335 + +/* Условие компиляции DSP28_28334: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28334 +/* Задаёт DSP28_EPWM1 = 1; данные DSP28_EPWM1. */ +#define DSP28_EPWM1 1 +/* Задаёт DSP28_EPWM2 = 1; данные DSP28_EPWM2. */ +#define DSP28_EPWM2 1 +/* Задаёт DSP28_EPWM3 = 1; данные DSP28_EPWM3. */ +#define DSP28_EPWM3 1 +/* Задаёт DSP28_EPWM4 = 1; данные DSP28_EPWM4. */ +#define DSP28_EPWM4 1 +/* Задаёт DSP28_EPWM5 = 1; данные DSP28_EPWM5. */ +#define DSP28_EPWM5 1 +/* Задаёт DSP28_EPWM6 = 1; данные DSP28_EPWM6. */ +#define DSP28_EPWM6 1 +/* Задаёт DSP28_ECAP1 = 1; данные DSP28_ECAP1. */ +#define DSP28_ECAP1 1 +/* Задаёт DSP28_ECAP2 = 1; данные DSP28_ECAP2. */ +#define DSP28_ECAP2 1 +/* Задаёт DSP28_ECAP3 = 1; данные DSP28_ECAP3. */ +#define DSP28_ECAP3 1 +/* Задаёт DSP28_ECAP4 = 1; данные DSP28_ECAP4. */ +#define DSP28_ECAP4 1 +/* Задаёт DSP28_ECAP5 = 0; данные DSP28_ECAP5. */ +#define DSP28_ECAP5 0 +/* Задаёт DSP28_ECAP6 = 0; данные DSP28_ECAP6. */ +#define DSP28_ECAP6 0 +/* Задаёт DSP28_EQEP1 = 1; данные DSP28_EQEP1. */ +#define DSP28_EQEP1 1 +/* Задаёт DSP28_EQEP2 = 1; данные DSP28_EQEP2. */ +#define DSP28_EQEP2 1 +/* Задаёт DSP28_ECANA = 1; данные DSP28_ECANA. */ +#define DSP28_ECANA 1 +/* Задаёт DSP28_ECANB = 1; данные DSP28_ECANB. */ +#define DSP28_ECANB 1 +/* Задаёт DSP28_MCBSPA = 1; данные DSP28_MCBSPA. */ +#define DSP28_MCBSPA 1 +/* Задаёт DSP28_MCBSPB = 1; данные DSP28_MCBSPB. */ +#define DSP28_MCBSPB 1 +/* Задаёт DSP28_SPIA = 1; данные DSP28_SPIA. */ +#define DSP28_SPIA 1 +/* Задаёт DSP28_SCIA = 1; данные DSP28_SCIA. */ +#define DSP28_SCIA 1 +/* Задаёт DSP28_SCIB = 1; данные DSP28_SCIB. */ +#define DSP28_SCIB 1 +/* Задаёт DSP28_SCIC = 1; данные DSP28_SCIC. */ +#define DSP28_SCIC 1 +/* Задаёт DSP28_I2CA = 1; данные DSP28_I2CA. */ +#define DSP28_I2CA 1 +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end DSP28_28334 + +/* Условие компиляции DSP28_28332: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28332 +/* Задаёт DSP28_EPWM1 = 1; данные DSP28_EPWM1. */ +#define DSP28_EPWM1 1 +/* Задаёт DSP28_EPWM2 = 1; данные DSP28_EPWM2. */ +#define DSP28_EPWM2 1 +/* Задаёт DSP28_EPWM3 = 1; данные DSP28_EPWM3. */ +#define DSP28_EPWM3 1 +/* Задаёт DSP28_EPWM4 = 1; данные DSP28_EPWM4. */ +#define DSP28_EPWM4 1 +/* Задаёт DSP28_EPWM5 = 1; данные DSP28_EPWM5. */ +#define DSP28_EPWM5 1 +/* Задаёт DSP28_EPWM6 = 1; данные DSP28_EPWM6. */ +#define DSP28_EPWM6 1 +/* Задаёт DSP28_ECAP1 = 1; данные DSP28_ECAP1. */ +#define DSP28_ECAP1 1 +/* Задаёт DSP28_ECAP2 = 1; данные DSP28_ECAP2. */ +#define DSP28_ECAP2 1 +/* Задаёт DSP28_ECAP3 = 1; данные DSP28_ECAP3. */ +#define DSP28_ECAP3 1 +/* Задаёт DSP28_ECAP4 = 1; данные DSP28_ECAP4. */ +#define DSP28_ECAP4 1 +/* Задаёт DSP28_ECAP5 = 0; данные DSP28_ECAP5. */ +#define DSP28_ECAP5 0 +/* Задаёт DSP28_ECAP6 = 0; данные DSP28_ECAP6. */ +#define DSP28_ECAP6 0 +/* Задаёт DSP28_EQEP1 = 1; данные DSP28_EQEP1. */ +#define DSP28_EQEP1 1 +/* Задаёт DSP28_EQEP2 = 1; данные DSP28_EQEP2. */ +#define DSP28_EQEP2 1 +/* Задаёт DSP28_ECANA = 1; данные DSP28_ECANA. */ +#define DSP28_ECANA 1 +/* Задаёт DSP28_ECANB = 1; данные DSP28_ECANB. */ +#define DSP28_ECANB 1 +/* Задаёт DSP28_MCBSPA = 1; данные DSP28_MCBSPA. */ +#define DSP28_MCBSPA 1 +/* Задаёт DSP28_MCBSPB = 0; данные DSP28_MCBSPB. */ +#define DSP28_MCBSPB 0 +/* Задаёт DSP28_SPIA = 1; данные DSP28_SPIA. */ +#define DSP28_SPIA 1 +/* Задаёт DSP28_SCIA = 1; данные DSP28_SCIA. */ +#define DSP28_SCIA 1 +/* Задаёт DSP28_SCIB = 1; данные DSP28_SCIB. */ +#define DSP28_SCIB 1 +/* Задаёт DSP28_SCIC = 0; данные DSP28_SCIC. */ +#define DSP28_SCIC 0 +/* Задаёт DSP28_I2CA = 1; данные DSP28_I2CA. */ +#define DSP28_I2CA 1 +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end DSP28_28332 + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DEVICE_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h new file mode 100644 index 0000000..965ee77 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h @@ -0,0 +1,2109 @@ +/* Поставляемое TI описание ECan для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: May 7, 2007 16:05:39 $ +//########################################################################### +// +// FILE: DSP2833x_ECan.h +// +// TITLE: DSP2833x Device eCAN Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_ECAN_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_ECAN_H +/* Определяет защитный символ или переключатель DSP2833x_ECAN_H для последующей компиляции. */ +#define DSP2833x_ECAN_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +/* --------------------------------------------------- */ +/* eCAN Control & Status Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Mailbox enable register (CANME) bit definitions */ +/* Описывает структуру CANME_BITS; порядок полей определяет расположение данных. */ +struct CANME_BITS { // bit description + /* Битовое поле ME0, ширина 1 бит; данные ME0. */ + Uint16 ME0:1; // 0 Enable Mailbox 0 + /* Битовое поле ME1, ширина 1 бит; данные ME1. */ + Uint16 ME1:1; // 1 Enable Mailbox 1 + /* Битовое поле ME2, ширина 1 бит; данные ME2. */ + Uint16 ME2:1; // 2 Enable Mailbox 2 + /* Битовое поле ME3, ширина 1 бит; данные ME3. */ + Uint16 ME3:1; // 3 Enable Mailbox 3 + /* Битовое поле ME4, ширина 1 бит; данные ME4. */ + Uint16 ME4:1; // 4 Enable Mailbox 4 + /* Битовое поле ME5, ширина 1 бит; данные ME5. */ + Uint16 ME5:1; // 5 Enable Mailbox 5 + /* Битовое поле ME6, ширина 1 бит; данные ME6. */ + Uint16 ME6:1; // 6 Enable Mailbox 6 + /* Битовое поле ME7, ширина 1 бит; данные ME7. */ + Uint16 ME7:1; // 7 Enable Mailbox 7 + /* Битовое поле ME8, ширина 1 бит; данные ME8. */ + Uint16 ME8:1; // 8 Enable Mailbox 8 + /* Битовое поле ME9, ширина 1 бит; данные ME9. */ + Uint16 ME9:1; // 9 Enable Mailbox 9 + /* Битовое поле ME10, ширина 1 бит; данные ME10. */ + Uint16 ME10:1; // 10 Enable Mailbox 10 + /* Битовое поле ME11, ширина 1 бит; данные ME11. */ + Uint16 ME11:1; // 11 Enable Mailbox 11 + /* Битовое поле ME12, ширина 1 бит; данные ME12. */ + Uint16 ME12:1; // 12 Enable Mailbox 12 + /* Битовое поле ME13, ширина 1 бит; данные ME13. */ + Uint16 ME13:1; // 13 Enable Mailbox 13 + /* Битовое поле ME14, ширина 1 бит; данные ME14. */ + Uint16 ME14:1; // 14 Enable Mailbox 14 + /* Битовое поле ME15, ширина 1 бит; данные ME15. */ + Uint16 ME15:1; // 15 Enable Mailbox 15 + /* Битовое поле ME16, ширина 1 бит; данные ME16. */ + Uint16 ME16:1; // 16 Enable Mailbox 16 + /* Битовое поле ME17, ширина 1 бит; данные ME17. */ + Uint16 ME17:1; // 17 Enable Mailbox 17 + /* Битовое поле ME18, ширина 1 бит; данные ME18. */ + Uint16 ME18:1; // 18 Enable Mailbox 18 + /* Битовое поле ME19, ширина 1 бит; данные ME19. */ + Uint16 ME19:1; // 19 Enable Mailbox 19 + /* Битовое поле ME20, ширина 1 бит; данные ME20. */ + Uint16 ME20:1; // 20 Enable Mailbox 20 + /* Битовое поле ME21, ширина 1 бит; данные ME21. */ + Uint16 ME21:1; // 21 Enable Mailbox 21 + /* Битовое поле ME22, ширина 1 бит; данные ME22. */ + Uint16 ME22:1; // 22 Enable Mailbox 22 + /* Битовое поле ME23, ширина 1 бит; данные ME23. */ + Uint16 ME23:1; // 23 Enable Mailbox 23 + /* Битовое поле ME24, ширина 1 бит; данные ME24. */ + Uint16 ME24:1; // 24 Enable Mailbox 24 + /* Битовое поле ME25, ширина 1 бит; данные ME25. */ + Uint16 ME25:1; // 25 Enable Mailbox 25 + /* Битовое поле ME26, ширина 1 бит; данные ME26. */ + Uint16 ME26:1; // 26 Enable Mailbox 26 + /* Битовое поле ME27, ширина 1 бит; данные ME27. */ + Uint16 ME27:1; // 27 Enable Mailbox 27 + /* Битовое поле ME28, ширина 1 бит; данные ME28. */ + Uint16 ME28:1; // 28 Enable Mailbox 28 + /* Битовое поле ME29, ширина 1 бит; данные ME29. */ + Uint16 ME29:1; // 29 Enable Mailbox 29 + /* Битовое поле ME30, ширина 1 бит; данные ME30. */ + Uint16 ME30:1; // 30 Enable Mailbox 30 + /* Битовое поле ME31, ширина 1 бит; данные ME31. */ + Uint16 ME31:1; // 31 Enable Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANME_REG в одной области памяти. */ +union CANME_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANME_BITS bit;; порядок полей определяет расположение данных. */ + struct CANME_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Mailbox direction register (CANMD) bit definitions */ +/* Описывает структуру CANMD_BITS; порядок полей определяет расположение данных. */ +struct CANMD_BITS { // bit description + /* Битовое поле MD0, ширина 1 бит; данные MD0. */ + Uint16 MD0:1; // 0 0 -> Tx 1 -> Rx + /* Битовое поле MD1, ширина 1 бит; данные MD1. */ + Uint16 MD1:1; // 1 0 -> Tx 1 -> Rx + /* Битовое поле MD2, ширина 1 бит; данные MD2. */ + Uint16 MD2:1; // 2 0 -> Tx 1 -> Rx + /* Битовое поле MD3, ширина 1 бит; данные MD3. */ + Uint16 MD3:1; // 3 0 -> Tx 1 -> Rx + /* Битовое поле MD4, ширина 1 бит; данные MD4. */ + Uint16 MD4:1; // 4 0 -> Tx 1 -> Rx + /* Битовое поле MD5, ширина 1 бит; данные MD5. */ + Uint16 MD5:1; // 5 0 -> Tx 1 -> Rx + /* Битовое поле MD6, ширина 1 бит; данные MD6. */ + Uint16 MD6:1; // 6 0 -> Tx 1 -> Rx + /* Битовое поле MD7, ширина 1 бит; данные MD7. */ + Uint16 MD7:1; // 7 0 -> Tx 1 -> Rx + /* Битовое поле MD8, ширина 1 бит; данные MD8. */ + Uint16 MD8:1; // 8 0 -> Tx 1 -> Rx + /* Битовое поле MD9, ширина 1 бит; данные MD9. */ + Uint16 MD9:1; // 9 0 -> Tx 1 -> Rx + /* Битовое поле MD10, ширина 1 бит; данные MD10. */ + Uint16 MD10:1; // 10 0 -> Tx 1 -> Rx + /* Битовое поле MD11, ширина 1 бит; данные MD11. */ + Uint16 MD11:1; // 11 0 -> Tx 1 -> Rx + /* Битовое поле MD12, ширина 1 бит; данные MD12. */ + Uint16 MD12:1; // 12 0 -> Tx 1 -> Rx + /* Битовое поле MD13, ширина 1 бит; данные MD13. */ + Uint16 MD13:1; // 13 0 -> Tx 1 -> Rx + /* Битовое поле MD14, ширина 1 бит; данные MD14. */ + Uint16 MD14:1; // 14 0 -> Tx 1 -> Rx + /* Битовое поле MD15, ширина 1 бит; данные MD15. */ + Uint16 MD15:1; // 15 0 -> Tx 1 -> Rx + /* Битовое поле MD16, ширина 1 бит; данные MD16. */ + Uint16 MD16:1; // 16 0 -> Tx 1 -> Rx + /* Битовое поле MD17, ширина 1 бит; данные MD17. */ + Uint16 MD17:1; // 17 0 -> Tx 1 -> Rx + /* Битовое поле MD18, ширина 1 бит; данные MD18. */ + Uint16 MD18:1; // 18 0 -> Tx 1 -> Rx + /* Битовое поле MD19, ширина 1 бит; данные MD19. */ + Uint16 MD19:1; // 19 0 -> Tx 1 -> Rx + /* Битовое поле MD20, ширина 1 бит; данные MD20. */ + Uint16 MD20:1; // 20 0 -> Tx 1 -> Rx + /* Битовое поле MD21, ширина 1 бит; данные MD21. */ + Uint16 MD21:1; // 21 0 -> Tx 1 -> Rx + /* Битовое поле MD22, ширина 1 бит; данные MD22. */ + Uint16 MD22:1; // 22 0 -> Tx 1 -> Rx + /* Битовое поле MD23, ширина 1 бит; данные MD23. */ + Uint16 MD23:1; // 23 0 -> Tx 1 -> Rx + /* Битовое поле MD24, ширина 1 бит; данные MD24. */ + Uint16 MD24:1; // 24 0 -> Tx 1 -> Rx + /* Битовое поле MD25, ширина 1 бит; данные MD25. */ + Uint16 MD25:1; // 25 0 -> Tx 1 -> Rx + /* Битовое поле MD26, ширина 1 бит; данные MD26. */ + Uint16 MD26:1; // 26 0 -> Tx 1 -> Rx + /* Битовое поле MD27, ширина 1 бит; данные MD27. */ + Uint16 MD27:1; // 27 0 -> Tx 1 -> Rx + /* Битовое поле MD28, ширина 1 бит; данные MD28. */ + Uint16 MD28:1; // 28 0 -> Tx 1 -> Rx + /* Битовое поле MD29, ширина 1 бит; данные MD29. */ + Uint16 MD29:1; // 29 0 -> Tx 1 -> Rx + /* Битовое поле MD30, ширина 1 бит; данные MD30. */ + Uint16 MD30:1; // 30 0 -> Tx 1 -> Rx + /* Битовое поле MD31, ширина 1 бит; данные MD31. */ + Uint16 MD31:1; // 31 0 -> Tx 1 -> Rx + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMD_REG в одной области памяти. */ +union CANMD_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMD_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMD_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Request Set register (CANTRS) bit definitions */ +/* Описывает структуру CANTRS_BITS; порядок полей определяет расположение данных. */ +struct CANTRS_BITS { // bit description + /* Битовое поле TRS0, ширина 1 бит; данные TRS0. */ + Uint16 TRS0:1; // 0 TRS for Mailbox 0 + /* Битовое поле TRS1, ширина 1 бит; данные TRS1. */ + Uint16 TRS1:1; // 1 TRS for Mailbox 1 + /* Битовое поле TRS2, ширина 1 бит; данные TRS2. */ + Uint16 TRS2:1; // 2 TRS for Mailbox 2 + /* Битовое поле TRS3, ширина 1 бит; данные TRS3. */ + Uint16 TRS3:1; // 3 TRS for Mailbox 3 + /* Битовое поле TRS4, ширина 1 бит; данные TRS4. */ + Uint16 TRS4:1; // 4 TRS for Mailbox 4 + /* Битовое поле TRS5, ширина 1 бит; данные TRS5. */ + Uint16 TRS5:1; // 5 TRS for Mailbox 5 + /* Битовое поле TRS6, ширина 1 бит; данные TRS6. */ + Uint16 TRS6:1; // 6 TRS for Mailbox 6 + /* Битовое поле TRS7, ширина 1 бит; данные TRS7. */ + Uint16 TRS7:1; // 7 TRS for Mailbox 7 + /* Битовое поле TRS8, ширина 1 бит; данные TRS8. */ + Uint16 TRS8:1; // 8 TRS for Mailbox 8 + /* Битовое поле TRS9, ширина 1 бит; данные TRS9. */ + Uint16 TRS9:1; // 9 TRS for Mailbox 9 + /* Битовое поле TRS10, ширина 1 бит; данные TRS10. */ + Uint16 TRS10:1; // 10 TRS for Mailbox 10 + /* Битовое поле TRS11, ширина 1 бит; данные TRS11. */ + Uint16 TRS11:1; // 11 TRS for Mailbox 11 + /* Битовое поле TRS12, ширина 1 бит; данные TRS12. */ + Uint16 TRS12:1; // 12 TRS for Mailbox 12 + /* Битовое поле TRS13, ширина 1 бит; данные TRS13. */ + Uint16 TRS13:1; // 13 TRS for Mailbox 13 + /* Битовое поле TRS14, ширина 1 бит; данные TRS14. */ + Uint16 TRS14:1; // 14 TRS for Mailbox 14 + /* Битовое поле TRS15, ширина 1 бит; данные TRS15. */ + Uint16 TRS15:1; // 15 TRS for Mailbox 15 + /* Битовое поле TRS16, ширина 1 бит; данные TRS16. */ + Uint16 TRS16:1; // 16 TRS for Mailbox 16 + /* Битовое поле TRS17, ширина 1 бит; данные TRS17. */ + Uint16 TRS17:1; // 17 TRS for Mailbox 17 + /* Битовое поле TRS18, ширина 1 бит; данные TRS18. */ + Uint16 TRS18:1; // 18 TRS for Mailbox 18 + /* Битовое поле TRS19, ширина 1 бит; данные TRS19. */ + Uint16 TRS19:1; // 19 TRS for Mailbox 19 + /* Битовое поле TRS20, ширина 1 бит; данные TRS20. */ + Uint16 TRS20:1; // 20 TRS for Mailbox 20 + /* Битовое поле TRS21, ширина 1 бит; данные TRS21. */ + Uint16 TRS21:1; // 21 TRS for Mailbox 21 + /* Битовое поле TRS22, ширина 1 бит; данные TRS22. */ + Uint16 TRS22:1; // 22 TRS for Mailbox 22 + /* Битовое поле TRS23, ширина 1 бит; данные TRS23. */ + Uint16 TRS23:1; // 23 TRS for Mailbox 23 + /* Битовое поле TRS24, ширина 1 бит; данные TRS24. */ + Uint16 TRS24:1; // 24 TRS for Mailbox 24 + /* Битовое поле TRS25, ширина 1 бит; данные TRS25. */ + Uint16 TRS25:1; // 25 TRS for Mailbox 25 + /* Битовое поле TRS26, ширина 1 бит; данные TRS26. */ + Uint16 TRS26:1; // 26 TRS for Mailbox 26 + /* Битовое поле TRS27, ширина 1 бит; данные TRS27. */ + Uint16 TRS27:1; // 27 TRS for Mailbox 27 + /* Битовое поле TRS28, ширина 1 бит; данные TRS28. */ + Uint16 TRS28:1; // 28 TRS for Mailbox 28 + /* Битовое поле TRS29, ширина 1 бит; данные TRS29. */ + Uint16 TRS29:1; // 29 TRS for Mailbox 29 + /* Битовое поле TRS30, ширина 1 бит; данные TRS30. */ + Uint16 TRS30:1; // 30 TRS for Mailbox 30 + /* Битовое поле TRS31, ширина 1 бит; данные TRS31. */ + Uint16 TRS31:1; // 31 TRS for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTRS_REG в одной области памяти. */ +union CANTRS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTRS_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTRS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Request Reset register (CANTRR) bit definitions */ +/* Описывает структуру CANTRR_BITS; порядок полей определяет расположение данных. */ +struct CANTRR_BITS { // bit description + /* Битовое поле TRR0, ширина 1 бит; данные TRR0. */ + Uint16 TRR0:1; // 0 TRR for Mailbox 0 + /* Битовое поле TRR1, ширина 1 бит; данные TRR1. */ + Uint16 TRR1:1; // 1 TRR for Mailbox 1 + /* Битовое поле TRR2, ширина 1 бит; данные TRR2. */ + Uint16 TRR2:1; // 2 TRR for Mailbox 2 + /* Битовое поле TRR3, ширина 1 бит; данные TRR3. */ + Uint16 TRR3:1; // 3 TRR for Mailbox 3 + /* Битовое поле TRR4, ширина 1 бит; данные TRR4. */ + Uint16 TRR4:1; // 4 TRR for Mailbox 4 + /* Битовое поле TRR5, ширина 1 бит; данные TRR5. */ + Uint16 TRR5:1; // 5 TRR for Mailbox 5 + /* Битовое поле TRR6, ширина 1 бит; данные TRR6. */ + Uint16 TRR6:1; // 6 TRR for Mailbox 6 + /* Битовое поле TRR7, ширина 1 бит; данные TRR7. */ + Uint16 TRR7:1; // 7 TRR for Mailbox 7 + /* Битовое поле TRR8, ширина 1 бит; данные TRR8. */ + Uint16 TRR8:1; // 8 TRR for Mailbox 8 + /* Битовое поле TRR9, ширина 1 бит; данные TRR9. */ + Uint16 TRR9:1; // 9 TRR for Mailbox 9 + /* Битовое поле TRR10, ширина 1 бит; данные TRR10. */ + Uint16 TRR10:1; // 10 TRR for Mailbox 10 + /* Битовое поле TRR11, ширина 1 бит; данные TRR11. */ + Uint16 TRR11:1; // 11 TRR for Mailbox 11 + /* Битовое поле TRR12, ширина 1 бит; данные TRR12. */ + Uint16 TRR12:1; // 12 TRR for Mailbox 12 + /* Битовое поле TRR13, ширина 1 бит; данные TRR13. */ + Uint16 TRR13:1; // 13 TRR for Mailbox 13 + /* Битовое поле TRR14, ширина 1 бит; данные TRR14. */ + Uint16 TRR14:1; // 14 TRR for Mailbox 14 + /* Битовое поле TRR15, ширина 1 бит; данные TRR15. */ + Uint16 TRR15:1; // 15 TRR for Mailbox 15 + /* Битовое поле TRR16, ширина 1 бит; данные TRR16. */ + Uint16 TRR16:1; // 16 TRR for Mailbox 16 + /* Битовое поле TRR17, ширина 1 бит; данные TRR17. */ + Uint16 TRR17:1; // 17 TRR for Mailbox 17 + /* Битовое поле TRR18, ширина 1 бит; данные TRR18. */ + Uint16 TRR18:1; // 18 TRR for Mailbox 18 + /* Битовое поле TRR19, ширина 1 бит; данные TRR19. */ + Uint16 TRR19:1; // 19 TRR for Mailbox 19 + /* Битовое поле TRR20, ширина 1 бит; данные TRR20. */ + Uint16 TRR20:1; // 20 TRR for Mailbox 20 + /* Битовое поле TRR21, ширина 1 бит; данные TRR21. */ + Uint16 TRR21:1; // 21 TRR for Mailbox 21 + /* Битовое поле TRR22, ширина 1 бит; данные TRR22. */ + Uint16 TRR22:1; // 22 TRR for Mailbox 22 + /* Битовое поле TRR23, ширина 1 бит; данные TRR23. */ + Uint16 TRR23:1; // 23 TRR for Mailbox 23 + /* Битовое поле TRR24, ширина 1 бит; данные TRR24. */ + Uint16 TRR24:1; // 24 TRR for Mailbox 24 + /* Битовое поле TRR25, ширина 1 бит; данные TRR25. */ + Uint16 TRR25:1; // 25 TRR for Mailbox 25 + /* Битовое поле TRR26, ширина 1 бит; данные TRR26. */ + Uint16 TRR26:1; // 26 TRR for Mailbox 26 + /* Битовое поле TRR27, ширина 1 бит; данные TRR27. */ + Uint16 TRR27:1; // 27 TRR for Mailbox 27 + /* Битовое поле TRR28, ширина 1 бит; данные TRR28. */ + Uint16 TRR28:1; // 28 TRR for Mailbox 28 + /* Битовое поле TRR29, ширина 1 бит; данные TRR29. */ + Uint16 TRR29:1; // 29 TRR for Mailbox 29 + /* Битовое поле TRR30, ширина 1 бит; данные TRR30. */ + Uint16 TRR30:1; // 30 TRR for Mailbox 30 + /* Битовое поле TRR31, ширина 1 бит; данные TRR31. */ + Uint16 TRR31:1; // 31 TRR for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTRR_REG в одной области памяти. */ +union CANTRR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTRR_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTRR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Acknowledge register (CANTA) bit definitions */ +/* Описывает структуру CANTA_BITS; порядок полей определяет расположение данных. */ +struct CANTA_BITS { // bit description + /* Битовое поле TA0, ширина 1 бит; данные TA0. */ + Uint16 TA0:1; // 0 TA for Mailbox 0 + /* Битовое поле TA1, ширина 1 бит; данные TA1. */ + Uint16 TA1:1; // 1 TA for Mailbox 1 + /* Битовое поле TA2, ширина 1 бит; данные TA2. */ + Uint16 TA2:1; // 2 TA for Mailbox 2 + /* Битовое поле TA3, ширина 1 бит; данные TA3. */ + Uint16 TA3:1; // 3 TA for Mailbox 3 + /* Битовое поле TA4, ширина 1 бит; данные TA4. */ + Uint16 TA4:1; // 4 TA for Mailbox 4 + /* Битовое поле TA5, ширина 1 бит; данные TA5. */ + Uint16 TA5:1; // 5 TA for Mailbox 5 + /* Битовое поле TA6, ширина 1 бит; данные TA6. */ + Uint16 TA6:1; // 6 TA for Mailbox 6 + /* Битовое поле TA7, ширина 1 бит; данные TA7. */ + Uint16 TA7:1; // 7 TA for Mailbox 7 + /* Битовое поле TA8, ширина 1 бит; данные TA8. */ + Uint16 TA8:1; // 8 TA for Mailbox 8 + /* Битовое поле TA9, ширина 1 бит; данные TA9. */ + Uint16 TA9:1; // 9 TA for Mailbox 9 + /* Битовое поле TA10, ширина 1 бит; данные TA10. */ + Uint16 TA10:1; // 10 TA for Mailbox 10 + /* Битовое поле TA11, ширина 1 бит; данные TA11. */ + Uint16 TA11:1; // 11 TA for Mailbox 11 + /* Битовое поле TA12, ширина 1 бит; данные TA12. */ + Uint16 TA12:1; // 12 TA for Mailbox 12 + /* Битовое поле TA13, ширина 1 бит; данные TA13. */ + Uint16 TA13:1; // 13 TA for Mailbox 13 + /* Битовое поле TA14, ширина 1 бит; данные TA14. */ + Uint16 TA14:1; // 14 TA for Mailbox 14 + /* Битовое поле TA15, ширина 1 бит; данные TA15. */ + Uint16 TA15:1; // 15 TA for Mailbox 15 + /* Битовое поле TA16, ширина 1 бит; данные TA16. */ + Uint16 TA16:1; // 16 TA for Mailbox 16 + /* Битовое поле TA17, ширина 1 бит; данные TA17. */ + Uint16 TA17:1; // 17 TA for Mailbox 17 + /* Битовое поле TA18, ширина 1 бит; данные TA18. */ + Uint16 TA18:1; // 18 TA for Mailbox 18 + /* Битовое поле TA19, ширина 1 бит; данные TA19. */ + Uint16 TA19:1; // 19 TA for Mailbox 19 + /* Битовое поле TA20, ширина 1 бит; данные TA20. */ + Uint16 TA20:1; // 20 TA for Mailbox 20 + /* Битовое поле TA21, ширина 1 бит; данные TA21. */ + Uint16 TA21:1; // 21 TA for Mailbox 21 + /* Битовое поле TA22, ширина 1 бит; данные TA22. */ + Uint16 TA22:1; // 22 TA for Mailbox 22 + /* Битовое поле TA23, ширина 1 бит; данные TA23. */ + Uint16 TA23:1; // 23 TA for Mailbox 23 + /* Битовое поле TA24, ширина 1 бит; данные TA24. */ + Uint16 TA24:1; // 24 TA for Mailbox 24 + /* Битовое поле TA25, ширина 1 бит; данные TA25. */ + Uint16 TA25:1; // 25 TA for Mailbox 25 + /* Битовое поле TA26, ширина 1 бит; данные TA26. */ + Uint16 TA26:1; // 26 TA for Mailbox 26 + /* Битовое поле TA27, ширина 1 бит; данные TA27. */ + Uint16 TA27:1; // 27 TA for Mailbox 27 + /* Битовое поле TA28, ширина 1 бит; данные TA28. */ + Uint16 TA28:1; // 28 TA for Mailbox 28 + /* Битовое поле TA29, ширина 1 бит; данные TA29. */ + Uint16 TA29:1; // 29 TA for Mailbox 29 + /* Битовое поле TA30, ширина 1 бит; данные TA30. */ + Uint16 TA30:1; // 30 TA for Mailbox 30 + /* Битовое поле TA31, ширина 1 бит; данные TA31. */ + Uint16 TA31:1; // 31 TA for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTA_REG в одной области памяти. */ +union CANTA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTA_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Abort Acknowledge register (CANAA) bit definitions */ +/* Описывает структуру CANAA_BITS; порядок полей определяет расположение данных. */ +struct CANAA_BITS { // bit description + /* Битовое поле AA0, ширина 1 бит; данные AA0. */ + Uint16 AA0:1; // 0 AA for Mailbox 0 + /* Битовое поле AA1, ширина 1 бит; данные AA1. */ + Uint16 AA1:1; // 1 AA for Mailbox 1 + /* Битовое поле AA2, ширина 1 бит; данные AA2. */ + Uint16 AA2:1; // 2 AA for Mailbox 2 + /* Битовое поле AA3, ширина 1 бит; данные AA3. */ + Uint16 AA3:1; // 3 AA for Mailbox 3 + /* Битовое поле AA4, ширина 1 бит; данные AA4. */ + Uint16 AA4:1; // 4 AA for Mailbox 4 + /* Битовое поле AA5, ширина 1 бит; данные AA5. */ + Uint16 AA5:1; // 5 AA for Mailbox 5 + /* Битовое поле AA6, ширина 1 бит; данные AA6. */ + Uint16 AA6:1; // 6 AA for Mailbox 6 + /* Битовое поле AA7, ширина 1 бит; данные AA7. */ + Uint16 AA7:1; // 7 AA for Mailbox 7 + /* Битовое поле AA8, ширина 1 бит; данные AA8. */ + Uint16 AA8:1; // 8 AA for Mailbox 8 + /* Битовое поле AA9, ширина 1 бит; данные AA9. */ + Uint16 AA9:1; // 9 AA for Mailbox 9 + /* Битовое поле AA10, ширина 1 бит; данные AA10. */ + Uint16 AA10:1; // 10 AA for Mailbox 10 + /* Битовое поле AA11, ширина 1 бит; данные AA11. */ + Uint16 AA11:1; // 11 AA for Mailbox 11 + /* Битовое поле AA12, ширина 1 бит; данные AA12. */ + Uint16 AA12:1; // 12 AA for Mailbox 12 + /* Битовое поле AA13, ширина 1 бит; данные AA13. */ + Uint16 AA13:1; // 13 AA for Mailbox 13 + /* Битовое поле AA14, ширина 1 бит; данные AA14. */ + Uint16 AA14:1; // 14 AA for Mailbox 14 + /* Битовое поле AA15, ширина 1 бит; данные AA15. */ + Uint16 AA15:1; // 15 AA for Mailbox 15 + /* Битовое поле AA16, ширина 1 бит; данные AA16. */ + Uint16 AA16:1; // 16 AA for Mailbox 16 + /* Битовое поле AA17, ширина 1 бит; данные AA17. */ + Uint16 AA17:1; // 17 AA for Mailbox 17 + /* Битовое поле AA18, ширина 1 бит; данные AA18. */ + Uint16 AA18:1; // 18 AA for Mailbox 18 + /* Битовое поле AA19, ширина 1 бит; данные AA19. */ + Uint16 AA19:1; // 19 AA for Mailbox 19 + /* Битовое поле AA20, ширина 1 бит; данные AA20. */ + Uint16 AA20:1; // 20 AA for Mailbox 20 + /* Битовое поле AA21, ширина 1 бит; данные AA21. */ + Uint16 AA21:1; // 21 AA for Mailbox 21 + /* Битовое поле AA22, ширина 1 бит; данные AA22. */ + Uint16 AA22:1; // 22 AA for Mailbox 22 + /* Битовое поле AA23, ширина 1 бит; данные AA23. */ + Uint16 AA23:1; // 23 AA for Mailbox 23 + /* Битовое поле AA24, ширина 1 бит; данные AA24. */ + Uint16 AA24:1; // 24 AA for Mailbox 24 + /* Битовое поле AA25, ширина 1 бит; данные AA25. */ + Uint16 AA25:1; // 25 AA for Mailbox 25 + /* Битовое поле AA26, ширина 1 бит; данные AA26. */ + Uint16 AA26:1; // 26 AA for Mailbox 26 + /* Битовое поле AA27, ширина 1 бит; данные AA27. */ + Uint16 AA27:1; // 27 AA for Mailbox 27 + /* Битовое поле AA28, ширина 1 бит; данные AA28. */ + Uint16 AA28:1; // 28 AA for Mailbox 28 + /* Битовое поле AA29, ширина 1 бит; данные AA29. */ + Uint16 AA29:1; // 29 AA for Mailbox 29 + /* Битовое поле AA30, ширина 1 бит; данные AA30. */ + Uint16 AA30:1; // 30 AA for Mailbox 30 + /* Битовое поле AA31, ширина 1 бит; данные AA31. */ + Uint16 AA31:1; // 31 AA for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANAA_REG в одной области памяти. */ +union CANAA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANAA_BITS bit;; порядок полей определяет расположение данных. */ + struct CANAA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Received Message Pending register (CANRMP) bit definitions */ +/* Описывает структуру CANRMP_BITS; порядок полей определяет расположение данных. */ +struct CANRMP_BITS { // bit description + /* Битовое поле RMP0, ширина 1 бит; данные RMP0. */ + Uint16 RMP0:1; // 0 RMP for Mailbox 0 + /* Битовое поле RMP1, ширина 1 бит; данные RMP1. */ + Uint16 RMP1:1; // 1 RMP for Mailbox 1 + /* Битовое поле RMP2, ширина 1 бит; данные RMP2. */ + Uint16 RMP2:1; // 2 RMP for Mailbox 2 + /* Битовое поле RMP3, ширина 1 бит; данные RMP3. */ + Uint16 RMP3:1; // 3 RMP for Mailbox 3 + /* Битовое поле RMP4, ширина 1 бит; данные RMP4. */ + Uint16 RMP4:1; // 4 RMP for Mailbox 4 + /* Битовое поле RMP5, ширина 1 бит; данные RMP5. */ + Uint16 RMP5:1; // 5 RMP for Mailbox 5 + /* Битовое поле RMP6, ширина 1 бит; данные RMP6. */ + Uint16 RMP6:1; // 6 RMP for Mailbox 6 + /* Битовое поле RMP7, ширина 1 бит; данные RMP7. */ + Uint16 RMP7:1; // 7 RMP for Mailbox 7 + /* Битовое поле RMP8, ширина 1 бит; данные RMP8. */ + Uint16 RMP8:1; // 8 RMP for Mailbox 8 + /* Битовое поле RMP9, ширина 1 бит; данные RMP9. */ + Uint16 RMP9:1; // 9 RMP for Mailbox 9 + /* Битовое поле RMP10, ширина 1 бит; данные RMP10. */ + Uint16 RMP10:1; // 10 RMP for Mailbox 10 + /* Битовое поле RMP11, ширина 1 бит; данные RMP11. */ + Uint16 RMP11:1; // 11 RMP for Mailbox 11 + /* Битовое поле RMP12, ширина 1 бит; данные RMP12. */ + Uint16 RMP12:1; // 12 RMP for Mailbox 12 + /* Битовое поле RMP13, ширина 1 бит; данные RMP13. */ + Uint16 RMP13:1; // 13 RMP for Mailbox 13 + /* Битовое поле RMP14, ширина 1 бит; данные RMP14. */ + Uint16 RMP14:1; // 14 RMP for Mailbox 14 + /* Битовое поле RMP15, ширина 1 бит; данные RMP15. */ + Uint16 RMP15:1; // 15 RMP for Mailbox 15 + /* Битовое поле RMP16, ширина 1 бит; данные RMP16. */ + Uint16 RMP16:1; // 16 RMP for Mailbox 16 + /* Битовое поле RMP17, ширина 1 бит; данные RMP17. */ + Uint16 RMP17:1; // 17 RMP for Mailbox 17 + /* Битовое поле RMP18, ширина 1 бит; данные RMP18. */ + Uint16 RMP18:1; // 18 RMP for Mailbox 18 + /* Битовое поле RMP19, ширина 1 бит; данные RMP19. */ + Uint16 RMP19:1; // 19 RMP for Mailbox 19 + /* Битовое поле RMP20, ширина 1 бит; данные RMP20. */ + Uint16 RMP20:1; // 20 RMP for Mailbox 20 + /* Битовое поле RMP21, ширина 1 бит; данные RMP21. */ + Uint16 RMP21:1; // 21 RMP for Mailbox 21 + /* Битовое поле RMP22, ширина 1 бит; данные RMP22. */ + Uint16 RMP22:1; // 22 RMP for Mailbox 22 + /* Битовое поле RMP23, ширина 1 бит; данные RMP23. */ + Uint16 RMP23:1; // 23 RMP for Mailbox 23 + /* Битовое поле RMP24, ширина 1 бит; данные RMP24. */ + Uint16 RMP24:1; // 24 RMP for Mailbox 24 + /* Битовое поле RMP25, ширина 1 бит; данные RMP25. */ + Uint16 RMP25:1; // 25 RMP for Mailbox 25 + /* Битовое поле RMP26, ширина 1 бит; данные RMP26. */ + Uint16 RMP26:1; // 26 RMP for Mailbox 26 + /* Битовое поле RMP27, ширина 1 бит; данные RMP27. */ + Uint16 RMP27:1; // 27 RMP for Mailbox 27 + /* Битовое поле RMP28, ширина 1 бит; данные RMP28. */ + Uint16 RMP28:1; // 28 RMP for Mailbox 28 + /* Битовое поле RMP29, ширина 1 бит; данные RMP29. */ + Uint16 RMP29:1; // 29 RMP for Mailbox 29 + /* Битовое поле RMP30, ширина 1 бит; данные RMP30. */ + Uint16 RMP30:1; // 30 RMP for Mailbox 30 + /* Битовое поле RMP31, ширина 1 бит; данные RMP31. */ + Uint16 RMP31:1; // 31 RMP for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRMP_REG в одной области памяти. */ +union CANRMP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRMP_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRMP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Received Message Lost register (CANRML) bit definitions */ +/* Описывает структуру CANRML_BITS; порядок полей определяет расположение данных. */ +struct CANRML_BITS { // bit description + /* Битовое поле RML0, ширина 1 бит; данные RML0. */ + Uint16 RML0:1; // 0 RML for Mailbox 0 + /* Битовое поле RML1, ширина 1 бит; данные RML1. */ + Uint16 RML1:1; // 1 RML for Mailbox 1 + /* Битовое поле RML2, ширина 1 бит; данные RML2. */ + Uint16 RML2:1; // 2 RML for Mailbox 2 + /* Битовое поле RML3, ширина 1 бит; данные RML3. */ + Uint16 RML3:1; // 3 RML for Mailbox 3 + /* Битовое поле RML4, ширина 1 бит; данные RML4. */ + Uint16 RML4:1; // 4 RML for Mailbox 4 + /* Битовое поле RML5, ширина 1 бит; данные RML5. */ + Uint16 RML5:1; // 5 RML for Mailbox 5 + /* Битовое поле RML6, ширина 1 бит; данные RML6. */ + Uint16 RML6:1; // 6 RML for Mailbox 6 + /* Битовое поле RML7, ширина 1 бит; данные RML7. */ + Uint16 RML7:1; // 7 RML for Mailbox 7 + /* Битовое поле RML8, ширина 1 бит; данные RML8. */ + Uint16 RML8:1; // 8 RML for Mailbox 8 + /* Битовое поле RML9, ширина 1 бит; данные RML9. */ + Uint16 RML9:1; // 9 RML for Mailbox 9 + /* Битовое поле RML10, ширина 1 бит; данные RML10. */ + Uint16 RML10:1; // 10 RML for Mailbox 10 + /* Битовое поле RML11, ширина 1 бит; данные RML11. */ + Uint16 RML11:1; // 11 RML for Mailbox 11 + /* Битовое поле RML12, ширина 1 бит; данные RML12. */ + Uint16 RML12:1; // 12 RML for Mailbox 12 + /* Битовое поле RML13, ширина 1 бит; данные RML13. */ + Uint16 RML13:1; // 13 RML for Mailbox 13 + /* Битовое поле RML14, ширина 1 бит; данные RML14. */ + Uint16 RML14:1; // 14 RML for Mailbox 14 + /* Битовое поле RML15, ширина 1 бит; данные RML15. */ + Uint16 RML15:1; // 15 RML for Mailbox 15 + /* Битовое поле RML16, ширина 1 бит; данные RML16. */ + Uint16 RML16:1; // 16 RML for Mailbox 16 + /* Битовое поле RML17, ширина 1 бит; данные RML17. */ + Uint16 RML17:1; // 17 RML for Mailbox 17 + /* Битовое поле RML18, ширина 1 бит; данные RML18. */ + Uint16 RML18:1; // 18 RML for Mailbox 18 + /* Битовое поле RML19, ширина 1 бит; данные RML19. */ + Uint16 RML19:1; // 19 RML for Mailbox 19 + /* Битовое поле RML20, ширина 1 бит; данные RML20. */ + Uint16 RML20:1; // 20 RML for Mailbox 20 + /* Битовое поле RML21, ширина 1 бит; данные RML21. */ + Uint16 RML21:1; // 21 RML for Mailbox 21 + /* Битовое поле RML22, ширина 1 бит; данные RML22. */ + Uint16 RML22:1; // 22 RML for Mailbox 22 + /* Битовое поле RML23, ширина 1 бит; данные RML23. */ + Uint16 RML23:1; // 23 RML for Mailbox 23 + /* Битовое поле RML24, ширина 1 бит; данные RML24. */ + Uint16 RML24:1; // 24 RML for Mailbox 24 + /* Битовое поле RML25, ширина 1 бит; данные RML25. */ + Uint16 RML25:1; // 25 RML for Mailbox 25 + /* Битовое поле RML26, ширина 1 бит; данные RML26. */ + Uint16 RML26:1; // 26 RML for Mailbox 26 + /* Битовое поле RML27, ширина 1 бит; данные RML27. */ + Uint16 RML27:1; // 27 RML for Mailbox 27 + /* Битовое поле RML28, ширина 1 бит; данные RML28. */ + Uint16 RML28:1; // 28 RML for Mailbox 28 + /* Битовое поле RML29, ширина 1 бит; данные RML29. */ + Uint16 RML29:1; // 29 RML for Mailbox 29 + /* Битовое поле RML30, ширина 1 бит; данные RML30. */ + Uint16 RML30:1; // 30 RML for Mailbox 30 + /* Битовое поле RML31, ширина 1 бит; данные RML31. */ + Uint16 RML31:1; // 31 RML for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRML_REG в одной области памяти. */ +union CANRML_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRML_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRML_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Remote Frame Pending register (CANRFP) bit definitions */ +/* Описывает структуру CANRFP_BITS; порядок полей определяет расположение данных. */ +struct CANRFP_BITS { // bit description + /* Битовое поле RFP0, ширина 1 бит; данные RFP0. */ + Uint16 RFP0:1; // 0 RFP for Mailbox 0 + /* Битовое поле RFP1, ширина 1 бит; данные RFP1. */ + Uint16 RFP1:1; // 1 RFP for Mailbox 1 + /* Битовое поле RFP2, ширина 1 бит; данные RFP2. */ + Uint16 RFP2:1; // 2 RFP for Mailbox 2 + /* Битовое поле RFP3, ширина 1 бит; данные RFP3. */ + Uint16 RFP3:1; // 3 RFP for Mailbox 3 + /* Битовое поле RFP4, ширина 1 бит; данные RFP4. */ + Uint16 RFP4:1; // 4 RFP for Mailbox 4 + /* Битовое поле RFP5, ширина 1 бит; данные RFP5. */ + Uint16 RFP5:1; // 5 RFP for Mailbox 5 + /* Битовое поле RFP6, ширина 1 бит; данные RFP6. */ + Uint16 RFP6:1; // 6 RFP for Mailbox 6 + /* Битовое поле RFP7, ширина 1 бит; данные RFP7. */ + Uint16 RFP7:1; // 7 RFP for Mailbox 7 + /* Битовое поле RFP8, ширина 1 бит; данные RFP8. */ + Uint16 RFP8:1; // 8 RFP for Mailbox 8 + /* Битовое поле RFP9, ширина 1 бит; данные RFP9. */ + Uint16 RFP9:1; // 9 RFP for Mailbox 9 + /* Битовое поле RFP10, ширина 1 бит; данные RFP10. */ + Uint16 RFP10:1; // 10 RFP for Mailbox 10 + /* Битовое поле RFP11, ширина 1 бит; данные RFP11. */ + Uint16 RFP11:1; // 11 RFP for Mailbox 11 + /* Битовое поле RFP12, ширина 1 бит; данные RFP12. */ + Uint16 RFP12:1; // 12 RFP for Mailbox 12 + /* Битовое поле RFP13, ширина 1 бит; данные RFP13. */ + Uint16 RFP13:1; // 13 RFP for Mailbox 13 + /* Битовое поле RFP14, ширина 1 бит; данные RFP14. */ + Uint16 RFP14:1; // 14 RFP for Mailbox 14 + /* Битовое поле RFP15, ширина 1 бит; данные RFP15. */ + Uint16 RFP15:1; // 15 RFP for Mailbox 15 + /* Битовое поле RFP16, ширина 1 бит; данные RFP16. */ + Uint16 RFP16:1; // 16 RFP for Mailbox 16 + /* Битовое поле RFP17, ширина 1 бит; данные RFP17. */ + Uint16 RFP17:1; // 17 RFP for Mailbox 17 + /* Битовое поле RFP18, ширина 1 бит; данные RFP18. */ + Uint16 RFP18:1; // 18 RFP for Mailbox 18 + /* Битовое поле RFP19, ширина 1 бит; данные RFP19. */ + Uint16 RFP19:1; // 19 RFP for Mailbox 19 + /* Битовое поле RFP20, ширина 1 бит; данные RFP20. */ + Uint16 RFP20:1; // 20 RFP for Mailbox 20 + /* Битовое поле RFP21, ширина 1 бит; данные RFP21. */ + Uint16 RFP21:1; // 21 RFP for Mailbox 21 + /* Битовое поле RFP22, ширина 1 бит; данные RFP22. */ + Uint16 RFP22:1; // 22 RFP for Mailbox 22 + /* Битовое поле RFP23, ширина 1 бит; данные RFP23. */ + Uint16 RFP23:1; // 23 RFP for Mailbox 23 + /* Битовое поле RFP24, ширина 1 бит; данные RFP24. */ + Uint16 RFP24:1; // 24 RFP for Mailbox 24 + /* Битовое поле RFP25, ширина 1 бит; данные RFP25. */ + Uint16 RFP25:1; // 25 RFP for Mailbox 25 + /* Битовое поле RFP26, ширина 1 бит; данные RFP26. */ + Uint16 RFP26:1; // 26 RFP for Mailbox 26 + /* Битовое поле RFP27, ширина 1 бит; данные RFP27. */ + Uint16 RFP27:1; // 27 RFP for Mailbox 27 + /* Битовое поле RFP28, ширина 1 бит; данные RFP28. */ + Uint16 RFP28:1; // 28 RFP for Mailbox 28 + /* Битовое поле RFP29, ширина 1 бит; данные RFP29. */ + Uint16 RFP29:1; // 29 RFP for Mailbox 29 + /* Битовое поле RFP30, ширина 1 бит; данные RFP30. */ + Uint16 RFP30:1; // 30 RFP for Mailbox 30 + /* Битовое поле RFP31, ширина 1 бит; данные RFP31. */ + Uint16 RFP31:1; // 31 RFP for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRFP_REG в одной области памяти. */ +union CANRFP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRFP_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRFP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Global Acceptance Mask register (CANGAM) bit definitions */ +/* Описывает структуру CANGAM_BITS; порядок полей определяет расположение данных. */ +struct CANGAM_BITS { // bits description + /* Битовое поле GAM150, ширина 16 бит; данные GAM150. */ + Uint16 GAM150:16; // 15:0 Global acceptance mask bits 0-15 + /* Битовое поле GAM2816, ширина 13 бит; данные GAM2816. */ + Uint16 GAM2816:13; // 28:16 Global acceptance mask bits 16-28 + /* Битовое поле rsvd, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:2; // 30:29 reserved + /* Битовое поле AMI, ширина 1 бит; данные AMI. */ + Uint16 AMI:1; // 31 AMI bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGAM_REG в одной области памяти. */ +union CANGAM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGAM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGAM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Master Control register (CANMC) bit definitions */ +/* Описывает структуру CANMC_BITS; порядок полей определяет расположение данных. */ +struct CANMC_BITS { // bits description + /* Битовое поле MBNR, ширина 5 бит; данные MBNR. */ + Uint16 MBNR:5; // 4:0 MBX # for CDR bit + /* Битовое поле SRES, ширина 1 бит; данные SRES. */ + Uint16 SRES:1; // 5 Soft reset + /* Битовое поле STM, ширина 1 бит; данные STM. */ + Uint16 STM:1; // 6 Self-test mode + /* Битовое поле ABO, ширина 1 бит; данные ABO. */ + Uint16 ABO:1; // 7 Auto bus-on + /* Битовое поле CDR, ширина 1 бит; данные CDR. */ + Uint16 CDR:1; // 8 Change data request + /* Битовое поле WUBA, ширина 1 бит; данные WUBA. */ + Uint16 WUBA:1; // 9 Wake-up on bus activity + /* Битовое поле DBO, ширина 1 бит; данные DBO. */ + Uint16 DBO:1; // 10 Data-byte order + /* Битовое поле PDR, ширина 1 бит; данные PDR. */ + Uint16 PDR:1; // 11 Power-down mode request + /* Битовое поле CCR, ширина 1 бит; данные CCR. */ + Uint16 CCR:1; // 12 Change configuration request + /* Битовое поле SCB, ширина 1 бит; данные SCB. */ + Uint16 SCB:1; // 13 SCC compatibility bit + /* Битовое поле TCC, ширина 1 бит; данные TCC. */ + Uint16 TCC:1; // 14 TSC MSB clear bit + /* Битовое поле MBCC, ширина 1 бит; данные MBCC. */ + Uint16 MBCC:1; // 15 TSC clear bit thru mailbox 16 + /* Битовое поле SUSP, ширина 1 бит; данные SUSP. */ + Uint16 SUSP:1; // 16 SUSPEND free/soft bit + /* Битовое поле rsvd, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:15; // 31:17 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMC_REG в одной области памяти. */ +union CANMC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Bit -timing configuration register (CANBTC) bit definitions */ +/* Описывает структуру CANBTC_BITS; порядок полей определяет расположение данных. */ +struct CANBTC_BITS { // bits description + /* Битовое поле TSEG2REG, ширина 3 бит; данные TSEG2REG. */ + Uint16 TSEG2REG:3; // 2:0 TSEG2 register value + /* Битовое поле TSEG1REG, ширина 4 бит; данные TSEG1REG. */ + Uint16 TSEG1REG:4; // 6:3 TSEG1 register value + /* Битовое поле SAM, ширина 1 бит; данные SAM. */ + Uint16 SAM:1; // 7 Sample-point setting + /* Битовое поле SJWREG, ширина 2 бит; данные SJWREG. */ + Uint16 SJWREG:2; // 9:8 Synchroniztion Jump Width register value + /* Битовое поле rsvd1, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:6; // 15:10 reserved + /* Битовое поле BRPREG, ширина 8 бит; данные BRPREG. */ + Uint16 BRPREG:8; // 23:16 Baudrate prescaler register value + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 31:24 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANBTC_REG в одной области памяти. */ +union CANBTC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANBTC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANBTC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Error & Status register (CANES) bit definitions */ +/* Описывает структуру CANES_BITS; порядок полей определяет расположение данных. */ +struct CANES_BITS { // bits description + /* Битовое поле TM, ширина 1 бит; данные TM. */ + Uint16 TM:1; // 0 Transmit Mode + /* Битовое поле RM, ширина 1 бит; данные RM. */ + Uint16 RM:1; // 1 Receive Mode + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 2 reserved + /* Битовое поле PDA, ширина 1 бит; данные PDA. */ + Uint16 PDA:1; // 3 Power-down acknowledge + /* Битовое поле CCE, ширина 1 бит; данные CCE. */ + Uint16 CCE:1; // 4 Change Configuration Enable + /* Битовое поле SMA, ширина 1 бит; данные SMA. */ + Uint16 SMA:1; // 5 Suspend Mode Acknowledge + /* Битовое поле rsvd2, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:10; // 15:6 reserved + /* Битовое поле EW, ширина 1 бит; данные EW. */ + Uint16 EW:1; // 16 Warning status + /* Битовое поле EP, ширина 1 бит; данные EP. */ + Uint16 EP:1; // 17 Error Passive status + /* Битовое поле BO, ширина 1 бит; данные BO. */ + Uint16 BO:1; // 18 Bus-off status + /* Битовое поле ACKE, ширина 1 бит; данные ACKE. */ + Uint16 ACKE:1; // 19 Acknowledge error + /* Битовое поле SE, ширина 1 бит; данные SE. */ + Uint16 SE:1; // 20 Stuff error + /* Битовое поле CRCE, ширина 1 бит; данные CRCE. */ + Uint16 CRCE:1; // 21 CRC error + /* Битовое поле SA1, ширина 1 бит; данные SA1. */ + Uint16 SA1:1; // 22 Stuck at Dominant error + /* Битовое поле BE, ширина 1 бит; данные BE. */ + Uint16 BE:1; // 23 Bit error + /* Битовое поле FE, ширина 1 бит; данные FE. */ + Uint16 FE:1; // 24 Framing error + /* Битовое поле rsvd3, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:7; // 31:25 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANES_REG в одной области памяти. */ +union CANES_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANES_BITS bit;; порядок полей определяет расположение данных. */ + struct CANES_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Transmit Error Counter register (CANTEC) bit definitions */ +/* Описывает структуру CANTEC_BITS; порядок полей определяет расположение данных. */ +struct CANTEC_BITS { // bits description + /* Битовое поле TEC, ширина 8 бит; данные TEC. */ + Uint16 TEC:8; // 7:0 TEC + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved + /* Битовое поле rsvd2, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTEC_REG в одной области памяти. */ +union CANTEC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTEC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTEC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Receive Error Counter register (CANREC) bit definitions */ +/* Описывает структуру CANREC_BITS; порядок полей определяет расположение данных. */ +struct CANREC_BITS { // bits description + /* Битовое поле REC, ширина 8 бит; данные REC. */ + Uint16 REC:8; // 7:0 REC + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved + /* Битовое поле rsvd2, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANREC_REG в одной области памяти. */ +union CANREC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANREC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANREC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Global Interrupt Flag 0 (CANGIF0) bit definitions */ +/* Описывает структуру CANGIF0_BITS; порядок полей определяет расположение данных. */ +struct CANGIF0_BITS { // bits description + /* Битовое поле MIV0, ширина 5 бит; данные MIV0. */ + Uint16 MIV0:5; // 4:0 Mailbox Interrupt Vector + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved + /* Битовое поле WLIF0, ширина 1 бит; данные WLIF0. */ + Uint16 WLIF0:1; // 8 Warning level interrupt flag + /* Битовое поле EPIF0, ширина 1 бит; данные EPIF0. */ + Uint16 EPIF0:1; // 9 Error-passive interrupt flag + /* Битовое поле BOIF0, ширина 1 бит; данные BOIF0. */ + Uint16 BOIF0:1; // 10 Bus-off interrupt flag + /* Битовое поле RMLIF0, ширина 1 бит; данные RMLIF0. */ + Uint16 RMLIF0:1; // 11 Received message lost interrupt flag + /* Битовое поле WUIF0, ширина 1 бит; данные WUIF0. */ + Uint16 WUIF0:1; // 12 Wakeup interrupt flag + /* Битовое поле WDIF0, ширина 1 бит; данные WDIF0. */ + Uint16 WDIF0:1; // 13 Write denied interrupt flag + /* Битовое поле AAIF0, ширина 1 бит; данные AAIF0. */ + Uint16 AAIF0:1; // 14 Abort Ack interrupt flag + /* Битовое поле GMIF0, ширина 1 бит; данные GMIF0. */ + Uint16 GMIF0:1; // 15 Global MBX interrupt flag + /* Битовое поле TCOF0, ширина 1 бит; данные TCOF0. */ + Uint16 TCOF0:1; // 16 TSC Overflow flag + /* Битовое поле MTOF0, ширина 1 бит; данные MTOF0. */ + Uint16 MTOF0:1; // 17 Mailbox Timeout flag + /* Битовое поле rsvd2, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:14; // 31:18 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGIF0_REG в одной области памяти. */ +union CANGIF0_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGIF0_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGIF0_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Global Interrupt Mask register (CANGIM) bit definitions */ +/* Описывает структуру CANGIM_BITS; порядок полей определяет расположение данных. */ +struct CANGIM_BITS { // bits description + /* Битовое поле I0EN, ширина 1 бит; данные I0EN. */ + Uint16 I0EN:1; // 0 Interrupt 0 enable + /* Битовое поле I1EN, ширина 1 бит; данные I1EN. */ + Uint16 I1EN:1; // 1 Interrupt 1 enable + /* Битовое поле GIL, ширина 1 бит; данные GIL. */ + Uint16 GIL:1; // 2 Global Interrupt Level + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 7:3 reserved + /* Битовое поле WLIM, ширина 1 бит; данные WLIM. */ + Uint16 WLIM:1; // 8 Warning level interrupt mask + /* Битовое поле EPIM, ширина 1 бит; данные EPIM. */ + Uint16 EPIM:1; // 9 Error-passive interrupt mask + /* Битовое поле BOIM, ширина 1 бит; данные BOIM. */ + Uint16 BOIM:1; // 10 Bus-off interrupt mask + /* Битовое поле RMLIM, ширина 1 бит; данные RMLIM. */ + Uint16 RMLIM:1; // 11 Received message lost interrupt mask + /* Битовое поле WUIM, ширина 1 бит; данные WUIM. */ + Uint16 WUIM:1; // 12 Wakeup interrupt mask + /* Битовое поле WDIM, ширина 1 бит; данные WDIM. */ + Uint16 WDIM:1; // 13 Write denied interrupt mask + /* Битовое поле AAIM, ширина 1 бит; данные AAIM. */ + Uint16 AAIM:1; // 14 Abort Ack interrupt mask + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved + /* Битовое поле TCOM, ширина 1 бит; данные TCOM. */ + Uint16 TCOM:1; // 16 TSC overflow interrupt mask + /* Битовое поле MTOM, ширина 1 бит; данные MTOM. */ + Uint16 MTOM:1; // 17 MBX Timeout interrupt mask + /* Битовое поле rsvd3, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:14; // 31:18 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGIM_REG в одной области памяти. */ +union CANGIM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGIM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGIM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Global Interrupt Flag 1 (eCANGIF1) bit definitions */ +/* Описывает структуру CANGIF1_BITS; порядок полей определяет расположение данных. */ +struct CANGIF1_BITS { // bits description + /* Битовое поле MIV1, ширина 5 бит; данные MIV1. */ + Uint16 MIV1:5; // 4:0 Mailbox Interrupt Vector + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved + /* Битовое поле WLIF1, ширина 1 бит; данные WLIF1. */ + Uint16 WLIF1:1; // 8 Warning level interrupt flag + /* Битовое поле EPIF1, ширина 1 бит; данные EPIF1. */ + Uint16 EPIF1:1; // 9 Error-passive interrupt flag + /* Битовое поле BOIF1, ширина 1 бит; данные BOIF1. */ + Uint16 BOIF1:1; // 10 Bus-off interrupt flag + /* Битовое поле RMLIF1, ширина 1 бит; данные RMLIF1. */ + Uint16 RMLIF1:1; // 11 Received message lost interrupt flag + /* Битовое поле WUIF1, ширина 1 бит; данные WUIF1. */ + Uint16 WUIF1:1; // 12 Wakeup interrupt flag + /* Битовое поле WDIF1, ширина 1 бит; данные WDIF1. */ + Uint16 WDIF1:1; // 13 Write denied interrupt flag + /* Битовое поле AAIF1, ширина 1 бит; данные AAIF1. */ + Uint16 AAIF1:1; // 14 Abort Ack interrupt flag + /* Битовое поле GMIF1, ширина 1 бит; данные GMIF1. */ + Uint16 GMIF1:1; // 15 Global MBX interrupt flag + /* Битовое поле TCOF1, ширина 1 бит; данные TCOF1. */ + Uint16 TCOF1:1; // 16 TSC Overflow flag + /* Битовое поле MTOF1, ширина 1 бит; данные MTOF1. */ + Uint16 MTOF1:1; // 17 Mailbox Timeout flag + /* Битовое поле rsvd2, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:14; // 31:18 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGIF1_REG в одной области памяти. */ +union CANGIF1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGIF1_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGIF1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Mailbox Interrupt Mask register (CANMIM) bit definitions */ +/* Описывает структуру CANMIM_BITS; порядок полей определяет расположение данных. */ +struct CANMIM_BITS { // bit description + /* Битовое поле MIM0, ширина 1 бит; данные MIM0. */ + Uint16 MIM0:1; // 0 MIM for Mailbox 0 + /* Битовое поле MIM1, ширина 1 бит; данные MIM1. */ + Uint16 MIM1:1; // 1 MIM for Mailbox 1 + /* Битовое поле MIM2, ширина 1 бит; данные MIM2. */ + Uint16 MIM2:1; // 2 MIM for Mailbox 2 + /* Битовое поле MIM3, ширина 1 бит; данные MIM3. */ + Uint16 MIM3:1; // 3 MIM for Mailbox 3 + /* Битовое поле MIM4, ширина 1 бит; данные MIM4. */ + Uint16 MIM4:1; // 4 MIM for Mailbox 4 + /* Битовое поле MIM5, ширина 1 бит; данные MIM5. */ + Uint16 MIM5:1; // 5 MIM for Mailbox 5 + /* Битовое поле MIM6, ширина 1 бит; данные MIM6. */ + Uint16 MIM6:1; // 6 MIM for Mailbox 6 + /* Битовое поле MIM7, ширина 1 бит; данные MIM7. */ + Uint16 MIM7:1; // 7 MIM for Mailbox 7 + /* Битовое поле MIM8, ширина 1 бит; данные MIM8. */ + Uint16 MIM8:1; // 8 MIM for Mailbox 8 + /* Битовое поле MIM9, ширина 1 бит; данные MIM9. */ + Uint16 MIM9:1; // 9 MIM for Mailbox 9 + /* Битовое поле MIM10, ширина 1 бит; данные MIM10. */ + Uint16 MIM10:1; // 10 MIM for Mailbox 10 + /* Битовое поле MIM11, ширина 1 бит; данные MIM11. */ + Uint16 MIM11:1; // 11 MIM for Mailbox 11 + /* Битовое поле MIM12, ширина 1 бит; данные MIM12. */ + Uint16 MIM12:1; // 12 MIM for Mailbox 12 + /* Битовое поле MIM13, ширина 1 бит; данные MIM13. */ + Uint16 MIM13:1; // 13 MIM for Mailbox 13 + /* Битовое поле MIM14, ширина 1 бит; данные MIM14. */ + Uint16 MIM14:1; // 14 MIM for Mailbox 14 + /* Битовое поле MIM15, ширина 1 бит; данные MIM15. */ + Uint16 MIM15:1; // 15 MIM for Mailbox 15 + /* Битовое поле MIM16, ширина 1 бит; данные MIM16. */ + Uint16 MIM16:1; // 16 MIM for Mailbox 16 + /* Битовое поле MIM17, ширина 1 бит; данные MIM17. */ + Uint16 MIM17:1; // 17 MIM for Mailbox 17 + /* Битовое поле MIM18, ширина 1 бит; данные MIM18. */ + Uint16 MIM18:1; // 18 MIM for Mailbox 18 + /* Битовое поле MIM19, ширина 1 бит; данные MIM19. */ + Uint16 MIM19:1; // 19 MIM for Mailbox 19 + /* Битовое поле MIM20, ширина 1 бит; данные MIM20. */ + Uint16 MIM20:1; // 20 MIM for Mailbox 20 + /* Битовое поле MIM21, ширина 1 бит; данные MIM21. */ + Uint16 MIM21:1; // 21 MIM for Mailbox 21 + /* Битовое поле MIM22, ширина 1 бит; данные MIM22. */ + Uint16 MIM22:1; // 22 MIM for Mailbox 22 + /* Битовое поле MIM23, ширина 1 бит; данные MIM23. */ + Uint16 MIM23:1; // 23 MIM for Mailbox 23 + /* Битовое поле MIM24, ширина 1 бит; данные MIM24. */ + Uint16 MIM24:1; // 24 MIM for Mailbox 24 + /* Битовое поле MIM25, ширина 1 бит; данные MIM25. */ + Uint16 MIM25:1; // 25 MIM for Mailbox 25 + /* Битовое поле MIM26, ширина 1 бит; данные MIM26. */ + Uint16 MIM26:1; // 26 MIM for Mailbox 26 + /* Битовое поле MIM27, ширина 1 бит; данные MIM27. */ + Uint16 MIM27:1; // 27 MIM for Mailbox 27 + /* Битовое поле MIM28, ширина 1 бит; данные MIM28. */ + Uint16 MIM28:1; // 28 MIM for Mailbox 28 + /* Битовое поле MIM29, ширина 1 бит; данные MIM29. */ + Uint16 MIM29:1; // 29 MIM for Mailbox 29 + /* Битовое поле MIM30, ширина 1 бит; данные MIM30. */ + Uint16 MIM30:1; // 30 MIM for Mailbox 30 + /* Битовое поле MIM31, ширина 1 бит; данные MIM31. */ + Uint16 MIM31:1; // 31 MIM for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMIM_REG в одной области памяти. */ +union CANMIM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMIM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMIM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Mailbox Interrupt Level register (CANMIL) bit definitions */ +/* Описывает структуру CANMIL_BITS; порядок полей определяет расположение данных. */ +struct CANMIL_BITS { // bit description + /* Битовое поле MIL0, ширина 1 бит; данные MIL0. */ + Uint16 MIL0:1; // 0 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL1, ширина 1 бит; данные MIL1. */ + Uint16 MIL1:1; // 1 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL2, ширина 1 бит; данные MIL2. */ + Uint16 MIL2:1; // 2 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL3, ширина 1 бит; данные MIL3. */ + Uint16 MIL3:1; // 3 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL4, ширина 1 бит; данные MIL4. */ + Uint16 MIL4:1; // 4 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL5, ширина 1 бит; данные MIL5. */ + Uint16 MIL5:1; // 5 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL6, ширина 1 бит; данные MIL6. */ + Uint16 MIL6:1; // 6 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL7, ширина 1 бит; данные MIL7. */ + Uint16 MIL7:1; // 7 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL8, ширина 1 бит; данные MIL8. */ + Uint16 MIL8:1; // 8 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL9, ширина 1 бит; данные MIL9. */ + Uint16 MIL9:1; // 9 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL10, ширина 1 бит; данные MIL10. */ + Uint16 MIL10:1; // 10 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL11, ширина 1 бит; данные MIL11. */ + Uint16 MIL11:1; // 11 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL12, ширина 1 бит; данные MIL12. */ + Uint16 MIL12:1; // 12 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL13, ширина 1 бит; данные MIL13. */ + Uint16 MIL13:1; // 13 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL14, ширина 1 бит; данные MIL14. */ + Uint16 MIL14:1; // 14 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL15, ширина 1 бит; данные MIL15. */ + Uint16 MIL15:1; // 15 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL16, ширина 1 бит; данные MIL16. */ + Uint16 MIL16:1; // 16 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL17, ширина 1 бит; данные MIL17. */ + Uint16 MIL17:1; // 17 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL18, ширина 1 бит; данные MIL18. */ + Uint16 MIL18:1; // 18 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL19, ширина 1 бит; данные MIL19. */ + Uint16 MIL19:1; // 19 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL20, ширина 1 бит; данные MIL20. */ + Uint16 MIL20:1; // 20 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL21, ширина 1 бит; данные MIL21. */ + Uint16 MIL21:1; // 21 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL22, ширина 1 бит; данные MIL22. */ + Uint16 MIL22:1; // 22 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL23, ширина 1 бит; данные MIL23. */ + Uint16 MIL23:1; // 23 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL24, ширина 1 бит; данные MIL24. */ + Uint16 MIL24:1; // 24 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL25, ширина 1 бит; данные MIL25. */ + Uint16 MIL25:1; // 25 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL26, ширина 1 бит; данные MIL26. */ + Uint16 MIL26:1; // 26 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL27, ширина 1 бит; данные MIL27. */ + Uint16 MIL27:1; // 27 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL28, ширина 1 бит; данные MIL28. */ + Uint16 MIL28:1; // 28 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL29, ширина 1 бит; данные MIL29. */ + Uint16 MIL29:1; // 29 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL30, ширина 1 бит; данные MIL30. */ + Uint16 MIL30:1; // 30 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL31, ширина 1 бит; данные MIL31. */ + Uint16 MIL31:1; // 31 0 -> Int 9.5 1 -> Int 9.6 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMIL_REG в одной области памяти. */ +union CANMIL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMIL_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMIL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Overwrite Protection Control register (CANOPC) bit definitions */ +/* Описывает структуру CANOPC_BITS; порядок полей определяет расположение данных. */ +struct CANOPC_BITS { // bit description + /* Битовое поле OPC0, ширина 1 бит; данные OPC0. */ + Uint16 OPC0:1; // 0 OPC for Mailbox 0 + /* Битовое поле OPC1, ширина 1 бит; данные OPC1. */ + Uint16 OPC1:1; // 1 OPC for Mailbox 1 + /* Битовое поле OPC2, ширина 1 бит; данные OPC2. */ + Uint16 OPC2:1; // 2 OPC for Mailbox 2 + /* Битовое поле OPC3, ширина 1 бит; данные OPC3. */ + Uint16 OPC3:1; // 3 OPC for Mailbox 3 + /* Битовое поле OPC4, ширина 1 бит; данные OPC4. */ + Uint16 OPC4:1; // 4 OPC for Mailbox 4 + /* Битовое поле OPC5, ширина 1 бит; данные OPC5. */ + Uint16 OPC5:1; // 5 OPC for Mailbox 5 + /* Битовое поле OPC6, ширина 1 бит; данные OPC6. */ + Uint16 OPC6:1; // 6 OPC for Mailbox 6 + /* Битовое поле OPC7, ширина 1 бит; данные OPC7. */ + Uint16 OPC7:1; // 7 OPC for Mailbox 7 + /* Битовое поле OPC8, ширина 1 бит; данные OPC8. */ + Uint16 OPC8:1; // 8 OPC for Mailbox 8 + /* Битовое поле OPC9, ширина 1 бит; данные OPC9. */ + Uint16 OPC9:1; // 9 OPC for Mailbox 9 + /* Битовое поле OPC10, ширина 1 бит; данные OPC10. */ + Uint16 OPC10:1; // 10 OPC for Mailbox 10 + /* Битовое поле OPC11, ширина 1 бит; данные OPC11. */ + Uint16 OPC11:1; // 11 OPC for Mailbox 11 + /* Битовое поле OPC12, ширина 1 бит; данные OPC12. */ + Uint16 OPC12:1; // 12 OPC for Mailbox 12 + /* Битовое поле OPC13, ширина 1 бит; данные OPC13. */ + Uint16 OPC13:1; // 13 OPC for Mailbox 13 + /* Битовое поле OPC14, ширина 1 бит; данные OPC14. */ + Uint16 OPC14:1; // 14 OPC for Mailbox 14 + /* Битовое поле OPC15, ширина 1 бит; данные OPC15. */ + Uint16 OPC15:1; // 15 OPC for Mailbox 15 + /* Битовое поле OPC16, ширина 1 бит; данные OPC16. */ + Uint16 OPC16:1; // 16 OPC for Mailbox 16 + /* Битовое поле OPC17, ширина 1 бит; данные OPC17. */ + Uint16 OPC17:1; // 17 OPC for Mailbox 17 + /* Битовое поле OPC18, ширина 1 бит; данные OPC18. */ + Uint16 OPC18:1; // 18 OPC for Mailbox 18 + /* Битовое поле OPC19, ширина 1 бит; данные OPC19. */ + Uint16 OPC19:1; // 19 OPC for Mailbox 19 + /* Битовое поле OPC20, ширина 1 бит; данные OPC20. */ + Uint16 OPC20:1; // 20 OPC for Mailbox 20 + /* Битовое поле OPC21, ширина 1 бит; данные OPC21. */ + Uint16 OPC21:1; // 21 OPC for Mailbox 21 + /* Битовое поле OPC22, ширина 1 бит; данные OPC22. */ + Uint16 OPC22:1; // 22 OPC for Mailbox 22 + /* Битовое поле OPC23, ширина 1 бит; данные OPC23. */ + Uint16 OPC23:1; // 23 OPC for Mailbox 23 + /* Битовое поле OPC24, ширина 1 бит; данные OPC24. */ + Uint16 OPC24:1; // 24 OPC for Mailbox 24 + /* Битовое поле OPC25, ширина 1 бит; данные OPC25. */ + Uint16 OPC25:1; // 25 OPC for Mailbox 25 + /* Битовое поле OPC26, ширина 1 бит; данные OPC26. */ + Uint16 OPC26:1; // 26 OPC for Mailbox 26 + /* Битовое поле OPC27, ширина 1 бит; данные OPC27. */ + Uint16 OPC27:1; // 27 OPC for Mailbox 27 + /* Битовое поле OPC28, ширина 1 бит; данные OPC28. */ + Uint16 OPC28:1; // 28 OPC for Mailbox 28 + /* Битовое поле OPC29, ширина 1 бит; данные OPC29. */ + Uint16 OPC29:1; // 29 OPC for Mailbox 29 + /* Битовое поле OPC30, ширина 1 бит; данные OPC30. */ + Uint16 OPC30:1; // 30 OPC for Mailbox 30 + /* Битовое поле OPC31, ширина 1 бит; данные OPC31. */ + Uint16 OPC31:1; // 31 OPC for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANOPC_REG в одной области памяти. */ +union CANOPC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANOPC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANOPC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN TX I/O Control Register (CANTIOC) bit definitions */ +/* Описывает структуру CANTIOC_BITS; порядок полей определяет расположение данных. */ +struct CANTIOC_BITS { // bits description + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 2:0 reserved + /* Битовое поле TXFUNC, ширина 1 бит; данные TXFUNC. */ + Uint16 TXFUNC:1; // 3 TXFUNC + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved + /* Битовое поле rsvd3, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTIOC_REG в одной области памяти. */ +union CANTIOC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTIOC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTIOC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN RX I/O Control Register (CANRIOC) bit definitions */ +/* Описывает структуру CANRIOC_BITS; порядок полей определяет расположение данных. */ +struct CANRIOC_BITS { // bits description + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 2:0 reserved + /* Битовое поле RXFUNC, ширина 1 бит; данные RXFUNC. */ + Uint16 RXFUNC:1; // 3 RXFUNC + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved + /* Битовое поле rsvd3, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRIOC_REG в одной области памяти. */ +union CANRIOC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRIOC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRIOC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Time-out Control register (CANTOC) bit definitions */ +/* Описывает структуру CANTOC_BITS; порядок полей определяет расположение данных. */ +struct CANTOC_BITS { // bit description + /* Битовое поле TOC0, ширина 1 бит; данные TOC0. */ + Uint16 TOC0:1; // 0 TOC for Mailbox 0 + /* Битовое поле TOC1, ширина 1 бит; данные TOC1. */ + Uint16 TOC1:1; // 1 TOC for Mailbox 1 + /* Битовое поле TOC2, ширина 1 бит; данные TOC2. */ + Uint16 TOC2:1; // 2 TOC for Mailbox 2 + /* Битовое поле TOC3, ширина 1 бит; данные TOC3. */ + Uint16 TOC3:1; // 3 TOC for Mailbox 3 + /* Битовое поле TOC4, ширина 1 бит; данные TOC4. */ + Uint16 TOC4:1; // 4 TOC for Mailbox 4 + /* Битовое поле TOC5, ширина 1 бит; данные TOC5. */ + Uint16 TOC5:1; // 5 TOC for Mailbox 5 + /* Битовое поле TOC6, ширина 1 бит; данные TOC6. */ + Uint16 TOC6:1; // 6 TOC for Mailbox 6 + /* Битовое поле TOC7, ширина 1 бит; данные TOC7. */ + Uint16 TOC7:1; // 7 TOC for Mailbox 7 + /* Битовое поле TOC8, ширина 1 бит; данные TOC8. */ + Uint16 TOC8:1; // 8 TOC for Mailbox 8 + /* Битовое поле TOC9, ширина 1 бит; данные TOC9. */ + Uint16 TOC9:1; // 9 TOC for Mailbox 9 + /* Битовое поле TOC10, ширина 1 бит; данные TOC10. */ + Uint16 TOC10:1; // 10 TOC for Mailbox 10 + /* Битовое поле TOC11, ширина 1 бит; данные TOC11. */ + Uint16 TOC11:1; // 11 TOC for Mailbox 11 + /* Битовое поле TOC12, ширина 1 бит; данные TOC12. */ + Uint16 TOC12:1; // 12 TOC for Mailbox 12 + /* Битовое поле TOC13, ширина 1 бит; данные TOC13. */ + Uint16 TOC13:1; // 13 TOC for Mailbox 13 + /* Битовое поле TOC14, ширина 1 бит; данные TOC14. */ + Uint16 TOC14:1; // 14 TOC for Mailbox 14 + /* Битовое поле TOC15, ширина 1 бит; данные TOC15. */ + Uint16 TOC15:1; // 15 TOC for Mailbox 15 + /* Битовое поле TOC16, ширина 1 бит; данные TOC16. */ + Uint16 TOC16:1; // 16 TOC for Mailbox 16 + /* Битовое поле TOC17, ширина 1 бит; данные TOC17. */ + Uint16 TOC17:1; // 17 TOC for Mailbox 17 + /* Битовое поле TOC18, ширина 1 бит; данные TOC18. */ + Uint16 TOC18:1; // 18 TOC for Mailbox 18 + /* Битовое поле TOC19, ширина 1 бит; данные TOC19. */ + Uint16 TOC19:1; // 19 TOC for Mailbox 19 + /* Битовое поле TOC20, ширина 1 бит; данные TOC20. */ + Uint16 TOC20:1; // 20 TOC for Mailbox 20 + /* Битовое поле TOC21, ширина 1 бит; данные TOC21. */ + Uint16 TOC21:1; // 21 TOC for Mailbox 21 + /* Битовое поле TOC22, ширина 1 бит; данные TOC22. */ + Uint16 TOC22:1; // 22 TOC for Mailbox 22 + /* Битовое поле TOC23, ширина 1 бит; данные TOC23. */ + Uint16 TOC23:1; // 23 TOC for Mailbox 23 + /* Битовое поле TOC24, ширина 1 бит; данные TOC24. */ + Uint16 TOC24:1; // 24 TOC for Mailbox 24 + /* Битовое поле TOC25, ширина 1 бит; данные TOC25. */ + Uint16 TOC25:1; // 25 TOC for Mailbox 25 + /* Битовое поле TOC26, ширина 1 бит; данные TOC26. */ + Uint16 TOC26:1; // 26 TOC for Mailbox 26 + /* Битовое поле TOC27, ширина 1 бит; данные TOC27. */ + Uint16 TOC27:1; // 27 TOC for Mailbox 27 + /* Битовое поле TOC28, ширина 1 бит; данные TOC28. */ + Uint16 TOC28:1; // 28 TOC for Mailbox 28 + /* Битовое поле TOC29, ширина 1 бит; данные TOC29. */ + Uint16 TOC29:1; // 29 TOC for Mailbox 29 + /* Битовое поле TOC30, ширина 1 бит; данные TOC30. */ + Uint16 TOC30:1; // 30 TOC for Mailbox 30 + /* Битовое поле TOC31, ширина 1 бит; данные TOC31. */ + Uint16 TOC31:1; // 31 TOC for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTOC_REG в одной области памяти. */ +union CANTOC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTOC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTOC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Time-out Status register (CANTOS) bit definitions */ +/* Описывает структуру CANTOS_BITS; порядок полей определяет расположение данных. */ +struct CANTOS_BITS { // bit description + /* Битовое поле TOS0, ширина 1 бит; данные TOS0. */ + Uint16 TOS0:1; // 0 TOS for Mailbox 0 + /* Битовое поле TOS1, ширина 1 бит; данные TOS1. */ + Uint16 TOS1:1; // 1 TOS for Mailbox 1 + /* Битовое поле TOS2, ширина 1 бит; данные TOS2. */ + Uint16 TOS2:1; // 2 TOS for Mailbox 2 + /* Битовое поле TOS3, ширина 1 бит; данные TOS3. */ + Uint16 TOS3:1; // 3 TOS for Mailbox 3 + /* Битовое поле TOS4, ширина 1 бит; данные TOS4. */ + Uint16 TOS4:1; // 4 TOS for Mailbox 4 + /* Битовое поле TOS5, ширина 1 бит; данные TOS5. */ + Uint16 TOS5:1; // 5 TOS for Mailbox 5 + /* Битовое поле TOS6, ширина 1 бит; данные TOS6. */ + Uint16 TOS6:1; // 6 TOS for Mailbox 6 + /* Битовое поле TOS7, ширина 1 бит; данные TOS7. */ + Uint16 TOS7:1; // 7 TOS for Mailbox 7 + /* Битовое поле TOS8, ширина 1 бит; данные TOS8. */ + Uint16 TOS8:1; // 8 TOS for Mailbox 8 + /* Битовое поле TOS9, ширина 1 бит; данные TOS9. */ + Uint16 TOS9:1; // 9 TOS for Mailbox 9 + /* Битовое поле TOS10, ширина 1 бит; данные TOS10. */ + Uint16 TOS10:1; // 10 TOS for Mailbox 10 + /* Битовое поле TOS11, ширина 1 бит; данные TOS11. */ + Uint16 TOS11:1; // 11 TOS for Mailbox 11 + /* Битовое поле TOS12, ширина 1 бит; данные TOS12. */ + Uint16 TOS12:1; // 12 TOS for Mailbox 12 + /* Битовое поле TOS13, ширина 1 бит; данные TOS13. */ + Uint16 TOS13:1; // 13 TOS for Mailbox 13 + /* Битовое поле TOS14, ширина 1 бит; данные TOS14. */ + Uint16 TOS14:1; // 14 TOS for Mailbox 14 + /* Битовое поле TOS15, ширина 1 бит; данные TOS15. */ + Uint16 TOS15:1; // 15 TOS for Mailbox 15 + /* Битовое поле TOS16, ширина 1 бит; данные TOS16. */ + Uint16 TOS16:1; // 16 TOS for Mailbox 16 + /* Битовое поле TOS17, ширина 1 бит; данные TOS17. */ + Uint16 TOS17:1; // 17 TOS for Mailbox 17 + /* Битовое поле TOS18, ширина 1 бит; данные TOS18. */ + Uint16 TOS18:1; // 18 TOS for Mailbox 18 + /* Битовое поле TOS19, ширина 1 бит; данные TOS19. */ + Uint16 TOS19:1; // 19 TOS for Mailbox 19 + /* Битовое поле TOS20, ширина 1 бит; данные TOS20. */ + Uint16 TOS20:1; // 20 TOS for Mailbox 20 + /* Битовое поле TOS21, ширина 1 бит; данные TOS21. */ + Uint16 TOS21:1; // 21 TOS for Mailbox 21 + /* Битовое поле TOS22, ширина 1 бит; данные TOS22. */ + Uint16 TOS22:1; // 22 TOS for Mailbox 22 + /* Битовое поле TOS23, ширина 1 бит; данные TOS23. */ + Uint16 TOS23:1; // 23 TOS for Mailbox 23 + /* Битовое поле TOS24, ширина 1 бит; данные TOS24. */ + Uint16 TOS24:1; // 24 TOS for Mailbox 24 + /* Битовое поле TOS25, ширина 1 бит; данные TOS25. */ + Uint16 TOS25:1; // 25 TOS for Mailbox 25 + /* Битовое поле TOS26, ширина 1 бит; данные TOS26. */ + Uint16 TOS26:1; // 26 TOS for Mailbox 26 + /* Битовое поле TOS27, ширина 1 бит; данные TOS27. */ + Uint16 TOS27:1; // 27 TOS for Mailbox 27 + /* Битовое поле TOS28, ширина 1 бит; данные TOS28. */ + Uint16 TOS28:1; // 28 TOS for Mailbox 28 + /* Битовое поле TOS29, ширина 1 бит; данные TOS29. */ + Uint16 TOS29:1; // 29 TOS for Mailbox 29 + /* Битовое поле TOS30, ширина 1 бит; данные TOS30. */ + Uint16 TOS30:1; // 30 TOS for Mailbox 30 + /* Битовое поле TOS31, ширина 1 бит; данные TOS31. */ + Uint16 TOS31:1; // 31 TOS for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTOS_REG в одной области памяти. */ +union CANTOS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTOS_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTOS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/**************************************/ +/* eCAN Control & Status register file */ +/**************************************/ + +/* Описывает структуру ECAN_REGS; порядок полей определяет расположение данных. */ +struct ECAN_REGS { + /* Объединяет несколько представлений CANME_REG CANME; в одной области памяти. */ + union CANME_REG CANME; // Mailbox Enable + /* Объединяет несколько представлений CANMD_REG CANMD; в одной области памяти. */ + union CANMD_REG CANMD; // Mailbox Direction + /* Объединяет несколько представлений CANTRS_REG CANTRS; в одной области памяти. */ + union CANTRS_REG CANTRS; // Transmit Request Set + /* Объединяет несколько представлений CANTRR_REG CANTRR; в одной области памяти. */ + union CANTRR_REG CANTRR; // Transmit Request Reset + /* Объединяет несколько представлений CANTA_REG CANTA; в одной области памяти. */ + union CANTA_REG CANTA; // Transmit Acknowledge + /* Объединяет несколько представлений CANAA_REG CANAA; в одной области памяти. */ + union CANAA_REG CANAA; // Abort Acknowledge + /* Объединяет несколько представлений CANRMP_REG CANRMP; в одной области памяти. */ + union CANRMP_REG CANRMP; // Received Message Pending + /* Объединяет несколько представлений CANRML_REG CANRML; в одной области памяти. */ + union CANRML_REG CANRML; // Received Message Lost + /* Объединяет несколько представлений CANRFP_REG CANRFP; в одной области памяти. */ + union CANRFP_REG CANRFP; // Remote Frame Pending + /* Объединяет несколько представлений CANGAM_REG CANGAM; в одной области памяти. */ + union CANGAM_REG CANGAM; // Global Acceptance Mask + /* Объединяет несколько представлений CANMC_REG CANMC; в одной области памяти. */ + union CANMC_REG CANMC; // Master Control + /* Объединяет несколько представлений CANBTC_REG CANBTC; в одной области памяти. */ + union CANBTC_REG CANBTC; // Bit Timing + /* Объединяет несколько представлений CANES_REG CANES; в одной области памяти. */ + union CANES_REG CANES; // Error Status + /* Объединяет несколько представлений CANTEC_REG CANTEC; в одной области памяти. */ + union CANTEC_REG CANTEC; // Transmit Error Counter + /* Объединяет несколько представлений CANREC_REG CANREC; в одной области памяти. */ + union CANREC_REG CANREC; // Receive Error Counter + /* Объединяет несколько представлений CANGIF0_REG CANGIF0; в одной области памяти. */ + union CANGIF0_REG CANGIF0; // Global Interrupt Flag 0 + /* Объединяет несколько представлений CANGIM_REG CANGIM; в одной области памяти. */ + union CANGIM_REG CANGIM; // Global Interrupt Mask 0 + /* Объединяет несколько представлений CANGIF1_REG CANGIF1; в одной области памяти. */ + union CANGIF1_REG CANGIF1; // Global Interrupt Flag 1 + /* Объединяет несколько представлений CANMIM_REG CANMIM; в одной области памяти. */ + union CANMIM_REG CANMIM; // Mailbox Interrupt Mask + /* Объединяет несколько представлений CANMIL_REG CANMIL; в одной области памяти. */ + union CANMIL_REG CANMIL; // Mailbox Interrupt Level + /* Объединяет несколько представлений CANOPC_REG CANOPC; в одной области памяти. */ + union CANOPC_REG CANOPC; // Overwrite Protection Control + /* Объединяет несколько представлений CANTIOC_REG CANTIOC; в одной области памяти. */ + union CANTIOC_REG CANTIOC; // TX I/O Control + /* Объединяет несколько представлений CANRIOC_REG CANRIOC; в одной области памяти. */ + union CANRIOC_REG CANRIOC; // RX I/O Control + /* Объявляет CANTSC — данные CANTSC. */ + Uint32 CANTSC; // Time-stamp counter + /* Объединяет несколько представлений CANTOC_REG CANTOC; в одной области памяти. */ + union CANTOC_REG CANTOC; // Time-out Control + /* Объединяет несколько представлений CANTOS_REG CANTOS; в одной области памяти. */ + union CANTOS_REG CANTOS; // Time-out Status + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* --------------------------------------------------- */ +/* eCAN Mailbox Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Message ID (MSGID) bit definitions */ +/* Описывает структуру CANMSGID_BITS; порядок полей определяет расположение данных. */ +struct CANMSGID_BITS { // bits description + /* Битовое поле EXTMSGID_L, ширина 16 бит; данные EXTMSGID_L. */ + Uint16 EXTMSGID_L:16; // 0:15 + /* Битовое поле EXTMSGID_H, ширина 2 бит; данные EXTMSGID_H. */ + Uint16 EXTMSGID_H:2; // 16:17 + /* Битовое поле STDMSGID, ширина 11 бит; данные STDMSGID. */ + Uint16 STDMSGID:11; // 18:28 + /* Битовое поле AAM, ширина 1 бит; данные AAM. */ + Uint16 AAM:1; // 29 + /* Битовое поле AME, ширина 1 бит; данные AME. */ + Uint16 AME:1; // 30 + /* Битовое поле IDE, ширина 1 бит; данные IDE. */ + Uint16 IDE:1; // 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMSGID_REG в одной области памяти. */ +union CANMSGID_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMSGID_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMSGID_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Control Register (MSGCTRL) bit definitions */ +/* Описывает структуру CANMSGCTRL_BITS; порядок полей определяет расположение данных. */ +struct CANMSGCTRL_BITS { // bits description + /* Битовое поле DLC, ширина 4 бит; данные DLC. */ + Uint16 DLC:4; // 0:3 + /* Битовое поле RTR, ширина 1 бит; данные RTR. */ + Uint16 RTR:1; // 4 + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved + /* Битовое поле TPL, ширина 5 бит; данные TPL. */ + Uint16 TPL:5; // 12:8 + /* Битовое поле rsvd2, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:3; // 15:13 reserved + /* Битовое поле rsvd3, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMSGCTRL_REG в одной области памяти. */ +union CANMSGCTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMSGCTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMSGCTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Data Register low (MDR_L) word definitions */ +/* Описывает структуру CANMDL_WORDS; порядок полей определяет расположение данных. */ +struct CANMDL_WORDS { // bits description + /* Битовое поле LOW_WORD, ширина 16 бит; LOW слово. */ + Uint16 LOW_WORD:16; // 0:15 + /* Битовое поле HI_WORD, ширина 16 бит; HI слово. */ + Uint16 HI_WORD:16; // 31:16 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Data Register low (MDR_L) byte definitions */ +/* Описывает структуру CANMDL_BYTES; порядок полей определяет расположение данных. */ +struct CANMDL_BYTES { // bits description + /* Битовое поле BYTE3, ширина 8 бит; данные BYTE3. */ + Uint16 BYTE3:8; // 31:24 + /* Битовое поле BYTE2, ширина 8 бит; данные BYTE2. */ + Uint16 BYTE2:8; // 23:16 + /* Битовое поле BYTE1, ширина 8 бит; данные BYTE1. */ + Uint16 BYTE1:8; // 15:8 + /* Битовое поле BYTE0, ширина 8 бит; данные BYTE0. */ + Uint16 BYTE0:8; // 7:0 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Allow access to the bit fields or entire register */ + +/* Объединяет несколько представлений CANMDL_REG в одной области памяти. */ +union CANMDL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMDL_WORDS word;; порядок полей определяет расположение данных. */ + struct CANMDL_WORDS word; + /* Описывает структуру CANMDL_BYTES byte;; порядок полей определяет расположение данных. */ + struct CANMDL_BYTES byte; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +/* eCAN Message Data Register high (MDR_H) word definitions */ +/* Описывает структуру CANMDH_WORDS; порядок полей определяет расположение данных. */ +struct CANMDH_WORDS { // bits description + /* Битовое поле LOW_WORD, ширина 16 бит; LOW слово. */ + Uint16 LOW_WORD:16; // 0:15 + /* Битовое поле HI_WORD, ширина 16 бит; HI слово. */ + Uint16 HI_WORD:16; // 31:16 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Data Register low (MDR_H) byte definitions */ +/* Описывает структуру CANMDH_BYTES; порядок полей определяет расположение данных. */ +struct CANMDH_BYTES { // bits description + /* Битовое поле BYTE7, ширина 8 бит; данные BYTE7. */ + Uint16 BYTE7:8; // 63:56 + /* Битовое поле BYTE6, ширина 8 бит; данные BYTE6. */ + Uint16 BYTE6:8; // 55:48 + /* Битовое поле BYTE5, ширина 8 бит; данные BYTE5. */ + Uint16 BYTE5:8; // 47:40 + /* Битовое поле BYTE4, ширина 8 бит; данные BYTE4. */ + Uint16 BYTE4:8; // 39:32 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMDH_REG в одной области памяти. */ +union CANMDH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMDH_WORDS word;; порядок полей определяет расположение данных. */ + struct CANMDH_WORDS word; + /* Описывает структуру CANMDH_BYTES byte;; порядок полей определяет расположение данных. */ + struct CANMDH_BYTES byte; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру MBOX; порядок полей определяет расположение данных. */ +struct MBOX { + /* Объединяет несколько представлений CANMSGID_REG MSGID; в одной области памяти. */ + union CANMSGID_REG MSGID; + /* Объединяет несколько представлений CANMSGCTRL_REG MSGCTRL; в одной области памяти. */ + union CANMSGCTRL_REG MSGCTRL; + /* Объединяет несколько представлений CANMDL_REG MDL; в одной области памяти. */ + union CANMDL_REG MDL; + /* Объединяет несколько представлений CANMDH_REG MDH; в одной области памяти. */ + union CANMDH_REG MDH; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/**************************************/ +/* eCAN Mailboxes */ +/**************************************/ + +/* Описывает структуру ECAN_MBOXES; порядок полей определяет расположение данных. */ +struct ECAN_MBOXES { + /* Описывает структуру MBOX MBOX0;; порядок полей определяет расположение данных. */ + struct MBOX MBOX0; + /* Описывает структуру MBOX MBOX1;; порядок полей определяет расположение данных. */ + struct MBOX MBOX1; + /* Описывает структуру MBOX MBOX2;; порядок полей определяет расположение данных. */ + struct MBOX MBOX2; + /* Описывает структуру MBOX MBOX3;; порядок полей определяет расположение данных. */ + struct MBOX MBOX3; + /* Описывает структуру MBOX MBOX4;; порядок полей определяет расположение данных. */ + struct MBOX MBOX4; + /* Описывает структуру MBOX MBOX5;; порядок полей определяет расположение данных. */ + struct MBOX MBOX5; + /* Описывает структуру MBOX MBOX6;; порядок полей определяет расположение данных. */ + struct MBOX MBOX6; + /* Описывает структуру MBOX MBOX7;; порядок полей определяет расположение данных. */ + struct MBOX MBOX7; + /* Описывает структуру MBOX MBOX8;; порядок полей определяет расположение данных. */ + struct MBOX MBOX8; + /* Описывает структуру MBOX MBOX9;; порядок полей определяет расположение данных. */ + struct MBOX MBOX9; + /* Описывает структуру MBOX MBOX10;; порядок полей определяет расположение данных. */ + struct MBOX MBOX10; + /* Описывает структуру MBOX MBOX11;; порядок полей определяет расположение данных. */ + struct MBOX MBOX11; + /* Описывает структуру MBOX MBOX12;; порядок полей определяет расположение данных. */ + struct MBOX MBOX12; + /* Описывает структуру MBOX MBOX13;; порядок полей определяет расположение данных. */ + struct MBOX MBOX13; + /* Описывает структуру MBOX MBOX14;; порядок полей определяет расположение данных. */ + struct MBOX MBOX14; + /* Описывает структуру MBOX MBOX15;; порядок полей определяет расположение данных. */ + struct MBOX MBOX15; + /* Описывает структуру MBOX MBOX16;; порядок полей определяет расположение данных. */ + struct MBOX MBOX16; + /* Описывает структуру MBOX MBOX17;; порядок полей определяет расположение данных. */ + struct MBOX MBOX17; + /* Описывает структуру MBOX MBOX18;; порядок полей определяет расположение данных. */ + struct MBOX MBOX18; + /* Описывает структуру MBOX MBOX19;; порядок полей определяет расположение данных. */ + struct MBOX MBOX19; + /* Описывает структуру MBOX MBOX20;; порядок полей определяет расположение данных. */ + struct MBOX MBOX20; + /* Описывает структуру MBOX MBOX21;; порядок полей определяет расположение данных. */ + struct MBOX MBOX21; + /* Описывает структуру MBOX MBOX22;; порядок полей определяет расположение данных. */ + struct MBOX MBOX22; + /* Описывает структуру MBOX MBOX23;; порядок полей определяет расположение данных. */ + struct MBOX MBOX23; + /* Описывает структуру MBOX MBOX24;; порядок полей определяет расположение данных. */ + struct MBOX MBOX24; + /* Описывает структуру MBOX MBOX25;; порядок полей определяет расположение данных. */ + struct MBOX MBOX25; + /* Описывает структуру MBOX MBOX26;; порядок полей определяет расположение данных. */ + struct MBOX MBOX26; + /* Описывает структуру MBOX MBOX27;; порядок полей определяет расположение данных. */ + struct MBOX MBOX27; + /* Описывает структуру MBOX MBOX28;; порядок полей определяет расположение данных. */ + struct MBOX MBOX28; + /* Описывает структуру MBOX MBOX29;; порядок полей определяет расположение данных. */ + struct MBOX MBOX29; + /* Описывает структуру MBOX MBOX30;; порядок полей определяет расположение данных. */ + struct MBOX MBOX30; + /* Описывает структуру MBOX MBOX31;; порядок полей определяет расположение данных. */ + struct MBOX MBOX31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Local Acceptance Mask (LAM) bit definitions */ +/* Описывает структуру CANLAM_BITS; порядок полей определяет расположение данных. */ +struct CANLAM_BITS { // bits description + /* Битовое поле LAM_L, ширина 16 бит; данные LAM_L. */ + Uint16 LAM_L:16; // 0:15 + /* Битовое поле LAM_H, ширина 13 бит; данные LAM_H. */ + Uint16 LAM_H:13; // 16:28 + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 29:30 reserved + /* Битовое поле LAMI, ширина 1 бит; данные LAMI. */ + Uint16 LAMI:1; // 31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANLAM_REG в одной области памяти. */ +union CANLAM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANLAM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANLAM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/**************************************/ +/* eCAN Local Acceptance Masks */ +/**************************************/ + +/* eCAN LAM File */ +/* Описывает структуру LAM_REGS; порядок полей определяет расположение данных. */ +struct LAM_REGS { + /* Объединяет несколько представлений CANLAM_REG LAM0; в одной области памяти. */ + union CANLAM_REG LAM0; + /* Объединяет несколько представлений CANLAM_REG LAM1; в одной области памяти. */ + union CANLAM_REG LAM1; + /* Объединяет несколько представлений CANLAM_REG LAM2; в одной области памяти. */ + union CANLAM_REG LAM2; + /* Объединяет несколько представлений CANLAM_REG LAM3; в одной области памяти. */ + union CANLAM_REG LAM3; + /* Объединяет несколько представлений CANLAM_REG LAM4; в одной области памяти. */ + union CANLAM_REG LAM4; + /* Объединяет несколько представлений CANLAM_REG LAM5; в одной области памяти. */ + union CANLAM_REG LAM5; + /* Объединяет несколько представлений CANLAM_REG LAM6; в одной области памяти. */ + union CANLAM_REG LAM6; + /* Объединяет несколько представлений CANLAM_REG LAM7; в одной области памяти. */ + union CANLAM_REG LAM7; + /* Объединяет несколько представлений CANLAM_REG LAM8; в одной области памяти. */ + union CANLAM_REG LAM8; + /* Объединяет несколько представлений CANLAM_REG LAM9; в одной области памяти. */ + union CANLAM_REG LAM9; + /* Объединяет несколько представлений CANLAM_REG LAM10; в одной области памяти. */ + union CANLAM_REG LAM10; + /* Объединяет несколько представлений CANLAM_REG LAM11; в одной области памяти. */ + union CANLAM_REG LAM11; + /* Объединяет несколько представлений CANLAM_REG LAM12; в одной области памяти. */ + union CANLAM_REG LAM12; + /* Объединяет несколько представлений CANLAM_REG LAM13; в одной области памяти. */ + union CANLAM_REG LAM13; + /* Объединяет несколько представлений CANLAM_REG LAM14; в одной области памяти. */ + union CANLAM_REG LAM14; + /* Объединяет несколько представлений CANLAM_REG LAM15; в одной области памяти. */ + union CANLAM_REG LAM15; + /* Объединяет несколько представлений CANLAM_REG LAM16; в одной области памяти. */ + union CANLAM_REG LAM16; + /* Объединяет несколько представлений CANLAM_REG LAM17; в одной области памяти. */ + union CANLAM_REG LAM17; + /* Объединяет несколько представлений CANLAM_REG LAM18; в одной области памяти. */ + union CANLAM_REG LAM18; + /* Объединяет несколько представлений CANLAM_REG LAM19; в одной области памяти. */ + union CANLAM_REG LAM19; + /* Объединяет несколько представлений CANLAM_REG LAM20; в одной области памяти. */ + union CANLAM_REG LAM20; + /* Объединяет несколько представлений CANLAM_REG LAM21; в одной области памяти. */ + union CANLAM_REG LAM21; + /* Объединяет несколько представлений CANLAM_REG LAM22; в одной области памяти. */ + union CANLAM_REG LAM22; + /* Объединяет несколько представлений CANLAM_REG LAM23; в одной области памяти. */ + union CANLAM_REG LAM23; + /* Объединяет несколько представлений CANLAM_REG LAM24; в одной области памяти. */ + union CANLAM_REG LAM24; + /* Объединяет несколько представлений CANLAM_REG LAM25; в одной области памяти. */ + union CANLAM_REG LAM25; + /* Объединяет несколько представлений CANLAM_REG LAM26; в одной области памяти. */ + union CANLAM_REG LAM26; + /* Объединяет несколько представлений CANLAM_REG LAM27; в одной области памяти. */ + union CANLAM_REG LAM27; + /* Объединяет несколько представлений CANLAM_REG LAM28; в одной области памяти. */ + union CANLAM_REG LAM28; + /* Объединяет несколько представлений CANLAM_REG LAM29; в одной области памяти. */ + union CANLAM_REG LAM29; + /* Объединяет несколько представлений CANLAM_REG LAM30; в одной области памяти. */ + union CANLAM_REG LAM30; + /* Объединяет несколько представлений CANLAM_REG LAM31; в одной области памяти. */ + union CANLAM_REG LAM31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Mailbox MOTS File */ + +/* Описывает структуру MOTS_REGS; порядок полей определяет расположение данных. */ +struct MOTS_REGS { + /* Объявляет MOTS0 — данные MOTS0. */ + Uint32 MOTS0; + /* Объявляет MOTS1 — данные MOTS1. */ + Uint32 MOTS1; + /* Объявляет MOTS2 — данные MOTS2. */ + Uint32 MOTS2; + /* Объявляет MOTS3 — данные MOTS3. */ + Uint32 MOTS3; + /* Объявляет MOTS4 — данные MOTS4. */ + Uint32 MOTS4; + /* Объявляет MOTS5 — данные MOTS5. */ + Uint32 MOTS5; + /* Объявляет MOTS6 — данные MOTS6. */ + Uint32 MOTS6; + /* Объявляет MOTS7 — данные MOTS7. */ + Uint32 MOTS7; + /* Объявляет MOTS8 — данные MOTS8. */ + Uint32 MOTS8; + /* Объявляет MOTS9 — данные MOTS9. */ + Uint32 MOTS9; + /* Объявляет MOTS10 — данные MOTS10. */ + Uint32 MOTS10; + /* Объявляет MOTS11 — данные MOTS11. */ + Uint32 MOTS11; + /* Объявляет MOTS12 — данные MOTS12. */ + Uint32 MOTS12; + /* Объявляет MOTS13 — данные MOTS13. */ + Uint32 MOTS13; + /* Объявляет MOTS14 — данные MOTS14. */ + Uint32 MOTS14; + /* Объявляет MOTS15 — данные MOTS15. */ + Uint32 MOTS15; + /* Объявляет MOTS16 — данные MOTS16. */ + Uint32 MOTS16; + /* Объявляет MOTS17 — данные MOTS17. */ + Uint32 MOTS17; + /* Объявляет MOTS18 — данные MOTS18. */ + Uint32 MOTS18; + /* Объявляет MOTS19 — данные MOTS19. */ + Uint32 MOTS19; + /* Объявляет MOTS20 — данные MOTS20. */ + Uint32 MOTS20; + /* Объявляет MOTS21 — данные MOTS21. */ + Uint32 MOTS21; + /* Объявляет MOTS22 — данные MOTS22. */ + Uint32 MOTS22; + /* Объявляет MOTS23 — данные MOTS23. */ + Uint32 MOTS23; + /* Объявляет MOTS24 — данные MOTS24. */ + Uint32 MOTS24; + /* Объявляет MOTS25 — данные MOTS25. */ + Uint32 MOTS25; + /* Объявляет MOTS26 — данные MOTS26. */ + Uint32 MOTS26; + /* Объявляет MOTS27 — данные MOTS27. */ + Uint32 MOTS27; + /* Объявляет MOTS28 — данные MOTS28. */ + Uint32 MOTS28; + /* Объявляет MOTS29 — данные MOTS29. */ + Uint32 MOTS29; + /* Объявляет MOTS30 — данные MOTS30. */ + Uint32 MOTS30; + /* Объявляет MOTS31 — данные MOTS31. */ + Uint32 MOTS31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Mailbox MOTO File */ + +/* Описывает структуру MOTO_REGS; порядок полей определяет расположение данных. */ +struct MOTO_REGS { + /* Объявляет MOTO0 — данные MOTO0. */ + Uint32 MOTO0; + /* Объявляет MOTO1 — данные MOTO1. */ + Uint32 MOTO1; + /* Объявляет MOTO2 — данные MOTO2. */ + Uint32 MOTO2; + /* Объявляет MOTO3 — данные MOTO3. */ + Uint32 MOTO3; + /* Объявляет MOTO4 — данные MOTO4. */ + Uint32 MOTO4; + /* Объявляет MOTO5 — данные MOTO5. */ + Uint32 MOTO5; + /* Объявляет MOTO6 — данные MOTO6. */ + Uint32 MOTO6; + /* Объявляет MOTO7 — данные MOTO7. */ + Uint32 MOTO7; + /* Объявляет MOTO8 — данные MOTO8. */ + Uint32 MOTO8; + /* Объявляет MOTO9 — данные MOTO9. */ + Uint32 MOTO9; + /* Объявляет MOTO10 — данные MOTO10. */ + Uint32 MOTO10; + /* Объявляет MOTO11 — данные MOTO11. */ + Uint32 MOTO11; + /* Объявляет MOTO12 — данные MOTO12. */ + Uint32 MOTO12; + /* Объявляет MOTO13 — данные MOTO13. */ + Uint32 MOTO13; + /* Объявляет MOTO14 — данные MOTO14. */ + Uint32 MOTO14; + /* Объявляет MOTO15 — данные MOTO15. */ + Uint32 MOTO15; + /* Объявляет MOTO16 — данные MOTO16. */ + Uint32 MOTO16; + /* Объявляет MOTO17 — данные MOTO17. */ + Uint32 MOTO17; + /* Объявляет MOTO18 — данные MOTO18. */ + Uint32 MOTO18; + /* Объявляет MOTO19 — данные MOTO19. */ + Uint32 MOTO19; + /* Объявляет MOTO20 — данные MOTO20. */ + Uint32 MOTO20; + /* Объявляет MOTO21 — данные MOTO21. */ + Uint32 MOTO21; + /* Объявляет MOTO22 — данные MOTO22. */ + Uint32 MOTO22; + /* Объявляет MOTO23 — данные MOTO23. */ + Uint32 MOTO23; + /* Объявляет MOTO24 — данные MOTO24. */ + Uint32 MOTO24; + /* Объявляет MOTO25 — данные MOTO25. */ + Uint32 MOTO25; + /* Объявляет MOTO26 — данные MOTO26. */ + Uint32 MOTO26; + /* Объявляет MOTO27 — данные MOTO27. */ + Uint32 MOTO27; + /* Объявляет MOTO28 — данные MOTO28. */ + Uint32 MOTO28; + /* Объявляет MOTO29 — данные MOTO29. */ + Uint32 MOTO29; + /* Объявляет MOTO30 — данные MOTO30. */ + Uint32 MOTO30; + /* Объявляет MOTO31 — данные MOTO31. */ + Uint32 MOTO31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// eCAN External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_REGS ECanaRegs;; порядок элементов сохраняется. */ +extern volatile struct ECAN_REGS ECanaRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_MBOXES ECanaMboxes;; порядок элементов сохраняется. */ +extern volatile struct ECAN_MBOXES ECanaMboxes; +/* Продолжает список аргументов, полей или выражение extern volatile struct LAM_REGS ECanaLAMRegs;; порядок элементов сохраняется. */ +extern volatile struct LAM_REGS ECanaLAMRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTO_REGS ECanaMOTORegs;; порядок элементов сохраняется. */ +extern volatile struct MOTO_REGS ECanaMOTORegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTS_REGS ECanaMOTSRegs;; порядок элементов сохраняется. */ +extern volatile struct MOTS_REGS ECanaMOTSRegs; + +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_REGS ECanbRegs;; порядок элементов сохраняется. */ +extern volatile struct ECAN_REGS ECanbRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_MBOXES ECanbMboxes;; порядок элементов сохраняется. */ +extern volatile struct ECAN_MBOXES ECanbMboxes; +/* Продолжает список аргументов, полей или выражение extern volatile struct LAM_REGS ECanbLAMRegs;; порядок элементов сохраняется. */ +extern volatile struct LAM_REGS ECanbLAMRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTO_REGS ECanbMOTORegs;; порядок элементов сохраняется. */ +extern volatile struct MOTO_REGS ECanbMOTORegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTS_REGS ECanbMOTSRegs;; порядок элементов сохраняется. */ +extern volatile struct MOTS_REGS ECanbMOTSRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_ECAN.H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h new file mode 100644 index 0000000..6ff4cea --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h @@ -0,0 +1,245 @@ +/* Поставляемое TI описание ECap для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:07 $ +//########################################################################### +// +// FILE: DSP2833x_ECap.h +// +// TITLE: DSP2833x Enhanced Capture Module Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_ECAP_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_ECAP_H +/* Определяет защитный символ или переключатель DSP2833x_ECAP_H для последующей компиляции. */ +#define DSP2833x_ECAP_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Capture control register 1 bit definitions */ +/* Описывает структуру ECCTL1_BITS; порядок полей определяет расположение данных. */ +struct ECCTL1_BITS { // bits description + /* Битовое поле CAP1POL, ширина 1 бит; данные CAP1POL. */ + Uint16 CAP1POL:1; // 0 Capture Event 1 Polarity select + /* Битовое поле CTRRST1, ширина 1 бит; данные CTRRST1. */ + Uint16 CTRRST1:1; // 1 Counter Reset on Capture Event 1 + /* Битовое поле CAP2POL, ширина 1 бит; данные CAP2POL. */ + Uint16 CAP2POL:1; // 2 Capture Event 2 Polarity select + /* Битовое поле CTRRST2, ширина 1 бит; данные CTRRST2. */ + Uint16 CTRRST2:1; // 3 Counter Reset on Capture Event 2 + /* Битовое поле CAP3POL, ширина 1 бит; данные CAP3POL. */ + Uint16 CAP3POL:1; // 4 Capture Event 3 Polarity select + /* Битовое поле CTRRST3, ширина 1 бит; данные CTRRST3. */ + Uint16 CTRRST3:1; // 5 Counter Reset on Capture Event 3 + /* Битовое поле CAP4POL, ширина 1 бит; данные CAP4POL. */ + Uint16 CAP4POL:1; // 6 Capture Event 4 Polarity select + /* Битовое поле CTRRST4, ширина 1 бит; данные CTRRST4. */ + Uint16 CTRRST4:1; // 7 Counter Reset on Capture Event 4 + /* Битовое поле CAPLDEN, ширина 1 бит; данные CAPLDEN. */ + Uint16 CAPLDEN:1; // 8 Enable Loading CAP1-4 regs on a Cap Event + /* Битовое поле PRESCALE, ширина 5 бит; предделитель. */ + Uint16 PRESCALE:5; // 13:9 Event Filter prescale select + /* Битовое поле FREE_SOFT, ширина 2 бит; данные FREE_SOFT. */ + Uint16 FREE_SOFT:2; // 15:14 Emulation mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ECCTL1_REG в одной области памяти. */ +union ECCTL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECCTL1_BITS bit;; порядок полей определяет расположение данных. */ + struct ECCTL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// In V1.1 the STOPVALUE bit field was changed to +// STOP_WRAP. This correlated to a silicon change from +// F2833x Rev 0 to Rev A. +//---------------------------------------------------- +// Capture control register 2 bit definitions */ +/* Описывает структуру ECCTL2_BITS; порядок полей определяет расположение данных. */ +struct ECCTL2_BITS { // bits description + /* Битовое поле CONT_ONESHT, ширина 1 бит; данные CONT_ONESHT. */ + Uint16 CONT_ONESHT:1; // 0 Continuous or one-shot + /* Битовое поле STOP_WRAP, ширина 2 бит; данные STOP_WRAP. */ + Uint16 STOP_WRAP:2; // 2:1 Stop value for one-shot, Wrap for continuous + /* Битовое поле REARM, ширина 1 бит; данные REARM. */ + Uint16 REARM:1; // 3 One-shot re-arm + /* Битовое поле TSCTRSTOP, ширина 1 бит; данные TSCTRSTOP. */ + Uint16 TSCTRSTOP:1; // 4 TSCNT counter stop + /* Битовое поле SYNCI_EN, ширина 1 бит; данные SYNCI_EN. */ + Uint16 SYNCI_EN:1; // 5 Counter sync-in select + /* Битовое поле SYNCO_SEL, ширина 2 бит; данные SYNCO_SEL. */ + Uint16 SYNCO_SEL:2; // 7:6 Sync-out mode + /* Битовое поле SWSYNC, ширина 1 бит; данные SWSYNC. */ + Uint16 SWSYNC:1; // 8 SW forced counter sync + /* Битовое поле CAP_APWM, ширина 1 бит; данные CAP_APWM. */ + Uint16 CAP_APWM:1; // 9 CAP/APWM operating mode select + /* Битовое поле APWMPOL, ширина 1 бит; данные APWMPOL. */ + Uint16 APWMPOL:1; // 10 APWM output polarity select + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 15:11 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ECCTL2_REG в одной области памяти. */ +union ECCTL2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECCTL2_BITS bit;; порядок полей определяет расположение данных. */ + struct ECCTL2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// ECAP interrupt enable register bit definitions */ +/* Описывает структуру ECEINT_BITS; порядок полей определяет расположение данных. */ +struct ECEINT_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле CEVT1, ширина 1 бит; данные CEVT1. */ + Uint16 CEVT1:1; // 1 Capture Event 1 Interrupt Enable + /* Битовое поле CEVT2, ширина 1 бит; данные CEVT2. */ + Uint16 CEVT2:1; // 2 Capture Event 2 Interrupt Enable + /* Битовое поле CEVT3, ширина 1 бит; данные CEVT3. */ + Uint16 CEVT3:1; // 3 Capture Event 3 Interrupt Enable + /* Битовое поле CEVT4, ширина 1 бит; данные CEVT4. */ + Uint16 CEVT4:1; // 4 Capture Event 4 Interrupt Enable + /* Битовое поле CTROVF, ширина 1 бит; данные CTROVF. */ + Uint16 CTROVF:1; // 5 Counter Overflow Interrupt Enable + /* Битовое поле CTR_EQ_PRD, ширина 1 бит; данные CTR_EQ_PRD. */ + Uint16 CTR_EQ_PRD:1; // 6 Period Equal Interrupt Enable + /* Битовое поле CTR_EQ_CMP, ширина 1 бит; данные CTR_EQ_CMP. */ + Uint16 CTR_EQ_CMP:1; // 7 Compare Equal Interrupt Enable + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ECEINT_REG в одной области памяти. */ +union ECEINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECEINT_BITS bit;; порядок полей определяет расположение данных. */ + struct ECEINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// ECAP interrupt flag register bit definitions */ +/* Описывает структуру ECFLG_BITS; порядок полей определяет расположение данных. */ +struct ECFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global Flag + /* Битовое поле CEVT1, ширина 1 бит; данные CEVT1. */ + Uint16 CEVT1:1; // 1 Capture Event 1 Interrupt Flag + /* Битовое поле CEVT2, ширина 1 бит; данные CEVT2. */ + Uint16 CEVT2:1; // 2 Capture Event 2 Interrupt Flag + /* Битовое поле CEVT3, ширина 1 бит; данные CEVT3. */ + Uint16 CEVT3:1; // 3 Capture Event 3 Interrupt Flag + /* Битовое поле CEVT4, ширина 1 бит; данные CEVT4. */ + Uint16 CEVT4:1; // 4 Capture Event 4 Interrupt Flag + /* Битовое поле CTROVF, ширина 1 бит; данные CTROVF. */ + Uint16 CTROVF:1; // 5 Counter Overflow Interrupt Flag + /* Битовое поле CTR_EQ_PRD, ширина 1 бит; данные CTR_EQ_PRD. */ + Uint16 CTR_EQ_PRD:1; // 6 Period Equal Interrupt Flag + /* Битовое поле CTR_EQ_CMP, ширина 1 бит; данные CTR_EQ_CMP. */ + Uint16 CTR_EQ_CMP:1; // 7 Compare Equal Interrupt Flag + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ECFLG_REG в одной области памяти. */ +union ECFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct ECFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- + +/* Описывает структуру ECAP_REGS; порядок полей определяет расположение данных. */ +struct ECAP_REGS { + /* Объявляет TSCTR — данные TSCTR. */ + Uint32 TSCTR; // Time stamp counter + /* Объявляет CTRPHS — данные CTRPHS. */ + Uint32 CTRPHS; // Counter phase + /* Объявляет CAP1 — данные CAP1. */ + Uint32 CAP1; // Capture 1 + /* Объявляет CAP2 — данные CAP2. */ + Uint32 CAP2; // Capture 2 + /* Объявляет CAP3 — данные CAP3. */ + Uint32 CAP3; // Capture 3 + /* Объявляет CAP4 — данные CAP4. */ + Uint32 CAP4; // Capture 4 + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[8]; // reserved + /* Объединяет несколько представлений ECCTL1_REG ECCTL1; в одной области памяти. */ + union ECCTL1_REG ECCTL1; // Capture Control Reg 1 + /* Объединяет несколько представлений ECCTL2_REG ECCTL2; в одной области памяти. */ + union ECCTL2_REG ECCTL2; // Capture Control Reg 2 + /* Объединяет несколько представлений ECEINT_REG ECEINT; в одной области памяти. */ + union ECEINT_REG ECEINT; // ECAP interrupt enable + /* Объединяет несколько представлений ECFLG_REG ECFLG; в одной области памяти. */ + union ECFLG_REG ECFLG; // ECAP interrupt flags + /* Объединяет несколько представлений ECFLG_REG ECCLR; в одной области памяти. */ + union ECFLG_REG ECCLR; // ECAP interrupt clear + /* Объединяет несколько представлений ECEINT_REG ECFRC; в одной области памяти. */ + union ECEINT_REG ECFRC; // ECAP interrupt force + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[6]; // reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap1Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap2Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap2Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap3Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap3Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap4Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap4Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap5Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap5Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap6Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap6Regs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_ECAP_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h new file mode 100644 index 0000000..b6ed86c --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h @@ -0,0 +1,720 @@ +/* Поставляемое TI описание EPwm для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:10 $ +//########################################################################### +// +// FILE: DSP2833x_EPwm.h +// +// TITLE: DSP2833x Enhanced PWM Module Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EPWM_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EPWM_H +/* Определяет защитный символ или переключатель DSP2833x_EPWM_H для последующей компиляции. */ +#define DSP2833x_EPWM_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Time base control register bit definitions */ +/* Описывает структуру TBCTL_BITS; порядок полей определяет расположение данных. */ +struct TBCTL_BITS { // bits description + /* Битовое поле CTRMODE, ширина 2 бит; данные CTRMODE. */ + Uint16 CTRMODE:2; // 1:0 Counter Mode + /* Битовое поле PHSEN, ширина 1 бит; данные PHSEN. */ + Uint16 PHSEN:1; // 2 Phase load enable + /* Битовое поле PRDLD, ширина 1 бит; данные PRDLD. */ + Uint16 PRDLD:1; // 3 Active period load + /* Битовое поле SYNCOSEL, ширина 2 бит; данные SYNCOSEL. */ + Uint16 SYNCOSEL:2; // 5:4 Sync output select + /* Битовое поле SWFSYNC, ширина 1 бит; данные SWFSYNC. */ + Uint16 SWFSYNC:1; // 6 Software force sync pulse + /* Битовое поле HSPCLKDIV, ширина 3 бит; данные HSPCLKDIV. */ + Uint16 HSPCLKDIV:3; // 9:7 High speed time pre-scale + /* Битовое поле CLKDIV, ширина 3 бит; данные CLKDIV. */ + Uint16 CLKDIV:3; // 12:10 Timebase clock pre-scale + /* Битовое поле PHSDIR, ширина 1 бит; данные PHSDIR. */ + Uint16 PHSDIR:1; // 13 Phase Direction + /* Битовое поле FREE_SOFT, ширина 2 бит; данные FREE_SOFT. */ + Uint16 FREE_SOFT:2; // 15:14 Emulation mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TBCTL_REG в одной области памяти. */ +union TBCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TBCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct TBCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Time base status register bit definitions */ +/* Описывает структуру TBSTS_BITS; порядок полей определяет расположение данных. */ +struct TBSTS_BITS { // bits description + /* Битовое поле CTRDIR, ширина 1 бит; данные CTRDIR. */ + Uint16 CTRDIR:1; // 0 Counter direction status + /* Битовое поле SYNCI, ширина 1 бит; данные SYNCI. */ + Uint16 SYNCI:1; // 1 External input sync status + /* Битовое поле CTRMAX, ширина 1 бит; данные CTRMAX. */ + Uint16 CTRMAX:1; // 2 Counter max latched status + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TBSTS_REG в одной области памяти. */ +union TBSTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TBSTS_BITS bit;; порядок полей определяет расположение данных. */ + struct TBSTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Compare control register bit definitions */ +/* Описывает структуру CMPCTL_BITS; порядок полей определяет расположение данных. */ +struct CMPCTL_BITS { // bits description + /* Битовое поле LOADAMODE, ширина 2 бит; данные LOADAMODE. */ + Uint16 LOADAMODE:2; // 0:1 Active compare A + /* Битовое поле LOADBMODE, ширина 2 бит; данные LOADBMODE. */ + Uint16 LOADBMODE:2; // 3:2 Active compare B + /* Битовое поле SHDWAMODE, ширина 1 бит; данные SHDWAMODE. */ + Uint16 SHDWAMODE:1; // 4 Compare A block operating mode + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 5 reserved + /* Битовое поле SHDWBMODE, ширина 1 бит; данные SHDWBMODE. */ + Uint16 SHDWBMODE:1; // 6 Compare B block operating mode + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 7 reserved + /* Битовое поле SHDWAFULL, ширина 1 бит; данные SHDWAFULL. */ + Uint16 SHDWAFULL:1; // 8 Compare A Shadow registers full Status + /* Битовое поле SHDWBFULL, ширина 1 бит; данные SHDWBFULL. */ + Uint16 SHDWBFULL:1; // 9 Compare B Shadow registers full Status + /* Битовое поле rsvd3, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений CMPCTL_REG в одной области памяти. */ +union CMPCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CMPCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct CMPCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Action qualifier register bit definitions */ +/* Описывает структуру AQCTL_BITS; порядок полей определяет расположение данных. */ +struct AQCTL_BITS { // bits description + /* Битовое поле ZRO, ширина 2 бит; данные ZRO. */ + Uint16 ZRO:2; // 1:0 Action Counter = Zero + /* Битовое поле PRD, ширина 2 бит; данные PRD. */ + Uint16 PRD:2; // 3:2 Action Counter = Period + /* Битовое поле CAU, ширина 2 бит; данные CAU. */ + Uint16 CAU:2; // 5:4 Action Counter = Compare A up + /* Битовое поле CAD, ширина 2 бит; данные CAD. */ + Uint16 CAD:2; // 7:6 Action Counter = Compare A down + /* Битовое поле CBU, ширина 2 бит; данные CBU. */ + Uint16 CBU:2; // 9:8 Action Counter = Compare B up + /* Битовое поле CBD, ширина 2 бит; данные CBD. */ + Uint16 CBD:2; // 11:10 Action Counter = Compare B down + /* Битовое поле rsvd, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений AQCTL_REG в одной области памяти. */ +union AQCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру AQCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct AQCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Action qualifier SW force register bit definitions */ +/* Описывает структуру AQSFRC_BITS; порядок полей определяет расположение данных. */ +struct AQSFRC_BITS { // bits description + /* Битовое поле ACTSFA, ширина 2 бит; данные ACTSFA. */ + Uint16 ACTSFA:2; // 1:0 Action when One-time SW Force A invoked + /* Битовое поле OTSFA, ширина 1 бит; данные OTSFA. */ + Uint16 OTSFA:1; // 2 One-time SW Force A output + /* Битовое поле ACTSFB, ширина 2 бит; данные ACTSFB. */ + Uint16 ACTSFB:2; // 4:3 Action when One-time SW Force B invoked + /* Битовое поле OTSFB, ширина 1 бит; данные OTSFB. */ + Uint16 OTSFB:1; // 5 One-time SW Force A output + /* Битовое поле RLDCSF, ширина 2 бит; данные RLDCSF. */ + Uint16 RLDCSF:2; // 7:6 Reload from Shadow options + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений AQSFRC_REG в одной области памяти. */ +union AQSFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру AQSFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct AQSFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Action qualifier continuous SW force register bit definitions */ +/* Описывает структуру AQCSFRC_BITS; порядок полей определяет расположение данных. */ +struct AQCSFRC_BITS { // bits description + /* Битовое поле CSFA, ширина 2 бит; данные CSFA. */ + Uint16 CSFA:2; // 1:0 Continuous Software Force on output A + /* Битовое поле CSFB, ширина 2 бит; данные CSFB. */ + Uint16 CSFB:2; // 3:2 Continuous Software Force on output B + /* Битовое поле rsvd1, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений AQCSFRC_REG в одной области памяти. */ +union AQCSFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру AQCSFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct AQCSFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// As of version 1.1 +// Changed the MODE bit-field to OUT_MODE +// Added the bit-field IN_MODE +// This corresponds to changes in silicon as of F2833x devices +// Rev A silicon. +//---------------------------------------------------- +// Dead-band generator control register bit definitions +/* Описывает структуру DBCTL_BITS; порядок полей определяет расположение данных. */ +struct DBCTL_BITS { // bits description + /* Битовое поле OUT_MODE, ширина 2 бит; OUT режим. */ + Uint16 OUT_MODE:2; // 1:0 Dead Band Output Mode Control + /* Битовое поле POLSEL, ширина 2 бит; данные POLSEL. */ + Uint16 POLSEL:2; // 3:2 Polarity Select Control + /* Битовое поле IN_MODE, ширина 2 бит; IN режим. */ + Uint16 IN_MODE:2; // 5:4 Dead Band Input Select Mode Control + /* Битовое поле rsvd1, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:10; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DBCTL_REG в одной области памяти. */ +union DBCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DBCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct DBCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone select register bit definitions +/* Описывает структуру TZSEL_BITS; порядок полей определяет расположение данных. */ +struct TZSEL_BITS { // bits description + /* Битовое поле CBC1, ширина 1 бит; данные CBC1. */ + Uint16 CBC1:1; // 0 TZ1 CBC select + /* Битовое поле CBC2, ширина 1 бит; данные CBC2. */ + Uint16 CBC2:1; // 1 TZ2 CBC select + /* Битовое поле CBC3, ширина 1 бит; данные CBC3. */ + Uint16 CBC3:1; // 2 TZ3 CBC select + /* Битовое поле CBC4, ширина 1 бит; данные CBC4. */ + Uint16 CBC4:1; // 3 TZ4 CBC select + /* Битовое поле CBC5, ширина 1 бит; данные CBC5. */ + Uint16 CBC5:1; // 4 TZ5 CBC select + /* Битовое поле CBC6, ширина 1 бит; данные CBC6. */ + Uint16 CBC6:1; // 5 TZ6 CBC select + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 7:6 reserved + /* Битовое поле OSHT1, ширина 1 бит; данные OSHT1. */ + Uint16 OSHT1:1; // 8 One-shot TZ1 select + /* Битовое поле OSHT2, ширина 1 бит; данные OSHT2. */ + Uint16 OSHT2:1; // 9 One-shot TZ2 select + /* Битовое поле OSHT3, ширина 1 бит; данные OSHT3. */ + Uint16 OSHT3:1; // 10 One-shot TZ3 select + /* Битовое поле OSHT4, ширина 1 бит; данные OSHT4. */ + Uint16 OSHT4:1; // 11 One-shot TZ4 select + /* Битовое поле OSHT5, ширина 1 бит; данные OSHT5. */ + Uint16 OSHT5:1; // 12 One-shot TZ5 select + /* Битовое поле OSHT6, ширина 1 бит; данные OSHT6. */ + Uint16 OSHT6:1; // 13 One-shot TZ6 select + /* Битовое поле rsvd2, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:2; // 15:14 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZSEL_REG в одной области памяти. */ +union TZSEL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZSEL_BITS bit;; порядок полей определяет расположение данных. */ + struct TZSEL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone control register bit definitions */ +/* Описывает структуру TZCTL_BITS; порядок полей определяет расположение данных. */ +struct TZCTL_BITS { // bits description + /* Битовое поле TZA, ширина 2 бит; данные TZA. */ + Uint16 TZA:2; // 1:0 TZ1 to TZ6 Trip Action On EPWMxA + /* Битовое поле TZB, ширина 2 бит; данные TZB. */ + Uint16 TZB:2; // 3:2 TZ1 to TZ6 Trip Action On EPWMxB + /* Битовое поле rsvd, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZCTL_REG в одной области памяти. */ +union TZCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct TZCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone control register bit definitions */ +/* Описывает структуру TZEINT_BITS; порядок полей определяет расположение данных. */ +struct TZEINT_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int Enable + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int Enable + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений TZEINT_REG в одной области памяти. */ +union TZEINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZEINT_BITS bit;; порядок полей определяет расположение данных. */ + struct TZEINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone flag register bit definitions */ +/* Описывает структуру TZFLG_BITS; порядок полей определяет расположение данных. */ +struct TZFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global status + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZFLG_REG в одной области памяти. */ +union TZFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct TZFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Trip zone flag clear register bit definitions */ +/* Описывает структуру TZCLR_BITS; порядок полей определяет расположение данных. */ +struct TZCLR_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global status + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZCLR_REG в одной области памяти. */ +union TZCLR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZCLR_BITS bit;; порядок полей определяет расположение данных. */ + struct TZCLR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Trip zone flag force register bit definitions */ +/* Описывает структуру TZFRC_BITS; порядок полей определяет расположение данных. */ +struct TZFRC_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZFRC_REG в одной области памяти. */ +union TZFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct TZFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Event trigger select register bit definitions */ +/* Описывает структуру ETSEL_BITS; порядок полей определяет расположение данных. */ +struct ETSEL_BITS { // bits description + /* Битовое поле INTSEL, ширина 3 бит; данные INTSEL. */ + Uint16 INTSEL:3; // 2:0 EPWMxINTn Select + /* Битовое поле INTEN, ширина 1 бит; данные INTEN. */ + Uint16 INTEN:1; // 3 EPWMxINTn Enable + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 7:4 reserved + /* Битовое поле SOCASEL, ширина 3 бит; данные SOCASEL. */ + Uint16 SOCASEL:3; // 10:8 Start of conversion A Select + /* Битовое поле SOCAEN, ширина 1 бит; данные SOCAEN. */ + Uint16 SOCAEN:1; // 11 Start of conversion A Enable + /* Битовое поле SOCBSEL, ширина 3 бит; данные SOCBSEL. */ + Uint16 SOCBSEL:3; // 14:12 Start of conversion B Select + /* Битовое поле SOCBEN, ширина 1 бит; данные SOCBEN. */ + Uint16 SOCBEN:1; // 15 Start of conversion B Enable +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETSEL_REG в одной области памяти. */ +union ETSEL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETSEL_BITS bit;; порядок полей определяет расположение данных. */ + struct ETSEL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Event trigger pre-scale register bit definitions */ +/* Описывает структуру ETPS_BITS; порядок полей определяет расположение данных. */ +struct ETPS_BITS { // bits description + /* Битовое поле INTPRD, ширина 2 бит; данные INTPRD. */ + Uint16 INTPRD:2; // 1:0 EPWMxINTn Period Select + /* Битовое поле INTCNT, ширина 2 бит; данные INTCNT. */ + Uint16 INTCNT:2; // 3:2 EPWMxINTn Counter Register + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 7:4 reserved + /* Битовое поле SOCAPRD, ширина 2 бит; данные SOCAPRD. */ + Uint16 SOCAPRD:2; // 9:8 EPWMxSOCA Period Select + /* Битовое поле SOCACNT, ширина 2 бит; данные SOCACNT. */ + Uint16 SOCACNT:2; // 11:10 EPWMxSOCA Counter Register + /* Битовое поле SOCBPRD, ширина 2 бит; данные SOCBPRD. */ + Uint16 SOCBPRD:2; // 13:12 EPWMxSOCB Period Select + /* Битовое поле SOCBCNT, ширина 2 бит; данные SOCBCNT. */ + Uint16 SOCBCNT:2; // 15:14 EPWMxSOCB Counter Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETPS_REG в одной области памяти. */ +union ETPS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETPS_BITS bit;; порядок полей определяет расположение данных. */ + struct ETPS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Event trigger Flag register bit definitions */ +/* Описывает структуру ETFLG_BITS; порядок полей определяет расположение данных. */ +struct ETFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 EPWMxINTn Flag + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле SOCA, ширина 1 бит; данные SOCA. */ + Uint16 SOCA:1; // 2 EPWMxSOCA Flag + /* Битовое поле SOCB, ширина 1 бит; данные SOCB. */ + Uint16 SOCB:1; // 3 EPWMxSOCB Flag + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETFLG_REG в одной области памяти. */ +union ETFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct ETFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Event trigger Clear register bit definitions */ +/* Описывает структуру ETCLR_BITS; порядок полей определяет расположение данных. */ +struct ETCLR_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 EPWMxINTn Clear + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле SOCA, ширина 1 бит; данные SOCA. */ + Uint16 SOCA:1; // 2 EPWMxSOCA Clear + /* Битовое поле SOCB, ширина 1 бит; данные SOCB. */ + Uint16 SOCB:1; // 3 EPWMxSOCB Clear + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETCLR_REG в одной области памяти. */ +union ETCLR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETCLR_BITS bit;; порядок полей определяет расположение данных. */ + struct ETCLR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Event trigger Force register bit definitions */ +/* Описывает структуру ETFRC_BITS; порядок полей определяет расположение данных. */ +struct ETFRC_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 EPWMxINTn Force + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле SOCA, ширина 1 бит; данные SOCA. */ + Uint16 SOCA:1; // 2 EPWMxSOCA Force + /* Битовое поле SOCB, ширина 1 бит; данные SOCB. */ + Uint16 SOCB:1; // 3 EPWMxSOCB Force + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETFRC_REG в одной области памяти. */ +union ETFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct ETFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; +//---------------------------------------------------- +// PWM chopper control register bit definitions */ +/* Описывает структуру PCCTL_BITS; порядок полей определяет расположение данных. */ +struct PCCTL_BITS { // bits description + /* Битовое поле CHPEN, ширина 1 бит; данные CHPEN. */ + Uint16 CHPEN:1; // 0 PWM chopping enable + /* Битовое поле OSHTWTH, ширина 4 бит; данные OSHTWTH. */ + Uint16 OSHTWTH:4; // 4:1 One-shot pulse width + /* Битовое поле CHPFREQ, ширина 3 бит; данные CHPFREQ. */ + Uint16 CHPFREQ:3; // 7:5 Chopping clock frequency + /* Битовое поле CHPDUTY, ширина 3 бит; данные CHPDUTY. */ + Uint16 CHPDUTY:3; // 10:8 Chopping clock Duty cycle + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 15:11 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений PCCTL_REG в одной области памяти. */ +union PCCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct PCCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру HRCNFG_BITS; порядок полей определяет расположение данных. */ +struct HRCNFG_BITS { // bits description + /* Битовое поле EDGMODE, ширина 2 бит; данные EDGMODE. */ + Uint16 EDGMODE:2; // 1:0 Edge Mode select Bits + /* Битовое поле CTLMODE, ширина 1 бит; данные CTLMODE. */ + Uint16 CTLMODE:1; // 2 Control mode Select Bit + /* Битовое поле HRLOAD, ширина 1 бит; данные HRLOAD. */ + Uint16 HRLOAD:1; // 3 Shadow mode Select Bit + /* Битовое поле rsvd1, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений HRCNFG_REG в одной области памяти. */ +union HRCNFG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру HRCNFG_BITS bit;; порядок полей определяет расположение данных. */ + struct HRCNFG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру TBPHS_HRPWM_REG; порядок полей определяет расположение данных. */ +struct TBPHS_HRPWM_REG { // bits description + /* Объявляет TBPHSHR — данные TBPHSHR. */ + Uint16 TBPHSHR; // 15:0 Extension register for HRPWM Phase (8 bits) + /* Объявляет TBPHS — данные TBPHS. */ + Uint16 TBPHS; // 31:16 Phase offset register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TBPHS_HRPWM_GROUP в одной области памяти. */ +union TBPHS_HRPWM_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру TBPHS_HRPWM_REG half;; порядок полей определяет расположение данных. */ + struct TBPHS_HRPWM_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру CMPA_HRPWM_REG; порядок полей определяет расположение данных. */ +struct CMPA_HRPWM_REG { // bits description + /* Объявляет CMPAHR — данные CMPAHR. */ + Uint16 CMPAHR; // 15:0 Extension register for HRPWM compare (8 bits) + /* Объявляет CMPA — данные CMPA. */ + Uint16 CMPA; // 31:16 Compare A reg +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений CMPA_HRPWM_GROUP в одной области памяти. */ +union CMPA_HRPWM_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CMPA_HRPWM_REG half;; порядок полей определяет расположение данных. */ + struct CMPA_HRPWM_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру EPWM_REGS; порядок полей определяет расположение данных. */ +struct EPWM_REGS { + /* Объединяет несколько представлений TBCTL_REG TBCTL; в одной области памяти. */ + union TBCTL_REG TBCTL; // + /* Объединяет несколько представлений TBSTS_REG TBSTS; в одной области памяти. */ + union TBSTS_REG TBSTS; // + /* Объединяет несколько представлений TBPHS_HRPWM_GROUP TBPHS; в одной области памяти. */ + union TBPHS_HRPWM_GROUP TBPHS; // Union of TBPHS:TBPHSHR + /* Объявляет TBCTR — данные TBCTR. */ + Uint16 TBCTR; // Counter + /* Объявляет TBPRD — данные TBPRD. */ + Uint16 TBPRD; // Period register set + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // + /* Объединяет несколько представлений CMPCTL_REG CMPCTL; в одной области памяти. */ + union CMPCTL_REG CMPCTL; // Compare control + /* Объединяет несколько представлений CMPA_HRPWM_GROUP CMPA; в одной области памяти. */ + union CMPA_HRPWM_GROUP CMPA; // Union of CMPA:CMPAHR + /* Объявляет CMPB — данные CMPB. */ + Uint16 CMPB; // Compare B reg + /* Объединяет несколько представлений AQCTL_REG AQCTLA; в одной области памяти. */ + union AQCTL_REG AQCTLA; // Action qual output A + /* Объединяет несколько представлений AQCTL_REG AQCTLB; в одной области памяти. */ + union AQCTL_REG AQCTLB; // Action qual output B + /* Объединяет несколько представлений AQSFRC_REG AQSFRC; в одной области памяти. */ + union AQSFRC_REG AQSFRC; // Action qual SW force + /* Объединяет несколько представлений AQCSFRC_REG AQCSFRC; в одной области памяти. */ + union AQCSFRC_REG AQCSFRC; // Action qualifier continuous SW force + /* Объединяет несколько представлений DBCTL_REG DBCTL; в одной области памяти. */ + union DBCTL_REG DBCTL; // Dead-band control + /* Объявляет DBRED — данные DBRED. */ + Uint16 DBRED; // Dead-band rising edge delay + /* Объявляет DBFED — данные DBFED. */ + Uint16 DBFED; // Dead-band falling edge delay + /* Объединяет несколько представлений TZSEL_REG TZSEL; в одной области памяти. */ + union TZSEL_REG TZSEL; // Trip zone select + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; + /* Объединяет несколько представлений TZCTL_REG TZCTL; в одной области памяти. */ + union TZCTL_REG TZCTL; // Trip zone control + /* Объединяет несколько представлений TZEINT_REG TZEINT; в одной области памяти. */ + union TZEINT_REG TZEINT; // Trip zone interrupt enable + /* Объединяет несколько представлений TZFLG_REG TZFLG; в одной области памяти. */ + union TZFLG_REG TZFLG; // Trip zone interrupt flags + /* Объединяет несколько представлений TZCLR_REG TZCLR; в одной области памяти. */ + union TZCLR_REG TZCLR; // Trip zone clear + /* Объединяет несколько представлений TZFRC_REG TZFRC; в одной области памяти. */ + union TZFRC_REG TZFRC; // Trip zone force interrupt + /* Объединяет несколько представлений ETSEL_REG ETSEL; в одной области памяти. */ + union ETSEL_REG ETSEL; // Event trigger selection + /* Объединяет несколько представлений ETPS_REG ETPS; в одной области памяти. */ + union ETPS_REG ETPS; // Event trigger pre-scaler + /* Объединяет несколько представлений ETFLG_REG ETFLG; в одной области памяти. */ + union ETFLG_REG ETFLG; // Event trigger flags + /* Объединяет несколько представлений ETCLR_REG ETCLR; в одной области памяти. */ + union ETCLR_REG ETCLR; // Event trigger clear + /* Объединяет несколько представлений ETFRC_REG ETFRC; в одной области памяти. */ + union ETFRC_REG ETFRC; // Event trigger force + /* Объединяет несколько представлений PCCTL_REG PCCTL; в одной области памяти. */ + union PCCTL_REG PCCTL; // PWM chopper control + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // + /* Объединяет несколько представлений HRCNFG_REG HRCNFG; в одной области памяти. */ + union HRCNFG_REG HRCNFG; // HRPWM Config Reg +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//--------------------------------------------------------------------------- +// External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm1Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm2Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm2Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm3Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm3Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm4Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm4Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm5Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm5Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm6Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm6Regs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_EPWM_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h new file mode 100644 index 0000000..455839e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h @@ -0,0 +1,407 @@ +/* Поставляемое TI описание EQep для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:13 $ +//########################################################################### +// +// FILE: DSP2833x_EQep.h +// +// TITLE: DSP2833x Enhanced Quadrature Encoder Pulse Module +// Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EQEP_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EQEP_H +/* Определяет защитный символ или переключатель DSP2833x_EQEP_H для последующей компиляции. */ +#define DSP2833x_EQEP_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Capture decoder control register bit definitions */ +/* Описывает структуру QDECCTL_BITS; порядок полей определяет расположение данных. */ +struct QDECCTL_BITS { // bits description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле QSP, ширина 1 бит; данные QSP. */ + Uint16 QSP:1; // 5 QEPS input polarity + /* Битовое поле QIP, ширина 1 бит; данные QIP. */ + Uint16 QIP:1; // 6 QEPI input polarity + /* Битовое поле QBP, ширина 1 бит; данные QBP. */ + Uint16 QBP:1; // 7 QEPB input polarity + /* Битовое поле QAP, ширина 1 бит; данные QAP. */ + Uint16 QAP:1; // 8 QEPA input polarity + /* Битовое поле IGATE, ширина 1 бит; данные IGATE. */ + Uint16 IGATE:1; // 9 Index pulse gating option + /* Битовое поле SWAP, ширина 1 бит; данные SWAP. */ + Uint16 SWAP:1; // 10 CLK/DIR signal source for Position Counter + /* Битовое поле XCR, ширина 1 бит; данные XCR. */ + Uint16 XCR:1; // 11 External clock rate + /* Битовое поле SPSEL, ширина 1 бит; данные SPSEL. */ + Uint16 SPSEL:1; // 12 Sync output pin select + /* Битовое поле SOEN, ширина 1 бит; данные SOEN. */ + Uint16 SOEN:1; // 13 Enable position compare sync + /* Битовое поле QSRC, ширина 2 бит; данные QSRC. */ + Uint16 QSRC:2; // 15:14 Position counter source +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QDECCTL_REG в одной области памяти. */ +union QDECCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QDECCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QDECCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// QEP control register bit definitions */ +/* Описывает структуру QEPCTL_BITS; порядок полей определяет расположение данных. */ +struct QEPCTL_BITS { // bits description + /* Битовое поле WDE, ширина 1 бит; данные WDE. */ + Uint16 WDE:1; // 0 QEP watchdog enable + /* Битовое поле UTE, ширина 1 бит; данные UTE. */ + Uint16 UTE:1; // 1 QEP unit timer enable + /* Битовое поле QCLM, ширина 1 бит; данные QCLM. */ + Uint16 QCLM:1; // 2 QEP capture latch mode + /* Битовое поле QPEN, ширина 1 бит; данные QPEN. */ + Uint16 QPEN:1; // 3 Quadrature position counter enable + /* Битовое поле IEL, ширина 2 бит; данные IEL. */ + Uint16 IEL:2; // 5:4 Index event latch + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 6 Strobe event latch + /* Битовое поле SWI, ширина 1 бит; данные SWI. */ + Uint16 SWI:1; // 7 Software init position counter + /* Битовое поле IEI, ширина 2 бит; данные IEI. */ + Uint16 IEI:2; // 9:8 Index event init of position count + /* Битовое поле SEI, ширина 2 бит; данные SEI. */ + Uint16 SEI:2; // 11:10 Strobe event init + /* Битовое поле PCRM, ширина 2 бит; данные PCRM. */ + Uint16 PCRM:2; // 13:12 Position counter reset + /* Битовое поле FREE_SOFT, ширина 2 бит; данные FREE_SOFT. */ + Uint16 FREE_SOFT:2; // 15:14 Emulation mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QEPCTL_REG в одной области памяти. */ +union QEPCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QEPCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QEPCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Quadrature capture control register bit definitions */ +/* Описывает структуру QCAPCTL_BITS; порядок полей определяет расположение данных. */ +struct QCAPCTL_BITS { // bits description + /* Битовое поле UPPS, ширина 4 бит; данные UPPS. */ + Uint16 UPPS:4; // 3:0 Unit position pre-scale + /* Битовое поле CCPS, ширина 3 бит; данные CCPS. */ + Uint16 CCPS:3; // 6:4 QEP capture timer pre-scale + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 14:7 reserved + /* Битовое поле CEN, ширина 1 бит; данные CEN. */ + Uint16 CEN:1; // 15 Enable QEP capture +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QCAPCTL_REG в одной области памяти. */ +union QCAPCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QCAPCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QCAPCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//---------------------------------------------------- +// Position compare control register bit definitions */ +/* Описывает структуру QPOSCTL_BITS; порядок полей определяет расположение данных. */ +struct QPOSCTL_BITS { // bits description + /* Битовое поле PCSPW, ширина 12 бит; данные PCSPW. */ + Uint16 PCSPW:12; // 11:0 Position compare sync pulse width + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 12 Position compare enable/disable + /* Битовое поле PCPOL, ширина 1 бит; данные PCPOL. */ + Uint16 PCPOL:1; // 13 Polarity of sync output + /* Битовое поле PCLOAD, ширина 1 бит; данные PCLOAD. */ + Uint16 PCLOAD:1; // 14 Position compare of shadow load + /* Битовое поле PCSHDW, ширина 1 бит; данные PCSHDW. */ + Uint16 PCSHDW:1; // 15 Position compare shadow enable +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QPOSCTL_REG в одной области памяти. */ +union QPOSCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QPOSCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QPOSCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// QEP interrupt control register bit definitions */ +/* Описывает структуру QEINT_BITS; порядок полей определяет расположение данных. */ +struct QEINT_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 1 Position counter error + /* Битовое поле QPE, ширина 1 бит; данные QPE. */ + Uint16 QPE:1; // 2 Quadrature phase error + /* Битовое поле QDC, ширина 1 бит; данные QDC. */ + Uint16 QDC:1; // 3 Quadrature dir change + /* Битовое поле WTO, ширина 1 бит; данные WTO. */ + Uint16 WTO:1; // 4 Watchdog timeout + /* Битовое поле PCU, ширина 1 бит; данные PCU. */ + Uint16 PCU:1; // 5 Position counter underflow + /* Битовое поле PCO, ширина 1 бит; данные PCO. */ + Uint16 PCO:1; // 6 Position counter overflow + /* Битовое поле PCR, ширина 1 бит; данные PCR. */ + Uint16 PCR:1; // 7 Position compare ready + /* Битовое поле PCM, ширина 1 бит; данные PCM. */ + Uint16 PCM:1; // 8 Position compare match + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 9 Strobe event latch + /* Битовое поле IEL, ширина 1 бит; данные IEL. */ + Uint16 IEL:1; // 10 Event latch + /* Битовое поле UTO, ширина 1 бит; данные UTO. */ + Uint16 UTO:1; // 11 Unit timeout + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QEINT_REG в одной области памяти. */ +union QEINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QEINT_BITS bit;; порядок полей определяет расположение данных. */ + struct QEINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// QEP interrupt status register bit definitions */ +/* Описывает структуру QFLG_BITS; порядок полей определяет расположение данных. */ +struct QFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global interrupt + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 1 Position counter error + /* Битовое поле PHE, ширина 1 бит; данные PHE. */ + Uint16 PHE:1; // 2 Quadrature phase error + /* Битовое поле QDC, ширина 1 бит; данные QDC. */ + Uint16 QDC:1; // 3 Quadrature dir change + /* Битовое поле WTO, ширина 1 бит; данные WTO. */ + Uint16 WTO:1; // 4 Watchdog timeout + /* Битовое поле PCU, ширина 1 бит; данные PCU. */ + Uint16 PCU:1; // 5 Position counter underflow + /* Битовое поле PCO, ширина 1 бит; данные PCO. */ + Uint16 PCO:1; // 6 Position counter overflow + /* Битовое поле PCR, ширина 1 бит; данные PCR. */ + Uint16 PCR:1; // 7 Position compare ready + /* Битовое поле PCM, ширина 1 бит; данные PCM. */ + Uint16 PCM:1; // 8 Position compare match + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 9 Strobe event latch + /* Битовое поле IEL, ширина 1 бит; данные IEL. */ + Uint16 IEL:1; // 10 Event latch + /* Битовое поле UTO, ширина 1 бит; данные UTO. */ + Uint16 UTO:1; // 11 Unit timeout + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QFLG_REG в одной области памяти. */ +union QFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct QFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// QEP interrupt force register bit definitions */ +/* Описывает структуру QFRC_BITS; порядок полей определяет расположение данных. */ +struct QFRC_BITS { // bits description + /* Битовое поле reserved, ширина 1 бит; Зарезервировано; сохраняет положение следующих полей в аппаратном регистре. */ + Uint16 reserved:1; // 0 Reserved + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 1 Position counter error + /* Битовое поле PHE, ширина 1 бит; данные PHE. */ + Uint16 PHE:1; // 2 Quadrature phase error + /* Битовое поле QDC, ширина 1 бит; данные QDC. */ + Uint16 QDC:1; // 3 Quadrature dir change + /* Битовое поле WTO, ширина 1 бит; данные WTO. */ + Uint16 WTO:1; // 4 Watchdog timeout + /* Битовое поле PCU, ширина 1 бит; данные PCU. */ + Uint16 PCU:1; // 5 Position counter underflow + /* Битовое поле PCO, ширина 1 бит; данные PCO. */ + Uint16 PCO:1; // 6 Position counter overflow + /* Битовое поле PCR, ширина 1 бит; данные PCR. */ + Uint16 PCR:1; // 7 Position compare ready + /* Битовое поле PCM, ширина 1 бит; данные PCM. */ + Uint16 PCM:1; // 8 Position compare match + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 9 Strobe event latch + /* Битовое поле IEL, ширина 1 бит; данные IEL. */ + Uint16 IEL:1; // 10 Event latch + /* Битовое поле UTO, ширина 1 бит; данные UTO. */ + Uint16 UTO:1; // 11 Unit timeout + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QFRC_REG в одной области памяти. */ +union QFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct QFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// V1.1 Added UPEVNT (bit 7) This reflects changes +// made as of F2833x Rev A devices +//---------------------------------------------------- +// QEP status register bit definitions */ +/* Описывает структуру QEPSTS_BITS; порядок полей определяет расположение данных. */ +struct QEPSTS_BITS { // bits description + /* Битовое поле PCEF, ширина 1 бит; данные PCEF. */ + Uint16 PCEF:1; // 0 Position counter error + /* Битовое поле FIMF, ширина 1 бит; данные FIMF. */ + Uint16 FIMF:1; // 1 First index marker + /* Битовое поле CDEF, ширина 1 бит; данные CDEF. */ + Uint16 CDEF:1; // 2 Capture direction error + /* Битовое поле COEF, ширина 1 бит; данные COEF. */ + Uint16 COEF:1; // 3 Capture overflow error + /* Битовое поле QDLF, ширина 1 бит; данные QDLF. */ + Uint16 QDLF:1; // 4 QEP direction latch + /* Битовое поле QDF, ширина 1 бит; данные QDF. */ + Uint16 QDF:1; // 5 Quadrature direction + /* Битовое поле FIDF, ширина 1 бит; данные FIDF. */ + Uint16 FIDF:1; // 6 Direction on first index marker + /* Битовое поле UPEVNT, ширина 1 бит; данные UPEVNT. */ + Uint16 UPEVNT:1; // 7 Unit position event flag + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QEPSTS_REG в одной области памяти. */ +union QEPSTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QEPSTS_BITS bit;; порядок полей определяет расположение данных. */ + struct QEPSTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- + +/* Описывает структуру EQEP_REGS; порядок полей определяет расположение данных. */ +struct EQEP_REGS { + /* Объявляет QPOSCNT — данные QPOSCNT. */ + Uint32 QPOSCNT; // Position counter + /* Объявляет QPOSINIT — данные QPOSINIT. */ + Uint32 QPOSINIT; // Position counter init + /* Объявляет QPOSMAX — данные QPOSMAX. */ + Uint32 QPOSMAX; // Maximum position count + /* Объявляет QPOSCMP — данные QPOSCMP. */ + Uint32 QPOSCMP; // Position compare + /* Объявляет QPOSILAT — данные QPOSILAT. */ + Uint32 QPOSILAT; // Index position latch + /* Объявляет QPOSSLAT — данные QPOSSLAT. */ + Uint32 QPOSSLAT; // Strobe position latch + /* Объявляет QPOSLAT — данные QPOSLAT. */ + Uint32 QPOSLAT; // Position latch + /* Объявляет QUTMR — данные QUTMR. */ + Uint32 QUTMR; // Unit timer + /* Объявляет QUPRD — данные QUPRD. */ + Uint32 QUPRD; // Unit period + /* Объявляет QWDTMR — данные QWDTMR. */ + Uint16 QWDTMR; // QEP watchdog timer + /* Объявляет QWDPRD — данные QWDPRD. */ + Uint16 QWDPRD; // QEP watchdog period + /* Объединяет несколько представлений QDECCTL_REG QDECCTL; в одной области памяти. */ + union QDECCTL_REG QDECCTL; // Quadrature decoder control + /* Объединяет несколько представлений QEPCTL_REG QEPCTL; в одной области памяти. */ + union QEPCTL_REG QEPCTL; // QEP control + /* Объединяет несколько представлений QCAPCTL_REG QCAPCTL; в одной области памяти. */ + union QCAPCTL_REG QCAPCTL; // Quadrature capture control + /* Объединяет несколько представлений QPOSCTL_REG QPOSCTL; в одной области памяти. */ + union QPOSCTL_REG QPOSCTL; // Position compare control + /* Объединяет несколько представлений QEINT_REG QEINT; в одной области памяти. */ + union QEINT_REG QEINT; // QEP interrupt control + /* Объединяет несколько представлений QFLG_REG QFLG; в одной области памяти. */ + union QFLG_REG QFLG; // QEP interrupt flag + /* Объединяет несколько представлений QFLG_REG QCLR; в одной области памяти. */ + union QFLG_REG QCLR; // QEP interrupt clear + /* Объединяет несколько представлений QFRC_REG QFRC; в одной области памяти. */ + union QFRC_REG QFRC; // QEP interrupt force + /* Объединяет несколько представлений QEPSTS_REG QEPSTS; в одной области памяти. */ + union QEPSTS_REG QEPSTS; // QEP status + /* Объявляет QCTMR — данные QCTMR. */ + Uint16 QCTMR; // QEP capture timer + /* Объявляет QCPRD — данные QCPRD. */ + Uint16 QCPRD; // QEP capture period + /* Объявляет QCTMRLAT — данные QCTMRLAT. */ + Uint16 QCTMRLAT; // QEP capture latch + /* Объявляет QCPRDLAT — данные QCPRDLAT. */ + Uint16 QCPRDLAT; // QEP capture period latch + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[30]; // reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct EQEP_REGS EQep1Regs;; порядок элементов сохраняется. */ +extern volatile struct EQEP_REGS EQep1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EQEP_REGS EQep2Regs;; порядок элементов сохраняется. */ +extern volatile struct EQEP_REGS EQep2Regs; + + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_EQEP_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h new file mode 100644 index 0000000..772b340 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h @@ -0,0 +1,711 @@ +/* Поставляемое TI описание Gpio для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/4 $ +// Checkin $Date: November 15, 2007 09:58:53 $ +//########################################################################### +// +// FILE: DSP2833x_Gpio.h +// +// TITLE: DSP2833x General Purpose I/O Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_GPIO_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_GPIO_H +/* Определяет защитный символ или переключатель DSP2833x_GPIO_H для последующей компиляции. */ +#define DSP2833x_GPIO_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// GPIO A control register bit definitions */ +/* Описывает структуру GPACTRL_BITS; порядок полей определяет расположение данных. */ +struct GPACTRL_BITS { // bits description + /* Битовое поле QUALPRD0, ширина 8 бит; данные QUALPRD0. */ + Uint16 QUALPRD0:8; // 7:0 Qual period + /* Битовое поле QUALPRD1, ширина 8 бит; данные QUALPRD1. */ + Uint16 QUALPRD1:8; // 15:8 Qual period + /* Битовое поле QUALPRD2, ширина 8 бит; данные QUALPRD2. */ + Uint16 QUALPRD2:8; // 23:16 Qual period + /* Битовое поле QUALPRD3, ширина 8 бит; данные QUALPRD3. */ + Uint16 QUALPRD3:8; // 31:24 Qual period +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPACTRL_REG в одной области памяти. */ +union GPACTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPACTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct GPACTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// GPIO B control register bit definitions */ +/* Описывает структуру GPBCTRL_BITS; порядок полей определяет расположение данных. */ +struct GPBCTRL_BITS { // bits description + /* Битовое поле QUALPRD0, ширина 8 бит; данные QUALPRD0. */ + Uint16 QUALPRD0:8; // 7:0 Qual period + /* Битовое поле QUALPRD1, ширина 8 бит; данные QUALPRD1. */ + Uint16 QUALPRD1:8; // 15:8 Qual period + /* Битовое поле QUALPRD2, ширина 8 бит; данные QUALPRD2. */ + Uint16 QUALPRD2:8; // 23:16 Qual period + /* Битовое поле QUALPRD3, ширина 8 бит; данные QUALPRD3. */ + Uint16 QUALPRD3:8; // 31:24 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPBCTRL_REG в одной области памяти. */ +union GPBCTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPBCTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct GPBCTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// GPIO A Qual/MUX select register bit definitions */ +/* Описывает структуру GPA1_BITS; порядок полей определяет расположение данных. */ +struct GPA1_BITS { // bits description + /* Битовое поле GPIO0, ширина 2 бит; аппаратная линия ввода/вывода GPIO0. */ + Uint16 GPIO0:2; // 1:0 GPIO0 + /* Битовое поле GPIO1, ширина 2 бит; аппаратная линия ввода/вывода GPIO1. */ + Uint16 GPIO1:2; // 3:2 GPIO1 + /* Битовое поле GPIO2, ширина 2 бит; аппаратная линия ввода/вывода GPIO2. */ + Uint16 GPIO2:2; // 5:4 GPIO2 + /* Битовое поле GPIO3, ширина 2 бит; аппаратная линия ввода/вывода GPIO3. */ + Uint16 GPIO3:2; // 7:6 GPIO3 + /* Битовое поле GPIO4, ширина 2 бит; аппаратная линия ввода/вывода GPIO4. */ + Uint16 GPIO4:2; // 9:8 GPIO4 + /* Битовое поле GPIO5, ширина 2 бит; аппаратная линия ввода/вывода GPIO5. */ + Uint16 GPIO5:2; // 11:10 GPIO5 + /* Битовое поле GPIO6, ширина 2 бит; аппаратная линия ввода/вывода GPIO6. */ + Uint16 GPIO6:2; // 13:12 GPIO6 + /* Битовое поле GPIO7, ширина 2 бит; аппаратная линия ввода/вывода GPIO7. */ + Uint16 GPIO7:2; // 15:14 GPIO7 + /* Битовое поле GPIO8, ширина 2 бит; аппаратная линия ввода/вывода GPIO8. */ + Uint16 GPIO8:2; // 17:16 GPIO8 + /* Битовое поле GPIO9, ширина 2 бит; аппаратная линия ввода/вывода GPIO9. */ + Uint16 GPIO9:2; // 19:18 GPIO9 + /* Битовое поле GPIO10, ширина 2 бит; аппаратная линия ввода/вывода GPIO10. */ + Uint16 GPIO10:2; // 21:20 GPIO10 + /* Битовое поле GPIO11, ширина 2 бит; аппаратная линия ввода/вывода GPIO11. */ + Uint16 GPIO11:2; // 23:22 GPIO11 + /* Битовое поле GPIO12, ширина 2 бит; аппаратная линия ввода/вывода GPIO12. */ + Uint16 GPIO12:2; // 25:24 GPIO12 + /* Битовое поле GPIO13, ширина 2 бит; аппаратная линия ввода/вывода GPIO13. */ + Uint16 GPIO13:2; // 27:26 GPIO13 + /* Битовое поле GPIO14, ширина 2 бит; аппаратная линия ввода/вывода GPIO14. */ + Uint16 GPIO14:2; // 29:28 GPIO14 + /* Битовое поле GPIO15, ширина 2 бит; аппаратная линия ввода/вывода GPIO15. */ + Uint16 GPIO15:2; // 31:30 GPIO15 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру GPA2_BITS; порядок полей определяет расположение данных. */ +struct GPA2_BITS { // bits description + /* Битовое поле GPIO16, ширина 2 бит; аппаратная линия ввода/вывода GPIO16. */ + Uint16 GPIO16:2; // 1:0 GPIO16 + /* Битовое поле GPIO17, ширина 2 бит; аппаратная линия ввода/вывода GPIO17. */ + Uint16 GPIO17:2; // 3:2 GPIO17 + /* Битовое поле GPIO18, ширина 2 бит; аппаратная линия ввода/вывода GPIO18. */ + Uint16 GPIO18:2; // 5:4 GPIO18 + /* Битовое поле GPIO19, ширина 2 бит; аппаратная линия ввода/вывода GPIO19. */ + Uint16 GPIO19:2; // 7:6 GPIO19 + /* Битовое поле GPIO20, ширина 2 бит; аппаратная линия ввода/вывода GPIO20. */ + Uint16 GPIO20:2; // 9:8 GPIO20 + /* Битовое поле GPIO21, ширина 2 бит; аппаратная линия ввода/вывода GPIO21. */ + Uint16 GPIO21:2; // 11:10 GPIO21 + /* Битовое поле GPIO22, ширина 2 бит; аппаратная линия ввода/вывода GPIO22. */ + Uint16 GPIO22:2; // 13:12 GPIO22 + /* Битовое поле GPIO23, ширина 2 бит; аппаратная линия ввода/вывода GPIO23. */ + Uint16 GPIO23:2; // 15:14 GPIO23 + /* Битовое поле GPIO24, ширина 2 бит; аппаратная линия ввода/вывода GPIO24. */ + Uint16 GPIO24:2; // 17:16 GPIO24 + /* Битовое поле GPIO25, ширина 2 бит; аппаратная линия ввода/вывода GPIO25. */ + Uint16 GPIO25:2; // 19:18 GPIO25 + /* Битовое поле GPIO26, ширина 2 бит; аппаратная линия ввода/вывода GPIO26. */ + Uint16 GPIO26:2; // 21:20 GPIO26 + /* Битовое поле GPIO27, ширина 2 бит; аппаратная линия ввода/вывода GPIO27. */ + Uint16 GPIO27:2; // 23:22 GPIO27 + /* Битовое поле GPIO28, ширина 2 бит; аппаратная линия ввода/вывода GPIO28. */ + Uint16 GPIO28:2; // 25:24 GPIO28 + /* Битовое поле GPIO29, ширина 2 бит; аппаратная линия ввода/вывода GPIO29. */ + Uint16 GPIO29:2; // 27:26 GPIO29 + /* Битовое поле GPIO30, ширина 2 бит; аппаратная линия ввода/вывода GPIO30. */ + Uint16 GPIO30:2; // 29:28 GPIO30 + /* Битовое поле GPIO31, ширина 2 бит; аппаратная линия ввода/вывода GPIO31. */ + Uint16 GPIO31:2; // 31:30 GPIO31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPB1_BITS; порядок полей определяет расположение данных. */ +struct GPB1_BITS { // bits description + /* Битовое поле GPIO32, ширина 2 бит; аппаратная линия ввода/вывода GPIO32. */ + Uint16 GPIO32:2; // 1:0 GPIO32 + /* Битовое поле GPIO33, ширина 2 бит; аппаратная линия ввода/вывода GPIO33. */ + Uint16 GPIO33:2; // 3:2 GPIO33 + /* Битовое поле GPIO34, ширина 2 бит; аппаратная линия ввода/вывода GPIO34. */ + Uint16 GPIO34:2; // 5:4 GPIO34 + /* Битовое поле GPIO35, ширина 2 бит; аппаратная линия ввода/вывода GPIO35. */ + Uint16 GPIO35:2; // 7:6 GPIO35 + /* Битовое поле GPIO36, ширина 2 бит; аппаратная линия ввода/вывода GPIO36. */ + Uint16 GPIO36:2; // 9:8 GPIO36 + /* Битовое поле GPIO37, ширина 2 бит; аппаратная линия ввода/вывода GPIO37. */ + Uint16 GPIO37:2; // 11:10 GPIO37 + /* Битовое поле GPIO38, ширина 2 бит; аппаратная линия ввода/вывода GPIO38. */ + Uint16 GPIO38:2; // 13:12 GPIO38 + /* Битовое поле GPIO39, ширина 2 бит; аппаратная линия ввода/вывода GPIO39. */ + Uint16 GPIO39:2; // 15:14 GPIO39 + /* Битовое поле GPIO40, ширина 2 бит; аппаратная линия ввода/вывода GPIO40. */ + Uint16 GPIO40:2; // 17:16 GPIO40 + /* Битовое поле GPIO41, ширина 2 бит; аппаратная линия ввода/вывода GPIO41. */ + Uint16 GPIO41:2; // 19:16 GPIO41 + /* Битовое поле GPIO42, ширина 2 бит; аппаратная линия ввода/вывода GPIO42. */ + Uint16 GPIO42:2; // 21:20 GPIO42 + /* Битовое поле GPIO43, ширина 2 бит; аппаратная линия ввода/вывода GPIO43. */ + Uint16 GPIO43:2; // 23:22 GPIO43 + /* Битовое поле GPIO44, ширина 2 бит; аппаратная линия ввода/вывода GPIO44. */ + Uint16 GPIO44:2; // 25:24 GPIO44 + /* Битовое поле GPIO45, ширина 2 бит; аппаратная линия ввода/вывода GPIO45. */ + Uint16 GPIO45:2; // 27:26 GPIO45 + /* Битовое поле GPIO46, ширина 2 бит; аппаратная линия ввода/вывода GPIO46. */ + Uint16 GPIO46:2; // 29:28 GPIO46 + /* Битовое поле GPIO47, ширина 2 бит; аппаратная линия ввода/вывода GPIO47. */ + Uint16 GPIO47:2; // 31:30 GPIO47 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPB2_BITS; порядок полей определяет расположение данных. */ +struct GPB2_BITS { // bits description + /* Битовое поле GPIO48, ширина 2 бит; аппаратная линия ввода/вывода GPIO48. */ + Uint16 GPIO48:2; // 1:0 GPIO48 + /* Битовое поле GPIO49, ширина 2 бит; аппаратная линия ввода/вывода GPIO49. */ + Uint16 GPIO49:2; // 3:2 GPIO49 + /* Битовое поле GPIO50, ширина 2 бит; аппаратная линия ввода/вывода GPIO50. */ + Uint16 GPIO50:2; // 5:4 GPIO50 + /* Битовое поле GPIO51, ширина 2 бит; аппаратная линия ввода/вывода GPIO51. */ + Uint16 GPIO51:2; // 7:6 GPIO51 + /* Битовое поле GPIO52, ширина 2 бит; аппаратная линия ввода/вывода GPIO52. */ + Uint16 GPIO52:2; // 9:8 GPIO52 + /* Битовое поле GPIO53, ширина 2 бит; аппаратная линия ввода/вывода GPIO53. */ + Uint16 GPIO53:2; // 11:10 GPIO53 + /* Битовое поле GPIO54, ширина 2 бит; аппаратная линия ввода/вывода GPIO54. */ + Uint16 GPIO54:2; // 13:12 GPIO54 + /* Битовое поле GPIO55, ширина 2 бит; аппаратная линия ввода/вывода GPIO55. */ + Uint16 GPIO55:2; // 15:14 GPIO55 + /* Битовое поле GPIO56, ширина 2 бит; аппаратная линия ввода/вывода GPIO56. */ + Uint16 GPIO56:2; // 17:16 GPIO56 + /* Битовое поле GPIO57, ширина 2 бит; аппаратная линия ввода/вывода GPIO57. */ + Uint16 GPIO57:2; // 19:18 GPIO57 + /* Битовое поле GPIO58, ширина 2 бит; аппаратная линия ввода/вывода GPIO58. */ + Uint16 GPIO58:2; // 21:20 GPIO58 + /* Битовое поле GPIO59, ширина 2 бит; аппаратная линия ввода/вывода GPIO59. */ + Uint16 GPIO59:2; // 23:22 GPIO59 + /* Битовое поле GPIO60, ширина 2 бит; аппаратная линия ввода/вывода GPIO60. */ + Uint16 GPIO60:2; // 25:24 GPIO60 + /* Битовое поле GPIO61, ширина 2 бит; аппаратная линия ввода/вывода GPIO61. */ + Uint16 GPIO61:2; // 27:26 GPIO61 + /* Битовое поле GPIO62, ширина 2 бит; аппаратная линия ввода/вывода GPIO62. */ + Uint16 GPIO62:2; // 29:28 GPIO62 + /* Битовое поле GPIO63, ширина 2 бит; аппаратная линия ввода/вывода GPIO63. */ + Uint16 GPIO63:2; // 31:30 GPIO63 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPC1_BITS; порядок полей определяет расположение данных. */ +struct GPC1_BITS { // bits description + /* Битовое поле GPIO64, ширина 2 бит; аппаратная линия ввода/вывода GPIO64. */ + Uint16 GPIO64:2; // 1:0 GPIO64 + /* Битовое поле GPIO65, ширина 2 бит; аппаратная линия ввода/вывода GPIO65. */ + Uint16 GPIO65:2; // 3:2 GPIO65 + /* Битовое поле GPIO66, ширина 2 бит; аппаратная линия ввода/вывода GPIO66. */ + Uint16 GPIO66:2; // 5:4 GPIO66 + /* Битовое поле GPIO67, ширина 2 бит; аппаратная линия ввода/вывода GPIO67. */ + Uint16 GPIO67:2; // 7:6 GPIO67 + /* Битовое поле GPIO68, ширина 2 бит; аппаратная линия ввода/вывода GPIO68. */ + Uint16 GPIO68:2; // 9:8 GPIO68 + /* Битовое поле GPIO69, ширина 2 бит; аппаратная линия ввода/вывода GPIO69. */ + Uint16 GPIO69:2; // 11:10 GPIO69 + /* Битовое поле GPIO70, ширина 2 бит; аппаратная линия ввода/вывода GPIO70. */ + Uint16 GPIO70:2; // 13:12 GPIO70 + /* Битовое поле GPIO71, ширина 2 бит; аппаратная линия ввода/вывода GPIO71. */ + Uint16 GPIO71:2; // 15:14 GPIO71 + /* Битовое поле GPIO72, ширина 2 бит; аппаратная линия ввода/вывода GPIO72. */ + Uint16 GPIO72:2; // 17:16 GPIO72 + /* Битовое поле GPIO73, ширина 2 бит; аппаратная линия ввода/вывода GPIO73. */ + Uint16 GPIO73:2; // 19:18 GPIO73 + /* Битовое поле GPIO74, ширина 2 бит; аппаратная линия ввода/вывода GPIO74. */ + Uint16 GPIO74:2; // 21:20 GPIO74 + /* Битовое поле GPIO75, ширина 2 бит; аппаратная линия ввода/вывода GPIO75. */ + Uint16 GPIO75:2; // 23:22 GPIO75 + /* Битовое поле GPIO76, ширина 2 бит; аппаратная линия ввода/вывода GPIO76. */ + Uint16 GPIO76:2; // 25:24 GPIO76 + /* Битовое поле GPIO77, ширина 2 бит; аппаратная линия ввода/вывода GPIO77. */ + Uint16 GPIO77:2; // 27:26 GPIO77 + /* Битовое поле GPIO78, ширина 2 бит; аппаратная линия ввода/вывода GPIO78. */ + Uint16 GPIO78:2; // 29:28 GPIO78 + /* Битовое поле GPIO79, ширина 2 бит; аппаратная линия ввода/вывода GPIO79. */ + Uint16 GPIO79:2; // 31:30 GPIO79 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру GPC2_BITS; порядок полей определяет расположение данных. */ +struct GPC2_BITS { // bits description + /* Битовое поле GPIO80, ширина 2 бит; аппаратная линия ввода/вывода GPIO80. */ + Uint16 GPIO80:2; // 1:0 GPIO80 + /* Битовое поле GPIO81, ширина 2 бит; аппаратная линия ввода/вывода GPIO81. */ + Uint16 GPIO81:2; // 3:2 GPIO81 + /* Битовое поле GPIO82, ширина 2 бит; аппаратная линия ввода/вывода GPIO82. */ + Uint16 GPIO82:2; // 5:4 GPIO82 + /* Битовое поле GPIO83, ширина 2 бит; аппаратная линия ввода/вывода GPIO83. */ + Uint16 GPIO83:2; // 7:6 GPIO83 + /* Битовое поле GPIO84, ширина 2 бит; аппаратная линия ввода/вывода GPIO84. */ + Uint16 GPIO84:2; // 9:8 GPIO84 + /* Битовое поле GPIO85, ширина 2 бит; аппаратная линия ввода/вывода GPIO85. */ + Uint16 GPIO85:2; // 11:10 GPIO85 + /* Битовое поле GPIO86, ширина 2 бит; аппаратная линия ввода/вывода GPIO86. */ + Uint16 GPIO86:2; // 13:12 GPIO86 + /* Битовое поле GPIO87, ширина 2 бит; аппаратная линия ввода/вывода GPIO87. */ + Uint16 GPIO87:2; // 15:14 GPIO87 + /* Битовое поле rsvd, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений GPA1_REG в одной области памяти. */ +union GPA1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPA1_BITS bit;; порядок полей определяет расположение данных. */ + struct GPA1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPA2_REG в одной области памяти. */ +union GPA2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPA2_BITS bit;; порядок полей определяет расположение данных. */ + struct GPA2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPB1_REG в одной области памяти. */ +union GPB1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPB1_BITS bit;; порядок полей определяет расположение данных. */ + struct GPB1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPB2_REG в одной области памяти. */ +union GPB2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPB2_BITS bit;; порядок полей определяет расположение данных. */ + struct GPB2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPC1_REG в одной области памяти. */ +union GPC1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPC1_BITS bit;; порядок полей определяет расположение данных. */ + struct GPC1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPC2_REG в одной области памяти. */ +union GPC2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPC2_BITS bit;; порядок полей определяет расположение данных. */ + struct GPC2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// GPIO A DIR/TOGGLE/SET/CLEAR register bit definitions */ +/* Описывает структуру GPADAT_BITS; порядок полей определяет расположение данных. */ +struct GPADAT_BITS { // bits description + /* Битовое поле GPIO0, ширина 1 бит; аппаратная линия ввода/вывода GPIO0. */ + Uint16 GPIO0:1; // 0 GPIO0 + /* Битовое поле GPIO1, ширина 1 бит; аппаратная линия ввода/вывода GPIO1. */ + Uint16 GPIO1:1; // 1 GPIO1 + /* Битовое поле GPIO2, ширина 1 бит; аппаратная линия ввода/вывода GPIO2. */ + Uint16 GPIO2:1; // 2 GPIO2 + /* Битовое поле GPIO3, ширина 1 бит; аппаратная линия ввода/вывода GPIO3. */ + Uint16 GPIO3:1; // 3 GPIO3 + /* Битовое поле GPIO4, ширина 1 бит; аппаратная линия ввода/вывода GPIO4. */ + Uint16 GPIO4:1; // 4 GPIO4 + /* Битовое поле GPIO5, ширина 1 бит; аппаратная линия ввода/вывода GPIO5. */ + Uint16 GPIO5:1; // 5 GPIO5 + /* Битовое поле GPIO6, ширина 1 бит; аппаратная линия ввода/вывода GPIO6. */ + Uint16 GPIO6:1; // 6 GPIO6 + /* Битовое поле GPIO7, ширина 1 бит; аппаратная линия ввода/вывода GPIO7. */ + Uint16 GPIO7:1; // 7 GPIO7 + /* Битовое поле GPIO8, ширина 1 бит; аппаратная линия ввода/вывода GPIO8. */ + Uint16 GPIO8:1; // 8 GPIO8 + /* Битовое поле GPIO9, ширина 1 бит; аппаратная линия ввода/вывода GPIO9. */ + Uint16 GPIO9:1; // 9 GPIO9 + /* Битовое поле GPIO10, ширина 1 бит; аппаратная линия ввода/вывода GPIO10. */ + Uint16 GPIO10:1; // 10 GPIO10 + /* Битовое поле GPIO11, ширина 1 бит; аппаратная линия ввода/вывода GPIO11. */ + Uint16 GPIO11:1; // 11 GPIO11 + /* Битовое поле GPIO12, ширина 1 бит; аппаратная линия ввода/вывода GPIO12. */ + Uint16 GPIO12:1; // 12 GPIO12 + /* Битовое поле GPIO13, ширина 1 бит; аппаратная линия ввода/вывода GPIO13. */ + Uint16 GPIO13:1; // 13 GPIO13 + /* Битовое поле GPIO14, ширина 1 бит; аппаратная линия ввода/вывода GPIO14. */ + Uint16 GPIO14:1; // 14 GPIO14 + /* Битовое поле GPIO15, ширина 1 бит; аппаратная линия ввода/вывода GPIO15. */ + Uint16 GPIO15:1; // 15 GPIO15 + /* Битовое поле GPIO16, ширина 1 бит; аппаратная линия ввода/вывода GPIO16. */ + Uint16 GPIO16:1; // 16 GPIO16 + /* Битовое поле GPIO17, ширина 1 бит; аппаратная линия ввода/вывода GPIO17. */ + Uint16 GPIO17:1; // 17 GPIO17 + /* Битовое поле GPIO18, ширина 1 бит; аппаратная линия ввода/вывода GPIO18. */ + Uint16 GPIO18:1; // 18 GPIO18 + /* Битовое поле GPIO19, ширина 1 бит; аппаратная линия ввода/вывода GPIO19. */ + Uint16 GPIO19:1; // 19 GPIO19 + /* Битовое поле GPIO20, ширина 1 бит; аппаратная линия ввода/вывода GPIO20. */ + Uint16 GPIO20:1; // 20 GPIO20 + /* Битовое поле GPIO21, ширина 1 бит; аппаратная линия ввода/вывода GPIO21. */ + Uint16 GPIO21:1; // 21 GPIO21 + /* Битовое поле GPIO22, ширина 1 бит; аппаратная линия ввода/вывода GPIO22. */ + Uint16 GPIO22:1; // 22 GPIO22 + /* Битовое поле GPIO23, ширина 1 бит; аппаратная линия ввода/вывода GPIO23. */ + Uint16 GPIO23:1; // 23 GPIO23 + /* Битовое поле GPIO24, ширина 1 бит; аппаратная линия ввода/вывода GPIO24. */ + Uint16 GPIO24:1; // 24 GPIO24 + /* Битовое поле GPIO25, ширина 1 бит; аппаратная линия ввода/вывода GPIO25. */ + Uint16 GPIO25:1; // 25 GPIO25 + /* Битовое поле GPIO26, ширина 1 бит; аппаратная линия ввода/вывода GPIO26. */ + Uint16 GPIO26:1; // 26 GPIO26 + /* Битовое поле GPIO27, ширина 1 бит; аппаратная линия ввода/вывода GPIO27. */ + Uint16 GPIO27:1; // 27 GPIO27 + /* Битовое поле GPIO28, ширина 1 бит; аппаратная линия ввода/вывода GPIO28. */ + Uint16 GPIO28:1; // 28 GPIO28 + /* Битовое поле GPIO29, ширина 1 бит; аппаратная линия ввода/вывода GPIO29. */ + Uint16 GPIO29:1; // 29 GPIO29 + /* Битовое поле GPIO30, ширина 1 бит; аппаратная линия ввода/вывода GPIO30. */ + Uint16 GPIO30:1; // 30 GPIO30 + /* Битовое поле GPIO31, ширина 1 бит; аппаратная линия ввода/вывода GPIO31. */ + Uint16 GPIO31:1; // 31 GPIO31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPBDAT_BITS; порядок полей определяет расположение данных. */ +struct GPBDAT_BITS { // bits description + /* Битовое поле GPIO32, ширина 1 бит; аппаратная линия ввода/вывода GPIO32. */ + Uint16 GPIO32:1; // 0 GPIO32 + /* Битовое поле GPIO33, ширина 1 бит; аппаратная линия ввода/вывода GPIO33. */ + Uint16 GPIO33:1; // 1 GPIO33 + /* Битовое поле GPIO34, ширина 1 бит; аппаратная линия ввода/вывода GPIO34. */ + Uint16 GPIO34:1; // 2 GPIO34 + /* Битовое поле GPIO35, ширина 1 бит; аппаратная линия ввода/вывода GPIO35. */ + Uint16 GPIO35:1; // 3 GPIO35 + /* Битовое поле GPIO36, ширина 1 бит; аппаратная линия ввода/вывода GPIO36. */ + Uint16 GPIO36:1; // 4 GPIO36 + /* Битовое поле GPIO37, ширина 1 бит; аппаратная линия ввода/вывода GPIO37. */ + Uint16 GPIO37:1; // 5 GPIO37 + /* Битовое поле GPIO38, ширина 1 бит; аппаратная линия ввода/вывода GPIO38. */ + Uint16 GPIO38:1; // 6 GPIO38 + /* Битовое поле GPIO39, ширина 1 бит; аппаратная линия ввода/вывода GPIO39. */ + Uint16 GPIO39:1; // 7 GPIO39 + /* Битовое поле GPIO40, ширина 1 бит; аппаратная линия ввода/вывода GPIO40. */ + Uint16 GPIO40:1; // 8 GPIO40 + /* Битовое поле GPIO41, ширина 1 бит; аппаратная линия ввода/вывода GPIO41. */ + Uint16 GPIO41:1; // 9 GPIO41 + /* Битовое поле GPIO42, ширина 1 бит; аппаратная линия ввода/вывода GPIO42. */ + Uint16 GPIO42:1; // 10 GPIO42 + /* Битовое поле GPIO43, ширина 1 бит; аппаратная линия ввода/вывода GPIO43. */ + Uint16 GPIO43:1; // 11 GPIO43 + /* Битовое поле GPIO44, ширина 1 бит; аппаратная линия ввода/вывода GPIO44. */ + Uint16 GPIO44:1; // 12 GPIO44 + /* Битовое поле GPIO45, ширина 1 бит; аппаратная линия ввода/вывода GPIO45. */ + Uint16 GPIO45:1; // 13 GPIO45 + /* Битовое поле GPIO46, ширина 1 бит; аппаратная линия ввода/вывода GPIO46. */ + Uint16 GPIO46:1; // 14 GPIO46 + /* Битовое поле GPIO47, ширина 1 бит; аппаратная линия ввода/вывода GPIO47. */ + Uint16 GPIO47:1; // 15 GPIO47 + /* Битовое поле GPIO48, ширина 1 бит; аппаратная линия ввода/вывода GPIO48. */ + Uint16 GPIO48:1; // 16 GPIO48 + /* Битовое поле GPIO49, ширина 1 бит; аппаратная линия ввода/вывода GPIO49. */ + Uint16 GPIO49:1; // 17 GPIO49 + /* Битовое поле GPIO50, ширина 1 бит; аппаратная линия ввода/вывода GPIO50. */ + Uint16 GPIO50:1; // 18 GPIO50 + /* Битовое поле GPIO51, ширина 1 бит; аппаратная линия ввода/вывода GPIO51. */ + Uint16 GPIO51:1; // 19 GPIO51 + /* Битовое поле GPIO52, ширина 1 бит; аппаратная линия ввода/вывода GPIO52. */ + Uint16 GPIO52:1; // 20 GPIO52 + /* Битовое поле GPIO53, ширина 1 бит; аппаратная линия ввода/вывода GPIO53. */ + Uint16 GPIO53:1; // 21 GPIO53 + /* Битовое поле GPIO54, ширина 1 бит; аппаратная линия ввода/вывода GPIO54. */ + Uint16 GPIO54:1; // 22 GPIO54 + /* Битовое поле GPIO55, ширина 1 бит; аппаратная линия ввода/вывода GPIO55. */ + Uint16 GPIO55:1; // 23 GPIO55 + /* Битовое поле GPIO56, ширина 1 бит; аппаратная линия ввода/вывода GPIO56. */ + Uint16 GPIO56:1; // 24 GPIO56 + /* Битовое поле GPIO57, ширина 1 бит; аппаратная линия ввода/вывода GPIO57. */ + Uint16 GPIO57:1; // 25 GPIO57 + /* Битовое поле GPIO58, ширина 1 бит; аппаратная линия ввода/вывода GPIO58. */ + Uint16 GPIO58:1; // 26 GPIO58 + /* Битовое поле GPIO59, ширина 1 бит; аппаратная линия ввода/вывода GPIO59. */ + Uint16 GPIO59:1; // 27 GPIO59 + /* Битовое поле GPIO60, ширина 1 бит; аппаратная линия ввода/вывода GPIO60. */ + Uint16 GPIO60:1; // 28 GPIO60 + /* Битовое поле GPIO61, ширина 1 бит; аппаратная линия ввода/вывода GPIO61. */ + Uint16 GPIO61:1; // 29 GPIO61 + /* Битовое поле GPIO62, ширина 1 бит; аппаратная линия ввода/вывода GPIO62. */ + Uint16 GPIO62:1; // 30 GPIO62 + /* Битовое поле GPIO63, ширина 1 бит; аппаратная линия ввода/вывода GPIO63. */ + Uint16 GPIO63:1; // 31 GPIO63 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPCDAT_BITS; порядок полей определяет расположение данных. */ +struct GPCDAT_BITS { // bits description + /* Битовое поле GPIO64, ширина 1 бит; аппаратная линия ввода/вывода GPIO64. */ + Uint16 GPIO64:1; // 0 GPIO64 + /* Битовое поле GPIO65, ширина 1 бит; аппаратная линия ввода/вывода GPIO65. */ + Uint16 GPIO65:1; // 1 GPIO65 + /* Битовое поле GPIO66, ширина 1 бит; аппаратная линия ввода/вывода GPIO66. */ + Uint16 GPIO66:1; // 2 GPIO66 + /* Битовое поле GPIO67, ширина 1 бит; аппаратная линия ввода/вывода GPIO67. */ + Uint16 GPIO67:1; // 3 GPIO67 + /* Битовое поле GPIO68, ширина 1 бит; аппаратная линия ввода/вывода GPIO68. */ + Uint16 GPIO68:1; // 4 GPIO68 + /* Битовое поле GPIO69, ширина 1 бит; аппаратная линия ввода/вывода GPIO69. */ + Uint16 GPIO69:1; // 5 GPIO69 + /* Битовое поле GPIO70, ширина 1 бит; аппаратная линия ввода/вывода GPIO70. */ + Uint16 GPIO70:1; // 6 GPIO70 + /* Битовое поле GPIO71, ширина 1 бит; аппаратная линия ввода/вывода GPIO71. */ + Uint16 GPIO71:1; // 7 GPIO71 + /* Битовое поле GPIO72, ширина 1 бит; аппаратная линия ввода/вывода GPIO72. */ + Uint16 GPIO72:1; // 8 GPIO72 + /* Битовое поле GPIO73, ширина 1 бит; аппаратная линия ввода/вывода GPIO73. */ + Uint16 GPIO73:1; // 9 GPIO73 + /* Битовое поле GPIO74, ширина 1 бит; аппаратная линия ввода/вывода GPIO74. */ + Uint16 GPIO74:1; // 10 GPIO74 + /* Битовое поле GPIO75, ширина 1 бит; аппаратная линия ввода/вывода GPIO75. */ + Uint16 GPIO75:1; // 11 GPIO75 + /* Битовое поле GPIO76, ширина 1 бит; аппаратная линия ввода/вывода GPIO76. */ + Uint16 GPIO76:1; // 12 GPIO76 + /* Битовое поле GPIO77, ширина 1 бит; аппаратная линия ввода/вывода GPIO77. */ + Uint16 GPIO77:1; // 13 GPIO77 + /* Битовое поле GPIO78, ширина 1 бит; аппаратная линия ввода/вывода GPIO78. */ + Uint16 GPIO78:1; // 14 GPIO78 + /* Битовое поле GPIO79, ширина 1 бит; аппаратная линия ввода/вывода GPIO79. */ + Uint16 GPIO79:1; // 15 GPIO79 + /* Битовое поле GPIO80, ширина 1 бит; аппаратная линия ввода/вывода GPIO80. */ + Uint16 GPIO80:1; // 16 GPIO80 + /* Битовое поле GPIO81, ширина 1 бит; аппаратная линия ввода/вывода GPIO81. */ + Uint16 GPIO81:1; // 17 GPIO81 + /* Битовое поле GPIO82, ширина 1 бит; аппаратная линия ввода/вывода GPIO82. */ + Uint16 GPIO82:1; // 18 GPIO82 + /* Битовое поле GPIO83, ширина 1 бит; аппаратная линия ввода/вывода GPIO83. */ + Uint16 GPIO83:1; // 19 GPIO83 + /* Битовое поле GPIO84, ширина 1 бит; аппаратная линия ввода/вывода GPIO84. */ + Uint16 GPIO84:1; // 20 GPIO84 + /* Битовое поле GPIO85, ширина 1 бит; аппаратная линия ввода/вывода GPIO85. */ + Uint16 GPIO85:1; // 21 GPIO85 + /* Битовое поле GPIO86, ширина 1 бит; аппаратная линия ввода/вывода GPIO86. */ + Uint16 GPIO86:1; // 22 GPIO86 + /* Битовое поле GPIO87, ширина 1 бит; аппаратная линия ввода/вывода GPIO87. */ + Uint16 GPIO87:1; // 23 GPIO87 + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 31:24 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений GPADAT_REG в одной области памяти. */ +union GPADAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPADAT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPADAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPBDAT_REG в одной области памяти. */ +union GPBDAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPBDAT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPBDAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPCDAT_REG в одной области памяти. */ +union GPCDAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPCDAT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPCDAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//---------------------------------------------------- +// GPIO Xint1/XINT2/XNMI select register bit definitions */ +/* Описывает структуру GPIOXINT_BITS; порядок полей определяет расположение данных. */ +struct GPIOXINT_BITS { // bits description + /* Битовое поле GPIOSEL, ширина 5 бит; аппаратная линия ввода/вывода GPIOSEL. */ + Uint16 GPIOSEL:5; // 4:0 Select GPIO interrupt input source + /* Битовое поле rsvd1, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPIOXINT_REG в одной области памяти. */ +union GPIOXINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру GPIOXINT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPIOXINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру GPIO_CTRL_REGS; порядок полей определяет расположение данных. */ +struct GPIO_CTRL_REGS { + /* Объединяет несколько представлений GPACTRL_REG GPACTRL; в одной области памяти. */ + union GPACTRL_REG GPACTRL; // GPIO A Control Register (GPIO0 to 31) + /* Объединяет несколько представлений GPA1_REG GPAQSEL1; в одной области памяти. */ + union GPA1_REG GPAQSEL1; // GPIO A Qualifier Select 1 Register (GPIO0 to 15) + /* Объединяет несколько представлений GPA2_REG GPAQSEL2; в одной области памяти. */ + union GPA2_REG GPAQSEL2; // GPIO A Qualifier Select 2 Register (GPIO16 to 31) + /* Объединяет несколько представлений GPA1_REG GPAMUX1; в одной области памяти. */ + union GPA1_REG GPAMUX1; // GPIO A Mux 1 Register (GPIO0 to 15) + /* Объединяет несколько представлений GPA2_REG GPAMUX2; в одной области памяти. */ + union GPA2_REG GPAMUX2; // GPIO A Mux 2 Register (GPIO16 to 31) + /* Объединяет несколько представлений GPADAT_REG GPADIR; в одной области памяти. */ + union GPADAT_REG GPADIR; // GPIO A Direction Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPAPUD; в одной области памяти. */ + union GPADAT_REG GPAPUD; // GPIO A Pull Up Disable Register (GPIO0 to 31) + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd1; + /* Объединяет несколько представлений GPBCTRL_REG GPBCTRL; в одной области памяти. */ + union GPBCTRL_REG GPBCTRL; // GPIO B Control Register (GPIO32 to 63) + /* Объединяет несколько представлений GPB1_REG GPBQSEL1; в одной области памяти. */ + union GPB1_REG GPBQSEL1; // GPIO B Qualifier Select 1 Register (GPIO32 to 47) + /* Объединяет несколько представлений GPB2_REG GPBQSEL2; в одной области памяти. */ + union GPB2_REG GPBQSEL2; // GPIO B Qualifier Select 2 Register (GPIO48 to 63) + /* Объединяет несколько представлений GPB1_REG GPBMUX1; в одной области памяти. */ + union GPB1_REG GPBMUX1; // GPIO B Mux 1 Register (GPIO32 to 47) + /* Объединяет несколько представлений GPB2_REG GPBMUX2; в одной области памяти. */ + union GPB2_REG GPBMUX2; // GPIO B Mux 2 Register (GPIO48 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBDIR; в одной области памяти. */ + union GPBDAT_REG GPBDIR; // GPIO B Direction Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBPUD; в одной области памяти. */ + union GPBDAT_REG GPBPUD; // GPIO B Pull Up Disable Register (GPIO32 to 63) + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[8]; + /* Объединяет несколько представлений GPC1_REG GPCMUX1; в одной области памяти. */ + union GPC1_REG GPCMUX1; // GPIO C Mux 1 Register (GPIO64 to 79) + /* Объединяет несколько представлений GPC2_REG GPCMUX2; в одной области памяти. */ + union GPC2_REG GPCMUX2; // GPIO C Mux 2 Register (GPIO80 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCDIR; в одной области памяти. */ + union GPCDAT_REG GPCDIR; // GPIO C Direction Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCPUD; в одной области памяти. */ + union GPCDAT_REG GPCPUD; // GPIO C Pull Up Disable Register (GPIO64 to 95) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPIO_DATA_REGS; порядок полей определяет расположение данных. */ +struct GPIO_DATA_REGS { + /* Объединяет несколько представлений GPADAT_REG GPADAT; в одной области памяти. */ + union GPADAT_REG GPADAT; // GPIO Data Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPASET; в одной области памяти. */ + union GPADAT_REG GPASET; // GPIO Data Set Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPACLEAR; в одной области памяти. */ + union GPADAT_REG GPACLEAR; // GPIO Data Clear Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPATOGGLE; в одной области памяти. */ + union GPADAT_REG GPATOGGLE; // GPIO Data Toggle Register (GPIO0 to 31) + /* Объединяет несколько представлений GPBDAT_REG GPBDAT; в одной области памяти. */ + union GPBDAT_REG GPBDAT; // GPIO Data Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBSET; в одной области памяти. */ + union GPBDAT_REG GPBSET; // GPIO Data Set Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBCLEAR; в одной области памяти. */ + union GPBDAT_REG GPBCLEAR; // GPIO Data Clear Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBTOGGLE; в одной области памяти. */ + union GPBDAT_REG GPBTOGGLE; // GPIO Data Toggle Register (GPIO32 to 63) + /* Объединяет несколько представлений GPCDAT_REG GPCDAT; в одной области памяти. */ + union GPCDAT_REG GPCDAT; // GPIO Data Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCSET; в одной области памяти. */ + union GPCDAT_REG GPCSET; // GPIO Data Set Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCCLEAR; в одной области памяти. */ + union GPCDAT_REG GPCCLEAR; // GPIO Data Clear Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCTOGGLE; в одной области памяти. */ + union GPCDAT_REG GPCTOGGLE; // GPIO Data Toggle Register (GPIO64 to 95) + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[8]; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPIO_INT_REGS; порядок полей определяет расположение данных. */ +struct GPIO_INT_REGS { + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT1SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT1SEL; // XINT1 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT2SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT2SEL; // XINT2 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXNMISEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXNMISEL; // XNMI_Xint13 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT3SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT3SEL; // XINT3 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT4SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT4SEL; // XINT4 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT5SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT5SEL; // XINT5 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT6SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT6SEL; // XINT6 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT7SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT7SEL; // XINT7 GPIO Input Selection + /* Объединяет несколько представлений GPADAT_REG GPIOLPMSEL; в одной области памяти. */ + union GPADAT_REG GPIOLPMSEL; // Low power modes GP I/O input select +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct GPIO_CTRL_REGS GpioCtrlRegs;; порядок элементов сохраняется. */ +extern volatile struct GPIO_CTRL_REGS GpioCtrlRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct GPIO_DATA_REGS GpioDataRegs;; порядок элементов сохраняется. */ +extern volatile struct GPIO_DATA_REGS GpioDataRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct GPIO_INT_REGS GpioIntRegs;; порядок элементов сохраняется. */ +extern volatile struct GPIO_INT_REGS GpioIntRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_GPIO_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h new file mode 100644 index 0000000..da548ce --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h @@ -0,0 +1,319 @@ +/* Поставляемое TI описание I2c для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: March 22, 2007 10:40:22 $ +//########################################################################### +// +// FILE: DSP2833x_I2c.h +// +// TITLE: DSP2833x Enhanced Quadrature Encoder Pulse Module +// Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_I2C_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_I2C_H +/* Определяет защитный символ или переключатель DSP2833x_I2C_H для последующей компиляции. */ +#define DSP2833x_I2C_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//---------------------------------------------------- +// I2C interrupt vector register bit definitions */ +/* Описывает структуру I2CISRC_BITS; порядок полей определяет расположение данных. */ +struct I2CISRC_BITS { // bits description + /* Битовое поле INTCODE, ширина 3 бит; данные INTCODE. */ + Uint16 INTCODE:3; // 2:0 Interrupt code + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CISRC_REG в одной области памяти. */ +union I2CISRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CISRC_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CISRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// I2C interrupt mask register bit definitions */ +/* Описывает структуру I2CIER_BITS; порядок полей определяет расположение данных. */ +struct I2CIER_BITS { // bits description + /* Битовое поле ARBL, ширина 1 бит; данные ARBL. */ + Uint16 ARBL:1; // 0 Arbitration lost interrupt + /* Битовое поле NACK, ширина 1 бит; данные NACK. */ + Uint16 NACK:1; // 1 No ack interrupt + /* Битовое поле ARDY, ширина 1 бит; данные ARDY. */ + Uint16 ARDY:1; // 2 Register access ready interrupt + /* Битовое поле RRDY, ширина 1 бит; данные RRDY. */ + Uint16 RRDY:1; // 3 Recieve data ready interrupt + /* Битовое поле XRDY, ширина 1 бит; данные XRDY. */ + Uint16 XRDY:1; // 4 Transmit data ready interrupt + /* Битовое поле SCD, ширина 1 бит; данные SCD. */ + Uint16 SCD:1; // 5 Stop condition detection + /* Битовое поле AAS, ширина 1 бит; данные AAS. */ + Uint16 AAS:1; // 6 Address as slave + /* Битовое поле rsvd, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:9; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CIER_REG в одной области памяти. */ +union I2CIER_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CIER_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CIER_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// I2C status register bit definitions */ +/* Описывает структуру I2CSTR_BITS; порядок полей определяет расположение данных. */ +struct I2CSTR_BITS { // bits description + /* Битовое поле ARBL, ширина 1 бит; данные ARBL. */ + Uint16 ARBL:1; // 0 Arbitration lost interrupt + /* Битовое поле NACK, ширина 1 бит; данные NACK. */ + Uint16 NACK:1; // 1 No ack interrupt + /* Битовое поле ARDY, ширина 1 бит; данные ARDY. */ + Uint16 ARDY:1; // 2 Register access ready interrupt + /* Битовое поле RRDY, ширина 1 бит; данные RRDY. */ + Uint16 RRDY:1; // 3 Recieve data ready interrupt + /* Битовое поле XRDY, ширина 1 бит; данные XRDY. */ + Uint16 XRDY:1; // 4 Transmit data ready interrupt + /* Битовое поле SCD, ширина 1 бит; данные SCD. */ + Uint16 SCD:1; // 5 Stop condition detection + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 7:6 reserved + /* Битовое поле AD0, ширина 1 бит; данные AD0. */ + Uint16 AD0:1; // 8 Address Zero + /* Битовое поле AAS, ширина 1 бит; данные AAS. */ + Uint16 AAS:1; // 9 Address as slave + /* Битовое поле XSMT, ширина 1 бит; данные XSMT. */ + Uint16 XSMT:1; // 10 XMIT shift empty + /* Битовое поле RSFULL, ширина 1 бит; данные RSFULL. */ + Uint16 RSFULL:1; // 11 Recieve shift full + /* Битовое поле BB, ширина 1 бит; данные BB. */ + Uint16 BB:1; // 12 Bus busy + /* Битовое поле NACKSNT, ширина 1 бит; данные NACKSNT. */ + Uint16 NACKSNT:1; // 13 A no ack sent + /* Битовое поле SDIR, ширина 1 бит; данные SDIR. */ + Uint16 SDIR:1; // 14 Slave direction + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CSTR_REG в одной области памяти. */ +union I2CSTR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CSTR_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CSTR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// I2C mode control register bit definitions */ +/* Описывает структуру I2CMDR_BITS; порядок полей определяет расположение данных. */ +struct I2CMDR_BITS { // bits description + /* Битовое поле BC, ширина 3 бит; данные BC. */ + Uint16 BC:3; // 2:0 Bit count + /* Битовое поле FDF, ширина 1 бит; данные FDF. */ + Uint16 FDF:1; // 3 Free data format + /* Битовое поле STB, ширина 1 бит; данные STB. */ + Uint16 STB:1; // 4 Start byte + /* Битовое поле IRS, ширина 1 бит; данные IRS. */ + Uint16 IRS:1; // 5 I2C Reset not + /* Битовое поле DLB, ширина 1 бит; данные DLB. */ + Uint16 DLB:1; // 6 Digital loopback + /* Битовое поле RM, ширина 1 бит; данные RM. */ + Uint16 RM:1; // 7 Repeat mode + /* Битовое поле XA, ширина 1 бит; данные XA. */ + Uint16 XA:1; // 8 Expand address + /* Битовое поле TRX, ширина 1 бит; данные TRX. */ + Uint16 TRX:1; // 9 Transmitter/reciever + /* Битовое поле MST, ширина 1 бит; данные MST. */ + Uint16 MST:1; // 10 Master/slave + /* Битовое поле STP, ширина 1 бит; данные STP. */ + Uint16 STP:1; // 11 Stop condition + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 12 reserved + /* Битовое поле STT, ширина 1 бит; данные STT. */ + Uint16 STT:1; // 13 Start condition + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 14 Emulation mode + /* Битовое поле NACKMOD, ширина 1 бит; данные NACKMOD. */ + Uint16 NACKMOD:1; // 15 No Ack mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CMDR_REG в одной области памяти. */ +union I2CMDR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CMDR_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CMDR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// I2C pre-scaler register bit definitions */ +/* Описывает структуру I2CPSC_BITS; порядок полей определяет расположение данных. */ +struct I2CPSC_BITS { // bits description + /* Битовое поле IPSC, ширина 8 бит; данные IPSC. */ + Uint16 IPSC:8; // 7:0 pre-scaler + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений I2CPSC_REG в одной области памяти. */ +union I2CPSC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CPSC_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CPSC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// TX FIFO control register bit definitions */ +/* Описывает структуру I2CFFTX_BITS; порядок полей определяет расположение данных. */ +struct I2CFFTX_BITS { // bits description + /* Битовое поле TXFFIL, ширина 5 бит; данные TXFFIL. */ + Uint16 TXFFIL:5; // 4:0 FIFO interrupt level + /* Битовое поле TXFFIENA, ширина 1 бит; данные TXFFIENA. */ + Uint16 TXFFIENA:1; // 5 FIFO interrupt enable/disable + /* Битовое поле TXFFINTCLR, ширина 1 бит; данные TXFFINTCLR. */ + Uint16 TXFFINTCLR:1; // 6 FIFO clear + /* Битовое поле TXFFINT, ширина 1 бит; данные TXFFINT. */ + Uint16 TXFFINT:1; // 7 FIFO interrupt flag + /* Битовое поле TXFFST, ширина 5 бит; данные TXFFST. */ + Uint16 TXFFST:5; // 12:8 FIFO level status + /* Битовое поле TXFFRST, ширина 1 бит; данные TXFFRST. */ + Uint16 TXFFRST:1; // 13 FIFO reset + /* Битовое поле I2CFFEN, ширина 1 бит; данные I2CFFEN. */ + Uint16 I2CFFEN:1; // 14 enable/disable TX & RX FIFOs + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 15 reserved + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CFFTX_REG в одной области памяти. */ +union I2CFFTX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CFFTX_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CFFTX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// RX FIFO control register bit definitions */ +/* Описывает структуру I2CFFRX_BITS; порядок полей определяет расположение данных. */ +struct I2CFFRX_BITS { // bits description + /* Битовое поле RXFFIL, ширина 5 бит; данные RXFFIL. */ + Uint16 RXFFIL:5; // 4:0 FIFO interrupt level + /* Битовое поле RXFFIENA, ширина 1 бит; данные RXFFIENA. */ + Uint16 RXFFIENA:1; // 5 FIFO interrupt enable/disable + /* Битовое поле RXFFINTCLR, ширина 1 бит; данные RXFFINTCLR. */ + Uint16 RXFFINTCLR:1; // 6 FIFO clear + /* Битовое поле RXFFINT, ширина 1 бит; данные RXFFINT. */ + Uint16 RXFFINT:1; // 7 FIFO interrupt flag + /* Битовое поле RXFFST, ширина 5 бит; данные RXFFST. */ + Uint16 RXFFST:5; // 12:8 FIFO level + /* Битовое поле RXFFRST, ширина 1 бит; данные RXFFRST. */ + Uint16 RXFFRST:1; // 13 FIFO reset + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 15:14 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CFFRX_REG в одной области памяти. */ +union I2CFFRX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CFFRX_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CFFRX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- + +/* Описывает структуру I2C_REGS; порядок полей определяет расположение данных. */ +struct I2C_REGS { + /* Объявляет I2COAR — данные I2COAR. */ + Uint16 I2COAR; // Own address register + /* Объединяет несколько представлений I2CIER_REG I2CIER; в одной области памяти. */ + union I2CIER_REG I2CIER; // Interrupt enable + /* Объединяет несколько представлений I2CSTR_REG I2CSTR; в одной области памяти. */ + union I2CSTR_REG I2CSTR; // Interrupt status + /* Объявляет I2CCLKL — данные I2CCLKL. */ + Uint16 I2CCLKL; // Clock divider low + /* Объявляет I2CCLKH — данные I2CCLKH. */ + Uint16 I2CCLKH; // Clock divider high + /* Объявляет I2CCNT — данные I2CCNT. */ + Uint16 I2CCNT; // Data count + /* Объявляет I2CDRR — данные I2CDRR. */ + Uint16 I2CDRR; // Data recieve + /* Объявляет I2CSAR — данные I2CSAR. */ + Uint16 I2CSAR; // Slave address + /* Объявляет I2CDXR — данные I2CDXR. */ + Uint16 I2CDXR; // Data transmit + /* Объединяет несколько представлений I2CMDR_REG I2CMDR; в одной области памяти. */ + union I2CMDR_REG I2CMDR; // Mode + /* Объединяет несколько представлений I2CISRC_REG I2CISRC; в одной области памяти. */ + union I2CISRC_REG I2CISRC; // Interrupt source + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объединяет несколько представлений I2CPSC_REG I2CPSC; в одной области памяти. */ + union I2CPSC_REG I2CPSC; // Pre-scaler + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[19]; // reserved + /* Объединяет несколько представлений I2CFFTX_REG I2CFFTX; в одной области памяти. */ + union I2CFFTX_REG I2CFFTX; // Transmit FIFO + /* Объединяет несколько представлений I2CFFRX_REG I2CFFRX; в одной области памяти. */ + union I2CFFRX_REG I2CFFRX; // Recieve FIFO +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct I2C_REGS I2caRegs;; порядок элементов сохраняется. */ +extern volatile struct I2C_REGS I2caRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_I2C_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h new file mode 100644 index 0000000..b70e765 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h @@ -0,0 +1,1299 @@ +/* Поставляемое TI описание Mcbsp для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/5 $ +// Checkin $Date: May 14, 2008 16:30:31 $ +//########################################################################### +// +// FILE: DSP2833x_Mcbsp.h +// +// TITLE: DSP2833x Device McBSP Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_MCBSP_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_MCBSP_H +/* Определяет защитный символ или переключатель DSP2833x_MCBSP_H для последующей компиляции. */ +#define DSP2833x_MCBSP_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// McBSP Individual Register Bit Definitions: +// +// McBSP DRR2 register bit definitions: +/* Описывает структуру DRR2_BITS; порядок полей определяет расположение данных. */ +struct DRR2_BITS { // bit description + /* Битовое поле HWLB, ширина 8 бит; данные HWLB. */ + Uint16 HWLB:8; // 16:23 High word low byte + /* Битовое поле HWHB, ширина 8 бит; данные HWHB. */ + Uint16 HWHB:8; // 24:31 High word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DRR2_REG в одной области памяти. */ +union DRR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DRR2_BITS bit;; порядок полей определяет расположение данных. */ + struct DRR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// McBSP DRR1 register bit definitions: +/* Описывает структуру DRR1_BITS; порядок полей определяет расположение данных. */ +struct DRR1_BITS { // bit description + /* Битовое поле LWLB, ширина 8 бит; данные LWLB. */ + Uint16 LWLB:8; // 16:23 Low word low byte + /* Битовое поле LWHB, ширина 8 бит; данные LWHB. */ + Uint16 LWHB:8; // 24:31 low word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DRR1_REG в одной области памяти. */ +union DRR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DRR1_BITS bit;; порядок полей определяет расположение данных. */ + struct DRR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// McBSP DXR2 register bit definitions: +/* Описывает структуру DXR2_BITS; порядок полей определяет расположение данных. */ +struct DXR2_BITS { // bit description + /* Битовое поле HWLB, ширина 8 бит; данные HWLB. */ + Uint16 HWLB:8; // 16:23 High word low byte + /* Битовое поле HWHB, ширина 8 бит; данные HWHB. */ + Uint16 HWHB:8; // 24:31 High word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DXR2_REG в одной области памяти. */ +union DXR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DXR2_BITS bit;; порядок полей определяет расположение данных. */ + struct DXR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// McBSP DXR1 register bit definitions: +/* Описывает структуру DXR1_BITS; порядок полей определяет расположение данных. */ +struct DXR1_BITS { // bit description + /* Битовое поле LWLB, ширина 8 бит; данные LWLB. */ + Uint16 LWLB:8; // 16:23 Low word low byte + /* Битовое поле LWHB, ширина 8 бит; данные LWHB. */ + Uint16 LWHB:8; // 24:31 low word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DXR1_REG в одной области памяти. */ +union DXR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DXR1_BITS bit;; порядок полей определяет расположение данных. */ + struct DXR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SPCR2 control register bit definitions: +/* Описывает структуру SPCR2_BITS; порядок полей определяет расположение данных. */ +struct SPCR2_BITS { // bit description + /* Битовое поле XRST, ширина 1 бит; данные XRST. */ + Uint16 XRST:1; // 0 transmit reset + /* Битовое поле XRDY, ширина 1 бит; данные XRDY. */ + Uint16 XRDY:1; // 1 transmit ready + /* Битовое поле XEMPTY, ширина 1 бит; данные XEMPTY. */ + Uint16 XEMPTY:1; // 2 Transmit empty + /* Битовое поле XSYNCERR, ширина 1 бит; данные XSYNCERR. */ + Uint16 XSYNCERR:1; // 3 Transmit syn errorINT flag + /* Битовое поле XINTM, ширина 2 бит; данные XINTM. */ + Uint16 XINTM:2; // 5:4 Transmit interrupt types + /* Битовое поле GRST, ширина 1 бит; данные GRST. */ + Uint16 GRST:1; // 6 CLKG reset + /* Битовое поле FRST, ширина 1 бит; данные FRST. */ + Uint16 FRST:1; // 7 Frame sync reset + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 8 SOFT bit + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 9 FREE bit + /* Битовое поле rsvd, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPCR2_REG в одной области памяти. */ +union SPCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct SPCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SPCR1 control register bit definitions: +/* Описывает структуру SPCR1_BITS; порядок полей определяет расположение данных. */ +struct SPCR1_BITS { // bit description + /* Битовое поле RRST, ширина 1 бит; данные RRST. */ + Uint16 RRST:1; // 0 Receive reset + /* Битовое поле RRDY, ширина 1 бит; данные RRDY. */ + Uint16 RRDY:1; // 1 Receive ready + /* Битовое поле RFULL, ширина 1 бит; данные RFULL. */ + Uint16 RFULL:1; // 2 Receive full + /* Битовое поле RSYNCERR, ширина 1 бит; данные RSYNCERR. */ + Uint16 RSYNCERR:1; // 7 Receive syn error + /* Битовое поле RINTM, ширина 2 бит; данные RINTM. */ + Uint16 RINTM:2; // 5:4 Receive interrupt types + /* Битовое поле ABIS, ширина 1 бит; данные ABIS. */ + Uint16 ABIS:1; // 6 ABIS mode select + /* Битовое поле DXENA, ширина 1 бит; данные DXENA. */ + Uint16 DXENA:1; // 7 DX hi-z enable + /* Битовое поле rsvd, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:3; // 10:8 reserved + /* Битовое поле CLKSTP, ширина 2 бит; данные CLKSTP. */ + Uint16 CLKSTP:2; // 12:11 CLKSTOP mode bit + /* Битовое поле RJUST, ширина 2 бит; данные RJUST. */ + Uint16 RJUST:2; // 13:14 Right justified + /* Битовое поле DLB, ширина 1 бит; данные DLB. */ + Uint16 DLB:1; // 15 Digital loop back +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPCR1_REG в одной области памяти. */ +union SPCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct SPCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCR2 control register bit definitions: +/* Описывает структуру RCR2_BITS; порядок полей определяет расположение данных. */ +struct RCR2_BITS { // bit description + /* Битовое поле RDATDLY, ширина 2 бит; данные RDATDLY. */ + Uint16 RDATDLY:2; // 1:0 Receive data delay + /* Битовое поле RFIG, ширина 1 бит; данные RFIG. */ + Uint16 RFIG:1; // 2 Receive frame sync ignore + /* Битовое поле RCOMPAND, ширина 2 бит; данные RCOMPAND. */ + Uint16 RCOMPAND:2; // 4:3 Receive Companding Mode selects + /* Битовое поле RWDLEN2, ширина 3 бит; данные RWDLEN2. */ + Uint16 RWDLEN2:3; // 7:5 Receive word length + /* Битовое поле RFRLEN2, ширина 7 бит; данные RFRLEN2. */ + Uint16 RFRLEN2:7; // 14:8 Receive Frame sync + /* Битовое поле RPHASE, ширина 1 бит; данные RPHASE. */ + Uint16 RPHASE:1; // 15 Receive Phase +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCR2_REG в одной области памяти. */ +union RCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct RCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCR1 control register bit definitions: +/* Описывает структуру RCR1_BITS; порядок полей определяет расположение данных. */ +struct RCR1_BITS { // bit description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле RWDLEN1, ширина 3 бит; данные RWDLEN1. */ + Uint16 RWDLEN1:3; // 7:5 Receive word length + /* Битовое поле RFRLEN1, ширина 7 бит; данные RFRLEN1. */ + Uint16 RFRLEN1:7; // 14:8 Receive frame length + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCR1_REG в одной области памяти. */ +union RCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct RCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCR2 control register bit definitions: + +/* Описывает структуру XCR2_BITS; порядок полей определяет расположение данных. */ +struct XCR2_BITS { // bit description + /* Битовое поле XDATDLY, ширина 2 бит; данные XDATDLY. */ + Uint16 XDATDLY:2; // 1:0 Transmit data delay + /* Битовое поле XFIG, ширина 1 бит; данные XFIG. */ + Uint16 XFIG:1; // 2 Transmit frame sync ignore + /* Битовое поле XCOMPAND, ширина 2 бит; данные XCOMPAND. */ + Uint16 XCOMPAND:2; // 4:3 Transmit Companding Mode selects + /* Битовое поле XWDLEN2, ширина 3 бит; данные XWDLEN2. */ + Uint16 XWDLEN2:3; // 7:5 Transmit word length + /* Битовое поле XFRLEN2, ширина 7 бит; данные XFRLEN2. */ + Uint16 XFRLEN2:7; // 14:8 Transmit Frame sync + /* Битовое поле XPHASE, ширина 1 бит; данные XPHASE. */ + Uint16 XPHASE:1; // 15 Transmit Phase +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCR2_REG в одной области памяти. */ +union XCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct XCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCR1 control register bit definitions: +/* Описывает структуру XCR1_BITS; порядок полей определяет расположение данных. */ +struct XCR1_BITS { // bit description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле XWDLEN1, ширина 3 бит; данные XWDLEN1. */ + Uint16 XWDLEN1:3; // 7:5 Transmit word length + /* Битовое поле XFRLEN1, ширина 7 бит; данные XFRLEN1. */ + Uint16 XFRLEN1:7; // 14:8 Transmit frame length + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCR1_REG в одной области памяти. */ +union XCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct XCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SRGR2 Sample rate generator control register bit definitions: +/* Описывает структуру SRGR2_BITS; порядок полей определяет расположение данных. */ +struct SRGR2_BITS { // bit description + /* Битовое поле FPER, ширина 12 бит; данные FPER. */ + Uint16 FPER:12; // 11:0 Frame period + /* Битовое поле FSGM, ширина 1 бит; данные FSGM. */ + Uint16 FSGM:1; // 12 Frame sync generator mode + /* Битовое поле CLKSM, ширина 1 бит; данные CLKSM. */ + Uint16 CLKSM:1; // 13 Sample rate generator mode + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 14 reserved + /* Битовое поле GSYNC, ширина 1 бит; данные GSYNC. */ + Uint16 GSYNC:1; // 15 CLKG sync +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SRGR2_REG в одной области памяти. */ +union SRGR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SRGR2_BITS bit;; порядок полей определяет расположение данных. */ + struct SRGR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SRGR1 control register bit definitions: +/* Описывает структуру SRGR1_BITS; порядок полей определяет расположение данных. */ +struct SRGR1_BITS { // bit description + /* Битовое поле CLKGDV, ширина 8 бит; данные CLKGDV. */ + Uint16 CLKGDV:8; // 7:0 CLKG divider + /* Битовое поле FWID, ширина 8 бит; данные FWID. */ + Uint16 FWID:8; // 15:8 Frame width +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SRGR1_REG в одной области памяти. */ +union SRGR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SRGR1_BITS bit;; порядок полей определяет расположение данных. */ + struct SRGR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// MCR2 Multichannel control register bit definitions: +/* Описывает структуру MCR2_BITS; порядок полей определяет расположение данных. */ +struct MCR2_BITS { // bit description + /* Битовое поле XMCM, ширина 2 бит; данные XMCM. */ + Uint16 XMCM:2; // 1:0 Transmit multichannel mode + /* Битовое поле XCBLK, ширина 3 бит; данные XCBLK. */ + Uint16 XCBLK:3; // 2:4 Transmit current block + /* Битовое поле XPABLK, ширина 2 бит; данные XPABLK. */ + Uint16 XPABLK:2; // 5:6 Transmit partition A Block + /* Битовое поле XPBBLK, ширина 2 бит; данные XPBBLK. */ + Uint16 XPBBLK:2; // 7:8 Transmit partition B Block + /* Битовое поле XMCME, ширина 1 бит; данные XMCME. */ + Uint16 XMCME:1; // 9 Transmit multi-channel enhance mode + /* Битовое поле rsvd, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MCR2_REG в одной области памяти. */ +union MCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct MCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// MCR1 Multichannel control register bit definitions: +/* Описывает структуру MCR1_BITS; порядок полей определяет расположение данных. */ +struct MCR1_BITS { // bit description + /* Битовое поле RMCM, ширина 1 бит; данные RMCM. */ + Uint16 RMCM:1; // 0 Receive multichannel mode + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 1 reserved + /* Битовое поле RCBLK, ширина 3 бит; данные RCBLK. */ + Uint16 RCBLK:3; // 4:2 Receive current block + /* Битовое поле RPABLK, ширина 2 бит; данные RPABLK. */ + Uint16 RPABLK:2; // 6:5 Receive partition A Block + /* Битовое поле RPBBLK, ширина 2 бит; данные RPBBLK. */ + Uint16 RPBBLK:2; // 7:8 Receive partition B Block + /* Битовое поле RMCME, ширина 1 бит; данные RMCME. */ + Uint16 RMCME:1; // 9 Receive multi-channel enhance mode + /* Битовое поле rsvd1, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MCR1_REG в одной области памяти. */ +union MCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct MCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERA control register bit definitions: +/* Описывает структуру RCERA_BITS; порядок полей определяет расположение данных. */ +struct RCERA_BITS { // bit description + /* Битовое поле RCEA0, ширина 1 бит; данные RCEA0. */ + Uint16 RCEA0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEA1, ширина 1 бит; данные RCEA1. */ + Uint16 RCEA1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEA2, ширина 1 бит; данные RCEA2. */ + Uint16 RCEA2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEA3, ширина 1 бит; данные RCEA3. */ + Uint16 RCEA3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEA4, ширина 1 бит; данные RCEA4. */ + Uint16 RCEA4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEA5, ширина 1 бит; данные RCEA5. */ + Uint16 RCEA5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEA6, ширина 1 бит; данные RCEA6. */ + Uint16 RCEA6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEA7, ширина 1 бит; данные RCEA7. */ + Uint16 RCEA7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEA8, ширина 1 бит; данные RCEA8. */ + Uint16 RCEA8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEA9, ширина 1 бит; данные RCEA9. */ + Uint16 RCEA9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEA10, ширина 1 бит; данные RCEA10. */ + Uint16 RCEA10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEA11, ширина 1 бит; данные RCEA11. */ + Uint16 RCEA11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEA12, ширина 1 бит; данные RCEA12. */ + Uint16 RCEA12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEA13, ширина 1 бит; данные RCEA13. */ + Uint16 RCEA13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEA14, ширина 1 бит; данные RCEA14. */ + Uint16 RCEA14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEA15, ширина 1 бит; данные RCEA15. */ + Uint16 RCEA15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERA_REG в одной области памяти. */ +union RCERA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERA_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERB control register bit definitions: +/* Описывает структуру RCERB_BITS; порядок полей определяет расположение данных. */ +struct RCERB_BITS { // bit description + /* Битовое поле RCEB0, ширина 1 бит; данные RCEB0. */ + Uint16 RCEB0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEB1, ширина 1 бит; данные RCEB1. */ + Uint16 RCEB1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEB2, ширина 1 бит; данные RCEB2. */ + Uint16 RCEB2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEB3, ширина 1 бит; данные RCEB3. */ + Uint16 RCEB3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEB4, ширина 1 бит; данные RCEB4. */ + Uint16 RCEB4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEB5, ширина 1 бит; данные RCEB5. */ + Uint16 RCEB5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEB6, ширина 1 бит; данные RCEB6. */ + Uint16 RCEB6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEB7, ширина 1 бит; данные RCEB7. */ + Uint16 RCEB7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEB8, ширина 1 бит; данные RCEB8. */ + Uint16 RCEB8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEB9, ширина 1 бит; данные RCEB9. */ + Uint16 RCEB9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEB10, ширина 1 бит; данные RCEB10. */ + Uint16 RCEB10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEB11, ширина 1 бит; данные RCEB11. */ + Uint16 RCEB11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEB12, ширина 1 бит; данные RCEB12. */ + Uint16 RCEB12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEB13, ширина 1 бит; данные RCEB13. */ + Uint16 RCEB13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEB14, ширина 1 бит; данные RCEB14. */ + Uint16 RCEB14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEB15, ширина 1 бит; данные RCEB15. */ + Uint16 RCEB15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERB_REG в одной области памяти. */ +union RCERB_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERB_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERB_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERA control register bit definitions: +/* Описывает структуру XCERA_BITS; порядок полей определяет расположение данных. */ +struct XCERA_BITS { // bit description + /* Битовое поле XCERA0, ширина 1 бит; данные XCERA0. */ + Uint16 XCERA0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERA1, ширина 1 бит; данные XCERA1. */ + Uint16 XCERA1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERA2, ширина 1 бит; данные XCERA2. */ + Uint16 XCERA2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERA3, ширина 1 бит; данные XCERA3. */ + Uint16 XCERA3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERA4, ширина 1 бит; данные XCERA4. */ + Uint16 XCERA4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERA5, ширина 1 бит; данные XCERA5. */ + Uint16 XCERA5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERA6, ширина 1 бит; данные XCERA6. */ + Uint16 XCERA6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERA7, ширина 1 бит; данные XCERA7. */ + Uint16 XCERA7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERA8, ширина 1 бит; данные XCERA8. */ + Uint16 XCERA8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERA9, ширина 1 бит; данные XCERA9. */ + Uint16 XCERA9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERA10, ширина 1 бит; данные XCERA10. */ + Uint16 XCERA10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERA11, ширина 1 бит; данные XCERA11. */ + Uint16 XCERA11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERA12, ширина 1 бит; данные XCERA12. */ + Uint16 XCERA12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERA13, ширина 1 бит; данные XCERA13. */ + Uint16 XCERA13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERA14, ширина 1 бит; данные XCERA14. */ + Uint16 XCERA14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERA15, ширина 1 бит; данные XCERA15. */ + Uint16 XCERA15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERA_REG в одной области памяти. */ +union XCERA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERA_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERB control register bit definitions: +/* Описывает структуру XCERB_BITS; порядок полей определяет расположение данных. */ +struct XCERB_BITS { // bit description + /* Битовое поле XCERB0, ширина 1 бит; данные XCERB0. */ + Uint16 XCERB0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERB1, ширина 1 бит; данные XCERB1. */ + Uint16 XCERB1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERB2, ширина 1 бит; данные XCERB2. */ + Uint16 XCERB2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERB3, ширина 1 бит; данные XCERB3. */ + Uint16 XCERB3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERB4, ширина 1 бит; данные XCERB4. */ + Uint16 XCERB4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERB5, ширина 1 бит; данные XCERB5. */ + Uint16 XCERB5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERB6, ширина 1 бит; данные XCERB6. */ + Uint16 XCERB6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERB7, ширина 1 бит; данные XCERB7. */ + Uint16 XCERB7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERB8, ширина 1 бит; данные XCERB8. */ + Uint16 XCERB8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERB9, ширина 1 бит; данные XCERB9. */ + Uint16 XCERB9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERB10, ширина 1 бит; данные XCERB10. */ + Uint16 XCERB10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERB11, ширина 1 бит; данные XCERB11. */ + Uint16 XCERB11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERB12, ширина 1 бит; данные XCERB12. */ + Uint16 XCERB12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERB13, ширина 1 бит; данные XCERB13. */ + Uint16 XCERB13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERB14, ширина 1 бит; данные XCERB14. */ + Uint16 XCERB14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERB15, ширина 1 бит; данные XCERB15. */ + Uint16 XCERB15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERB_REG в одной области памяти. */ +union XCERB_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERB_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERB_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PCR control register bit definitions: +/* Описывает структуру PCR_BITS; порядок полей определяет расположение данных. */ +struct PCR_BITS { // bit description + /* Битовое поле CLKRP, ширина 1 бит; данные CLKRP. */ + Uint16 CLKRP:1; // 0 Receive Clock polarity + /* Битовое поле CLKXP, ширина 1 бит; данные CLKXP. */ + Uint16 CLKXP:1; // 1 Transmit clock polarity + /* Битовое поле FSRP, ширина 1 бит; данные FSRP. */ + Uint16 FSRP:1; // 2 Receive Frame synchronization polarity + /* Битовое поле FSXP, ширина 1 бит; данные FSXP. */ + Uint16 FSXP:1; // 3 Transmit Frame synchronization polarity + /* Битовое поле DR_STAT, ширина 1 бит; данные DR_STAT. */ + Uint16 DR_STAT:1; // 4 DR pin status - reserved for this McBSP + /* Битовое поле DX_STAT, ширина 1 бит; данные DX_STAT. */ + Uint16 DX_STAT:1; // 5 DX pin status - reserved for this McBSP + /* Битовое поле CLKS_STAT, ширина 1 бит; данные CLKS_STAT. */ + Uint16 CLKS_STAT:1; // 6 CLKS pin status - reserved for 28x -McBSP + /* Битовое поле SCLKME, ширина 1 бит; данные SCLKME. */ + Uint16 SCLKME:1; // 7 Enhanced sample clock mode selection bit. + /* Битовое поле CLKRM, ширина 1 бит; данные CLKRM. */ + Uint16 CLKRM:1; // 8 Receiver Clock Mode + /* Битовое поле CLKXM, ширина 1 бит; данные CLKXM. */ + Uint16 CLKXM:1; // 9 Transmitter Clock Mode. + /* Битовое поле FSRM, ширина 1 бит; данные FSRM. */ + Uint16 FSRM:1; // 10 Receive Frame Synchronization Mode + /* Битовое поле FSXM, ширина 1 бит; данные FSXM. */ + Uint16 FSXM:1; // 11 Transmit Frame Synchronization Mode + /* Битовое поле RIOEN, ширина 1 бит; данные RIOEN. */ + Uint16 RIOEN:1; // 12 General Purpose I/O Mode - reserved in this 28x-McBSP + /* Битовое поле XIOEN, ширина 1 бит; данные XIOEN. */ + Uint16 XIOEN:1; // 13 General Purpose I/O Mode - reserved in this 28x-McBSP + /* Битовое поле IDEL_EN, ширина 1 бит; данные IDEL_EN. */ + Uint16 IDEL_EN:1; // 14 reserved in this 28x-McBSP + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1 ; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCR_REG в одной области памяти. */ +union PCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCR_BITS bit;; порядок полей определяет расположение данных. */ + struct PCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERC control register bit definitions: +/* Описывает структуру RCERC_BITS; порядок полей определяет расположение данных. */ +struct RCERC_BITS { // bit description + /* Битовое поле RCEC0, ширина 1 бит; данные RCEC0. */ + Uint16 RCEC0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEC1, ширина 1 бит; данные RCEC1. */ + Uint16 RCEC1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEC2, ширина 1 бит; данные RCEC2. */ + Uint16 RCEC2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEC3, ширина 1 бит; данные RCEC3. */ + Uint16 RCEC3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEC4, ширина 1 бит; данные RCEC4. */ + Uint16 RCEC4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEC5, ширина 1 бит; данные RCEC5. */ + Uint16 RCEC5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEC6, ширина 1 бит; данные RCEC6. */ + Uint16 RCEC6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEC7, ширина 1 бит; данные RCEC7. */ + Uint16 RCEC7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEC8, ширина 1 бит; данные RCEC8. */ + Uint16 RCEC8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEC9, ширина 1 бит; данные RCEC9. */ + Uint16 RCEC9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEC10, ширина 1 бит; данные RCEC10. */ + Uint16 RCEC10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEC11, ширина 1 бит; данные RCEC11. */ + Uint16 RCEC11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEC12, ширина 1 бит; данные RCEC12. */ + Uint16 RCEC12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEC13, ширина 1 бит; данные RCEC13. */ + Uint16 RCEC13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEC14, ширина 1 бит; данные RCEC14. */ + Uint16 RCEC14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEC15, ширина 1 бит; данные RCEC15. */ + Uint16 RCEC15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERC_REG в одной области памяти. */ +union RCERC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERC_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERD control register bit definitions: +/* Описывает структуру RCERD_BITS; порядок полей определяет расположение данных. */ +struct RCERD_BITS { // bit description + /* Битовое поле RCED0, ширина 1 бит; данные RCED0. */ + Uint16 RCED0:1; // 0 Receive Channel enable bit + /* Битовое поле RCED1, ширина 1 бит; данные RCED1. */ + Uint16 RCED1:1; // 1 Receive Channel enable bit + /* Битовое поле RCED2, ширина 1 бит; данные RCED2. */ + Uint16 RCED2:1; // 2 Receive Channel enable bit + /* Битовое поле RCED3, ширина 1 бит; данные RCED3. */ + Uint16 RCED3:1; // 3 Receive Channel enable bit + /* Битовое поле RCED4, ширина 1 бит; данные RCED4. */ + Uint16 RCED4:1; // 4 Receive Channel enable bit + /* Битовое поле RCED5, ширина 1 бит; данные RCED5. */ + Uint16 RCED5:1; // 5 Receive Channel enable bit + /* Битовое поле RCED6, ширина 1 бит; данные RCED6. */ + Uint16 RCED6:1; // 6 Receive Channel enable bit + /* Битовое поле RCED7, ширина 1 бит; данные RCED7. */ + Uint16 RCED7:1; // 7 Receive Channel enable bit + /* Битовое поле RCED8, ширина 1 бит; данные RCED8. */ + Uint16 RCED8:1; // 8 Receive Channel enable bit + /* Битовое поле RCED9, ширина 1 бит; данные RCED9. */ + Uint16 RCED9:1; // 9 Receive Channel enable bit + /* Битовое поле RCED10, ширина 1 бит; данные RCED10. */ + Uint16 RCED10:1; // 10 Receive Channel enable bit + /* Битовое поле RCED11, ширина 1 бит; данные RCED11. */ + Uint16 RCED11:1; // 11 Receive Channel enable bit + /* Битовое поле RCED12, ширина 1 бит; данные RCED12. */ + Uint16 RCED12:1; // 12 Receive Channel enable bit + /* Битовое поле RCED13, ширина 1 бит; данные RCED13. */ + Uint16 RCED13:1; // 13 Receive Channel enable bit + /* Битовое поле RCED14, ширина 1 бит; данные RCED14. */ + Uint16 RCED14:1; // 14 Receive Channel enable bit + /* Битовое поле RCED15, ширина 1 бит; данные RCED15. */ + Uint16 RCED15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERD_REG в одной области памяти. */ +union RCERD_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERD_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERD_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERC control register bit definitions: +/* Описывает структуру XCERC_BITS; порядок полей определяет расположение данных. */ +struct XCERC_BITS { // bit description + /* Битовое поле XCERC0, ширина 1 бит; данные XCERC0. */ + Uint16 XCERC0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERC1, ширина 1 бит; данные XCERC1. */ + Uint16 XCERC1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERC2, ширина 1 бит; данные XCERC2. */ + Uint16 XCERC2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERC3, ширина 1 бит; данные XCERC3. */ + Uint16 XCERC3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERC4, ширина 1 бит; данные XCERC4. */ + Uint16 XCERC4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERC5, ширина 1 бит; данные XCERC5. */ + Uint16 XCERC5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERC6, ширина 1 бит; данные XCERC6. */ + Uint16 XCERC6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERC7, ширина 1 бит; данные XCERC7. */ + Uint16 XCERC7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERC8, ширина 1 бит; данные XCERC8. */ + Uint16 XCERC8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERC9, ширина 1 бит; данные XCERC9. */ + Uint16 XCERC9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERC10, ширина 1 бит; данные XCERC10. */ + Uint16 XCERC10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERC11, ширина 1 бит; данные XCERC11. */ + Uint16 XCERC11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERC12, ширина 1 бит; данные XCERC12. */ + Uint16 XCERC12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERC13, ширина 1 бит; данные XCERC13. */ + Uint16 XCERC13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERC14, ширина 1 бит; данные XCERC14. */ + Uint16 XCERC14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERC15, ширина 1 бит; данные XCERC15. */ + Uint16 XCERC15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERC_REG в одной области памяти. */ +union XCERC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERC_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERD control register bit definitions: +/* Описывает структуру XCERD_BITS; порядок полей определяет расположение данных. */ +struct XCERD_BITS { // bit description + /* Битовое поле XCERD0, ширина 1 бит; данные XCERD0. */ + Uint16 XCERD0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERD1, ширина 1 бит; данные XCERD1. */ + Uint16 XCERD1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERD2, ширина 1 бит; данные XCERD2. */ + Uint16 XCERD2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERD3, ширина 1 бит; данные XCERD3. */ + Uint16 XCERD3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERD4, ширина 1 бит; данные XCERD4. */ + Uint16 XCERD4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERD5, ширина 1 бит; данные XCERD5. */ + Uint16 XCERD5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERD6, ширина 1 бит; данные XCERD6. */ + Uint16 XCERD6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERD7, ширина 1 бит; данные XCERD7. */ + Uint16 XCERD7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERD8, ширина 1 бит; данные XCERD8. */ + Uint16 XCERD8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERD9, ширина 1 бит; данные XCERD9. */ + Uint16 XCERD9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERD10, ширина 1 бит; данные XCERD10. */ + Uint16 XCERD10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERD11, ширина 1 бит; данные XCERD11. */ + Uint16 XCERD11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERD12, ширина 1 бит; данные XCERD12. */ + Uint16 XCERD12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERD13, ширина 1 бит; данные XCERD13. */ + Uint16 XCERD13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERD14, ширина 1 бит; данные XCERD14. */ + Uint16 XCERD14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERD15, ширина 1 бит; данные XCERD15. */ + Uint16 XCERD15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERD_REG в одной области памяти. */ +union XCERD_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERD_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERD_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERE control register bit definitions: +/* Описывает структуру RCERE_BITS; порядок полей определяет расположение данных. */ +struct RCERE_BITS { // bit description + /* Битовое поле RCEE0, ширина 1 бит; данные RCEE0. */ + Uint16 RCEE0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEE1, ширина 1 бит; данные RCEE1. */ + Uint16 RCEE1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEE2, ширина 1 бит; данные RCEE2. */ + Uint16 RCEE2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEE3, ширина 1 бит; данные RCEE3. */ + Uint16 RCEE3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEE4, ширина 1 бит; данные RCEE4. */ + Uint16 RCEE4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEE5, ширина 1 бит; данные RCEE5. */ + Uint16 RCEE5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEE6, ширина 1 бит; данные RCEE6. */ + Uint16 RCEE6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEE7, ширина 1 бит; данные RCEE7. */ + Uint16 RCEE7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEE8, ширина 1 бит; данные RCEE8. */ + Uint16 RCEE8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEE9, ширина 1 бит; данные RCEE9. */ + Uint16 RCEE9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEE10, ширина 1 бит; данные RCEE10. */ + Uint16 RCEE10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEE11, ширина 1 бит; данные RCEE11. */ + Uint16 RCEE11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEE12, ширина 1 бит; данные RCEE12. */ + Uint16 RCEE12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEE13, ширина 1 бит; данные RCEE13. */ + Uint16 RCEE13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEE14, ширина 1 бит; данные RCEE14. */ + Uint16 RCEE14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEE15, ширина 1 бит; данные RCEE15. */ + Uint16 RCEE15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERE_REG в одной области памяти. */ +union RCERE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERE_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERF control register bit definitions: +/* Описывает структуру RCERF_BITS; порядок полей определяет расположение данных. */ +struct RCERF_BITS { // bit description + /* Битовое поле RCEF0, ширина 1 бит; данные RCEF0. */ + Uint16 RCEF0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEF1, ширина 1 бит; данные RCEF1. */ + Uint16 RCEF1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEF2, ширина 1 бит; данные RCEF2. */ + Uint16 RCEF2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEF3, ширина 1 бит; данные RCEF3. */ + Uint16 RCEF3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEF4, ширина 1 бит; данные RCEF4. */ + Uint16 RCEF4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEF5, ширина 1 бит; данные RCEF5. */ + Uint16 RCEF5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEF6, ширина 1 бит; данные RCEF6. */ + Uint16 RCEF6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEF7, ширина 1 бит; данные RCEF7. */ + Uint16 RCEF7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEF8, ширина 1 бит; данные RCEF8. */ + Uint16 RCEF8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEF9, ширина 1 бит; данные RCEF9. */ + Uint16 RCEF9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEF10, ширина 1 бит; данные RCEF10. */ + Uint16 RCEF10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEF11, ширина 1 бит; данные RCEF11. */ + Uint16 RCEF11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEF12, ширина 1 бит; данные RCEF12. */ + Uint16 RCEF12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEF13, ширина 1 бит; данные RCEF13. */ + Uint16 RCEF13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEF14, ширина 1 бит; данные RCEF14. */ + Uint16 RCEF14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEF15, ширина 1 бит; данные RCEF15. */ + Uint16 RCEF15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERF_REG в одной области памяти. */ +union RCERF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERF_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERE control register bit definitions: +/* Описывает структуру XCERE_BITS; порядок полей определяет расположение данных. */ +struct XCERE_BITS { // bit description + /* Битовое поле XCERE0, ширина 1 бит; данные XCERE0. */ + Uint16 XCERE0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERE1, ширина 1 бит; данные XCERE1. */ + Uint16 XCERE1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERE2, ширина 1 бит; данные XCERE2. */ + Uint16 XCERE2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERE3, ширина 1 бит; данные XCERE3. */ + Uint16 XCERE3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERE4, ширина 1 бит; данные XCERE4. */ + Uint16 XCERE4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERE5, ширина 1 бит; данные XCERE5. */ + Uint16 XCERE5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERE6, ширина 1 бит; данные XCERE6. */ + Uint16 XCERE6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERE7, ширина 1 бит; данные XCERE7. */ + Uint16 XCERE7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERE8, ширина 1 бит; данные XCERE8. */ + Uint16 XCERE8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERE9, ширина 1 бит; данные XCERE9. */ + Uint16 XCERE9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERE10, ширина 1 бит; данные XCERE10. */ + Uint16 XCERE10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERE11, ширина 1 бит; данные XCERE11. */ + Uint16 XCERE11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERE12, ширина 1 бит; данные XCERE12. */ + Uint16 XCERE12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERE13, ширина 1 бит; данные XCERE13. */ + Uint16 XCERE13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERE14, ширина 1 бит; данные XCERE14. */ + Uint16 XCERE14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERE15, ширина 1 бит; данные XCERE15. */ + Uint16 XCERE15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERE_REG в одной области памяти. */ +union XCERE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERE_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERF control register bit definitions: +/* Описывает структуру XCERF_BITS; порядок полей определяет расположение данных. */ +struct XCERF_BITS { // bit description + /* Битовое поле XCERF0, ширина 1 бит; данные XCERF0. */ + Uint16 XCERF0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERF1, ширина 1 бит; данные XCERF1. */ + Uint16 XCERF1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERF2, ширина 1 бит; данные XCERF2. */ + Uint16 XCERF2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERF3, ширина 1 бит; данные XCERF3. */ + Uint16 XCERF3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERF4, ширина 1 бит; данные XCERF4. */ + Uint16 XCERF4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERF5, ширина 1 бит; данные XCERF5. */ + Uint16 XCERF5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERF6, ширина 1 бит; данные XCERF6. */ + Uint16 XCERF6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERF7, ширина 1 бит; данные XCERF7. */ + Uint16 XCERF7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERF8, ширина 1 бит; данные XCERF8. */ + Uint16 XCERF8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERF9, ширина 1 бит; данные XCERF9. */ + Uint16 XCERF9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERF10, ширина 1 бит; данные XCERF10. */ + Uint16 XCERF10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERF11, ширина 1 бит; данные XCERF11. */ + Uint16 XCERF11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERF12, ширина 1 бит; данные XCERF12. */ + Uint16 XCERF12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERF13, ширина 1 бит; данные XCERF13. */ + Uint16 XCERF13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERF14, ширина 1 бит; данные XCERF14. */ + Uint16 XCERF14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERF15, ширина 1 бит; данные XCERF15. */ + Uint16 XCERF15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERF_REG в одной области памяти. */ +union XCERF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERF_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERG control register bit definitions: +/* Описывает структуру RCERG_BITS; порядок полей определяет расположение данных. */ +struct RCERG_BITS { // bit description + /* Битовое поле RCEG0, ширина 1 бит; данные RCEG0. */ + Uint16 RCEG0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEG1, ширина 1 бит; данные RCEG1. */ + Uint16 RCEG1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEG2, ширина 1 бит; данные RCEG2. */ + Uint16 RCEG2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEG3, ширина 1 бит; данные RCEG3. */ + Uint16 RCEG3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEG4, ширина 1 бит; данные RCEG4. */ + Uint16 RCEG4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEG5, ширина 1 бит; данные RCEG5. */ + Uint16 RCEG5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEG6, ширина 1 бит; данные RCEG6. */ + Uint16 RCEG6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEG7, ширина 1 бит; данные RCEG7. */ + Uint16 RCEG7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEG8, ширина 1 бит; данные RCEG8. */ + Uint16 RCEG8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEG9, ширина 1 бит; данные RCEG9. */ + Uint16 RCEG9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEG10, ширина 1 бит; данные RCEG10. */ + Uint16 RCEG10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEG11, ширина 1 бит; данные RCEG11. */ + Uint16 RCEG11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEG12, ширина 1 бит; данные RCEG12. */ + Uint16 RCEG12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEG13, ширина 1 бит; данные RCEG13. */ + Uint16 RCEG13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEG14, ширина 1 бит; данные RCEG14. */ + Uint16 RCEG14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEG15, ширина 1 бит; данные RCEG15. */ + Uint16 RCEG15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERG_REG в одной области памяти. */ +union RCERG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERG_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERH control register bit definitions: +/* Описывает структуру RCERH_BITS; порядок полей определяет расположение данных. */ +struct RCERH_BITS { // bit description + /* Битовое поле RCEH0, ширина 1 бит; данные RCEH0. */ + Uint16 RCEH0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEH1, ширина 1 бит; данные RCEH1. */ + Uint16 RCEH1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEH2, ширина 1 бит; данные RCEH2. */ + Uint16 RCEH2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEH3, ширина 1 бит; данные RCEH3. */ + Uint16 RCEH3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEH4, ширина 1 бит; данные RCEH4. */ + Uint16 RCEH4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEH5, ширина 1 бит; данные RCEH5. */ + Uint16 RCEH5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEH6, ширина 1 бит; данные RCEH6. */ + Uint16 RCEH6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEH7, ширина 1 бит; данные RCEH7. */ + Uint16 RCEH7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEH8, ширина 1 бит; данные RCEH8. */ + Uint16 RCEH8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEH9, ширина 1 бит; данные RCEH9. */ + Uint16 RCEH9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEH10, ширина 1 бит; данные RCEH10. */ + Uint16 RCEH10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEH11, ширина 1 бит; данные RCEH11. */ + Uint16 RCEH11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEH12, ширина 1 бит; данные RCEH12. */ + Uint16 RCEH12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEH13, ширина 1 бит; данные RCEH13. */ + Uint16 RCEH13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEH14, ширина 1 бит; данные RCEH14. */ + Uint16 RCEH14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEH15, ширина 1 бит; данные RCEH15. */ + Uint16 RCEH15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERH_REG в одной области памяти. */ +union RCERH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERH_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERH_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERG control register bit definitions: +/* Описывает структуру XCERG_BITS; порядок полей определяет расположение данных. */ +struct XCERG_BITS { // bit description + /* Битовое поле XCERG0, ширина 1 бит; данные XCERG0. */ + Uint16 XCERG0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERG1, ширина 1 бит; данные XCERG1. */ + Uint16 XCERG1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERG2, ширина 1 бит; данные XCERG2. */ + Uint16 XCERG2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERG3, ширина 1 бит; данные XCERG3. */ + Uint16 XCERG3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERG4, ширина 1 бит; данные XCERG4. */ + Uint16 XCERG4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERG5, ширина 1 бит; данные XCERG5. */ + Uint16 XCERG5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERG6, ширина 1 бит; данные XCERG6. */ + Uint16 XCERG6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERG7, ширина 1 бит; данные XCERG7. */ + Uint16 XCERG7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERG8, ширина 1 бит; данные XCERG8. */ + Uint16 XCERG8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERG9, ширина 1 бит; данные XCERG9. */ + Uint16 XCERG9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERG10, ширина 1 бит; данные XCERG10. */ + Uint16 XCERG10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERG11, ширина 1 бит; данные XCERG11. */ + Uint16 XCERG11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERG12, ширина 1 бит; данные XCERG12. */ + Uint16 XCERG12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERG13, ширина 1 бит; данные XCERG13. */ + Uint16 XCERG13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERG14, ширина 1 бит; данные XCERG14. */ + Uint16 XCERG14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERG15, ширина 1 бит; данные XCERG15. */ + Uint16 XCERG15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERG_REG в одной области памяти. */ +union XCERG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERG_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERH control register bit definitions: +/* Описывает структуру XCERH_BITS; порядок полей определяет расположение данных. */ +struct XCERH_BITS { // bit description + /* Битовое поле XCEH0, ширина 1 бит; данные XCEH0. */ + Uint16 XCEH0:1; // 0 Receive Channel enable bit + /* Битовое поле XCEH1, ширина 1 бит; данные XCEH1. */ + Uint16 XCEH1:1; // 1 Receive Channel enable bit + /* Битовое поле XCEH2, ширина 1 бит; данные XCEH2. */ + Uint16 XCEH2:1; // 2 Receive Channel enable bit + /* Битовое поле XCEH3, ширина 1 бит; данные XCEH3. */ + Uint16 XCEH3:1; // 3 Receive Channel enable bit + /* Битовое поле XCEH4, ширина 1 бит; данные XCEH4. */ + Uint16 XCEH4:1; // 4 Receive Channel enable bit + /* Битовое поле XCEH5, ширина 1 бит; данные XCEH5. */ + Uint16 XCEH5:1; // 5 Receive Channel enable bit + /* Битовое поле XCEH6, ширина 1 бит; данные XCEH6. */ + Uint16 XCEH6:1; // 6 Receive Channel enable bit + /* Битовое поле XCEH7, ширина 1 бит; данные XCEH7. */ + Uint16 XCEH7:1; // 7 Receive Channel enable bit + /* Битовое поле XCEH8, ширина 1 бит; данные XCEH8. */ + Uint16 XCEH8:1; // 8 Receive Channel enable bit + /* Битовое поле XCEH9, ширина 1 бит; данные XCEH9. */ + Uint16 XCEH9:1; // 9 Receive Channel enable bit + /* Битовое поле XCEH10, ширина 1 бит; данные XCEH10. */ + Uint16 XCEH10:1; // 10 Receive Channel enable bit + /* Битовое поле XCEH11, ширина 1 бит; данные XCEH11. */ + Uint16 XCEH11:1; // 11 Receive Channel enable bit + /* Битовое поле XCEH12, ширина 1 бит; данные XCEH12. */ + Uint16 XCEH12:1; // 12 Receive Channel enable bit + /* Битовое поле XCEH13, ширина 1 бит; данные XCEH13. */ + Uint16 XCEH13:1; // 13 Receive Channel enable bit + /* Битовое поле XCEH14, ширина 1 бит; данные XCEH14. */ + Uint16 XCEH14:1; // 14 Receive Channel enable bit + /* Битовое поле XCEH15, ширина 1 бит; данные XCEH15. */ + Uint16 XCEH15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERH_REG в одной области памяти. */ +union XCERH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERH_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERH_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// McBSP Interrupt enable register for RINT/XINT +/* Описывает структуру MFFINT_BITS; порядок полей определяет расположение данных. */ +struct MFFINT_BITS { // bits description + /* Битовое поле XINT, ширина 1 бит; данные XINT. */ + Uint16 XINT:1; // 0 XINT interrupt enable + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле RINT, ширина 1 бит; данные RINT. */ + Uint16 RINT:1; // 2 RINT interrupt enable + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MFFINT_REG в одной области памяти. */ +union MFFINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MFFINT_BITS bit;; порядок полей определяет расположение данных. */ + struct MFFINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// McBSP Register File: +// +/* Описывает структуру MCBSP_REGS; порядок полей определяет расположение данных. */ +struct MCBSP_REGS { + /* Объединяет несколько представлений DRR2_REG DRR2; в одной области памяти. */ + union DRR2_REG DRR2; // MCBSP Data receive register bits 31-16 + /* Объединяет несколько представлений DRR1_REG DRR1; в одной области памяти. */ + union DRR1_REG DRR1; // MCBSP Data receive register bits 15-0 + /* Объединяет несколько представлений DXR2_REG DXR2; в одной области памяти. */ + union DXR2_REG DXR2; // MCBSP Data transmit register bits 31-16 + /* Объединяет несколько представлений DXR1_REG DXR1; в одной области памяти. */ + union DXR1_REG DXR1; // MCBSP Data transmit register bits 15-0 + /* Объединяет несколько представлений SPCR2_REG SPCR2; в одной области памяти. */ + union SPCR2_REG SPCR2; // MCBSP control register bits 31-16 + /* Объединяет несколько представлений SPCR1_REG SPCR1; в одной области памяти. */ + union SPCR1_REG SPCR1; // MCBSP control register bits 15-0 + /* Объединяет несколько представлений RCR2_REG RCR2; в одной области памяти. */ + union RCR2_REG RCR2; // MCBSP receive control register bits 31-16 + /* Объединяет несколько представлений RCR1_REG RCR1; в одной области памяти. */ + union RCR1_REG RCR1; // MCBSP receive control register bits 15-0 + /* Объединяет несколько представлений XCR2_REG XCR2; в одной области памяти. */ + union XCR2_REG XCR2; // MCBSP transmit control register bits 31-16 + /* Объединяет несколько представлений XCR1_REG XCR1; в одной области памяти. */ + union XCR1_REG XCR1; // MCBSP transmit control register bits 15-0 + /* Объединяет несколько представлений SRGR2_REG SRGR2; в одной области памяти. */ + union SRGR2_REG SRGR2; // MCBSP sample rate gen register bits 31-16 + /* Объединяет несколько представлений SRGR1_REG SRGR1; в одной области памяти. */ + union SRGR1_REG SRGR1; // MCBSP sample rate gen register bits 15-0 + /* Объединяет несколько представлений MCR2_REG MCR2; в одной области памяти. */ + union MCR2_REG MCR2; // MCBSP multichannel register bits 31-16 + /* Объединяет несколько представлений MCR1_REG MCR1; в одной области памяти. */ + union MCR1_REG MCR1; // MCBSP multichannel register bits 15-0 + /* Объединяет несколько представлений RCERA_REG RCERA; в одной области памяти. */ + union RCERA_REG RCERA; // MCBSP Receive channel enable partition A + /* Объединяет несколько представлений RCERB_REG RCERB; в одной области памяти. */ + union RCERB_REG RCERB; // MCBSP Receive channel enable partition B + /* Объединяет несколько представлений XCERA_REG XCERA; в одной области памяти. */ + union XCERA_REG XCERA; // MCBSP Transmit channel enable partition A + /* Объединяет несколько представлений XCERB_REG XCERB; в одной области памяти. */ + union XCERB_REG XCERB; // MCBSP Transmit channel enable partition B + /* Объединяет несколько представлений PCR_REG PCR; в одной области памяти. */ + union PCR_REG PCR; // MCBSP Pin control register bits 15-0 + /* Объединяет несколько представлений RCERC_REG RCERC; в одной области памяти. */ + union RCERC_REG RCERC; // MCBSP Receive channel enable partition C + /* Объединяет несколько представлений RCERD_REG RCERD; в одной области памяти. */ + union RCERD_REG RCERD; // MCBSP Receive channel enable partition D + /* Объединяет несколько представлений XCERC_REG XCERC; в одной области памяти. */ + union XCERC_REG XCERC; // MCBSP Transmit channel enable partition C + /* Объединяет несколько представлений XCERD_REG XCERD; в одной области памяти. */ + union XCERD_REG XCERD; // MCBSP Transmit channel enable partition D + /* Объединяет несколько представлений RCERE_REG RCERE; в одной области памяти. */ + union RCERE_REG RCERE; // MCBSP Receive channel enable partition E + /* Объединяет несколько представлений RCERF_REG RCERF; в одной области памяти. */ + union RCERF_REG RCERF; // MCBSP Receive channel enable partition F + /* Объединяет несколько представлений XCERE_REG XCERE; в одной области памяти. */ + union XCERE_REG XCERE; // MCBSP Transmit channel enable partition E + /* Объединяет несколько представлений XCERF_REG XCERF; в одной области памяти. */ + union XCERF_REG XCERF; // MCBSP Transmit channel enable partition F + /* Объединяет несколько представлений RCERG_REG RCERG; в одной области памяти. */ + union RCERG_REG RCERG; // MCBSP Receive channel enable partition G + /* Объединяет несколько представлений RCERH_REG RCERH; в одной области памяти. */ + union RCERH_REG RCERH; // MCBSP Receive channel enable partition H + /* Объединяет несколько представлений XCERG_REG XCERG; в одной области памяти. */ + union XCERG_REG XCERG; // MCBSP Transmit channel enable partition G + /* Объединяет несколько представлений XCERH_REG XCERH; в одной области памяти. */ + union XCERH_REG XCERH; // MCBSP Transmit channel enable partition H + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[4]; // reserved + /* Объединяет несколько представлений MFFINT_REG MFFINT; в одной области памяти. */ + union MFFINT_REG MFFINT; // MCBSP Interrupt enable register for RINT/XINT + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// McBSP External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct MCBSP_REGS McbspaRegs;; порядок элементов сохраняется. */ +extern volatile struct MCBSP_REGS McbspaRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MCBSP_REGS McbspbRegs;; порядок элементов сохраняется. */ +extern volatile struct MCBSP_REGS McbspbRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_MCBSP_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h new file mode 100644 index 0000000..b7eece6 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h @@ -0,0 +1,260 @@ +/* Поставляемое TI описание PieCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:24 $ +//########################################################################### +// +// FILE: DSP2833x_PieCtrl.h +// +// TITLE: DSP2833x Device PIE Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + + +/* Начинает условие: DSP2833x_PIE_CTRL_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_PIE_CTRL_H +/* Определяет защитный символ или переключатель DSP2833x_PIE_CTRL_H для последующей компиляции. */ +#define DSP2833x_PIE_CTRL_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// PIE Control Register Bit Definitions: +// +// PIECTRL: Register bit definitions: +/* Описывает структуру PIECTRL_BITS; порядок полей определяет расположение данных. */ +struct PIECTRL_BITS { // bits description + /* Битовое поле ENPIE, ширина 1 бит; данные ENPIE. */ + Uint16 ENPIE:1; // 0 Enable PIE block + /* Битовое поле PIEVECT, ширина 15 бит; данные PIEVECT. */ + Uint16 PIEVECT:15; // 15:1 Fetched vector address +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIECTRL_REG в одной области памяти. */ +union PIECTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIECTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct PIECTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PIEIER: Register bit definitions: +/* Описывает структуру PIEIER_BITS; порядок полей определяет расположение данных. */ +struct PIEIER_BITS { // bits description + /* Битовое поле INTx1, ширина 1 бит; данные INTx1. */ + Uint16 INTx1:1; // 0 INTx.1 + /* Битовое поле INTx2, ширина 1 бит; данные INTx2. */ + Uint16 INTx2:1; // 1 INTx.2 + /* Битовое поле INTx3, ширина 1 бит; данные INTx3. */ + Uint16 INTx3:1; // 2 INTx.3 + /* Битовое поле INTx4, ширина 1 бит; данные INTx4. */ + Uint16 INTx4:1; // 3 INTx.4 + /* Битовое поле INTx5, ширина 1 бит; данные INTx5. */ + Uint16 INTx5:1; // 4 INTx.5 + /* Битовое поле INTx6, ширина 1 бит; данные INTx6. */ + Uint16 INTx6:1; // 5 INTx.6 + /* Битовое поле INTx7, ширина 1 бит; данные INTx7. */ + Uint16 INTx7:1; // 6 INTx.7 + /* Битовое поле INTx8, ширина 1 бит; данные INTx8. */ + Uint16 INTx8:1; // 7 INTx.8 + /* Битовое поле rsvd, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIEIER_REG в одной области памяти. */ +union PIEIER_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIEIER_BITS bit;; порядок полей определяет расположение данных. */ + struct PIEIER_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PIEIFR: Register bit definitions: +/* Описывает структуру PIEIFR_BITS; порядок полей определяет расположение данных. */ +struct PIEIFR_BITS { // bits description + /* Битовое поле INTx1, ширина 1 бит; данные INTx1. */ + Uint16 INTx1:1; // 0 INTx.1 + /* Битовое поле INTx2, ширина 1 бит; данные INTx2. */ + Uint16 INTx2:1; // 1 INTx.2 + /* Битовое поле INTx3, ширина 1 бит; данные INTx3. */ + Uint16 INTx3:1; // 2 INTx.3 + /* Битовое поле INTx4, ширина 1 бит; данные INTx4. */ + Uint16 INTx4:1; // 3 INTx.4 + /* Битовое поле INTx5, ширина 1 бит; данные INTx5. */ + Uint16 INTx5:1; // 4 INTx.5 + /* Битовое поле INTx6, ширина 1 бит; данные INTx6. */ + Uint16 INTx6:1; // 5 INTx.6 + /* Битовое поле INTx7, ширина 1 бит; данные INTx7. */ + Uint16 INTx7:1; // 6 INTx.7 + /* Битовое поле INTx8, ширина 1 бит; данные INTx8. */ + Uint16 INTx8:1; // 7 INTx.8 + /* Битовое поле rsvd, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIEIFR_REG в одной области памяти. */ +union PIEIFR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIEIFR_BITS bit;; порядок полей определяет расположение данных. */ + struct PIEIFR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PIEACK: Register bit definitions: +/* Описывает структуру PIEACK_BITS; порядок полей определяет расположение данных. */ +struct PIEACK_BITS { // bits description + /* Битовое поле ACK1, ширина 1 бит; данные ACK1. */ + Uint16 ACK1:1; // 0 Acknowledge PIE interrupt group 1 + /* Битовое поле ACK2, ширина 1 бит; данные ACK2. */ + Uint16 ACK2:1; // 1 Acknowledge PIE interrupt group 2 + /* Битовое поле ACK3, ширина 1 бит; данные ACK3. */ + Uint16 ACK3:1; // 2 Acknowledge PIE interrupt group 3 + /* Битовое поле ACK4, ширина 1 бит; данные ACK4. */ + Uint16 ACK4:1; // 3 Acknowledge PIE interrupt group 4 + /* Битовое поле ACK5, ширина 1 бит; данные ACK5. */ + Uint16 ACK5:1; // 4 Acknowledge PIE interrupt group 5 + /* Битовое поле ACK6, ширина 1 бит; данные ACK6. */ + Uint16 ACK6:1; // 5 Acknowledge PIE interrupt group 6 + /* Битовое поле ACK7, ширина 1 бит; данные ACK7. */ + Uint16 ACK7:1; // 6 Acknowledge PIE interrupt group 7 + /* Битовое поле ACK8, ширина 1 бит; данные ACK8. */ + Uint16 ACK8:1; // 7 Acknowledge PIE interrupt group 8 + /* Битовое поле ACK9, ширина 1 бит; данные ACK9. */ + Uint16 ACK9:1; // 8 Acknowledge PIE interrupt group 9 + /* Битовое поле ACK10, ширина 1 бит; данные ACK10. */ + Uint16 ACK10:1; // 9 Acknowledge PIE interrupt group 10 + /* Битовое поле ACK11, ширина 1 бит; данные ACK11. */ + Uint16 ACK11:1; // 10 Acknowledge PIE interrupt group 11 + /* Битовое поле ACK12, ширина 1 бит; данные ACK12. */ + Uint16 ACK12:1; // 11 Acknowledge PIE interrupt group 12 + /* Битовое поле rsvd, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIEACK_REG в одной области памяти. */ +union PIEACK_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIEACK_BITS bit;; порядок полей определяет расположение данных. */ + struct PIEACK_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// PIE Control Register File: +// +/* Описывает структуру PIE_CTRL_REGS; порядок полей определяет расположение данных. */ +struct PIE_CTRL_REGS { + /* Объединяет несколько представлений PIECTRL_REG PIECTRL; в одной области памяти. */ + union PIECTRL_REG PIECTRL; // PIE control register + /* Объединяет несколько представлений PIEACK_REG PIEACK; в одной области памяти. */ + union PIEACK_REG PIEACK; // PIE acknowledge + /* Объединяет несколько представлений PIEIER_REG PIEIER1; в одной области памяти. */ + union PIEIER_REG PIEIER1; // PIE int1 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR1; в одной области памяти. */ + union PIEIFR_REG PIEIFR1; // PIE int1 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER2; в одной области памяти. */ + union PIEIER_REG PIEIER2; // PIE INT2 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR2; в одной области памяти. */ + union PIEIFR_REG PIEIFR2; // PIE INT2 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER3; в одной области памяти. */ + union PIEIER_REG PIEIER3; // PIE INT3 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR3; в одной области памяти. */ + union PIEIFR_REG PIEIFR3; // PIE INT3 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER4; в одной области памяти. */ + union PIEIER_REG PIEIER4; // PIE INT4 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR4; в одной области памяти. */ + union PIEIFR_REG PIEIFR4; // PIE INT4 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER5; в одной области памяти. */ + union PIEIER_REG PIEIER5; // PIE INT5 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR5; в одной области памяти. */ + union PIEIFR_REG PIEIFR5; // PIE INT5 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER6; в одной области памяти. */ + union PIEIER_REG PIEIER6; // PIE INT6 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR6; в одной области памяти. */ + union PIEIFR_REG PIEIFR6; // PIE INT6 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER7; в одной области памяти. */ + union PIEIER_REG PIEIER7; // PIE INT7 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR7; в одной области памяти. */ + union PIEIFR_REG PIEIFR7; // PIE INT7 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER8; в одной области памяти. */ + union PIEIER_REG PIEIER8; // PIE INT8 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR8; в одной области памяти. */ + union PIEIFR_REG PIEIFR8; // PIE INT8 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER9; в одной области памяти. */ + union PIEIER_REG PIEIER9; // PIE INT9 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR9; в одной области памяти. */ + union PIEIFR_REG PIEIFR9; // PIE INT9 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER10; в одной области памяти. */ + union PIEIER_REG PIEIER10; // PIE int10 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR10; в одной области памяти. */ + union PIEIFR_REG PIEIFR10; // PIE int10 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER11; в одной области памяти. */ + union PIEIER_REG PIEIER11; // PIE int11 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR11; в одной области памяти. */ + union PIEIFR_REG PIEIFR11; // PIE int11 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER12; в одной области памяти. */ + union PIEIER_REG PIEIER12; // PIE int12 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR12; в одной области памяти. */ + union PIEIFR_REG PIEIFR12; // PIE int12 IFR register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Задаёт PIEACK_GROUP1 = 0x0001; данные PIEACK_GROUP1. */ +#define PIEACK_GROUP1 0x0001 +/* Задаёт PIEACK_GROUP2 = 0x0002; данные PIEACK_GROUP2. */ +#define PIEACK_GROUP2 0x0002 +/* Задаёт PIEACK_GROUP3 = 0x0004; данные PIEACK_GROUP3. */ +#define PIEACK_GROUP3 0x0004 +/* Задаёт PIEACK_GROUP4 = 0x0008; данные PIEACK_GROUP4. */ +#define PIEACK_GROUP4 0x0008 +/* Задаёт PIEACK_GROUP5 = 0x0010; данные PIEACK_GROUP5. */ +#define PIEACK_GROUP5 0x0010 +/* Задаёт PIEACK_GROUP6 = 0x0020; данные PIEACK_GROUP6. */ +#define PIEACK_GROUP6 0x0020 +/* Задаёт PIEACK_GROUP7 = 0x0040; данные PIEACK_GROUP7. */ +#define PIEACK_GROUP7 0x0040 +/* Задаёт PIEACK_GROUP8 = 0x0080; данные PIEACK_GROUP8. */ +#define PIEACK_GROUP8 0x0080 +/* Задаёт PIEACK_GROUP9 = 0x0100; данные PIEACK_GROUP9. */ +#define PIEACK_GROUP9 0x0100 +/* Задаёт PIEACK_GROUP10 = 0x0200; данные PIEACK_GROUP10. */ +#define PIEACK_GROUP10 0x0200 +/* Задаёт PIEACK_GROUP11 = 0x0400; данные PIEACK_GROUP11. */ +#define PIEACK_GROUP11 0x0400 +/* Задаёт PIEACK_GROUP12 = 0x0800; данные PIEACK_GROUP12. */ +#define PIEACK_GROUP12 0x0800 + +//--------------------------------------------------------------------------- +// PIE Control Registers External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct PIE_CTRL_REGS PieCtrlRegs;; порядок элементов сохраняется. */ +extern volatile struct PIE_CTRL_REGS PieCtrlRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_PIE_CTRL_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h new file mode 100644 index 0000000..b768be2 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h @@ -0,0 +1,349 @@ +/* Поставляемое TI описание PieVect для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: March 16, 2007 09:00:21 $ +//########################################################################### +// +// FILE: DSP2833x_PieVect.h +// +// TITLE: DSP2833x Devices PIE Vector Table Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_PIE_VECT_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_PIE_VECT_H +/* Определяет защитный символ или переключатель DSP2833x_PIE_VECT_H для последующей компиляции. */ +#define DSP2833x_PIE_VECT_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table Definition: +// +// Create a user type called PINT (pointer to interrupt): + +/* Объявляет интерфейс функции void; реализация вызывается через этот прототип. */ +typedef interrupt void(*PINT)(void); + +// Define Vector Table: +/* Описывает структуру PIE_VECT_TABLE; порядок полей определяет расположение данных. */ +struct PIE_VECT_TABLE { + +// Reset is never fetched from this table. +// It will always be fetched from 0x3FFFC0 in +// boot ROM + + /* Продолжает список аргументов, полей или выражение PINT PIE1_RESERVED;; порядок элементов сохраняется. */ + PINT PIE1_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE2_RESERVED;; порядок элементов сохраняется. */ + PINT PIE2_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE3_RESERVED;; порядок элементов сохраняется. */ + PINT PIE3_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE4_RESERVED;; порядок элементов сохраняется. */ + PINT PIE4_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE5_RESERVED;; порядок элементов сохраняется. */ + PINT PIE5_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE6_RESERVED;; порядок элементов сохраняется. */ + PINT PIE6_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE7_RESERVED;; порядок элементов сохраняется. */ + PINT PIE7_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE8_RESERVED;; порядок элементов сохраняется. */ + PINT PIE8_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE9_RESERVED;; порядок элементов сохраняется. */ + PINT PIE9_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE10_RESERVED;; порядок элементов сохраняется. */ + PINT PIE10_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE11_RESERVED;; порядок элементов сохраняется. */ + PINT PIE11_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE12_RESERVED;; порядок элементов сохраняется. */ + PINT PIE12_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE13_RESERVED;; порядок элементов сохраняется. */ + PINT PIE13_RESERVED; + +// Non-Peripheral Interrupts: + /* Продолжает список аргументов, полей или выражение PINT XINT13;; порядок элементов сохраняется. */ + PINT XINT13; // XINT13 / CPU-Timer1 + /* Продолжает список аргументов, полей или выражение PINT TINT2;; порядок элементов сохраняется. */ + PINT TINT2; // CPU-Timer2 + /* Продолжает список аргументов, полей или выражение PINT DATALOG;; порядок элементов сохраняется. */ + PINT DATALOG; // Datalogging interrupt + /* Продолжает список аргументов, полей или выражение PINT RTOSINT;; порядок элементов сохраняется. */ + PINT RTOSINT; // RTOS interrupt + /* Продолжает список аргументов, полей или выражение PINT EMUINT;; порядок элементов сохраняется. */ + PINT EMUINT; // Emulation interrupt + /* Продолжает список аргументов, полей или выражение PINT XNMI;; порядок элементов сохраняется. */ + PINT XNMI; // Non-maskable interrupt + /* Продолжает список аргументов, полей или выражение PINT ILLEGAL;; порядок элементов сохраняется. */ + PINT ILLEGAL; // Illegal operation TRAP + /* Продолжает список аргументов, полей или выражение PINT USER1;; порядок элементов сохраняется. */ + PINT USER1; // User Defined trap 1 + /* Продолжает список аргументов, полей или выражение PINT USER2;; порядок элементов сохраняется. */ + PINT USER2; // User Defined trap 2 + /* Продолжает список аргументов, полей или выражение PINT USER3;; порядок элементов сохраняется. */ + PINT USER3; // User Defined trap 3 + /* Продолжает список аргументов, полей или выражение PINT USER4;; порядок элементов сохраняется. */ + PINT USER4; // User Defined trap 4 + /* Продолжает список аргументов, полей или выражение PINT USER5;; порядок элементов сохраняется. */ + PINT USER5; // User Defined trap 5 + /* Продолжает список аргументов, полей или выражение PINT USER6;; порядок элементов сохраняется. */ + PINT USER6; // User Defined trap 6 + /* Продолжает список аргументов, полей или выражение PINT USER7;; порядок элементов сохраняется. */ + PINT USER7; // User Defined trap 7 + /* Продолжает список аргументов, полей или выражение PINT USER8;; порядок элементов сохраняется. */ + PINT USER8; // User Defined trap 8 + /* Продолжает список аргументов, полей или выражение PINT USER9;; порядок элементов сохраняется. */ + PINT USER9; // User Defined trap 9 + /* Продолжает список аргументов, полей или выражение PINT USER10;; порядок элементов сохраняется. */ + PINT USER10; // User Defined trap 10 + /* Продолжает список аргументов, полей или выражение PINT USER11;; порядок элементов сохраняется. */ + PINT USER11; // User Defined trap 11 + /* Продолжает список аргументов, полей или выражение PINT USER12;; порядок элементов сохраняется. */ + PINT USER12; // User Defined trap 12 + +// Group 1 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT SEQ1INT;; порядок элементов сохраняется. */ + PINT SEQ1INT; + /* Продолжает список аргументов, полей или выражение PINT SEQ2INT;; порядок элементов сохраняется. */ + PINT SEQ2INT; + /* Продолжает список аргументов, полей или выражение PINT rsvd1_3;; порядок элементов сохраняется. */ + PINT rsvd1_3; + /* Продолжает список аргументов, полей или выражение PINT XINT1;; порядок элементов сохраняется. */ + PINT XINT1; + /* Продолжает список аргументов, полей или выражение PINT XINT2;; порядок элементов сохраняется. */ + PINT XINT2; + /* Продолжает список аргументов, полей или выражение PINT ADCINT;; порядок элементов сохраняется. */ + PINT ADCINT; // ADC + /* Продолжает список аргументов, полей или выражение PINT TINT0;; порядок элементов сохраняется. */ + PINT TINT0; // Timer 0 + /* Продолжает список аргументов, полей или выражение PINT WAKEINT;; порядок элементов сохраняется. */ + PINT WAKEINT; // WD + +// Group 2 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT EPWM1_TZINT;; порядок элементов сохраняется. */ + PINT EPWM1_TZINT; // EPWM-1 + /* Продолжает список аргументов, полей или выражение PINT EPWM2_TZINT;; порядок элементов сохраняется. */ + PINT EPWM2_TZINT; // EPWM-2 + /* Продолжает список аргументов, полей или выражение PINT EPWM3_TZINT;; порядок элементов сохраняется. */ + PINT EPWM3_TZINT; // EPWM-3 + /* Продолжает список аргументов, полей или выражение PINT EPWM4_TZINT;; порядок элементов сохраняется. */ + PINT EPWM4_TZINT; // EPWM-4 + /* Продолжает список аргументов, полей или выражение PINT EPWM5_TZINT;; порядок элементов сохраняется. */ + PINT EPWM5_TZINT; // EPWM-5 + /* Продолжает список аргументов, полей или выражение PINT EPWM6_TZINT;; порядок элементов сохраняется. */ + PINT EPWM6_TZINT; // EPWM-6 + /* Продолжает список аргументов, полей или выражение PINT rsvd2_7;; порядок элементов сохраняется. */ + PINT rsvd2_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd2_8;; порядок элементов сохраняется. */ + PINT rsvd2_8; + +// Group 3 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT EPWM1_INT;; порядок элементов сохраняется. */ + PINT EPWM1_INT; // EPWM-1 + /* Продолжает список аргументов, полей или выражение PINT EPWM2_INT;; порядок элементов сохраняется. */ + PINT EPWM2_INT; // EPWM-2 + /* Продолжает список аргументов, полей или выражение PINT EPWM3_INT;; порядок элементов сохраняется. */ + PINT EPWM3_INT; // EPWM-3 + /* Продолжает список аргументов, полей или выражение PINT EPWM4_INT;; порядок элементов сохраняется. */ + PINT EPWM4_INT; // EPWM-4 + /* Продолжает список аргументов, полей или выражение PINT EPWM5_INT;; порядок элементов сохраняется. */ + PINT EPWM5_INT; // EPWM-5 + /* Продолжает список аргументов, полей или выражение PINT EPWM6_INT;; порядок элементов сохраняется. */ + PINT EPWM6_INT; // EPWM-6 + /* Продолжает список аргументов, полей или выражение PINT rsvd3_7;; порядок элементов сохраняется. */ + PINT rsvd3_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd3_8;; порядок элементов сохраняется. */ + PINT rsvd3_8; + +// Group 4 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT ECAP1_INT;; порядок элементов сохраняется. */ + PINT ECAP1_INT; // ECAP-1 + /* Продолжает список аргументов, полей или выражение PINT ECAP2_INT;; порядок элементов сохраняется. */ + PINT ECAP2_INT; // ECAP-2 + /* Продолжает список аргументов, полей или выражение PINT ECAP3_INT;; порядок элементов сохраняется. */ + PINT ECAP3_INT; // ECAP-3 + /* Продолжает список аргументов, полей или выражение PINT ECAP4_INT;; порядок элементов сохраняется. */ + PINT ECAP4_INT; // ECAP-4 + /* Продолжает список аргументов, полей или выражение PINT ECAP5_INT;; порядок элементов сохраняется. */ + PINT ECAP5_INT; // ECAP-5 + /* Продолжает список аргументов, полей или выражение PINT ECAP6_INT;; порядок элементов сохраняется. */ + PINT ECAP6_INT; // ECAP-6 + /* Продолжает список аргументов, полей или выражение PINT rsvd4_7;; порядок элементов сохраняется. */ + PINT rsvd4_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd4_8;; порядок элементов сохраняется. */ + PINT rsvd4_8; + +// Group 5 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT EQEP1_INT;; порядок элементов сохраняется. */ + PINT EQEP1_INT; // EQEP-1 + /* Продолжает список аргументов, полей или выражение PINT EQEP2_INT;; порядок элементов сохраняется. */ + PINT EQEP2_INT; // EQEP-2 + /* Продолжает список аргументов, полей или выражение PINT rsvd5_3;; порядок элементов сохраняется. */ + PINT rsvd5_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_4;; порядок элементов сохраняется. */ + PINT rsvd5_4; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_5;; порядок элементов сохраняется. */ + PINT rsvd5_5; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_6;; порядок элементов сохраняется. */ + PINT rsvd5_6; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_7;; порядок элементов сохраняется. */ + PINT rsvd5_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_8;; порядок элементов сохраняется. */ + PINT rsvd5_8; + +// Group 6 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT SPIRXINTA;; порядок элементов сохраняется. */ + PINT SPIRXINTA; // SPI-A + /* Продолжает список аргументов, полей или выражение PINT SPITXINTA;; порядок элементов сохраняется. */ + PINT SPITXINTA; // SPI-A + /* Продолжает список аргументов, полей или выражение PINT MRINTB;; порядок элементов сохраняется. */ + PINT MRINTB; // McBSP-B + /* Продолжает список аргументов, полей или выражение PINT MXINTB;; порядок элементов сохраняется. */ + PINT MXINTB; // McBSP-B + /* Продолжает список аргументов, полей или выражение PINT MRINTA;; порядок элементов сохраняется. */ + PINT MRINTA; // McBSP-A + /* Продолжает список аргументов, полей или выражение PINT MXINTA;; порядок элементов сохраняется. */ + PINT MXINTA; // McBSP-A + /* Продолжает список аргументов, полей или выражение PINT rsvd6_7;; порядок элементов сохраняется. */ + PINT rsvd6_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd6_8;; порядок элементов сохраняется. */ + PINT rsvd6_8; + +// Group 7 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT DINTCH1;; порядок элементов сохраняется. */ + PINT DINTCH1; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH2;; порядок элементов сохраняется. */ + PINT DINTCH2; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH3;; порядок элементов сохраняется. */ + PINT DINTCH3; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH4;; порядок элементов сохраняется. */ + PINT DINTCH4; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH5;; порядок элементов сохраняется. */ + PINT DINTCH5; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH6;; порядок элементов сохраняется. */ + PINT DINTCH6; // DMA + /* Продолжает список аргументов, полей или выражение PINT rsvd7_7;; порядок элементов сохраняется. */ + PINT rsvd7_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd7_8;; порядок элементов сохраняется. */ + PINT rsvd7_8; + +// Group 8 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT I2CINT1A;; порядок элементов сохраняется. */ + PINT I2CINT1A; // I2C-A + /* Продолжает список аргументов, полей или выражение PINT I2CINT2A;; порядок элементов сохраняется. */ + PINT I2CINT2A; // I2C-A + /* Продолжает список аргументов, полей или выражение PINT rsvd8_3;; порядок элементов сохраняется. */ + PINT rsvd8_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd8_4;; порядок элементов сохраняется. */ + PINT rsvd8_4; + /* Продолжает список аргументов, полей или выражение PINT SCIRXINTC;; порядок элементов сохраняется. */ + PINT SCIRXINTC; // SCI-C + /* Продолжает список аргументов, полей или выражение PINT SCITXINTC;; порядок элементов сохраняется. */ + PINT SCITXINTC; // SCI-C + /* Продолжает список аргументов, полей или выражение PINT rsvd8_7;; порядок элементов сохраняется. */ + PINT rsvd8_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd8_8;; порядок элементов сохраняется. */ + PINT rsvd8_8; + +// Group 9 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT SCIRXINTA;; порядок элементов сохраняется. */ + PINT SCIRXINTA; // SCI-A + /* Продолжает список аргументов, полей или выражение PINT SCITXINTA;; порядок элементов сохраняется. */ + PINT SCITXINTA; // SCI-A + /* Продолжает список аргументов, полей или выражение PINT SCIRXINTB;; порядок элементов сохраняется. */ + PINT SCIRXINTB; // SCI-B + /* Продолжает список аргументов, полей или выражение PINT SCITXINTB;; порядок элементов сохраняется. */ + PINT SCITXINTB; // SCI-B + /* Продолжает список аргументов, полей или выражение PINT ECAN0INTA;; порядок элементов сохраняется. */ + PINT ECAN0INTA; // eCAN-A + /* Продолжает список аргументов, полей или выражение PINT ECAN1INTA;; порядок элементов сохраняется. */ + PINT ECAN1INTA; // eCAN-A + /* Продолжает список аргументов, полей или выражение PINT ECAN0INTB;; порядок элементов сохраняется. */ + PINT ECAN0INTB; // eCAN-B + /* Продолжает список аргументов, полей или выражение PINT ECAN1INTB;; порядок элементов сохраняется. */ + PINT ECAN1INTB; // eCAN-B + +// Group 10 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT rsvd10_1;; порядок элементов сохраняется. */ + PINT rsvd10_1; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_2;; порядок элементов сохраняется. */ + PINT rsvd10_2; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_3;; порядок элементов сохраняется. */ + PINT rsvd10_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_4;; порядок элементов сохраняется. */ + PINT rsvd10_4; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_5;; порядок элементов сохраняется. */ + PINT rsvd10_5; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_6;; порядок элементов сохраняется. */ + PINT rsvd10_6; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_7;; порядок элементов сохраняется. */ + PINT rsvd10_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_8;; порядок элементов сохраняется. */ + PINT rsvd10_8; + +// Group 11 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT rsvd11_1;; порядок элементов сохраняется. */ + PINT rsvd11_1; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_2;; порядок элементов сохраняется. */ + PINT rsvd11_2; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_3;; порядок элементов сохраняется. */ + PINT rsvd11_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_4;; порядок элементов сохраняется. */ + PINT rsvd11_4; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_5;; порядок элементов сохраняется. */ + PINT rsvd11_5; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_6;; порядок элементов сохраняется. */ + PINT rsvd11_6; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_7;; порядок элементов сохраняется. */ + PINT rsvd11_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_8;; порядок элементов сохраняется. */ + PINT rsvd11_8; + +// Group 12 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT XINT3;; порядок элементов сохраняется. */ + PINT XINT3; // External interrupt + /* Продолжает список аргументов, полей или выражение PINT XINT4;; порядок элементов сохраняется. */ + PINT XINT4; + /* Продолжает список аргументов, полей или выражение PINT XINT5;; порядок элементов сохраняется. */ + PINT XINT5; + /* Продолжает список аргументов, полей или выражение PINT XINT6;; порядок элементов сохраняется. */ + PINT XINT6; + /* Продолжает список аргументов, полей или выражение PINT XINT7;; порядок элементов сохраняется. */ + PINT XINT7; + /* Продолжает список аргументов, полей или выражение PINT rsvd12_6;; порядок элементов сохраняется. */ + PINT rsvd12_6; + /* Продолжает список аргументов, полей или выражение PINT LVF;; порядок элементов сохраняется. */ + PINT LVF; // Latched overflow + /* Продолжает список аргументов, полей или выражение PINT LUF;; порядок элементов сохраняется. */ + PINT LUF; // Latched underflow +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern struct PIE_VECT_TABLE PieVectTable;; порядок элементов сохраняется. */ +extern struct PIE_VECT_TABLE PieVectTable; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_PIE_VECT_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h new file mode 100644 index 0000000..83b5a65 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h @@ -0,0 +1,377 @@ +/* Поставляемое TI описание Sci для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: March 1, 2007 15:57:02 $ +//########################################################################### +// +// FILE: DSP2833x_Sci.h +// +// TITLE: DSP2833x Device SCI Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SCI_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SCI_H +/* Определяет защитный символ или переключатель DSP2833x_SCI_H для последующей компиляции. */ +#define DSP2833x_SCI_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// SCI Individual Register Bit Definitions + +//---------------------------------------------------------- +// SCICCR communication control register bit definitions: +// + +/* Описывает структуру SCICCR_BITS; порядок полей определяет расположение данных. */ +struct SCICCR_BITS { // bit description + /* Битовое поле SCICHAR, ширина 3 бит; данные SCICHAR. */ + Uint16 SCICHAR:3; // 2:0 Character length control + /* Битовое поле ADDRIDLE_MODE, ширина 1 бит; ADDRIDLE режим. */ + Uint16 ADDRIDLE_MODE:1; // 3 ADDR/IDLE Mode control + /* Битовое поле LOOPBKENA, ширина 1 бит; данные LOOPBKENA. */ + Uint16 LOOPBKENA:1; // 4 Loop Back enable + /* Битовое поле PARITYENA, ширина 1 бит; данные PARITYENA. */ + Uint16 PARITYENA:1; // 5 Parity enable + /* Битовое поле PARITY, ширина 1 бит; чётность. */ + Uint16 PARITY:1; // 6 Even or Odd Parity + /* Битовое поле STOPBITS, ширина 1 бит; данные STOPBITS. */ + Uint16 STOPBITS:1; // 7 Number of Stop Bits + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений SCICCR_REG в одной области памяти. */ +union SCICCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCICCR_BITS bit;; порядок полей определяет расположение данных. */ + struct SCICCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------- +// SCICTL1 control register 1 bit definitions: +// + +/* Описывает структуру SCICTL1_BITS; порядок полей определяет расположение данных. */ +struct SCICTL1_BITS { // bit description + /* Битовое поле RXENA, ширина 1 бит; данные RXENA. */ + Uint16 RXENA:1; // 0 SCI receiver enable + /* Битовое поле TXENA, ширина 1 бит; данные TXENA. */ + Uint16 TXENA:1; // 1 SCI transmitter enable + /* Битовое поле SLEEP, ширина 1 бит; данные SLEEP. */ + Uint16 SLEEP:1; // 2 SCI sleep + /* Битовое поле TXWAKE, ширина 1 бит; данные TXWAKE. */ + Uint16 TXWAKE:1; // 3 Transmitter wakeup method + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 4 reserved + /* Битовое поле SWRESET, ширина 1 бит; данные SWRESET. */ + Uint16 SWRESET:1; // 5 Software reset + /* Битовое поле RXERRINTENA, ширина 1 бит; данные RXERRINTENA. */ + Uint16 RXERRINTENA:1; // 6 Recieve interrupt enable + /* Битовое поле rsvd1, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:9; // 15:7 reserved + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCICTL1_REG в одной области памяти. */ +union SCICTL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCICTL1_BITS bit;; порядок полей определяет расположение данных. */ + struct SCICTL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------- +// SCICTL2 control register 2 bit definitions: +// + +/* Описывает структуру SCICTL2_BITS; порядок полей определяет расположение данных. */ +struct SCICTL2_BITS { // bit description + /* Битовое поле TXINTENA, ширина 1 бит; данные TXINTENA. */ + Uint16 TXINTENA:1; // 0 Transmit interrupt enable + /* Битовое поле RXBKINTENA, ширина 1 бит; данные RXBKINTENA. */ + Uint16 RXBKINTENA:1; // 1 Receiver-buffer break enable + /* Битовое поле rsvd, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:4; // 5:2 reserved + /* Битовое поле TXEMPTY, ширина 1 бит; данные TXEMPTY. */ + Uint16 TXEMPTY:1; // 6 Transmitter empty flag + /* Битовое поле TXRDY, ширина 1 бит; данные TXRDY. */ + Uint16 TXRDY:1; // 7 Transmitter ready flag + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCICTL2_REG в одной области памяти. */ +union SCICTL2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCICTL2_BITS bit;; порядок полей определяет расположение данных. */ + struct SCICTL2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------- +// SCIRXST Receiver status register bit definitions: +// + +/* Описывает структуру SCIRXST_BITS; порядок полей определяет расположение данных. */ +struct SCIRXST_BITS { // bit description + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 0 reserved + /* Битовое поле RXWAKE, ширина 1 бит; данные RXWAKE. */ + Uint16 RXWAKE:1; // 1 Receiver wakeup detect flag + /* Битовое поле PE, ширина 1 бит; данные PE. */ + Uint16 PE:1; // 2 Parity error flag + /* Битовое поле OE, ширина 1 бит; данные OE. */ + Uint16 OE:1; // 3 Overrun error flag + /* Битовое поле FE, ширина 1 бит; данные FE. */ + Uint16 FE:1; // 4 Framing error flag + /* Битовое поле BRKDT, ширина 1 бит; данные BRKDT. */ + Uint16 BRKDT:1; // 5 Break-detect flag + /* Битовое поле RXRDY, ширина 1 бит; данные RXRDY. */ + Uint16 RXRDY:1; // 6 Receiver ready flag + /* Битовое поле RXERROR, ширина 1 бит; данные RXERROR. */ + Uint16 RXERROR:1; // 7 Receiver error flag + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIRXST_REG в одной области памяти. */ +union SCIRXST_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIRXST_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIRXST_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// SCIRXBUF Receiver Data Buffer with FIFO bit definitions: +// + +/* Описывает структуру SCIRXBUF_BITS; порядок полей определяет расположение данных. */ +struct SCIRXBUF_BITS { // bits description + /* Битовое поле RXDT, ширина 8 бит; данные RXDT. */ + Uint16 RXDT:8; // 7:0 Receive word + /* Битовое поле rsvd, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:6; // 13:8 reserved + /* Битовое поле SCIFFPE, ширина 1 бит; данные SCIFFPE. */ + Uint16 SCIFFPE:1; // 14 SCI PE error in FIFO mode + /* Битовое поле SCIFFFE, ширина 1 бит; данные SCIFFFE. */ + Uint16 SCIFFFE:1; // 15 SCI FE error in FIFO mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIRXBUF_REG в одной области памяти. */ +union SCIRXBUF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIRXBUF_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIRXBUF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------------------- +// SCIPRI Priority control register bit definitions: +// +// + +/* Описывает структуру SCIPRI_BITS; порядок полей определяет расположение данных. */ +struct SCIPRI_BITS { // bit description + /* Битовое поле rsvd, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:3; // 2:0 reserved + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 3 Free emulation suspend mode + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 4 Soft emulation suspend mode + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIPRI_REG в одной области памяти. */ +union SCIPRI_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIPRI_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIPRI_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------- +// SCI FIFO Transmit register bit definitions: +// +// + +/* Описывает структуру SCIFFTX_BITS; порядок полей определяет расположение данных. */ +struct SCIFFTX_BITS { // bit description + /* Битовое поле TXFFIL, ширина 5 бит; данные TXFFIL. */ + Uint16 TXFFIL:5; // 4:0 Interrupt level + /* Битовое поле TXFFIENA, ширина 1 бит; данные TXFFIENA. */ + Uint16 TXFFIENA:1; // 5 Interrupt enable + /* Битовое поле TXFFINTCLR, ширина 1 бит; данные TXFFINTCLR. */ + Uint16 TXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле TXFFINT, ширина 1 бит; данные TXFFINT. */ + Uint16 TXFFINT:1; // 7 INT flag + /* Битовое поле TXFFST, ширина 5 бит; данные TXFFST. */ + Uint16 TXFFST:5; // 12:8 FIFO status + /* Битовое поле TXFIFOXRESET, ширина 1 бит; данные TXFIFOXRESET. */ + Uint16 TXFIFOXRESET:1; // 13 FIFO reset + /* Битовое поле SCIFFENA, ширина 1 бит; данные SCIFFENA. */ + Uint16 SCIFFENA:1; // 14 Enhancement enable + /* Битовое поле SCIRST, ширина 1 бит; данные SCIRST. */ + Uint16 SCIRST:1; // 15 SCI reset rx/tx channels + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIFFTX_REG в одной области памяти. */ +union SCIFFTX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIFFTX_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIFFTX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------ +// SCI FIFO recieve register bit definitions: +// +// + +/* Описывает структуру SCIFFRX_BITS; порядок полей определяет расположение данных. */ +struct SCIFFRX_BITS { // bits description + /* Битовое поле RXFFIL, ширина 5 бит; данные RXFFIL. */ + Uint16 RXFFIL:5; // 4:0 Interrupt level + /* Битовое поле RXFFIENA, ширина 1 бит; данные RXFFIENA. */ + Uint16 RXFFIENA:1; // 5 Interrupt enable + /* Битовое поле RXFFINTCLR, ширина 1 бит; данные RXFFINTCLR. */ + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле RXFFINT, ширина 1 бит; данные RXFFINT. */ + Uint16 RXFFINT:1; // 7 INT flag + /* Битовое поле RXFFST, ширина 5 бит; данные RXFFST. */ + Uint16 RXFFST:5; // 12:8 FIFO status + /* Битовое поле RXFIFORESET, ширина 1 бит; данные RXFIFORESET. */ + Uint16 RXFIFORESET:1; // 13 FIFO reset + /* Битовое поле RXFFOVRCLR, ширина 1 бит; данные RXFFOVRCLR. */ + Uint16 RXFFOVRCLR:1; // 14 Clear overflow + /* Битовое поле RXFFOVF, ширина 1 бит; данные RXFFOVF. */ + Uint16 RXFFOVF:1; // 15 FIFO overflow + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIFFRX_REG в одной области памяти. */ +union SCIFFRX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIFFRX_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIFFRX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SCI FIFO control register bit definitions: +/* Описывает структуру SCIFFCT_BITS; порядок полей определяет расположение данных. */ +struct SCIFFCT_BITS { // bits description + /* Битовое поле FFTXDLY, ширина 8 бит; данные FFTXDLY. */ + Uint16 FFTXDLY:8; // 7:0 FIFO transmit delay + /* Битовое поле rsvd, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:5; // 12:8 reserved + /* Битовое поле CDC, ширина 1 бит; данные CDC. */ + Uint16 CDC:1; // 13 Auto baud mode enable + /* Битовое поле ABDCLR, ширина 1 бит; данные ABDCLR. */ + Uint16 ABDCLR:1; // 14 Auto baud clear + /* Битовое поле ABD, ширина 1 бит; данные ABD. */ + Uint16 ABD:1; // 15 Auto baud detect +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIFFCT_REG в одной области памяти. */ +union SCIFFCT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIFFCT_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIFFCT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SCI Register File: +// +/* Описывает структуру SCI_REGS; порядок полей определяет расположение данных. */ +struct SCI_REGS { + /* Объединяет несколько представлений SCICCR_REG SCICCR; в одной области памяти. */ + union SCICCR_REG SCICCR; // Communications control register + /* Объединяет несколько представлений SCICTL1_REG SCICTL1; в одной области памяти. */ + union SCICTL1_REG SCICTL1; // Control register 1 + /* Объявляет SCIHBAUD — данные SCIHBAUD. */ + Uint16 SCIHBAUD; // Baud rate (high) register + /* Объявляет SCILBAUD — данные SCILBAUD. */ + Uint16 SCILBAUD; // Baud rate (low) register + /* Объединяет несколько представлений SCICTL2_REG SCICTL2; в одной области памяти. */ + union SCICTL2_REG SCICTL2; // Control register 2 + /* Объединяет несколько представлений SCIRXST_REG SCIRXST; в одной области памяти. */ + union SCIRXST_REG SCIRXST; // Recieve status register + /* Объявляет SCIRXEMU — данные SCIRXEMU. */ + Uint16 SCIRXEMU; // Recieve emulation buffer register + /* Объединяет несколько представлений SCIRXBUF_REG SCIRXBUF; в одной области памяти. */ + union SCIRXBUF_REG SCIRXBUF; // Recieve data buffer + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объявляет SCITXBUF — данные SCITXBUF. */ + Uint16 SCITXBUF; // Transmit data buffer + /* Объединяет несколько представлений SCIFFTX_REG SCIFFTX; в одной области памяти. */ + union SCIFFTX_REG SCIFFTX; // FIFO transmit register + /* Объединяет несколько представлений SCIFFRX_REG SCIFFRX; в одной области памяти. */ + union SCIFFRX_REG SCIFFRX; // FIFO recieve register + /* Объединяет несколько представлений SCIFFCT_REG SCIFFCT; в одной области памяти. */ + union SCIFFCT_REG SCIFFCT; // FIFO control register + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // reserved + /* Объединяет несколько представлений SCIPRI_REG SCIPRI; в одной области памяти. */ + union SCIPRI_REG SCIPRI; // FIFO Priority control +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SCI External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct SCI_REGS SciaRegs;; порядок элементов сохраняется. */ +extern volatile struct SCI_REGS SciaRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct SCI_REGS ScibRegs;; порядок элементов сохраняется. */ +extern volatile struct SCI_REGS ScibRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct SCI_REGS ScicRegs;; порядок элементов сохраняется. */ +extern volatile struct SCI_REGS ScicRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_SCI_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h new file mode 100644 index 0000000..cdce516 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h @@ -0,0 +1,292 @@ +/* Поставляемое TI описание Spi для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: April 17, 2008 11:08:27 $ +//########################################################################### +// +// FILE: DSP2833x_Spi.h +// +// TITLE: DSP2833x Device SPI Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SPI_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SPI_H +/* Определяет защитный символ или переключатель DSP2833x_SPI_H для последующей компиляции. */ +#define DSP2833x_SPI_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// SPI Individual Register Bit Definitions: +// +// SPI FIFO Transmit register bit definitions: +/* Описывает структуру SPIFFTX_BITS; порядок полей определяет расположение данных. */ +struct SPIFFTX_BITS { // bit description + /* Битовое поле TXFFIL, ширина 5 бит; данные TXFFIL. */ + Uint16 TXFFIL:5; // 4:0 Interrupt level + /* Битовое поле TXFFIENA, ширина 1 бит; данные TXFFIENA. */ + Uint16 TXFFIENA:1; // 5 Interrupt enable + /* Битовое поле TXFFINTCLR, ширина 1 бит; данные TXFFINTCLR. */ + Uint16 TXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле TXFFINT, ширина 1 бит; данные TXFFINT. */ + Uint16 TXFFINT:1; // 7 INT flag + /* Битовое поле TXFFST, ширина 5 бит; данные TXFFST. */ + Uint16 TXFFST:5; // 12:8 FIFO status + /* Битовое поле TXFIFO, ширина 1 бит; данные TXFIFO. */ + Uint16 TXFIFO:1; // 13 FIFO reset + /* Битовое поле SPIFFENA, ширина 1 бит; данные SPIFFENA. */ + Uint16 SPIFFENA:1; // 14 Enhancement enable + /* Битовое поле SPIRST, ширина 1 бит; данные SPIRST. */ + Uint16 SPIRST:1; // 15 Reset SPI +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIFFTX_REG в одной области памяти. */ +union SPIFFTX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIFFTX_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIFFTX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------------- +// SPI FIFO recieve register bit definitions: +// +// +/* Описывает структуру SPIFFRX_BITS; порядок полей определяет расположение данных. */ +struct SPIFFRX_BITS { // bits description + /* Битовое поле RXFFIL, ширина 5 бит; данные RXFFIL. */ + Uint16 RXFFIL:5; // 4:0 Interrupt level + /* Битовое поле RXFFIENA, ширина 1 бит; данные RXFFIENA. */ + Uint16 RXFFIENA:1; // 5 Interrupt enable + /* Битовое поле RXFFINTCLR, ширина 1 бит; данные RXFFINTCLR. */ + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле RXFFINT, ширина 1 бит; данные RXFFINT. */ + Uint16 RXFFINT:1; // 7 INT flag + /* Битовое поле RXFFST, ширина 5 бит; данные RXFFST. */ + Uint16 RXFFST:5; // 12:8 FIFO status + /* Битовое поле RXFIFORESET, ширина 1 бит; данные RXFIFORESET. */ + Uint16 RXFIFORESET:1; // 13 FIFO reset + /* Битовое поле RXFFOVFCLR, ширина 1 бит; данные RXFFOVFCLR. */ + Uint16 RXFFOVFCLR:1; // 14 Clear overflow + /* Битовое поле RXFFOVF, ширина 1 бит; данные RXFFOVF. */ + Uint16 RXFFOVF:1; // 15 FIFO overflow + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIFFRX_REG в одной области памяти. */ +union SPIFFRX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIFFRX_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIFFRX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------------- +// SPI FIFO control register bit definitions: +// +// +/* Описывает структуру SPIFFCT_BITS; порядок полей определяет расположение данных. */ +struct SPIFFCT_BITS { // bits description + /* Битовое поле TXDLY, ширина 8 бит; данные TXDLY. */ + Uint16 TXDLY:8; // 7:0 FIFO transmit delay + /* Битовое поле rsvd, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIFFCT_REG в одной области памяти. */ +union SPIFFCT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIFFCT_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIFFCT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------- +// SPI configuration register bit definitions: +// +// +/* Описывает структуру SPICCR_BITS; порядок полей определяет расположение данных. */ +struct SPICCR_BITS { // bits description + /* Битовое поле SPICHAR, ширина 4 бит; данные SPICHAR. */ + Uint16 SPICHAR:4; // 3:0 Character length control + /* Битовое поле SPILBK, ширина 1 бит; данные SPILBK. */ + Uint16 SPILBK:1; // 4 Loop-back enable/disable + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 5 reserved + /* Битовое поле CLKPOLARITY, ширина 1 бит; данные CLKPOLARITY. */ + Uint16 CLKPOLARITY:1; // 6 Clock polarity + /* Битовое поле SPISWRESET, ширина 1 бит; данные SPISWRESET. */ + Uint16 SPISWRESET:1; // 7 SPI SW Reset + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPICCR_REG в одной области памяти. */ +union SPICCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPICCR_BITS bit;; порядок полей определяет расположение данных. */ + struct SPICCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------- +// SPI operation control register bit definitions: +// +// +/* Описывает структуру SPICTL_BITS; порядок полей определяет расположение данных. */ +struct SPICTL_BITS { // bits description + /* Битовое поле SPIINTENA, ширина 1 бит; данные SPIINTENA. */ + Uint16 SPIINTENA:1; // 0 Interrupt enable + /* Битовое поле TALK, ширина 1 бит; данные TALK. */ + Uint16 TALK:1; // 1 Master/Slave transmit enable + /* Битовое поле MASTER_SLAVE, ширина 1 бит; данные MASTER_SLAVE. */ + Uint16 MASTER_SLAVE:1; // 2 Network control mode + /* Битовое поле CLK_PHASE, ширина 1 бит; CLK фаза. */ + Uint16 CLK_PHASE:1; // 3 Clock phase select + /* Битовое поле OVERRUNINTENA, ширина 1 бит; данные OVERRUNINTENA. */ + Uint16 OVERRUNINTENA:1; // 4 Overrun interrupt enable + /* Битовое поле rsvd, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPICTL_REG в одной области памяти. */ +union SPICTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPICTL_BITS bit;; порядок полей определяет расположение данных. */ + struct SPICTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------- +// SPI status register bit definitions: +// +// +/* Описывает структуру SPISTS_BITS; порядок полей определяет расположение данных. */ +struct SPISTS_BITS { // bits description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле BUFFULL_FLAG, ширина 1 бит; BUFFULL флаг. */ + Uint16 BUFFULL_FLAG:1; // 5 SPI transmit buffer full flag + /* Битовое поле INT_FLAG, ширина 1 бит; INT флаг. */ + Uint16 INT_FLAG:1; // 6 SPI interrupt flag + /* Битовое поле OVERRUN_FLAG, ширина 1 бит; OVERRUN флаг. */ + Uint16 OVERRUN_FLAG:1; // 7 SPI reciever overrun flag + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPISTS_REG в одной области памяти. */ +union SPISTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPISTS_BITS bit;; порядок полей определяет расположение данных. */ + struct SPISTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------ +// SPI priority control register bit definitions: +// +// +/* Описывает структуру SPIPRI_BITS; порядок полей определяет расположение данных. */ +struct SPIPRI_BITS { // bits description + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 3:0 reserved + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 4 Free emulation mode control + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 5 Soft emulation mode control + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 6 reserved + /* Битовое поле rsvd3, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:9; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIPRI_REG в одной области памяти. */ +union SPIPRI_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIPRI_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIPRI_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SPI Register File: +// +/* Описывает структуру SPI_REGS; порядок полей определяет расположение данных. */ +struct SPI_REGS { + /* Объединяет несколько представлений SPICCR_REG SPICCR; в одной области памяти. */ + union SPICCR_REG SPICCR; // Configuration register + /* Объединяет несколько представлений SPICTL_REG SPICTL; в одной области памяти. */ + union SPICTL_REG SPICTL; // Operation control register + /* Объединяет несколько представлений SPISTS_REG SPISTS; в одной области памяти. */ + union SPISTS_REG SPISTS; // Status register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объявляет SPIBRR — данные SPIBRR. */ + Uint16 SPIBRR; // Baud Rate + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved + /* Объявляет SPIRXEMU — данные SPIRXEMU. */ + Uint16 SPIRXEMU; // Emulation buffer + /* Объявляет SPIRXBUF — данные SPIRXBUF. */ + Uint16 SPIRXBUF; // Serial input buffer + /* Объявляет SPITXBUF — данные SPITXBUF. */ + Uint16 SPITXBUF; // Serial output buffer + /* Объявляет SPIDAT — данные SPIDAT. */ + Uint16 SPIDAT; // Serial data + /* Объединяет несколько представлений SPIFFTX_REG SPIFFTX; в одной области памяти. */ + union SPIFFTX_REG SPIFFTX; // FIFO transmit register + /* Объединяет несколько представлений SPIFFRX_REG SPIFFRX; в одной области памяти. */ + union SPIFFRX_REG SPIFFRX; // FIFO recieve register + /* Объединяет несколько представлений SPIFFCT_REG SPIFFCT; в одной области памяти. */ + union SPIFFCT_REG SPIFFCT; // FIFO control register + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3[2]; // reserved + /* Объединяет несколько представлений SPIPRI_REG SPIPRI; в одной области памяти. */ + union SPIPRI_REG SPIPRI; // FIFO Priority control +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SPI External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct SPI_REGS SpiaRegs;; порядок элементов сохраняется. */ +extern volatile struct SPI_REGS SpiaRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_SPI_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h new file mode 100644 index 0000000..0ab964e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h @@ -0,0 +1,642 @@ +/* Поставляемое TI описание SysCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/5 $ +// Checkin $Date: May 12, 2008 09:34:58 $ +//########################################################################### +// +// FILE: DSP2833x_SysCtrl.h +// +// TITLE: DSP2833x Device System Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SYS_CTRL_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SYS_CTRL_H +/* Определяет защитный символ или переключатель DSP2833x_SYS_CTRL_H для последующей компиляции. */ +#define DSP2833x_SYS_CTRL_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// System Control Individual Register Bit Definitions: +// + + +// PLL Status Register +/* Описывает структуру PLLSTS_BITS; порядок полей определяет расположение данных. */ +struct PLLSTS_BITS { // bits description + /* Битовое поле PLLLOCKS, ширина 1 бит; данные PLLLOCKS. */ + Uint16 PLLLOCKS:1; // 0 PLL lock status + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле PLLOFF, ширина 1 бит; данные PLLOFF. */ + Uint16 PLLOFF:1; // 2 PLL off bit + /* Битовое поле MCLKSTS, ширина 1 бит; данные MCLKSTS. */ + Uint16 MCLKSTS:1; // 3 Missing clock status bit + /* Битовое поле MCLKCLR, ширина 1 бит; данные MCLKCLR. */ + Uint16 MCLKCLR:1; // 4 Missing clock clear bit + /* Битовое поле OSCOFF, ширина 1 бит; данные OSCOFF. */ + Uint16 OSCOFF:1; // 5 Oscillator clock off + /* Битовое поле MCLKOFF, ширина 1 бит; данные MCLKOFF. */ + Uint16 MCLKOFF:1; // 6 Missing clock detect + /* Битовое поле DIVSEL, ширина 2 бит; данные DIVSEL. */ + Uint16 DIVSEL:2; // 7 Divide Select + /* Битовое поле rsvd2, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:7; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PLLSTS_REG в одной области памяти. */ +union PLLSTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PLLSTS_BITS bit;; порядок полей определяет расположение данных. */ + struct PLLSTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// High speed peripheral clock register bit definitions: +/* Описывает структуру HISPCP_BITS; порядок полей определяет расположение данных. */ +struct HISPCP_BITS { // bits description + /* Битовое поле HSPCLK, ширина 3 бит; данные HSPCLK. */ + Uint16 HSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений HISPCP_REG в одной области памяти. */ +union HISPCP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру HISPCP_BITS bit;; порядок полей определяет расположение данных. */ + struct HISPCP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Low speed peripheral clock register bit definitions: +/* Описывает структуру LOSPCP_BITS; порядок полей определяет расположение данных. */ +struct LOSPCP_BITS { // bits description + /* Битовое поле LSPCLK, ширина 3 бит; данные LSPCLK. */ + Uint16 LSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений LOSPCP_REG в одной области памяти. */ +union LOSPCP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру LOSPCP_BITS bit;; порядок полей определяет расположение данных. */ + struct LOSPCP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Peripheral clock control register 0 bit definitions: +/* Описывает структуру PCLKCR0_BITS; порядок полей определяет расположение данных. */ +struct PCLKCR0_BITS { // bits description + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 1:0 reserved + /* Битовое поле TBCLKSYNC, ширина 1 бит; данные TBCLKSYNC. */ + Uint16 TBCLKSYNC:1; // 2 EWPM Module TBCLK enable/sync + /* Битовое поле ADCENCLK, ширина 1 бит; данные ADCENCLK. */ + Uint16 ADCENCLK:1; // 3 Enable high speed clk to ADC + /* Битовое поле I2CAENCLK, ширина 1 бит; данные I2CAENCLK. */ + Uint16 I2CAENCLK:1; // 4 Enable SYSCLKOUT to I2C-A + /* Битовое поле SCICENCLK, ширина 1 бит; данные SCICENCLK. */ + Uint16 SCICENCLK:1; // 5 Enalbe low speed clk to SCI-C + /* Битовое поле rsvd2, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:2; // 7:6 reserved + /* Битовое поле SPIAENCLK, ширина 1 бит; данные SPIAENCLK. */ + Uint16 SPIAENCLK:1; // 8 Enable low speed clk to SPI-A + /* Битовое поле rsvd3, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:1; // 9 reserved + /* Битовое поле SCIAENCLK, ширина 1 бит; данные SCIAENCLK. */ + Uint16 SCIAENCLK:1; // 10 Enable low speed clk to SCI-A + /* Битовое поле SCIBENCLK, ширина 1 бит; данные SCIBENCLK. */ + Uint16 SCIBENCLK:1; // 11 Enable low speed clk to SCI-B + /* Битовое поле MCBSPAENCLK, ширина 1 бит; данные MCBSPAENCLK. */ + Uint16 MCBSPAENCLK:1; // 12 Enable low speed clk to McBSP-A + /* Битовое поле MCBSPBENCLK, ширина 1 бит; данные MCBSPBENCLK. */ + Uint16 MCBSPBENCLK:1; // 13 Enable low speed clk to McBSP-B + /* Битовое поле ECANAENCLK, ширина 1 бит; данные ECANAENCLK. */ + Uint16 ECANAENCLK:1; // 14 Enable system clk to eCAN-A + /* Битовое поле ECANBENCLK, ширина 1 бит; данные ECANBENCLK. */ + Uint16 ECANBENCLK:1; // 15 Enable system clk to eCAN-B +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCLKCR0_REG в одной области памяти. */ +union PCLKCR0_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCLKCR0_BITS bit;; порядок полей определяет расположение данных. */ + struct PCLKCR0_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Peripheral clock control register 1 bit definitions: +/* Описывает структуру PCLKCR1_BITS; порядок полей определяет расположение данных. */ +struct PCLKCR1_BITS { // bits description + /* Битовое поле EPWM1ENCLK, ширина 1 бит; данные EPWM1ENCLK. */ + Uint16 EPWM1ENCLK:1; // 0 Enable SYSCLKOUT to EPWM1 + /* Битовое поле EPWM2ENCLK, ширина 1 бит; данные EPWM2ENCLK. */ + Uint16 EPWM2ENCLK:1; // 1 Enable SYSCLKOUT to EPWM2 + /* Битовое поле EPWM3ENCLK, ширина 1 бит; данные EPWM3ENCLK. */ + Uint16 EPWM3ENCLK:1; // 2 Enable SYSCLKOUT to EPWM3 + /* Битовое поле EPWM4ENCLK, ширина 1 бит; данные EPWM4ENCLK. */ + Uint16 EPWM4ENCLK:1; // 3 Enable SYSCLKOUT to EPWM4 + /* Битовое поле EPWM5ENCLK, ширина 1 бит; данные EPWM5ENCLK. */ + Uint16 EPWM5ENCLK:1; // 4 Enable SYSCLKOUT to EPWM5 + /* Битовое поле EPWM6ENCLK, ширина 1 бит; данные EPWM6ENCLK. */ + Uint16 EPWM6ENCLK:1; // 5 Enable SYSCLKOUT to EPWM6 + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 7:6 reserved + /* Битовое поле ECAP1ENCLK, ширина 1 бит; данные ECAP1ENCLK. */ + Uint16 ECAP1ENCLK:1; // 8 Enable SYSCLKOUT to ECAP1 + /* Битовое поле ECAP2ENCLK, ширина 1 бит; данные ECAP2ENCLK. */ + Uint16 ECAP2ENCLK:1; // 9 Enable SYSCLKOUT to ECAP2 + /* Битовое поле ECAP3ENCLK, ширина 1 бит; данные ECAP3ENCLK. */ + Uint16 ECAP3ENCLK:1; // 10 Enable SYSCLKOUT to ECAP3 + /* Битовое поле ECAP4ENCLK, ширина 1 бит; данные ECAP4ENCLK. */ + Uint16 ECAP4ENCLK:1; // 11 Enable SYSCLKOUT to ECAP4 + /* Битовое поле ECAP5ENCLK, ширина 1 бит; данные ECAP5ENCLK. */ + Uint16 ECAP5ENCLK:1; // 12 Enable SYSCLKOUT to ECAP5 + /* Битовое поле ECAP6ENCLK, ширина 1 бит; данные ECAP6ENCLK. */ + Uint16 ECAP6ENCLK:1; // 13 Enable SYSCLKOUT to ECAP6 + /* Битовое поле EQEP1ENCLK, ширина 1 бит; данные EQEP1ENCLK. */ + Uint16 EQEP1ENCLK:1; // 14 Enable SYSCLKOUT to EQEP1 + /* Битовое поле EQEP2ENCLK, ширина 1 бит; данные EQEP2ENCLK. */ + Uint16 EQEP2ENCLK:1; // 15 Enable SYSCLKOUT to EQEP2 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCLKCR1_REG в одной области памяти. */ +union PCLKCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCLKCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct PCLKCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// Peripheral clock control register 2 bit definitions: +/* Описывает структуру PCLKCR3_BITS; порядок полей определяет расположение данных. */ +struct PCLKCR3_BITS { // bits description + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 7:0 reserved + /* Битовое поле CPUTIMER0ENCLK, ширина 1 бит; данные CPUTIMER0ENCLK. */ + Uint16 CPUTIMER0ENCLK:1; // 8 Enable SYSCLKOUT to CPU-Timer 0 + /* Битовое поле CPUTIMER1ENCLK, ширина 1 бит; данные CPUTIMER1ENCLK. */ + Uint16 CPUTIMER1ENCLK:1; // 9 Enable SYSCLKOUT to CPU-Timer 1 + /* Битовое поле CPUTIMER2ENCLK, ширина 1 бит; данные CPUTIMER2ENCLK. */ + Uint16 CPUTIMER2ENCLK:1; // 10 Enable SYSCLKOUT to CPU-Timer 2 + /* Битовое поле DMAENCLK, ширина 1 бит; данные DMAENCLK. */ + Uint16 DMAENCLK:1; // 11 Enable the DMA clock + /* Битовое поле XINTFENCLK, ширина 1 бит; данные XINTFENCLK. */ + Uint16 XINTFENCLK:1; // 12 Enable SYSCLKOUT to XINTF + /* Битовое поле GPIOINENCLK, ширина 1 бит; аппаратная линия ввода/вывода GPIOINENCLK. */ + Uint16 GPIOINENCLK:1; // Enable GPIO input clock + /* Битовое поле rsvd2, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:2; // 15:14 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCLKCR3_REG в одной области памяти. */ +union PCLKCR3_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCLKCR3_BITS bit;; порядок полей определяет расположение данных. */ + struct PCLKCR3_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +// PLL control register bit definitions: +/* Описывает структуру PLLCR_BITS; порядок полей определяет расположение данных. */ +struct PLLCR_BITS { // bits description + /* Битовое поле DIV, ширина 4 бит; данные DIV. */ + Uint16 DIV:4; // 3:0 Set clock ratio for the PLL + /* Битовое поле rsvd1, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PLLCR_REG в одной области памяти. */ +union PLLCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PLLCR_BITS bit;; порядок полей определяет расположение данных. */ + struct PLLCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Low Power Mode 0 control register bit definitions: +/* Описывает структуру LPMCR0_BITS; порядок полей определяет расположение данных. */ +struct LPMCR0_BITS { // bits description + /* Битовое поле LPM, ширина 2 бит; данные LPM. */ + Uint16 LPM:2; // 1:0 Set the low power mode + /* Битовое поле QUALSTDBY, ширина 6 бит; данные QUALSTDBY. */ + Uint16 QUALSTDBY:6; // 7:2 Qualification + /* Битовое поле rsvd1, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:7; // 14:8 reserved + /* Битовое поле WDINTE, ширина 1 бит; данные WDINTE. */ + Uint16 WDINTE:1; // 15 Enables WD to wake the device from STANDBY +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений LPMCR0_REG в одной области памяти. */ +union LPMCR0_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру LPMCR0_BITS bit;; порядок полей определяет расположение данных. */ + struct LPMCR0_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Dual-mapping configuration register bit definitions: +/* Описывает структуру MAPCNF_BITS; порядок полей определяет расположение данных. */ +struct MAPCNF_BITS { // bits description + /* Битовое поле MAPEPWM, ширина 1 бит; данные MAPEPWM. */ + Uint16 MAPEPWM:1; // 0 EPWM dual-map enable + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; // 15:1 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MAPCNF_REG в одной области памяти. */ +union MAPCNF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MAPCNF_BITS bit;; порядок полей определяет расположение данных. */ + struct MAPCNF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// System Control Register File: +// +/* Описывает структуру SYS_CTRL_REGS; порядок полей определяет расположение данных. */ +struct SYS_CTRL_REGS { + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // 0 + /* Объединяет несколько представлений PLLSTS_REG PLLSTS; в одной области памяти. */ + union PLLSTS_REG PLLSTS; // 1 + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[8]; // 2-9 + /* Объединяет несколько представлений HISPCP_REG HISPCP; в одной области памяти. */ + union HISPCP_REG HISPCP; // 10: High-speed peripheral clock pre-scaler + /* Объединяет несколько представлений LOSPCP_REG LOSPCP; в одной области памяти. */ + union LOSPCP_REG LOSPCP; // 11: Low-speed peripheral clock pre-scaler + /* Объединяет несколько представлений PCLKCR0_REG PCLKCR0; в одной области памяти. */ + union PCLKCR0_REG PCLKCR0; // 12: Peripheral clock control register + /* Объединяет несколько представлений PCLKCR1_REG PCLKCR1; в одной области памяти. */ + union PCLKCR1_REG PCLKCR1; // 13: Peripheral clock control register + /* Объединяет несколько представлений LPMCR0_REG LPMCR0; в одной области памяти. */ + union LPMCR0_REG LPMCR0; // 14: Low-power mode control register 0 + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // 15: reserved + /* Объединяет несколько представлений PCLKCR3_REG PCLKCR3; в одной области памяти. */ + union PCLKCR3_REG PCLKCR3; // 16: Peripheral clock control register + /* Объединяет несколько представлений PLLCR_REG PLLCR; в одной области памяти. */ + union PLLCR_REG PLLCR; // 17: PLL control register + // No bit definitions are defined for SCSR because + // a read-modify-write instruction can clear the WDOVERRIDE bit + /* Объявляет SCSR — данные SCSR. */ + Uint16 SCSR; // 18: System control and status register + /* Объявляет WDCNTR — данные WDCNTR. */ + Uint16 WDCNTR; // 19: WD counter register + /* Объявляет rsvd4 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4; // 20 + /* Объявляет WDKEY — данные WDKEY. */ + Uint16 WDKEY; // 21: WD reset key register + /* Объявляет rsvd5 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5[3]; // 22-24 + // No bit definitions are defined for WDCR because + // the proper value must be written to the WDCHK field + // whenever writing to this register. + /* Объявляет WDCR — данные WDCR. */ + Uint16 WDCR; // 25: WD timer control register + /* Объявляет rsvd6 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd6[4]; // 26-29 + /* Объединяет несколько представлений MAPCNF_REG MAPCNF; в одной области памяти. */ + union MAPCNF_REG MAPCNF; // 30: Dual-mapping configuration register + /* Объявляет rsvd7 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd7[1]; // 31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* --------------------------------------------------- */ +/* CSM Registers */ +/* */ +/* ----------------------------------------------------*/ + +/* CSM Status & Control register bit definitions */ +/* Описывает структуру CSMSCR_BITS; порядок полей определяет расположение данных. */ +struct CSMSCR_BITS { // bit description + /* Битовое поле SECURE, ширина 1 бит; данные SECURE. */ + Uint16 SECURE:1; // 0 Secure flag + /* Битовое поле rsvd1, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:14; // 14-1 reserved + /* Битовое поле FORCESEC, ширина 1 бит; данные FORCESEC. */ + Uint16 FORCESEC:1; // 15 Force Secure control bit + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CSMSCR_REG в одной области памяти. */ +union CSMSCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CSMSCR_BITS bit;; порядок полей определяет расположение данных. */ + struct CSMSCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* CSM Register File */ +/* Описывает структуру CSM_REGS; порядок полей определяет расположение данных. */ +struct CSM_REGS { + /* Объявляет KEY0 — данные KEY0. */ + Uint16 KEY0; // KEY reg bits 15-0 + /* Объявляет KEY1 — данные KEY1. */ + Uint16 KEY1; // KEY reg bits 31-16 + /* Объявляет KEY2 — данные KEY2. */ + Uint16 KEY2; // KEY reg bits 47-32 + /* Объявляет KEY3 — данные KEY3. */ + Uint16 KEY3; // KEY reg bits 63-48 + /* Объявляет KEY4 — данные KEY4. */ + Uint16 KEY4; // KEY reg bits 79-64 + /* Объявляет KEY5 — данные KEY5. */ + Uint16 KEY5; // KEY reg bits 95-80 + /* Объявляет KEY6 — данные KEY6. */ + Uint16 KEY6; // KEY reg bits 111-96 + /* Объявляет KEY7 — данные KEY7. */ + Uint16 KEY7; // KEY reg bits 127-112 + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // reserved + /* Объявляет rsvd4 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4; // reserved + /* Объявляет rsvd5 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5; // reserved + /* Объявляет rsvd6 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd6; // reserved + /* Объявляет rsvd7 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd7; // reserved + /* Объединяет несколько представлений CSMSCR_REG CSMSCR; в одной области памяти. */ + union CSMSCR_REG CSMSCR; // CSM Status & Control register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Password locations */ +/* Описывает структуру CSM_PWL; порядок полей определяет расположение данных. */ +struct CSM_PWL { + /* Объявляет PSWD0 — данные PSWD0. */ + Uint16 PSWD0; // PSWD bits 15-0 + /* Объявляет PSWD1 — данные PSWD1. */ + Uint16 PSWD1; // PSWD bits 31-16 + /* Объявляет PSWD2 — данные PSWD2. */ + Uint16 PSWD2; // PSWD bits 47-32 + /* Объявляет PSWD3 — данные PSWD3. */ + Uint16 PSWD3; // PSWD bits 63-48 + /* Объявляет PSWD4 — данные PSWD4. */ + Uint16 PSWD4; // PSWD bits 79-64 + /* Объявляет PSWD5 — данные PSWD5. */ + Uint16 PSWD5; // PSWD bits 95-80 + /* Объявляет PSWD6 — данные PSWD6. */ + Uint16 PSWD6; // PSWD bits 111-96 + /* Объявляет PSWD7 — данные PSWD7. */ + Uint16 PSWD7; // PSWD bits 127-112 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +/* Flash Registers */ + +/* Задаёт FLASH_SLEEP = 0x0000;; данные FLASH_SLEEP. */ +#define FLASH_SLEEP 0x0000; +/* Задаёт FLASH_STANDBY = 0x0001;; данные FLASH_STANDBY. */ +#define FLASH_STANDBY 0x0001; +/* Задаёт FLASH_ACTIVE = 0x0003;; данные FLASH_ACTIVE. */ +#define FLASH_ACTIVE 0x0003; + + +/* Flash Option Register bit definitions */ +/* Описывает структуру FOPT_BITS; порядок полей определяет расположение данных. */ +struct FOPT_BITS { // bit description + /* Битовое поле ENPIPE, ширина 1 бит; данные ENPIPE. */ + Uint16 ENPIPE:1; // 0 Enable Pipeline Mode + /* Битовое поле rsvd, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:15; // 1-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FOPT_REG в одной области памяти. */ +union FOPT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FOPT_BITS bit;; порядок полей определяет расположение данных. */ + struct FOPT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Flash Power Modes Register bit definitions */ +/* Описывает структуру FPWR_BITS; порядок полей определяет расположение данных. */ +struct FPWR_BITS { // bit description + /* Битовое поле PWR, ширина 2 бит; данные PWR. */ + Uint16 PWR:2; // 0-1 Power Mode bits + /* Битовое поле rsvd, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:14; // 2-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FPWR_REG в одной области памяти. */ +union FPWR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FPWR_BITS bit;; порядок полей определяет расположение данных. */ + struct FPWR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Flash Status Register bit definitions */ +/* Описывает структуру FSTATUS_BITS; порядок полей определяет расположение данных. */ +struct FSTATUS_BITS { // bit description + /* Битовое поле PWRS, ширина 2 бит; данные PWRS. */ + Uint16 PWRS:2; // 0-1 Power Mode Status bits + /* Битовое поле STDBYWAITS, ширина 1 бит; данные STDBYWAITS. */ + Uint16 STDBYWAITS:1; // 2 Bank/Pump Sleep to Standby Wait Counter Status bits + /* Битовое поле ACTIVEWAITS, ширина 1 бит; данные ACTIVEWAITS. */ + Uint16 ACTIVEWAITS:1; // 3 Bank/Pump Standby to Active Wait Counter Status bits + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 4-7 reserved + /* Битовое поле V3STAT, ширина 1 бит; данные V3STAT. */ + Uint16 V3STAT:1; // 8 VDD3V Status Latch bit + /* Битовое поле rsvd2, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:7; // 9-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FSTATUS_REG в одной области памяти. */ +union FSTATUS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FSTATUS_BITS bit;; порядок полей определяет расположение данных. */ + struct FSTATUS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Flash Sleep to Standby Wait Counter Register bit definitions */ +/* Описывает структуру FSTDBYWAIT_BITS; порядок полей определяет расположение данных. */ +struct FSTDBYWAIT_BITS { // bit description + /* Битовое поле STDBYWAIT, ширина 9 бит; данные STDBYWAIT. */ + Uint16 STDBYWAIT:9; // 0-8 Bank/Pump Sleep to Standby Wait Count bits + /* Битовое поле rsvd, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:7; // 9-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FSTDBYWAIT_REG в одной области памяти. */ +union FSTDBYWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FSTDBYWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FSTDBYWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Flash Standby to Active Wait Counter Register bit definitions */ +/* Описывает структуру FACTIVEWAIT_BITS; порядок полей определяет расположение данных. */ +struct FACTIVEWAIT_BITS { // bit description + /* Битовое поле ACTIVEWAIT, ширина 9 бит; данные ACTIVEWAIT. */ + Uint16 ACTIVEWAIT:9; // 0-8 Bank/Pump Standby to Active Wait Count bits + /* Битовое поле rsvd, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:7; // 9-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FACTIVEWAIT_REG в одной области памяти. */ +union FACTIVEWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FACTIVEWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FACTIVEWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Bank Read Access Wait State Register bit definitions */ +/* Описывает структуру FBANKWAIT_BITS; порядок полей определяет расположение данных. */ +struct FBANKWAIT_BITS { // bit description + /* Битовое поле RANDWAIT, ширина 4 бит; данные RANDWAIT. */ + Uint16 RANDWAIT:4; // 0-3 Flash Random Read Wait State bits + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 4-7 reserved + /* Битовое поле PAGEWAIT, ширина 4 бит; данные PAGEWAIT. */ + Uint16 PAGEWAIT:4; // 8-11 Flash Paged Read Wait State bits + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 12-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FBANKWAIT_REG в одной области памяти. */ +union FBANKWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FBANKWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FBANKWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* OTP Read Access Wait State Register bit definitions */ +/* Описывает структуру FOTPWAIT_BITS; порядок полей определяет расположение данных. */ +struct FOTPWAIT_BITS { // bit description + /* Битовое поле OTPWAIT, ширина 5 бит; данные OTPWAIT. */ + Uint16 OTPWAIT:5; // 0-4 OTP Read Wait State bits + /* Битовое поле rsvd, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:11; // 5-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FOTPWAIT_REG в одной области памяти. */ +union FOTPWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FOTPWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FOTPWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру FLASH_REGS; порядок полей определяет расположение данных. */ +struct FLASH_REGS { + /* Объединяет несколько представлений FOPT_REG FOPT; в одной области памяти. */ + union FOPT_REG FOPT; // Option Register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объединяет несколько представлений FPWR_REG FPWR; в одной области памяти. */ + union FPWR_REG FPWR; // Power Modes Register + /* Объединяет несколько представлений FSTATUS_REG FSTATUS; в одной области памяти. */ + union FSTATUS_REG FSTATUS; // Status Register + /* Объединяет несколько представлений FSTDBYWAIT_REG FSTDBYWAIT; в одной области памяти. */ + union FSTDBYWAIT_REG FSTDBYWAIT; // Pump/Bank Sleep to Standby Wait State Register + /* Объединяет несколько представлений FACTIVEWAIT_REG FACTIVEWAIT; в одной области памяти. */ + union FACTIVEWAIT_REG FACTIVEWAIT; // Pump/Bank Standby to Active Wait State Register + /* Объединяет несколько представлений FBANKWAIT_REG FBANKWAIT; в одной области памяти. */ + union FBANKWAIT_REG FBANKWAIT; // Bank Read Access Wait State Register + /* Объединяет несколько представлений FOTPWAIT_REG FOTPWAIT; в одной области памяти. */ + union FOTPWAIT_REG FOTPWAIT; // OTP Read Access Wait State Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// System Control External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct SYS_CTRL_REGS SysCtrlRegs;; порядок элементов сохраняется. */ +extern volatile struct SYS_CTRL_REGS SysCtrlRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct CSM_REGS CsmRegs;; порядок элементов сохраняется. */ +extern volatile struct CSM_REGS CsmRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct CSM_PWL CsmPwl;; порядок элементов сохраняется. */ +extern volatile struct CSM_PWL CsmPwl; +/* Продолжает список аргументов, полей или выражение extern volatile struct FLASH_REGS FlashRegs;; порядок элементов сохраняется. */ +extern volatile struct FLASH_REGS FlashRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_SYS_CTRL_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h new file mode 100644 index 0000000..91eca18 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h @@ -0,0 +1,127 @@ +/* Поставляемое TI описание XIntrupt для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:39 $ +//########################################################################### +// +// FILE: DSP2833x_XIntrupt.h +// +// TITLE: DSP2833x Device External Interrupt Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_XINTRUPT_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_XINTRUPT_H +/* Определяет защитный символ или переключатель DSP2833x_XINTRUPT_H для последующей компиляции. */ +#define DSP2833x_XINTRUPT_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- + +/* Описывает структуру XINTCR_BITS; порядок полей определяет расположение данных. */ +struct XINTCR_BITS { + /* Битовое поле ENABLE, ширина 1 бит; разрешение. */ + Uint16 ENABLE:1; // 0 enable/disable + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле POLARITY, ширина 2 бит; данные POLARITY. */ + Uint16 POLARITY:2; // 3:2 pos/neg, both triggered + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; //15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XINTCR_REG в одной области памяти. */ +union XINTCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XINTCR_BITS bit;; порядок полей определяет расположение данных. */ + struct XINTCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру XNMICR_BITS; порядок полей определяет расположение данных. */ +struct XNMICR_BITS { + /* Битовое поле ENABLE, ширина 1 бит; разрешение. */ + Uint16 ENABLE:1; // 0 enable/disable + /* Битовое поле SELECT, ширина 1 бит; выбор. */ + Uint16 SELECT:1; // 1 Timer 1 or XNMI connected to int13 + /* Битовое поле POLARITY, ширина 2 бит; данные POLARITY. */ + Uint16 POLARITY:2; // 3:2 pos/neg, or both triggered + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XNMICR_REG в одной области памяти. */ +union XNMICR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XNMICR_BITS bit;; порядок полей определяет расположение данных. */ + struct XNMICR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// External Interrupt Register File: +// +/* Описывает структуру XINTRUPT_REGS; порядок полей определяет расположение данных. */ +struct XINTRUPT_REGS { + /* Объединяет несколько представлений XINTCR_REG XINT1CR; в одной области памяти. */ + union XINTCR_REG XINT1CR; + /* Объединяет несколько представлений XINTCR_REG XINT2CR; в одной области памяти. */ + union XINTCR_REG XINT2CR; + /* Объединяет несколько представлений XINTCR_REG XINT3CR; в одной области памяти. */ + union XINTCR_REG XINT3CR; + /* Объединяет несколько представлений XINTCR_REG XINT4CR; в одной области памяти. */ + union XINTCR_REG XINT4CR; + /* Объединяет несколько представлений XINTCR_REG XINT5CR; в одной области памяти. */ + union XINTCR_REG XINT5CR; + /* Объединяет несколько представлений XINTCR_REG XINT6CR; в одной области памяти. */ + union XINTCR_REG XINT6CR; + /* Объединяет несколько представлений XINTCR_REG XINT7CR; в одной области памяти. */ + union XINTCR_REG XINT7CR; + /* Объединяет несколько представлений XNMICR_REG XNMICR; в одной области памяти. */ + union XNMICR_REG XNMICR; + /* Объявляет XINT1CTR — данные XINT1CTR. */ + Uint16 XINT1CTR; + /* Объявляет XINT2CTR — данные XINT2CTR. */ + Uint16 XINT2CTR; + /* Объявляет rsvd — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd[5]; + /* Объявляет XNMICTR — данные XNMICTR. */ + Uint16 XNMICTR; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// External Interrupt References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct XINTRUPT_REGS XIntruptRegs;; порядок элементов сохраняется. */ +extern volatile struct XINTRUPT_REGS XIntruptRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_XINTF_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h new file mode 100644 index 0000000..63686b1 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h @@ -0,0 +1,197 @@ +/* Поставляемое TI описание Xintf для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 20, 2007 16:34:08 $ +//########################################################################### +// +// FILE: DSP2833x_Xintf.h +// +// TITLE: DSP2833x Device External Interface Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_XINTF_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_XINTF_H +/* Определяет защитный символ или переключатель DSP2833x_XINTF_H для последующей компиляции. */ +#define DSP2833x_XINTF_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +// XINTF timing register bit definitions: +/* Описывает структуру XTIMING_BITS; порядок полей определяет расположение данных. */ +struct XTIMING_BITS { // bits description + /* Битовое поле XWRTRAIL, ширина 2 бит; данные XWRTRAIL. */ + Uint16 XWRTRAIL:2; // 1:0 Write access trail timing + /* Битовое поле XWRACTIVE, ширина 3 бит; данные XWRACTIVE. */ + Uint16 XWRACTIVE:3; // 4:2 Write access active timing + /* Битовое поле XWRLEAD, ширина 2 бит; данные XWRLEAD. */ + Uint16 XWRLEAD:2; // 6:5 Write access lead timing + /* Битовое поле XRDTRAIL, ширина 2 бит; данные XRDTRAIL. */ + Uint16 XRDTRAIL:2; // 8:7 Read access trail timing + /* Битовое поле XRDACTIVE, ширина 3 бит; данные XRDACTIVE. */ + Uint16 XRDACTIVE:3; // 11:9 Read access active timing + /* Битовое поле XRDLEAD, ширина 2 бит; данные XRDLEAD. */ + Uint16 XRDLEAD:2; // 13:12 Read access lead timing + /* Битовое поле USEREADY, ширина 1 бит; данные USEREADY. */ + Uint16 USEREADY:1; // 14 Extend access using HW waitstates + /* Битовое поле READYMODE, ширина 1 бит; данные READYMODE. */ + Uint16 READYMODE:1; // 15 Ready mode + /* Битовое поле XSIZE, ширина 2 бит; данные XSIZE. */ + Uint16 XSIZE:2; // 17:16 XINTF bus width - must be written as 11b + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 21:18 reserved + /* Битовое поле X2TIMING, ширина 1 бит; данные X2TIMING. */ + Uint16 X2TIMING:1; // 22 Double lead/active/trail timing + /* Битовое поле rsvd3, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:9; // 31:23 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XTIMING_REG в одной области памяти. */ +union XTIMING_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру XTIMING_BITS bit;; порядок полей определяет расположение данных. */ + struct XTIMING_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XINTF control register bit definitions: +/* Описывает структуру XINTCNF2_BITS; порядок полей определяет расположение данных. */ +struct XINTCNF2_BITS { // bits description + /* Битовое поле WRBUFF, ширина 2 бит; данные WRBUFF. */ + Uint16 WRBUFF:2; // 1:0 Write buffer depth + /* Битовое поле CLKMODE, ширина 1 бит; данные CLKMODE. */ + Uint16 CLKMODE:1; // 2 Ratio for XCLKOUT with respect to XTIMCLK + /* Битовое поле CLKOFF, ширина 1 бит; данные CLKOFF. */ + Uint16 CLKOFF:1; // 3 Disable XCLKOUT + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 5:4 reserved + /* Битовое поле WLEVEL, ширина 2 бит; данные WLEVEL. */ + Uint16 WLEVEL:2; // 7:6 Current level of the write buffer + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 8 reserved + /* Битовое поле HOLD, ширина 1 бит; данные HOLD. */ + Uint16 HOLD:1; // 9 Hold enable/disable + /* Битовое поле HOLDS, ширина 1 бит; данные HOLDS. */ + Uint16 HOLDS:1; // 10 Current state of HOLDn input + /* Битовое поле HOLDAS, ширина 1 бит; данные HOLDAS. */ + Uint16 HOLDAS:1; // 11 Current state of HOLDAn output + /* Битовое поле rsvd3, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:4; // 15:12 reserved + /* Битовое поле XTIMCLK, ширина 3 бит; данные XTIMCLK. */ + Uint16 XTIMCLK:3; // 18:16 Ratio for XTIMCLK + /* Битовое поле rsvd4, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4:13; // 31:19 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XINTCNF2_REG в одной области памяти. */ +union XINTCNF2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру XINTCNF2_BITS bit;; порядок полей определяет расположение данных. */ + struct XINTCNF2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XINTF bank switching register bit definitions: +/* Описывает структуру XBANK_BITS; порядок полей определяет расположение данных. */ +struct XBANK_BITS { // bits description + /* Битовое поле BANK, ширина 3 бит; данные BANK. */ + Uint16 BANK:3; // 2:0 Zone for which banking is enabled + /* Битовое поле BCYC, ширина 3 бит; данные BCYC. */ + Uint16 BCYC:3; // 5:3 XTIMCLK cycles to add + /* Битовое поле rsvd, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:10; // 15:6 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XBANK_REG в одной области памяти. */ +union XBANK_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XBANK_BITS bit;; порядок полей определяет расположение данных. */ + struct XBANK_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру XRESET_BITS; порядок полей определяет расположение данных. */ +struct XRESET_BITS { + /* Битовое поле XHARDRESET, ширина 1 бит; данные XHARDRESET. */ + Uint16 XHARDRESET:1; + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XRESET_REG в одной области памяти. */ +union XRESET_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XBANK_BITS bit;; порядок полей определяет расположение данных. */ + struct XBANK_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// XINTF Register File: +// +/* Описывает структуру XINTF_REGS; порядок полей определяет расположение данных. */ +struct XINTF_REGS { + /* Объединяет несколько представлений XTIMING_REG XTIMING0; в одной области памяти. */ + union XTIMING_REG XTIMING0; + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd1[5]; + /* Объединяет несколько представлений XTIMING_REG XTIMING6; в одной области памяти. */ + union XTIMING_REG XTIMING6; + /* Объединяет несколько представлений XTIMING_REG XTIMING7; в одной области памяти. */ + union XTIMING_REG XTIMING7; + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd2[2]; + /* Объединяет несколько представлений XINTCNF2_REG XINTCNF2; в одной области памяти. */ + union XINTCNF2_REG XINTCNF2; + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd3; + /* Объединяет несколько представлений XBANK_REG XBANK; в одной области памяти. */ + union XBANK_REG XBANK; + /* Объявляет rsvd4 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4; + /* Объявляет XREVISION — данные XREVISION. */ + Uint16 XREVISION; + /* Объявляет rsvd5 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5[2]; + /* Объединяет несколько представлений XRESET_REG XRESET; в одной области памяти. */ + union XRESET_REG XRESET; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// XINTF External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct XINTF_REGS XintfRegs;; порядок элементов сохраняется. */ +extern volatile struct XINTF_REGS XintfRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_XINTF_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm new file mode 100644 index 0000000..1de162b --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm @@ -0,0 +1,51 @@ +; Поставляемое ti описание adc_cal для семейства c2833x. Пояснения в UTF-8. +;; TI File $Revision: /main/1 $ +;; Checkin $Date: July 30, 2007 10:29:23 $ +;;########################################################################### +;; +;; FILE: ADC_cal.asm +;; +;; TITLE: 2833x Boot Rom ADC Cal routine. +;; +;; Functions: +;; +;; _ADC_cal - Copies device specific calibration data into ADCREFSEL and ADCOFFTRIM registers +;; Notes: +;; +;;########################################################################### +;; $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +;; $Release Date: August 1, 2008 $ +;;########################################################################### + + ; Экспортирует символ для связывания с C-кодом. Операция: .def _ADC_cal. + .def _ADC_cal + ; Задаёт текстовый псевдоним константы для ассемблера. Операция: .asg "0x711C", ADCREFSEL_LOC. + .asg "0x711C", ADCREFSEL_LOC + +;----------------------------------------------- +; _ADC_cal +;----------------------------------------------- +;----------------------------------------------- +; This is the ADC cal routine.This routine is programmed into +; reserved memory by the factory. 0xAAAA and 0xBBBB are place- +; holders for calibration data. +;The actual values programmed by TI are device specific. +; +; This function assumes that the clocks have been +; enabled to the ADC module. +;----------------------------------------------- + + ; Выбирает секцию объектного файла для следующих инструкций. Операция: .sect ".adc_cal". + .sect ".adc_cal" + +; Объявляет метку _ADC_cal для перехода или вызова. Операция: _ADC_cal. +_ADC_cal + ; Загружает регистр страниц данных DP для доступа к указанной области. Операция: MOVW DP, #ADCREFSEL_LOC >> 6. + MOVW DP, #ADCREFSEL_LOC >> 6 + ; Переносит операнд в регистр или ячейку назначения. Операция: MOV @28, #0xAAAA. + MOV @28, #0xAAAA ; actual value may not be 0xAAAA + ; Переносит операнд в регистр или ячейку назначения. Операция: MOV @29, #0xBBBB. + MOV @29, #0xBBBB ; actual value may not be 0xBBBB + ; Возвращает управление вызывающему коду через длинный адрес возврата. Операция: LRETR. + LRETR +;eof ---------- diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c new file mode 100644 index 0000000..def985e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c @@ -0,0 +1,161 @@ +/* Поставляемое TI описание CpuTimers для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 16, 2007 08:37:30 $ +//########################################################################### +// +// FILE: DSP2833x_CpuTimers.c +// +// TITLE: CPU 32-bit Timers Initialization & Support Functions. +// +// NOTES: CpuTimer1 and CpuTimer2 are reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use these two timers in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // Examples Include File + +/* Описывает структуру CPUTIMER_VARS CpuTimer0;; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS CpuTimer0; + +// CpuTimer 1 and CpuTimer2 are used by DSP BIOS & other RTOS. Comment out if using DSP BIOS or other RTOS. +/* Описывает структуру CPUTIMER_VARS CpuTimer1;; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS CpuTimer1; +/* Описывает структуру CPUTIMER_VARS CpuTimer2;; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// InitCpuTimers: +//--------------------------------------------------------------------------- +// This function initializes all three CPU timers to a known state. +// +/* Начинает функцию InitCpuTimers; назначение модуля — поставляемое TI описание CpuTimers для семейства C2833x. */ +void InitCpuTimers(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + // CPU Timer 0 + // Initialize address pointers to respective timer registers: + /* Записывает CpuTimer0.RegsAddr значением &CpuTimer0Regs; данные RegsAddr. */ + CpuTimer0.RegsAddr = &CpuTimer0Regs; + // Initialize timer period to maximum: + /* Записывает CpuTimer0Regs.PRD.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer0Regs.PRD.all = 0xFFFFFFFF; + // Initialize pre-scale counter to divide by 1 (SYSCLKOUT): + /* Записывает CpuTimer0Regs.TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer0Regs.TPR.all = 0; + /* Записывает CpuTimer0Regs.TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer0Regs.TPRH.all = 0; + // Make sure timer is stopped: + /* Записывает CpuTimer0Regs.TCR.bit.TSS значением 1; данные TSS. */ + CpuTimer0Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + /* Записывает CpuTimer0Regs.TCR.bit.TRB значением 1; данные TRB. */ + CpuTimer0Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + /* Записывает CpuTimer0.InterruptCount значением 0; прерывание число. */ + CpuTimer0.InterruptCount = 0; + + +// CpuTimer 1 and CpuTimer2 are reserved for DSP BIOS & other RTOS +// Do not use these two timers if you ever plan on integrating +// DSP-BIOS or another realtime OS. +// +// Initialize address pointers to respective timer registers: + /* Записывает CpuTimer1.RegsAddr значением &CpuTimer1Regs; данные RegsAddr. */ + CpuTimer1.RegsAddr = &CpuTimer1Regs; + /* Записывает CpuTimer2.RegsAddr значением &CpuTimer2Regs; данные RegsAddr. */ + CpuTimer2.RegsAddr = &CpuTimer2Regs; + // Initialize timer period to maximum: + /* Записывает CpuTimer1Regs.PRD.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer1Regs.PRD.all = 0xFFFFFFFF; + /* Записывает CpuTimer2Regs.PRD.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer2Regs.PRD.all = 0xFFFFFFFF; + // Initialize pre-scale counter to divide by 1 (SYSCLKOUT): + /* Записывает CpuTimer1Regs.TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer1Regs.TPR.all = 0; + /* Записывает CpuTimer1Regs.TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer1Regs.TPRH.all = 0; + /* Записывает CpuTimer2Regs.TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer2Regs.TPR.all = 0; + /* Записывает CpuTimer2Regs.TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer2Regs.TPRH.all = 0; + // Make sure timers are stopped: + /* Записывает CpuTimer1Regs.TCR.bit.TSS значением 1; данные TSS. */ + CpuTimer1Regs.TCR.bit.TSS = 1; + /* Записывает CpuTimer2Regs.TCR.bit.TSS значением 1; данные TSS. */ + CpuTimer2Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + /* Записывает CpuTimer1Regs.TCR.bit.TRB значением 1; данные TRB. */ + CpuTimer1Regs.TCR.bit.TRB = 1; + /* Записывает CpuTimer2Regs.TCR.bit.TRB значением 1; данные TRB. */ + CpuTimer2Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + /* Записывает CpuTimer1.InterruptCount значением 0; прерывание число. */ + CpuTimer1.InterruptCount = 0; + /* Записывает CpuTimer2.InterruptCount значением 0; прерывание число. */ + CpuTimer2.InterruptCount = 0; + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// ConfigCpuTimer: +//--------------------------------------------------------------------------- +// This function initializes the selected timer to the period specified +// by the "Freq" and "Period" parameters. The "Freq" is entered as "MHz" +// and the period in "uSeconds". The timer is held in the stopped state +// after configuration. +// +/* Начинает функцию ConfigCpuTimer; назначение модуля — поставляемое TI описание CpuTimers для семейства C2833x. */ +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет temp — данные temp. */ + Uint32 temp; + + // Initialize timer period: + /* Записывает Timer->CPUFreqInMHz значением Freq; таймер CPU Freq In M Hz. */ + Timer->CPUFreqInMHz = Freq; + /* Записывает Timer->PeriodInUSec значением Period; таймер период In U Sec. */ + Timer->PeriodInUSec = Period; + /* Записывает temp значением (long) (Freq * Period); данные temp. */ + temp = (long) (Freq * Period); + /* Записывает Timer->RegsAddr->PRD.all значением temp; представление регистра целым словом без разбиения на битовые поля. */ + Timer->RegsAddr->PRD.all = temp; + + // Set pre-scale counter to divide by 1 (SYSCLKOUT): + /* Записывает Timer->RegsAddr->TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + Timer->RegsAddr->TPR.all = 0; + /* Записывает Timer->RegsAddr->TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + Timer->RegsAddr->TPRH.all = 0; + + // Initialize timer control register: + /* Записывает Timer->RegsAddr->TCR.bit.TSS значением 1; данные TSS. */ + Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 = Start/Restart Timer + /* Записывает Timer->RegsAddr->TCR.bit.TRB значением 1; данные TRB. */ + Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer + /* Записывает Timer->RegsAddr->TCR.bit.SOFT значением 0; данные SOFT. */ + Timer->RegsAddr->TCR.bit.SOFT = 0; + /* Записывает Timer->RegsAddr->TCR.bit.FREE значением 0; данные FREE. */ + Timer->RegsAddr->TCR.bit.FREE = 0; // Timer Free Run Disabled + /* Записывает Timer->RegsAddr->TCR.bit.TIE значением 1; данные TIE. */ + Timer->RegsAddr->TCR.bit.TIE = 1; // 0 = Disable/ 1 = Enable Timer Interrupt + + // Reset interrupt counter: + /* Записывает Timer->InterruptCount значением 0; таймер прерывание число. */ + Timer->InterruptCount = 0; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c new file mode 100644 index 0000000..74a8a7e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c @@ -0,0 +1,746 @@ +/* Поставляемое TI описание GlobalVariableDefs для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/4 $ +// Checkin $Date: June 2, 2008 11:12:33 $ +//########################################################################### +// +// FILE: DSP2833x_GlobalVariableDefs.c +// +// TITLE: DSP2833x Global Variables and Data Section Pragmas. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File + +//--------------------------------------------------------------------------- +// Define Global Peripheral Variables: +// +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("AdcRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("AdcRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(AdcRegs,"AdcRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(AdcRegs,"AdcRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ADC_REGS AdcRegs;; порядок элементов сохраняется. */ +volatile struct ADC_REGS AdcRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("AdcMirrorFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("AdcMirrorFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(AdcMirror,"AdcMirrorFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(AdcMirror,"AdcMirrorFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ADC_RESULT_MIRROR_REGS AdcMirror;; порядок элементов сохраняется. */ +volatile struct ADC_RESULT_MIRROR_REGS AdcMirror; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CpuTimer0RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CpuTimer0RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CpuTimer0Regs,"CpuTimer0RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CpuTimer0Regs,"CpuTimer0RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS CpuTimer0Regs;; порядок элементов сохраняется. */ +volatile struct CPUTIMER_REGS CpuTimer0Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CpuTimer1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CpuTimer1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CpuTimer1Regs,"CpuTimer1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CpuTimer1Regs,"CpuTimer1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS CpuTimer1Regs;; порядок элементов сохраняется. */ +volatile struct CPUTIMER_REGS CpuTimer1Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CpuTimer2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CpuTimer2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CpuTimer2Regs,"CpuTimer2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CpuTimer2Regs,"CpuTimer2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS CpuTimer2Regs;; порядок элементов сохраняется. */ +volatile struct CPUTIMER_REGS CpuTimer2Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CsmPwlFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CsmPwlFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CsmPwl,"CsmPwlFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CsmPwl,"CsmPwlFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CSM_PWL CsmPwl;; порядок элементов сохраняется. */ +volatile struct CSM_PWL CsmPwl; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CsmRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CsmRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CsmRegs,"CsmRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CsmRegs,"CsmRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CSM_REGS CsmRegs;; порядок элементов сохраняется. */ +volatile struct CSM_REGS CsmRegs; + + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("DevEmuRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("DevEmuRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(DevEmuRegs,"DevEmuRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(DevEmuRegs,"DevEmuRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct DEV_EMU_REGS DevEmuRegs;; порядок элементов сохраняется. */ +volatile struct DEV_EMU_REGS DevEmuRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("DmaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("DmaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(DmaRegs,"DmaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(DmaRegs,"DmaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct DMA_REGS DmaRegs;; порядок элементов сохраняется. */ +volatile struct DMA_REGS DmaRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaRegs,"ECanaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaRegs,"ECanaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_REGS ECanaRegs;; порядок элементов сохраняется. */ +volatile struct ECAN_REGS ECanaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaMboxesFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaMboxesFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaMboxes,"ECanaMboxesFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaMboxes,"ECanaMboxesFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_MBOXES ECanaMboxes;; порядок элементов сохраняется. */ +volatile struct ECAN_MBOXES ECanaMboxes; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaLAMRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaLAMRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaLAMRegs,"ECanaLAMRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaLAMRegs,"ECanaLAMRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct LAM_REGS ECanaLAMRegs;; порядок элементов сохраняется. */ +volatile struct LAM_REGS ECanaLAMRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaMOTSRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaMOTSRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaMOTSRegs,"ECanaMOTSRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaMOTSRegs,"ECanaMOTSRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTS_REGS ECanaMOTSRegs;; порядок элементов сохраняется. */ +volatile struct MOTS_REGS ECanaMOTSRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaMOTORegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaMOTORegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaMOTORegs,"ECanaMOTORegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaMOTORegs,"ECanaMOTORegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTO_REGS ECanaMOTORegs;; порядок элементов сохраняется. */ +volatile struct MOTO_REGS ECanaMOTORegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbRegs,"ECanbRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbRegs,"ECanbRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_REGS ECanbRegs;; порядок элементов сохраняется. */ +volatile struct ECAN_REGS ECanbRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbMboxesFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbMboxesFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbMboxes,"ECanbMboxesFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbMboxes,"ECanbMboxesFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_MBOXES ECanbMboxes;; порядок элементов сохраняется. */ +volatile struct ECAN_MBOXES ECanbMboxes; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbLAMRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbLAMRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbLAMRegs,"ECanbLAMRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbLAMRegs,"ECanbLAMRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct LAM_REGS ECanbLAMRegs;; порядок элементов сохраняется. */ +volatile struct LAM_REGS ECanbLAMRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbMOTSRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbMOTSRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbMOTSRegs,"ECanbMOTSRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbMOTSRegs,"ECanbMOTSRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTS_REGS ECanbMOTSRegs;; порядок элементов сохраняется. */ +volatile struct MOTS_REGS ECanbMOTSRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbMOTORegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbMOTORegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbMOTORegs,"ECanbMOTORegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbMOTORegs,"ECanbMOTORegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTO_REGS ECanbMOTORegs;; порядок элементов сохраняется. */ +volatile struct MOTO_REGS ECanbMOTORegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm1Regs,"EPwm1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm1Regs,"EPwm1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm1Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm1Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm2Regs,"EPwm2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm2Regs,"EPwm2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm2Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm2Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm3RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm3RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm3Regs,"EPwm3RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm3Regs,"EPwm3RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm3Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm3Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm4RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm4RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm4Regs,"EPwm4RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm4Regs,"EPwm4RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm4Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm4Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm5RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm5RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm5Regs,"EPwm5RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm5Regs,"EPwm5RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm5Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm5Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm6RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm6RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm6Regs,"EPwm6RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm6Regs,"EPwm6RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm6Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm6Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap1Regs,"ECap1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap1Regs,"ECap1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap1Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap1Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap2Regs,"ECap2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap2Regs,"ECap2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap2Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap2Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap3RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap3RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap3Regs,"ECap3RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap3Regs,"ECap3RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap3Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap3Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap4RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap4RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap4Regs,"ECap4RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap4Regs,"ECap4RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap4Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap4Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap5RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap5RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap5Regs,"ECap5RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap5Regs,"ECap5RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap5Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap5Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap6RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap6RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap6Regs,"ECap6RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap6Regs,"ECap6RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap6Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap6Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EQep1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EQep1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EQep1Regs,"EQep1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EQep1Regs,"EQep1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EQEP_REGS EQep1Regs;; порядок элементов сохраняется. */ +volatile struct EQEP_REGS EQep1Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EQep2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EQep2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EQep2Regs,"EQep2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EQep2Regs,"EQep2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EQEP_REGS EQep2Regs;; порядок элементов сохраняется. */ +volatile struct EQEP_REGS EQep2Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("GpioCtrlRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("GpioCtrlRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(GpioCtrlRegs,"GpioCtrlRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(GpioCtrlRegs,"GpioCtrlRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct GPIO_CTRL_REGS GpioCtrlRegs;; порядок элементов сохраняется. */ +volatile struct GPIO_CTRL_REGS GpioCtrlRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("GpioDataRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("GpioDataRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(GpioDataRegs,"GpioDataRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(GpioDataRegs,"GpioDataRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct GPIO_DATA_REGS GpioDataRegs;; порядок элементов сохраняется. */ +volatile struct GPIO_DATA_REGS GpioDataRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("GpioIntRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("GpioIntRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(GpioIntRegs,"GpioIntRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(GpioIntRegs,"GpioIntRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct GPIO_INT_REGS GpioIntRegs;; порядок элементов сохраняется. */ +volatile struct GPIO_INT_REGS GpioIntRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("I2caRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("I2caRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(I2caRegs,"I2caRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(I2caRegs,"I2caRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct I2C_REGS I2caRegs;; порядок элементов сохраняется. */ +volatile struct I2C_REGS I2caRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("McbspaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("McbspaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(McbspaRegs,"McbspaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(McbspaRegs,"McbspaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MCBSP_REGS McbspaRegs;; порядок элементов сохраняется. */ +volatile struct MCBSP_REGS McbspaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("McbspbRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("McbspbRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(McbspbRegs,"McbspbRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(McbspbRegs,"McbspbRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MCBSP_REGS McbspbRegs;; порядок элементов сохраняется. */ +volatile struct MCBSP_REGS McbspbRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("PartIdRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("PartIdRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(PartIdRegs,"PartIdRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(PartIdRegs,"PartIdRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct PARTID_REGS PartIdRegs;; порядок элементов сохраняется. */ +volatile struct PARTID_REGS PartIdRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("PieCtrlRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("PieCtrlRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(PieCtrlRegs,"PieCtrlRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(PieCtrlRegs,"PieCtrlRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct PIE_CTRL_REGS PieCtrlRegs;; порядок элементов сохраняется. */ +volatile struct PIE_CTRL_REGS PieCtrlRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("PieVectTableFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("PieVectTableFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(PieVectTable,"PieVectTableFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(PieVectTable,"PieVectTableFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Описывает структуру PIE_VECT_TABLE PieVectTable;; порядок полей определяет расположение данных. */ +struct PIE_VECT_TABLE PieVectTable; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("SciaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("SciaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(SciaRegs,"SciaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(SciaRegs,"SciaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SCI_REGS SciaRegs;; порядок элементов сохраняется. */ +volatile struct SCI_REGS SciaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ScibRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ScibRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ScibRegs,"ScibRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ScibRegs,"ScibRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SCI_REGS ScibRegs;; порядок элементов сохраняется. */ +volatile struct SCI_REGS ScibRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ScicRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ScicRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ScicRegs,"ScicRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ScicRegs,"ScicRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SCI_REGS ScicRegs;; порядок элементов сохраняется. */ +volatile struct SCI_REGS ScicRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("SpiaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("SpiaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(SpiaRegs,"SpiaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(SpiaRegs,"SpiaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SPI_REGS SpiaRegs;; порядок элементов сохраняется. */ +volatile struct SPI_REGS SpiaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("SysCtrlRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("SysCtrlRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(SysCtrlRegs,"SysCtrlRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(SysCtrlRegs,"SysCtrlRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SYS_CTRL_REGS SysCtrlRegs;; порядок элементов сохраняется. */ +volatile struct SYS_CTRL_REGS SysCtrlRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("FlashRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("FlashRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(FlashRegs,"FlashRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(FlashRegs,"FlashRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct FLASH_REGS FlashRegs;; порядок элементов сохраняется. */ +volatile struct FLASH_REGS FlashRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("XIntruptRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("XIntruptRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(XIntruptRegs,"XIntruptRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(XIntruptRegs,"XIntruptRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct XINTRUPT_REGS XIntruptRegs;; порядок элементов сохраняется. */ +volatile struct XINTRUPT_REGS XIntruptRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("XintfRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("XintfRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(XintfRegs,"XintfRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(XintfRegs,"XintfRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct XINTF_REGS XintfRegs;; порядок элементов сохраняется. */ +volatile struct XINTF_REGS XintfRegs; + + + +//=========================================================================== +// End of file. +//=========================================================================== + + + + + + + + + diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c new file mode 100644 index 0000000..0ca4201 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c @@ -0,0 +1,121 @@ +/* Поставляемое TI описание PieCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:46:35 $ +//########################################################################### +// +// FILE: DSP2833x_PieCtrl.c +// +// TITLE: DSP2833x Device PIE Control Register Initialization Functions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // DSP2833x Examples Include File + +//--------------------------------------------------------------------------- +// InitPieCtrl: +//--------------------------------------------------------------------------- +// This function initializes the PIE control registers to a known state. +// +/* Начинает функцию InitPieCtrl; назначение модуля — поставляемое TI описание PieCtrl для семейства C2833x. */ +void InitPieCtrl(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + // Disable Interrupts at the CPU level: + /* Запрет маскируемых прерываний ядра. */ + DINT; + + // Disable the PIE + /* Записывает PieCtrlRegs.PIECTRL.bit.ENPIE значением 0; данные ENPIE. */ + PieCtrlRegs.PIECTRL.bit.ENPIE = 0; + + // Clear all PIEIER registers: + /* Записывает PieCtrlRegs.PIEIER1.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER1.all = 0; + /* Записывает PieCtrlRegs.PIEIER2.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER2.all = 0; + /* Записывает PieCtrlRegs.PIEIER3.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER3.all = 0; + /* Записывает PieCtrlRegs.PIEIER4.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER4.all = 0; + /* Записывает PieCtrlRegs.PIEIER5.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER5.all = 0; + /* Записывает PieCtrlRegs.PIEIER6.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER6.all = 0; + /* Записывает PieCtrlRegs.PIEIER7.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER7.all = 0; + /* Записывает PieCtrlRegs.PIEIER8.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER8.all = 0; + /* Записывает PieCtrlRegs.PIEIER9.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER9.all = 0; + /* Записывает PieCtrlRegs.PIEIER10.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER10.all = 0; + /* Записывает PieCtrlRegs.PIEIER11.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER11.all = 0; + /* Записывает PieCtrlRegs.PIEIER12.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER12.all = 0; + + // Clear all PIEIFR registers: + /* Записывает PieCtrlRegs.PIEIFR1.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR1.all = 0; + /* Записывает PieCtrlRegs.PIEIFR2.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR2.all = 0; + /* Записывает PieCtrlRegs.PIEIFR3.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR3.all = 0; + /* Записывает PieCtrlRegs.PIEIFR4.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR4.all = 0; + /* Записывает PieCtrlRegs.PIEIFR5.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR5.all = 0; + /* Записывает PieCtrlRegs.PIEIFR6.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR6.all = 0; + /* Записывает PieCtrlRegs.PIEIFR7.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR7.all = 0; + /* Записывает PieCtrlRegs.PIEIFR8.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR8.all = 0; + /* Записывает PieCtrlRegs.PIEIFR9.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR9.all = 0; + /* Записывает PieCtrlRegs.PIEIFR10.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR10.all = 0; + /* Записывает PieCtrlRegs.PIEIFR11.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR11.all = 0; + /* Записывает PieCtrlRegs.PIEIFR12.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR12.all = 0; + + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// EnableInterrupts: +//--------------------------------------------------------------------------- +// This function enables the PIE module and CPU interrupts +// +/* Начинает функцию EnableInterrupts; назначение модуля — поставляемое TI описание PieCtrl для семейства C2833x. */ +void EnableInterrupts() +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + + // Enable the PIE + /* Записывает PieCtrlRegs.PIECTRL.bit.ENPIE значением 1; данные ENPIE. */ + PieCtrlRegs.PIECTRL.bit.ENPIE = 1; + + // Enables PIE to drive a pulse into the CPU + /* Записывает PieCtrlRegs.PIEACK.all значением 0xFFFF; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEACK.all = 0xFFFF; + + // Enable Interrupts at the CPU level + /* Разрешение маскируемых прерываний ядра. */ + EINT; + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c new file mode 100644 index 0000000..eaa98f3 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c @@ -0,0 +1,604 @@ +/* Поставляемое TI описание SysCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/7 $ +// Checkin $Date: September 20, 2007 13:30:31 $ +//########################################################################### +// +// FILE: DSP2833x_SysCtrl.c +// +// TITLE: DSP2833x Device System Control Initialization & Support Functions. +// +// DESCRIPTION: +// +// Example initialization of system resources. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // Examples Include File + +//#include "RS485.h" +//#include "message.h" + +// Functions that will be run from RAM need to be assigned to +// a different section. This section will then be mapped to a load and +// run address using the linker cmd file. + +/* Указание компилятору CODE_SECTION(InitFlash, "ramfuncs");: размещение данных или настройка обработки объявлений. */ +#pragma CODE_SECTION(InitFlash, "ramfuncs"); + +//--------------------------------------------------------------------------- +// InitSysCtrl: +//--------------------------------------------------------------------------- +// This function initializes the System Control registers to a known state. +// - Disables the watchdog +// - Set the PLLCR for proper SYSCLKOUT frequency +// - Set the pre-scaler for the high and low frequency peripheral clocks +// - Enable the clocks to the peripherals + +/* Объявляет SYSCLKOUT — данные SYSCLKOUT; LSPCLK — данные LSPCLK; HSPCLK — данные HSPCLK. */ +long SYSCLKOUT, LSPCLK, HSPCLK; + +/* Начинает функцию InitSysCtrl; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitSysCtrl(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + + // Disable the watchdog + /* Вызывает DisableDog с аргументами () в текущей последовательности операций. */ + DisableDog(); + + // Initialize the PLL control: PLLCR and DIVSEL + // DSP28_PLLCR and DSP28_DIVSEL are defined in DSP2833x_Examples.h + /* Инициализирует модуль вызовом InitPll(DSP28_PLLCR,DSP28_DIVSEL); перед его дальнейшим использованием. */ + InitPll(DSP28_PLLCR,DSP28_DIVSEL); + + // Initialize the peripheral clocks + /* Инициализирует модуль вызовом InitPeripheralClocks(); перед его дальнейшим использованием. */ + InitPeripheralClocks(); +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//--------------------------------------------------------------------------- +// Example: InitFlash: +//--------------------------------------------------------------------------- +// This function initializes the Flash Control registers + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results + +/* Начинает функцию InitFlash; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitFlash(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + //Enable Flash Pipeline mode to improve performance + //of code executed from Flash. + /* Записывает FlashRegs.FOPT.bit.ENPIPE значением 1; данные ENPIPE. */ + FlashRegs.FOPT.bit.ENPIPE = 1; + + // CAUTION + //Minimum waitstates required for the flash operating + //at a given CPU rate must be characterized by TI. + //Refer to the datasheet for the latest information. +/* Условие компиляции CPU_FRQ_150MHZ: выбранный блок включается в текущий вариант прошивки. */ +#if CPU_FRQ_150MHZ + //Set the Paged Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.PAGEWAIT значением 5; данные PAGEWAIT. */ + FlashRegs.FBANKWAIT.bit.PAGEWAIT = 5; + + //Set the Random Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.RANDWAIT значением 5; данные RANDWAIT. */ + FlashRegs.FBANKWAIT.bit.RANDWAIT = 5; + + //Set the Waitstate for the OTP + /* Записывает FlashRegs.FOTPWAIT.bit.OTPWAIT значением 8; данные OTPWAIT. */ + FlashRegs.FOTPWAIT.bit.OTPWAIT = 8; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции CPU_FRQ_100MHZ: выбранный блок включается в текущий вариант прошивки. */ +#if CPU_FRQ_100MHZ + //Set the Paged Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.PAGEWAIT значением 3; данные PAGEWAIT. */ + FlashRegs.FBANKWAIT.bit.PAGEWAIT = 3; + + //Set the Random Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.RANDWAIT значением 3; данные RANDWAIT. */ + FlashRegs.FBANKWAIT.bit.RANDWAIT = 3; + + //Set the Waitstate for the OTP + /* Записывает FlashRegs.FOTPWAIT.bit.OTPWAIT значением 5; данные OTPWAIT. */ + FlashRegs.FOTPWAIT.bit.OTPWAIT = 5; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + // CAUTION + //ONLY THE DEFAULT VALUE FOR THESE 2 REGISTERS SHOULD BE USED + /* Записывает FlashRegs.FSTDBYWAIT.bit.STDBYWAIT значением 0x01FF; данные STDBYWAIT. */ + FlashRegs.FSTDBYWAIT.bit.STDBYWAIT = 0x01FF; + /* Записывает FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT значением 0x01FF; данные ACTIVEWAIT. */ + FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT = 0x01FF; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + + //Force a pipeline flush to ensure that the write to + //the last register configured occurs before returning. + + /* Вызывает asm с аргументами (" RPT #7 || NOP") в текущей последовательности операций. */ + asm(" RPT #7 || NOP"); +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//--------------------------------------------------------------------------- +// Example: ServiceDog: +//--------------------------------------------------------------------------- +// This function resets the watchdog timer. +// Enable this function for using ServiceDog in the application + +/* Начинает функцию ServiceDog; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void ServiceDog(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Проверяет if(SysCtrlRegs.PLLCR.bit.DIV == DSP28_PLLCR); последующий оператор выполняется только при истинном условии. */ + if(SysCtrlRegs.PLLCR.bit.DIV == DSP28_PLLCR) + /* Проверяет if(SysCtrlRegs.PLLSTS.bit.DIVSEL == DSP28_DIVSEL); последующий оператор выполняется только при истинном условии. */ + if(SysCtrlRegs.PLLSTS.bit.DIVSEL == DSP28_DIVSEL) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.WDKEY значением 0x0055; данные WDKEY. */ + SysCtrlRegs.WDKEY = 0x0055; + /* Записывает SysCtrlRegs.WDKEY значением 0x00AA; данные WDKEY. */ + SysCtrlRegs.WDKEY = 0x00AA; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Завершает ServiceDog без возвращаемого значения. */ + return; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} } + + +//--------------------------------------------------------------------------- +// Example: DisableDog: +//--------------------------------------------------------------------------- +// This function disables the watchdog timer. + +/* Начинает функцию DisableDog; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void DisableDog(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.WDCR значением 0x0068; данные WDCR. */ + SysCtrlRegs.WDCR= 0x0068; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// Example: InitPll: +//--------------------------------------------------------------------------- +// This function initializes the PLLCR register. + +/* Начинает функцию InitPll; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitPll(Uint16 divval, Uint16 divsel) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет clkVal — данные clkVal. */ + long clkVal; + + // Make sure the PLL is not running in limp mode + /* Проверяет if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0); последующий оператор выполняется только при истинном условии. */ + if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + // Missing external clock has been detected + // Replace this line with a call to an appropriate + // SystemShutdown(); function. + /* Вызывает asm с аргументами (" ESTOP0") в текущей последовательности операций. */ + asm(" ESTOP0"); + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + // DIVSEL MUST be 0 before PLLCR can be changed from + // 0x0000. It is set to 0 by an external reset XRSn + // This puts us in 1/4 + /* Проверяет if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0); последующий оператор выполняется только при истинном условии. */ + if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением 0; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = 0; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + // Change the PLLCR +// if (SysCtrlRegs.PLLCR.bit.DIV != val) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + // Before setting PLLCR turn off missing clock detect logic + /* Записывает SysCtrlRegs.PLLSTS.bit.MCLKOFF значением 1; данные MCLKOFF. */ + SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1; + /* Записывает SysCtrlRegs.PLLCR.bit.DIV значением divval; данные DIV. */ + SysCtrlRegs.PLLCR.bit.DIV = divval; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + + /* Записывает clkVal значением (divval)?divval:1; данные clkVal. */ + clkVal = (divval)?divval:1; + /* Записывает clkVal значением XCLKIN * clkVal; данные clkVal. */ + clkVal = XCLKIN * clkVal; + + // Optional: Wait for PLL to lock. + // During this time the CPU will switch to OSCCLK/2 until + // the PLL is stable. Once the PLL is stable the CPU will + // switch to the new PLL value. + // + // This time-to-lock is monitored by a PLL lock counter. + // + // Code is not required to sit and wait for the PLL to lock. + // However, if the code does anything that is timing critical, + // and requires the correct clock be locked, then it is best to + // wait until this switching has completed. + + // Wait for the PLL lock bit to be set. + + // The watchdog should be disabled before this loop, or fed within + // the loop via ServiceDog(). + + // Uncomment to disable the watchdog + /* Вызывает DisableDog с аргументами () в текущей последовательности операций. */ + DisableDog(); + + /* Повторяет или ожидает, пока выполняется while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1). */ + while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + // Uncomment to service the watchdog + // ServiceDog(); + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.MCLKOFF значением 0; данные MCLKOFF. */ + SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + // If switching to 1/2 + /* Проверяет if((divsel == 1) или (divsel == 2)); последующий оператор выполняется только при истинном условии. */ + if((divsel == 1)||(divsel == 2)) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением divsel; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + /* Проверяет if(divsel == 0) clkVal /= 4; последующий оператор выполняется только при истинном условии. */ + if(divsel == 0) clkVal /= 4; + /* Проверяет if(divsel == 1) clkVal /= 4; последующий оператор выполняется только при истинном условии. */ + if(divsel == 1) clkVal /= 4; + /* Проверяет if(divsel == 2) clkVal /= 2; последующий оператор выполняется только при истинном условии. */ + if(divsel == 2) clkVal /= 2; + + // If switching to 1/1 + // * First go to 1/2 and let the power settle + // The time required will depend on the system, this is only an example + // * Then switch to 1/1 + + /* Проверяет if((divval == 0) и (divsel == 3)); последующий оператор выполняется только при истинном условии. */ + if((divval == 0) && (divsel == 3)) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением 2; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = 2; + /* Вызывает DELAY_US с аргументами (50L) в текущей последовательности операций. */ + DELAY_US(50L); +// pause_us(50L); + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением 3; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = 3; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + /* Записывает SYSCLKOUT значением clkVal; данные SYSCLKOUT. */ + SYSCLKOUT = clkVal; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//-------------------------------------------------------------------------- +// Example: InitPeripheralClocks: +//--------------------------------------------------------------------------- +// This function initializes the clocks to the peripheral modules. +// First the high and low clock prescalers are set +// Second the clocks are enabled to each peripheral. +// To reduce power, leave clocks to unused peripherals disabled +// +// Note: If a peripherals clock is not enabled then you cannot +// read or write to the registers for that peripheral + +/* Начинает функцию InitPeripheralClocks; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitPeripheralClocks(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет Val — данные Val. */ + long Val; + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + +// HISPCP/LOSPCP prescale register settings, normally it will be set to default values + +/* Условие компиляции CLKMULT == 0: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 0 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0000; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0000; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 1: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 1 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0000; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0000; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 2: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 2 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0001; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0001; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 3: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 3 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0002; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0002; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 4: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 4 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0002; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0002; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 5: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 5 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0003; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0003; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + /* Записывает SysCtrlRegs.LOSPCP.all значением 0x0000; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.LOSPCP.all = 0x0000; + + /* Записывает Val значением (SysCtrlRegs.HISPCP.all)?; данные Val. */ + Val = (SysCtrlRegs.HISPCP.all)? + /* Продолжает список аргументов, полей или выражение SysCtrlRegs.HISPCP.all*2 : 1;; порядок элементов сохраняется. */ + SysCtrlRegs.HISPCP.all*2 : 1; + /* Записывает Val значением SYSCLKOUT / Val; данные Val. */ + Val = SYSCLKOUT / Val; + + /* Записывает HSPCLK значением Val; данные HSPCLK. */ + HSPCLK = Val; + + /* Записывает Val значением (SysCtrlRegs.LOSPCP.all)?; данные Val. */ + Val = (SysCtrlRegs.LOSPCP.all)? + /* Продолжает список аргументов, полей или выражение SysCtrlRegs.LOSPCP.all*2 : 1;; порядок элементов сохраняется. */ + SysCtrlRegs.LOSPCP.all*2 : 1; + /* Записывает Val значением SYSCLKOUT / Val; данные Val. */ + Val = SYSCLKOUT / Val; + /* Записывает LSPCLK значением Val; данные LSPCLK. */ + LSPCLK = Val; + +// XCLKOUT to SYSCLKOUT ratio. By default XCLKOUT = 1/4 SYSCLKOUT + // XTIMCLK = SYSCLKOUT/2 + /* Записывает XintfRegs.XINTCNF2.bit.XTIMCLK значением 1; данные XTIMCLK. */ + XintfRegs.XINTCNF2.bit.XTIMCLK = 1; + // XCLKOUT = XTIMCLK/2 + /* Записывает XintfRegs.XINTCNF2.bit.CLKMODE значением 1; данные CLKMODE. */ + XintfRegs.XINTCNF2.bit.CLKMODE = 1; + // Enable XCLKOUT + /* Записывает XintfRegs.XINTCNF2.bit.CLKOFF значением 0; данные CLKOFF. */ + XintfRegs.XINTCNF2.bit.CLKOFF = 0; + +// Peripheral clock enables set for the selected peripherals. +// If you are not using a peripheral leave the clock off +// to save on power. +// +// Note: not all peripherals are available on all 2833x derivates. +// Refer to the datasheet for your particular device. +// +// This function is not written to be an example of efficient code. + + /* Записывает SysCtrlRegs.PCLKCR0.bit.ADCENCLK значением 1; данные ADCENCLK. */ + SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1; // ADC + + // *IMPORTANT* + // The ADC_cal function, which copies the ADC calibration values from TI reserved + // OTP into the ADCREFSEL and ADCOFFTRIM registers, occurs automatically in the + // Boot ROM. If the boot ROM code is bypassed during the debug process, the + // following function MUST be called for the ADC to function according + // to specification. The clocks to the ADC MUST be enabled before calling this + // function. + // See the device data manual and/or the ADC Reference + // Manual for more information. + + /* Вызывает ADC_cal с аргументами () в текущей последовательности операций. */ + ADC_cal(); + + + /* Записывает SysCtrlRegs.PCLKCR0.bit.I2CAENCLK значением 1; данные I2CAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 1; // I2C + /* Записывает SysCtrlRegs.PCLKCR0.bit.SCIAENCLK значением 1; данные SCIAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 1; // SCI-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.SCIBENCLK значением 1; данные SCIBENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SCIBENCLK = 1; // SCI-B + /* Записывает SysCtrlRegs.PCLKCR0.bit.SCICENCLK значением 1; данные SCICENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SCICENCLK = 1; // SCI-C + /* Записывает SysCtrlRegs.PCLKCR0.bit.SPIAENCLK значением 1; данные SPIAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1; // SPI-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.MCBSPAENCLK значением 1; данные MCBSPAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.MCBSPAENCLK = 1; // McBSP-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.MCBSPBENCLK значением 1; данные MCBSPBENCLK. */ + SysCtrlRegs.PCLKCR0.bit.MCBSPBENCLK = 1; // McBSP-B + /* Записывает SysCtrlRegs.PCLKCR0.bit.ECANAENCLK значением 1; данные ECANAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.ECANAENCLK=1; // eCAN-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.ECANBENCLK значением 1; данные ECANBENCLK. */ + SysCtrlRegs.PCLKCR0.bit.ECANBENCLK=1; // eCAN-B + + /* Записывает SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC значением 0; данные TBCLKSYNC. */ + SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Disable TBCLK within the ePWM + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK значением 1; данные EPWM1ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 1; // ePWM1 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK значением 1; данные EPWM2ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 1; // ePWM2 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK значением 1; данные EPWM3ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 1; // ePWM3 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK значением 1; данные EPWM4ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 1; // ePWM4 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK значением 1; данные EPWM5ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 1; // ePWM5 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK значением 1; данные EPWM6ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 1; // ePWM6 + /* Записывает SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC значением 1; данные TBCLKSYNC. */ + SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Enable TBCLK within the ePWM + + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP3ENCLK значением 1; данные ECAP3ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP3ENCLK = 1; // eCAP3 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP4ENCLK значением 1; данные ECAP4ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP4ENCLK = 1; // eCAP4 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP5ENCLK значением 1; данные ECAP5ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP5ENCLK = 1; // eCAP5 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP6ENCLK значением 1; данные ECAP6ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP6ENCLK = 1; // eCAP6 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK значением 1; данные ECAP1ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 1; // eCAP1 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP2ENCLK значением 1; данные ECAP2ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP2ENCLK = 1; // eCAP2 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK значением 1; данные EQEP1ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1; // eQEP1 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EQEP2ENCLK значением 1; данные EQEP2ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EQEP2ENCLK = 1; // eQEP2 + + /* Записывает SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK значением 1; данные CPUTIMER0ENCLK. */ + SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer 0 + /* Записывает SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK значением 1; данные CPUTIMER1ENCLK. */ + SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK = 1; // CPU Timer 1 + /* Записывает SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK значением 1; данные CPUTIMER2ENCLK. */ + SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK = 1; // CPU Timer 2 + + /* Записывает SysCtrlRegs.PCLKCR3.bit.DMAENCLK значением 1; данные DMAENCLK. */ + SysCtrlRegs.PCLKCR3.bit.DMAENCLK = 1; // DMA Clock + /* Записывает SysCtrlRegs.PCLKCR3.bit.XINTFENCLK значением 1; данные XINTFENCLK. */ + SysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 1; // XTIMCLK + /* Записывает SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK значением 1; аппаратная линия ввода/вывода GPIOINENCLK. */ + SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1; // GPIO input clock + + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// Example: CsmUnlock: +//--------------------------------------------------------------------------- +// This function unlocks the CSM. User must replace 0xFFFF's with current +// password for the DSP. Returns 1 if unlock is successful. + +/* Задаёт STATUS_FAIL = 0; состояние FAIL. */ +#define STATUS_FAIL 0 +/* Задаёт STATUS_SUCCESS = 1; состояние SUCCESS. */ +#define STATUS_SUCCESS 1 + +/* Начинает функцию CsmUnlock; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +Uint16 CsmUnlock() +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет temp — данные temp. volatile требует фактического чтения или записи при каждом доступе. */ + volatile Uint16 temp; + + // Load the key registers with the current password. The 0xFFFF's are dummy + // passwords. User should replace them with the correct password for the DSP. + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает CsmRegs.KEY0 значением 0xFFFF; данные KEY0. */ + CsmRegs.KEY0 = 0xFFFF; + /* Записывает CsmRegs.KEY1 значением 0xFFFF; данные KEY1. */ + CsmRegs.KEY1 = 0xFFFF; + /* Записывает CsmRegs.KEY2 значением 0xFFFF; данные KEY2. */ + CsmRegs.KEY2 = 0xFFFF; + /* Записывает CsmRegs.KEY3 значением 0xFFFF; данные KEY3. */ + CsmRegs.KEY3 = 0xFFFF; + /* Записывает CsmRegs.KEY4 значением 0xFFFF; данные KEY4. */ + CsmRegs.KEY4 = 0xFFFF; + /* Записывает CsmRegs.KEY5 значением 0xFFFF; данные KEY5. */ + CsmRegs.KEY5 = 0xFFFF; + /* Записывает CsmRegs.KEY6 значением 0xFFFF; данные KEY6. */ + CsmRegs.KEY6 = 0xFFFF; + /* Записывает CsmRegs.KEY7 значением 0xFFFF; данные KEY7. */ + CsmRegs.KEY7 = 0xFFFF; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + + // Perform a dummy read of the password locations + // if they match the key values, the CSM will unlock + + /* Записывает temp значением CsmPwl.PSWD0; данные temp. */ + temp = CsmPwl.PSWD0; + /* Записывает temp значением CsmPwl.PSWD1; данные temp. */ + temp = CsmPwl.PSWD1; + /* Записывает temp значением CsmPwl.PSWD2; данные temp. */ + temp = CsmPwl.PSWD2; + /* Записывает temp значением CsmPwl.PSWD3; данные temp. */ + temp = CsmPwl.PSWD3; + /* Записывает temp значением CsmPwl.PSWD4; данные temp. */ + temp = CsmPwl.PSWD4; + /* Записывает temp значением CsmPwl.PSWD5; данные temp. */ + temp = CsmPwl.PSWD5; + /* Записывает temp значением CsmPwl.PSWD6; данные temp. */ + temp = CsmPwl.PSWD6; + /* Записывает temp значением CsmPwl.PSWD7; данные temp. */ + temp = CsmPwl.PSWD7; + + // If the CSM unlocked, return succes, otherwise return + // failure. + /* Проверяет if (CsmRegs.CSMSCR.bit.SECURE == 0) return STATUS_SUCCESS; последующий оператор выполняется только при истинном условии. */ + if (CsmRegs.CSMSCR.bit.SECURE == 0) return STATUS_SUCCESS; + /* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */ + else return STATUS_FAIL; + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm new file mode 100644 index 0000000..9425409 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm @@ -0,0 +1,84 @@ +; Поставляемое ti описание usdelay для семейства c2833x. Пояснения в UTF-8. +;// TI File $Revision: /main/4 $ +;// Checkin $Date: July 30, 2007 10:28:57 $ +;//########################################################################### +;// +;// FILE: DSP2833x_usDelay.asm +;// +;// TITLE: Simple delay function +;// +;// DESCRIPTION: +;// +;// This is a simple delay function that can be used to insert a specified +;// delay into code. +;// +;// This function is only accurate if executed from internal zero-waitstate +;// SARAM. If it is executed from waitstate memory then the delay will be +;// longer then specified. +;// +;// To use this function: +;// +;// 1 - update the CPU clock speed in the DSP2833x_Examples.h +;// file. For example: +;// #define CPU_RATE 6.667L // for a 150MHz CPU clock speed +;// or #define CPU_RATE 10.000L // for a 100MHz CPU clock speed +;// +;// 2 - Call this function by using the DELAY_US(A) macro +;// that is defined in the DSP2833x_Examples.h file. This macro +;// will convert the number of microseconds specified +;// into a loop count for use with this function. +;// This count will be based on the CPU frequency you specify. +;// +;// 3 - For the most accurate delay +;// - Execute this function in 0 waitstate RAM. +;// - Disable interrupts before calling the function +;// If you do not disable interrupts, then think of +;// this as an "at least" delay function as the actual +;// delay may be longer. +;// +;// The C assembly call from the DELAY_US(time) macro will +;// look as follows: +;// +;// extern void Delay(long LoopCount); +;// +;// MOV AL,#LowLoopCount +;// MOV AH,#HighLoopCount +;// LCR _Delay +;// +;// Or as follows (if count is less then 16-bits): +;// +;// MOV ACC,#LoopCount +;// LCR _Delay +;// +;// +;//########################################################################### +;// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +;// $Release Date: August 1, 2008 $ +;//########################################################################### + + ; Экспортирует символ для связывания с C-кодом. Операция: .def _DSP28x_usDelay. + .def _DSP28x_usDelay + ; Выбирает секцию объектного файла для следующих инструкций. Операция: .sect ".text". + .sect ".text" + + ; Объявляет глобальный символ для линкера. Операция: .global __DSP28x_usDelay. + .global __DSP28x_usDelay +; Объявляет метку _DSP28x_usDelay: для перехода или вызова. Операция: _DSP28x_usDelay:. +_DSP28x_usDelay: + ; Вычитает операнд и обновляет арифметическое состояние. Операция: SUB ACC,#1. + SUB ACC,#1 + ; Выполняет условный переход по флагам результата. Операция: BF _DSP28x_usDelay,GEQ. + BF _DSP28x_usDelay,GEQ ;; Loop if ACC >= 0 + ; Возвращает управление вызывающему коду через длинный адрес возврата. Операция: LRETR. + LRETR + +;There is a 9/10 cycle overhead and each loop +;takes five cycles. The LoopCount is given by +;the following formula: +; DELAY_CPU_CYCLES = 9 + 5*LoopCount +; LoopCount = (DELAY_CPU_CYCLES - 9) / 5 +; The macro DELAY_US(A) performs this calculation for you +; +;//=========================================================================== +;// End of file. +;//=========================================================================== diff --git a/c/set-protocol/CMakeLists.txt b/c/set-protocol/CMakeLists.txt index 6a6b56d..3e41d91 100644 --- a/c/set-protocol/CMakeLists.txt +++ b/c/set-protocol/CMakeLists.txt @@ -44,6 +44,7 @@ set(SETPROTOCOL_LEGACY_SOURCES ) set(SETPROTOCOL_SOURCES + src/deif_xdi.c # Общий DEIF-кодек и автомат SLAVE используются всеми платформами. src/set_regmap.c src/set_emu_ump.c src/set_emu_tms.c @@ -94,6 +95,9 @@ endif() option(SETP_BUILD_TESTS "Build host tests" ON) if(SETP_BUILD_TESTS) enable_testing() + add_executable(test_deif_xdi tests/test_deif_xdi.c) # Эталонные MPDO, пассивные 90° и сервисы SLAVE проверяются непосредственно в C. + target_link_libraries(test_deif_xdi PRIVATE setprotocol_static) # Тест вызывает ту же реализацию, что Python и Android. + add_test(NAME deif_xdi COMMAND test_deif_xdi "${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/deif-xdi-v1.tsv") # Общая fixture используется также JNI/JVM-портом. add_executable(test_emulator_services tests/test_emulator_services.c ports/example-emulator/service.c) target_link_libraries(test_emulator_services PRIVATE setprotocol_static) add_test(NAME emulator_services COMMAND test_emulator_services) diff --git a/c/set-protocol/docs/DEIF_XDI.md b/c/set-protocol/docs/DEIF_XDI.md new file mode 100644 index 0000000..598cb13 --- /dev/null +++ b/c/set-protocol/docs/DEIF_XDI.md @@ -0,0 +1,104 @@ +# Общее ядро DEIF XDi / CANopen + +Единственная реализация профиля DEIF находится в `include/deif_xdi.h` и +`src/deif_xdi.c`. Desktop использует её через `python/set_devices/deif_native.py`, +Android — через `ports/android/set_deif_jni.c` и `deif/DeifXdi.kt`. +Кодеки, адресация, числовой каталог, NMT, сроки, SDO и выбор азимута +не реализуются повторно в Python или Kotlin. + +Основание профиля: DEIF XDi-net/CANopen reference manual 4189350066D, +§§1–3, §9.11, Appendix 3 и Appendix 5. Набор переменных соответствует +наблюдаемой библиотеке: азимут, RPM, RPM%, мощность AC2 и POWER%. +Абсолютная мощность остаётся RAW до подтверждения её физической единицы. + +## Два режима + +- **Пассивный наблюдатель** принимает данные без включения симуляции, + ничего не отправляет, скрывает устаревшее показание через пять секунд. +- **CAN-SLAVE** принимает данные от внешнего MASTER и производит Boot-up, + heartbeat, EMCY и ответы на явно поддерживаемые SDO. После 3000 мс без + обновления поля сохраняет последнее валидное число и сообщает Data lost; + мигание выполняет GUI по готовой маске устаревших входов. + +Пассивный режим предназначен в том числе для обычного приёма показаний +без занятия собственного Node-ID в сети. На MPDO в активном режиме +также нет ответного PDO. В нормальном обмене SLAVE передаёт heartbeat. + +## Азимут + +Фактическое значение `0x3001:02` и сетевое задание `0x3001:07` хранятся +независимо. `setp_deif_angle` возвращает значение и его тип: + +- `0` — пригодного показания нет; +- `1` — фактический угол; +- `2` — принятое задание, которое GUI обязан подписывать как задание. + +При исходной привязке фактического угла до первого кадра `0x02` допускается +показывать принятое `0x07`. После первого фактического кадра задание его +не подменяет. Ошибочный фактический I16 также не заменяется старым заданием. +Явная ручная привязка к `0x07` остаётся индикатором задания. +Локальный черновик MASTER не входит в состояние C-модели. + +Эталонный кадр `STD 0x201 / 01 01 30 07 84 03 00 00` должен показывать +**90° · задание** и при выключенной симуляции. Node-ID физического SLAVE +не является источником этой SAM-рассылки: источник здесь Node 1. + +## Адресация и сервисы + +SAM согласует источник с COB-ID и поддерживает legacy broadcast `0x27F`. +DAM проверяет собственный Node-ID и выбранный RPDO. XDi-net резервирует +RPDO1 для SAM и Node 127 для сервисного прибора. Чистый CANopen допускает +DAM RPDO1. Все кадры профиля являются Classic CAN STD data frames. + +После Boot-up выдаётся Pre-operational; стандартный self-start занимает +1000 мс. Исходный период heartbeat — 500 мс. NMT Start/Stop/Pre-operational, +Reset node и Reset communication принимаются только для собственного узла +либо broadcast 0. Reset communication сохраняет прикладные значения и +возвращает несохранённые коммуникационные параметры к исходным значениям. + +SDO обслуживается в Operational и Pre-operational, в Stopped не отвечает. +Чтение: `0x1000:00`, `0x1001:00`, `0x1017:00`, `0x1018:00/01` и привязанные +I16-переменные. До обновления переменной возвращается `0x7FFF`. +Запись: U16 `0x1017:00`. Ноль отключает HB только вне XDi-net. +Неизвестный индекс, подиндекс, неподдерживаемая запись или команда дают +стандартный SDO abort. Серийный номер и код конкретного изделия не выдумываются. + +Это явный поднабор профиля индикации, а не полный EDS прошивки. LSS, +segmented SDO, EEPROM, произвольные конфигурационные записи, TPDO mapping, +двухканальное резервирование и механика привода не моделируются. + +## Контракт портов + +Память состояния выделяет вызывающий через `setp_deif_state_size`. +Буфер должен иметь выравнивание не слабее `uint64_t`; ctypes использует +массив `uint64`, JNI — direct ByteBuffer. Private-layout состояния не +передаётся между языками и не сериализуется. + +Все часы передаются как монотонные миллисекунды. C не вызывает ОС, +не использует Qt/JVM и не выделяет динамическую память. Каждый прибор +имеет отдельный контекст. JNI-порт сериализует операции экземпляра. + +`setp_deif_poll` выдаёт готовые кадры однократно. Порт обслуживает его +регулярно и после запросов SDO; очередь ограничена 16 событиями. Экранная +пауза CAN-журнала не должна останавливать протокол. Потеря подключения, +ошибка TX и закрытие владельца останавливают активный сервер. + +`setp_deif_make/master/service/angle_command` создают готовые сообщения. +`setp_deif_selector_info/readdress/route` обслуживают редакторы профиля: +UI не извлекает endian, смещения или адресные маски самостоятельно. +Локализованные тексты и мигание готовых показаний остаются в GUI. + +При отсутствии нативного ядра порт выдаёт явную ошибку. Python/Kotlin +fallback протокола отсутствует. Windows source build может использовать +дополнительную сборку того же C-ядра `setprotocol_deif.dll`; путь задаёт +приложение либо стандартный загрузчик находит компонент рядом с основной +DLL. Новый автономный EXE использует собственную основную DLL с DEIF. + +## Проверки + +`tests/fixtures/deif-xdi-v1.tsv` — единые эталонные байты для C, Python и JNI. +Их используют `tests/test_deif_xdi.c`, `python/tests/test_deif_shared.py` и +`ports/android/tests/.../deif/DeifXdiTest.kt`. Отдельно проверяются пассивные +90°, независимый фактический угол, Boot-up, NMT, heartbeat и отсутствие +выдуманного ответного PDO. Desktop дополнительно проверяет миграцию старой +пустой привязки без включения симуляции и без физического TX. diff --git a/c/set-protocol/docs/EMULATOR_SERVICES.md b/c/set-protocol/docs/EMULATOR_SERVICES.md index cbdec5d..cf934d8 100644 --- a/c/set-protocol/docs/EMULATOR_SERVICES.md +++ b/c/set-protocol/docs/EMULATOR_SERVICES.md @@ -1,5 +1,31 @@ # Универсальное адресное пространство эмуляторов +## Подключение панелей к конкретному MCU + +Каталог `python/set_devices/mcu_profiles.py` связывает платы с общими сервисами, +моделью `DEVICE_INFO`, настройками подключения и аппаратным таймером. +`python/set_devices/qt_ports/emulator_workspace.py` принимает готовые панели +потребителя по ключам `settings`, `ump`, `tms2812`, `igbt`, `wavegen` и выбирает +их состав методом `select_mcu`. Общие алгоритмы УМП, 2812, IGBT и ЦАП остаются +в описанном ниже C-ядре; новая панель не создаёт вторую модель или соединение. + +SETGUI подключает эти инструменты из страниц «Терминал → STM32 → MCU». +Поддержаны эмулятор STM32F407VET6 с TIM6 72 МГц и порт STM32G474RB с TIM6 +160 МГц. Параметры COM хранятся отдельно; расчёт частот ЦАП, подписи Vin +и проверяемая модель SET v2 соответствуют выбранной плате. Профиль MCU +нельзя переключать во время обмена. Сам выбор профиля не отправляет команды. + +Общий автомат обнаружения находится в `python/set_devices/emulator_protocol.py`, +COM-адаптер и клиент IGBT — в `python/set_devices/qt_ports/emulator_serial.py` +и `igbt_client.py`. Они не импортируют SETGUI. Старые пути SETGUI только +реэкспортируют эти реализации для совместимости. + +STM32G474VET6 с прошивкой CANdle имеет отдельный профиль BOOT: приложение +`0x08008000`, размер до 480 КиБ, CAN 500 кбит/с, Type 7 / Device 15 / +Product 0, либо USART1 PA9/PA10 на 512000 бод, 8N1. Это другая прошивка, +чем эмулятор STM32G474RB. Профиль BOOT готовит форму обновления и проверяет +векторы приложения до начала CAN-передачи. + Общий код находится в `templates/c/set-protocol`. Прошивка платы задаёт память, GPIO и аппаратные callbacks; протокол и модели не включают STM32/HAL/USB/ОС, не выделяют heap и не читают системное время. Все вызовы одного экземпляра diff --git a/c/set-protocol/include/deif_xdi.h b/c/set-protocol/include/deif_xdi.h new file mode 100644 index 0000000..7924820 --- /dev/null +++ b/c/set-protocol/include/deif_xdi.h @@ -0,0 +1,41 @@ +#ifndef SETP_DEIF_XDI_H /* Защита переносимого ABI от повторного включения. */ +#define SETP_DEIF_XDI_H /* Контракт DEIF одинаков для ctypes, JNI и прошивок. */ +#include "pcan_abi.h" /* Общий макрос экспорта и целочисленные типы стабильного ABI. */ +#ifdef __cplusplus /* C++-потребители должны видеть тот же немодифицированный ABI символов. */ +extern "C" { /* Реализация остаётся C99 для ctypes, JNI и MCU. */ +#endif /* Начало совместимого C ABI. */ +typedef struct { /* Готовый стандартный CAN-кадр; упаковка транспортного моста остаётся отдельным слоем. */ + uint32_t can_id; /* 11-битный COB-ID, вычисленный ядром. */ + uint32_t dlc; /* Число используемых байтов Classic CAN, от нуля до восьми. */ + uint8_t data[8]; /* Готовые wire-байты без преобразований в GUI. */ +} setp_deif_frame_t; /* Размер структуры фиксирован: 16 байт без указателей. */ +PCAN_ABI_API int setp_deif_version(void); /* Версия этого независимого расширения ABI. */ +PCAN_ABI_API size_t setp_deif_state_size(void); /* Размер состояния, память выделяет вызывающая сторона. */ +PCAN_ABI_API int setp_deif_catalog(unsigned field, int32_t *metadata); /* base, subindex, десятичное разрешение; поле 0…7. */ +PCAN_ABI_API int setp_deif_selector(unsigned field, unsigned node, unsigned instance, unsigned dam, uint8_t *out); /* Четырёхбайтный селектор без дублирования endian в портах. */ +PCAN_ABI_API int setp_deif_inspect(uint32_t id, const uint8_t *data, size_t size, unsigned flags, int32_t *out); /* Метаданные кадра и детерминированный код ошибки. */ +PCAN_ABI_API int setp_deif_make(unsigned field, unsigned node, unsigned instance, int32_t value, uint32_t id, unsigned dam, setp_deif_frame_t *out); /* Данные MASTER, яркость и палитра. */ +PCAN_ABI_API int setp_deif_master(unsigned node, const int32_t *values, uint32_t id, unsigned dam, unsigned angle_subindex, setp_deif_frame_t *out); /* Порядок пяти объектов MASTER хранится только в C-каталоге. */ +PCAN_ABI_API int setp_deif_service(unsigned kind, unsigned node, unsigned value, setp_deif_frame_t *out); /* kind=0 строит heartbeat, kind=1 — локальную команду NMT. */ +PCAN_ABI_API int setp_deif_angle_command(const setp_deif_frame_t *actual, setp_deif_frame_t *out); /* Строит отдельное задание из фактического угла без изменения wire-байтов в UI. */ +PCAN_ABI_API int setp_deif_selector_info(const uint8_t *selector, int32_t *out); /* Node, index, subindex и DAM для редактора привязок. */ +PCAN_ABI_API int setp_deif_readdress(const uint8_t *selector, unsigned node, unsigned mode, uint8_t *out); /* Переносит только адрес; mode=2 сохраняет текущий SAM/DAM. */ +PCAN_ABI_API int setp_deif_route(unsigned node, unsigned dam, uint32_t previous, unsigned operation, uint32_t *out); /* COB-ID, Node и адрес; operation=0 согласовать, 1 сохранить, 2 извлечь Node. */ +PCAN_ABI_API int setp_deif_validate(uint32_t id, const uint8_t *data, size_t size, unsigned flags, unsigned slave); /* slave=0 проверяет MASTER, иначе серверные ответы своего узла. */ +PCAN_ABI_API int setp_deif_init(void *state, size_t size, unsigned node, unsigned source, unsigned xdi, unsigned self_start, unsigned pdo, unsigned group, unsigned services, uint32_t monitor_id); /* Инициализация профиля без системных часов и heap. */ +PCAN_ABI_API int setp_deif_bind(void *state, unsigned field, const uint8_t *selector, double scale); /* Привязка индикатора к явному объекту библиотеки. */ +PCAN_ABI_API int setp_deif_get_binding(void *state, unsigned field, uint8_t *selector, double *scale); /* Готовая привязка и масштаб текущего C-профиля. */ +PCAN_ABI_API int setp_deif_default_angle(void *state, uint8_t *selector, double *scale); /* Восстановление отсутствующей старой привязки с адресацией существующих полей. */ +PCAN_ABI_API int setp_deif_start(void *state, uint64_t now, unsigned reset_values); /* Время задаётся монотонными миллисекундами порта. */ +PCAN_ABI_API void setp_deif_stop(void *state); /* Выключенный узел прекращает все служебные события. */ +PCAN_ABI_API void setp_deif_reset_values(void *state); /* Сбрасывает только измерения и их временные отметки. */ +PCAN_ABI_API int setp_deif_accept(void *state, uint32_t id, const uint8_t *data, size_t size, unsigned flags, uint64_t now); /* Приём STD MPDO, NMT и expedited SDO. */ +PCAN_ABI_API size_t setp_deif_poll(void *state, uint64_t now, setp_deif_frame_t *out, size_t capacity); /* Таймеры и однократная выдача очереди Boot-up/HB/EMCY/SDO. */ +PCAN_ABI_API int setp_deif_read(void *state, unsigned field, uint64_t now, unsigned expiry_ms, double *value, int64_t *metadata); /* metadata: seen_ms, raw, статус, флаги seen/valid/stale. */ +PCAN_ABI_API unsigned setp_deif_lost(void *state, uint64_t now); /* Маска входов без обновлений 3000 мс. */ +PCAN_ABI_API int setp_deif_angle(void *state, uint64_t now, unsigned expiry_ms, double *value); /* 1 — фактический угол, 2 — явно помеченное задание, 0 — нет данных. */ +PCAN_ABI_API int setp_deif_meta(void *state, int64_t *out); /* active, NMT, start, lastHB, period, accepted, group, brightness, palette, error. */ +#ifdef __cplusplus /* Закрываем C ABI перед возвратом в C++-контекст клиента. */ +} /* extern C не влияет на чистый C99-компилятор. */ +#endif /* Совместимость с C++-портами. */ +#endif /* SETP_DEIF_XDI_H: все алгоритмы находятся в единственном C99-модуле. */ diff --git a/c/set-protocol/include/set_signal.h b/c/set-protocol/include/set_signal.h index cf2a768..e302b52 100644 --- a/c/set-protocol/include/set_signal.h +++ b/c/set-protocol/include/set_signal.h @@ -27,6 +27,15 @@ enum { SET_SIGNAL_POLYNOMIAL, SET_SIGNAL_LINEAR, SET_SIGNAL_PCHIP, SET_SIGNAL_SP PCAN_ABI_API int set_signal_reconstruct(const double *x, const double *y, size_t count, int method, unsigned degree, size_t output_count, int endpoint, double *out_x, double *out_y, double *meta, double *work, size_t work_count); +/* Дополнительный решатель получает уникальные нормированные X/Y и пишет degree+1 + * коэффициентов по возрастанию степени для аргумента 2*x-1. Код 0 означает успех, + * 3 — недостаточный ранг, 5 — ошибку памяти/решателя. NULL сохраняет прежний МНК. + * C99-подготовка, интерполяция, RMSE и размещение work одинаковы для всех решателей. */ +typedef int (*set_signal_fit_fn)(const double *, const double *, size_t, unsigned, double *); /* Обратный вызов отделяет необязательный C++-порт от переносимого ядра. */ +PCAN_ABI_API int set_signal_reconstruct_with_fit( /* Расширение ABI не меняет сигнатуру существующей функции для прошивок и GUI. */ + const double *x, const double *y, size_t count, int method, unsigned degree, /* Входные точки и степень имеют те же ограничения, что у исходного API. */ + size_t output_count, int endpoint, double *out_x, double *out_y, /* Результат остаётся в памяти вызывающего и сохраняет выбор конечной точки. */ + double *meta, double *work, size_t work_count, set_signal_fit_fn fit); /* Решатель используется только для полинома; рабочая память сохраняет прежний формат. */ /* Reject out-of-range voltages, never silently clip. vref must be positive. * All input is validated before any output is written. */ PCAN_ABI_API int set_signal_dac12(const double *volts, size_t count, double vref, diff --git a/c/set-protocol/ports/android/Android.mk b/c/set-protocol/ports/android/Android.mk index de1ba13..567f11d 100644 --- a/c/set-protocol/ports/android/Android.mk +++ b/c/set-protocol/ports/android/Android.mk @@ -30,5 +30,6 @@ LOCAL_SRC_FILES := \ ../../src/pcan_gas.c \ setprotocol_jni.c LOCAL_CFLAGS := -std=c99 -Wall -Wextra -Wpedantic -fvisibility=hidden +LOCAL_SRC_FILES += ../../src/deif_xdi.c set_deif_jni.c # Единственные DEIF-правила компилируются вместе с тонким JNI-портом. LOCAL_LDLIBS := -llog -lm include $(BUILD_SHARED_LIBRARY) diff --git a/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/deif/DeifXdi.kt b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/deif/DeifXdi.kt new file mode 100644 index 0000000..77c42b9 --- /dev/null +++ b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/deif/DeifXdi.kt @@ -0,0 +1,60 @@ +package ru.setcorp.setprotocol.deif // Общий Android/JVM-порт находится в templates, без зависимости от приложения. +import java.nio.ByteBuffer // Caller-owned direct buffer обеспечивает выравнивание и управляемое JVM время жизни. +import ru.setcorp.setprotocol.NativeSetProtocol // Загрузку общей нативной библиотеки выполняет существующий порт. + +internal object NativeDeifBridge { // Только JNI-объявления; здесь нет второго кодека или автомата. + external fun size(): Int // Размер private C-состояния сообщает само ядро. + external fun initialize(state: ByteBuffer, node: Int, source: Int, xdi: Boolean, automatic: Boolean, pdo: Int, group: Int, services: Boolean, monitorId: Long): Boolean // Профиль проверяет C. + external fun start(state: ByteBuffer, nowMs: Long, reset: Boolean): Boolean // Время передаётся явно для воспроизводимых тестов. + external fun stop(state: ByteBuffer) // Выключенный сервер не производит heartbeat. + external fun accept(state: ByteBuffer, id: Long, data: ByteArray, flags: Int, nowMs: Long): Boolean // Байты обрабатывает общий C-код. + external fun poll(state: ByteBuffer, nowMs: Long): IntArray // Готовые события возвращаются скалярами id, dlc, data[8]. + external fun snapshot(state: ByteBuffer, nowMs: Long, expiryMs: Int): DoubleArray // Числа, статусы и сроки уже вычислены в C. + external fun inspect(id: Long, data: ByteArray, flags: Int): IntArray // Журнал получает единый результат декодирования. +} // ABI не раскрывает Kotlin layout внутренних структур. +data class DeifFrame(val canId: Long, val data: ByteArray) // Готовый STD data frame передаётся существующему CAN-транспорту приложения. +data class DeifSnapshot( // Неизменяемая модель пригодна для Compose, другого GUI и JVM-тестов. + val active: Boolean, val nmt: Int, val accepted: Int, // Жизненный цикл и число действительно принятых MPDO. + val brightness: Int, val palette: Int, // Значения текущего профиля подсветки. + val angle: Double?, val angleIsSetpoint: Boolean, // Фактический угол отделён от явно помеченного принятого задания. + val values: List, val statuses: List, val lostFields: Set, // Порядок полей задаёт общий ABI C, недействительные числа не подменяются нулями. +) // Снимок не содержит указателя на состояние C. +class DeifXdi(node: Int = 13, source: Int = 1, xdi: Boolean = true, automatic: Boolean = true, pdo: Int = 2, group: Int = 1, private val services: Boolean = false, monitorId: Long = 0) : AutoCloseable { // Один независимый прибор на экземпляр. + private val state: ByteBuffer // Память остаётся управляемой JVM, C не использует malloc. + init { // Отсутствующее ядро является явной ошибкой сборки, fallback на Kotlin запрещён. + check(NativeSetProtocol.available) { "Не загружено общее C-ядро DEIF" } // Приложение не должно молча использовать иной алгоритм. + state = ByteBuffer.allocateDirect(NativeDeifBridge.size()) // Размер и выравнивание не дублируют private C-структуру. + require(NativeDeifBridge.initialize(state, node, source, xdi, automatic, pdo, group, services, monitorId)) { "DEIF: неверный Node-ID, источник или RPDO" } // Ограничения XDi-net проверяет C. + } // Создание пассивного наблюдателя ничего не отправляет. + @Synchronized fun start(nowMs: Long, resetValues: Boolean = true) { // NMT и таймеры безопасны при приёме и тиках из разных потоков. + check(NativeDeifBridge.start(state, nowMs, resetValues)) { "Не удалось запустить DEIF" } // Boot-up создаётся только в C-сервере. + } // Физическую отправку выбирает приложение по результату poll. + @Synchronized fun accept(id: Long, data: ByteArray, extended: Boolean = false, remote: Boolean = false, nowMs: Long): Boolean { // Имя транспорта фильтруется приложением до этого вызова. + return NativeDeifBridge.accept(state, id, data, (if (extended) 1 else 0) or (if (remote) 2 else 0), nowMs) // Флаги описывают тип CAN, payload не разбирается в Kotlin. + } // C различает NMT, MPDO, heartbeat и SDO. + @Synchronized fun poll(nowMs: Long): List { // События выдаются один раз, даже если экран журнала стоит на паузе. + return NativeDeifBridge.poll(state, nowMs).asList().chunked(10).map { row -> DeifFrame(row[0].toLong(), ByteArray(row[1]) { row[it + 2].toByte() }) } // Это раскладка скалярного ABI JNI, а не CAN-кодек. + } // Готовые byte arrays не меняются в транспортном слое. + @Synchronized fun snapshot(nowMs: Long): DeifSnapshot { // Тайм-аут наблюдателя сохраняет совместимость Desktop; сервер хранит число при Data lost. + val raw = NativeDeifBridge.snapshot(state, nowMs, if (services) 0 else 5000) // Правило выбора и свежести вычисляет C. + return DeifSnapshot(raw[0] != 0.0, raw[1].toInt(), raw[5].toInt(), raw[7].toInt(), raw[8].toInt(), if (raw[34] != 0.0) raw[35] else null, raw[34] == 2.0, // Метаданные профиля и готовый азимут. + List(6) { field -> val flags = raw[13 + field * 4].toInt(); if (flags and 2 != 0 && flags and 4 == 0) raw[10 + field * 4] else null }, // Порт отображает valid/stale-флаги, не повторяя таймеры. + List(6) { raw[12 + it * 4].toInt() }, (0..5).filter { raw[36].toInt() and (1 shl it) != 0 }.toSet()) // Имена и цвета ошибок остаются ответственностью GUI. + } // Снимок можно использовать в UI без обращения к байтам протокола. + @Synchronized override fun close() { NativeDeifBridge.stop(state) } // Жизненный цикл отменяет heartbeat и очередь до закрытия адаптера. + companion object { // Диагностическое представление не содержит второго парсера. + fun inspect(id: Long, data: ByteArray, extended: Boolean = false, remote: Boolean = false): IntArray { // Приложение передаёт целый транспортный кадр. + check(NativeSetProtocol.available) { "Не загружено общее C-ядро DEIF" } // Без C-декодера никакого угадывания формата нет. + return NativeDeifBridge.inspect(id, data, (if (extended) 1 else 0) or (if (remote) 2 else 0)) // Индексы результата закреплены ABI deif_xdi.h. + } // Один и тот же вход даёт одинаковые поля в Python и Android. + fun summary(id: Long, data: ByteArray, extended: Boolean = false, remote: Boolean = false): String { // Только локализованный текст поверх метаданных C. + val m = inspect(id, data, extended, remote) // Никакого endian-разбора в Kotlin. + return when (m[0]) { // Код результата сообщает общий декодер. + 2 -> "Heartbeat/Boot-up · Node ${m[2]} · NMT ${m[11]}" // Состояние относится к узлу, а не к подтверждению показаний. + 1 -> "DEIF Node ${m[2]} · 0x%04X:%02X · RAW %d".format(m[3], m[4], m[5]) // Физические единицы показывает отдельный снимок модели. + 3 -> "DEIF · яркость/Color · ${m[5]}" // U8 подсветки не получает масштаб RPM. + else -> "DEIF: кадр не принят, код ${m[0]}" // Неизвестный объект не интерпретируется заново портом. + } // Текст не влияет на протокольное принятие. + } // Журнал и индикатор используют один C-каталог. + } // Общий порт не зависит от конкретного Android-приложения. +} // Контекст освобождается JVM после закрытия владельца. diff --git a/c/set-protocol/ports/android/set_deif_jni.c b/c/set-protocol/ports/android/set_deif_jni.c new file mode 100644 index 0000000..a637be5 --- /dev/null +++ b/c/set-protocol/ports/android/set_deif_jni.c @@ -0,0 +1,32 @@ +#include /* JNI здесь преобразует только контейнеры Java и указатели C. */ +#include "deif_xdi.h" /* Все правила DEIF принадлежат общему переносимому ядру. */ +static void *deif_context(JNIEnv *e,jobject b) { /* Direct ByteBuffer владеет памятью состояния и освобождается JVM. */ + if(!b || (*e)->GetDirectBufferCapacity(e,b)<(jlong)setp_deif_state_size()) return NULL; return (*e)->GetDirectBufferAddress(e,b); /* Не допускаем короткий либо недиректный буфер. */ +} /* JNI не копирует private-layout структуры. */ +static int deif_input(JNIEnv *e,jbyteArray a,uint8_t *d) { /* Classic CAN ограничен восемью байтами. */ + jsize n; if(!a) return -1; n=(*e)->GetArrayLength(e,a); if(n>8) return -1; (*e)->GetByteArrayRegion(e,a,0,n,(jbyte *)d); return (int)n; /* Буфер локален текущему вызову JNI. */ +} /* Время жизни Java-указателей не пересекает вызов. */ +JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_size(JNIEnv *e,jobject self) { (void)e; (void)self; return (jint)setp_deif_state_size(); } /* Kotlin выделяет точно нужный объём без heap в C. */ +JNIEXPORT jboolean JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_initialize(JNIEnv *e,jobject self,jobject b,jint node,jint source,jboolean xdi,jboolean automatic,jint pdo,jint group,jboolean services,jlong id) { /* Параметры профиля передаются без повторения правил. */ + void *s=deif_context(e,b); (void)self; if(!s || id<0 || id>0x1FFFFFFF) return JNI_FALSE; return setp_deif_init(s,setp_deif_state_size(),(unsigned)node,(unsigned)source,xdi!=0,automatic!=0,(unsigned)pdo,(unsigned)group,services!=0,(uint32_t)id)?JNI_TRUE:JNI_FALSE; /* Сервисный Node и RPDO проверяет C. */ +} /* Источником исходных привязок остаётся C-каталог. */ +JNIEXPORT jboolean JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_start(JNIEnv *e,jobject self,jobject b,jlong now,jboolean reset) { (void)self; return now>=0 && setp_deif_start(deif_context(e,b),(uint64_t)now,reset!=0)?JNI_TRUE:JNI_FALSE; } /* Часы Android передаются в монотонных миллисекундах. */ +JNIEXPORT void JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_stop(JNIEnv *e,jobject self,jobject b) { (void)self; setp_deif_stop(deif_context(e,b)); } /* Закрытие сервера прекращает очередь событий. */ +JNIEXPORT jboolean JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_accept(JNIEnv *e,jobject self,jobject b,jlong id,jbyteArray a,jint flags,jlong now) { /* Принимается готовый транспортом CAN-кадр. */ + uint8_t d[8]; int n=deif_input(e,a,d); (void)self; if(n<0 || id<0 || id>0x1FFFFFFF || now<0) return JNI_FALSE; return setp_deif_accept(deif_context(e,b),(uint32_t)id,d,(size_t)n,(unsigned)flags,(uint64_t)now)?JNI_TRUE:JNI_FALSE; /* JNI не разбирает индекс, подиндекс или signed I16. */ +} /* C обслуживает адресацию, NMT и SDO одинаково для Desktop и Android. */ +JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_poll(JNIEnv *e,jobject self,jobject b,jlong now) { /* Очередь возвращается массивом скаляров ABI, а не вторым CAN-пакетом. */ + setp_deif_frame_t frames[16]; jint values[160]; size_t n,i,j; jintArray result; (void)self; if(now<0) return NULL; n=setp_deif_poll(deif_context(e,b),(uint64_t)now,frames,16); /* Все исходящие байты уже сформированы C-ядром. */ + for(i=0;iNewIntArray(e,(jsize)(n*10)); if(result) (*e)->SetIntArrayRegion(e,result,0,(jsize)(n*10),values); return result; /* Владение результатом передаётся JVM. */ +} /* JNI не создаёт фиктивного ответного PDO. */ +JNIEXPORT jdoubleArray JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_snapshot(JNIEnv *e,jobject self,jobject b,jlong now,jint expiry) { /* Универсальный скалярный снимок пригоден без Compose. */ + void *s=deif_context(e,b); int64_t meta[10],m[4]; jdouble values[37]; double v; unsigned i; jdoubleArray result; (void)self; if(now<0 || expiry<0 || !setp_deif_meta(s,meta)) return NULL; /* Layout состояния не дублируется в Kotlin. */ + for(i=0;i<10;i++) values[i]=(double)meta[i]; for(i=0;i<6;i++) { setp_deif_read(s,i,(uint64_t)now,(unsigned)expiry,&v,m); values[10+i*4]=v; values[11+i*4]=(double)m[0]; values[12+i*4]=(double)m[2]; values[13+i*4]=(double)m[3]; } /* Масштабы, статусы и свежесть вычислены C. */ + values[34]=(double)setp_deif_angle(s,(uint64_t)now,(unsigned)expiry,&v); values[35]=v; values[36]=setp_deif_lost(s,(uint64_t)now); /* Факт, задание и Data lost определяются общим алгоритмом. */ + result=(*e)->NewDoubleArray(e,37); if(result) (*e)->SetDoubleArrayRegion(e,result,0,37,values); return result; /* Java получает независимый неизменяемый снимок. */ +} /* Здесь нет системных часов и транспортного ввода-вывода. */ +JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_deif_NativeDeifBridge_inspect(JNIEnv *e,jobject self,jlong id,jbyteArray a,jint flags) { /* Общий декодер доступен также журналу Android. */ + uint8_t d[8]; int32_t m[12]={0}; jint values[13]; int n=deif_input(e,a,d),code; unsigned i; jintArray result; (void)self; code=n<0 || id<0 || id>0x1FFFFFFF?-1:setp_deif_inspect((uint32_t)id,d,(size_t)n,(unsigned)flags,m); /* Только C знает wire-формат DEIF. */ + values[0]=code; for(i=0;i<12;i++) values[i+1]=m[i]; result=(*e)->NewIntArray(e,13); if(result) (*e)->SetIntArrayRegion(e,result,0,13,values); return result; /* Метаданные индексируются по ABI, не по смещениям CAN-data. */ +} /* Локализованные подписи формирует Kotlin. */ diff --git a/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/deif/DeifXdiTest.kt b/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/deif/DeifXdiTest.kt new file mode 100644 index 0000000..c43038d --- /dev/null +++ b/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/deif/DeifXdiTest.kt @@ -0,0 +1,34 @@ +package ru.setcorp.setprotocol.deif // JVM-тест использует тот же пакет и JNI-порт, что Android GUI. +import org.junit.Assert.* // Сверяются значения, тип индикации и точные служебные байты. +import org.junit.Test // Обычный локальный JUnit запускает нативную host-библиотеку. +class DeifXdiTest { // В тесте отсутствует Kotlin-копия протокола. + private fun bytes(hex: String) = hex.chunked(2).map { it.toInt(16).toByte() }.toByteArray() // Конвертируется только текст тестовой fixture. + @Test fun sameVectorsAsCAndPython() { // Общий TSV фиксирует межъязыковую совместимость кодека. + val lines = javaClass.getResourceAsStream("/deif-xdi-v1.tsv")!!.bufferedReader().use { it.readLines() } // Fixture поставляется тем же submodule templates. + lines.filter { it.isNotBlank() && !it.startsWith("#") }.forEach { line -> // Комментарии не являются тестовыми пакетами. + val row = line.trim().split(Regex("\\s+")) // Столбцы описывают ожидаемый результат независимо от реализации C. + val flags = row[2].toInt() // Метаданные теста задают STD/EXT/RTR. + val result = DeifXdi.inspect(row[0].toLong(16), bytes(row[1]), flags and 1 != 0, flags and 2 != 0) // JNI вызывает единственный C-декодер. + assertEquals(line, row[3].toInt(), result[0]); assertEquals(line, row[4].toInt(), result[5]) // Сверяем тип принятия и знаковый RAW. + assertEquals(line, row[5].toInt(16), result[3]); assertEquals(line, row[6].toInt(16), result[4]) // Индекс и подиндекс не декодируются повторно в Kotlin. + } // Каждый ошибочный формат проверяется тем же контрактом. + } // Тест не зависит от Android Runtime. + @Test fun passiveNinetyDegreesDoesNotRequireSimulation() { // Воспроизводит выключенный флаг симуляции на снимке пользователя. + DeifXdi().use { model -> // Пассивный наблюдатель не создаёт heartbeat. + assertTrue(model.accept(0x201, bytes("0101300784030000"), nowMs = 10000)) // MASTER Node 1 передаёт сетевое задание RAW 900. + assertEquals(90.0, model.snapshot(10000).angle!!, 0.0); assertTrue(model.snapshot(10000).angleIsSetpoint) // 90° видны с честной пометкой задания. + assertTrue(model.poll(10000).isEmpty()) // Показание не требует физической отправки или включённого SLAVE-сервера. + assertTrue(model.accept(0x201, bytes("01013002E5010000"), nowMs = 10100)) // Отдельное фактическое сообщение передаёт 48,5°. + assertEquals(48.5, model.snapshot(10100).angle!!, 0.0); assertFalse(model.snapshot(10100).angleIsSetpoint) // Угол и тип отображения совпадают с C- и Python-тестами. + } // Close освобождает протокольный сеанс, память direct buffer управляется JVM. + } // Черновика MASTER в API общего ядра вообще нет. + @Test fun slaveOnlySendsHeartbeatForNormalMpdo() { // Обычный приём рассылки не должен создавать ответный PDO. + DeifXdi(node = 13, services = true).use { model -> // Сервисный режим использует адрес Node 13. + model.start(0); val boot = model.poll(0).single() // Boot-up должен быть выдан ровно один раз. + assertEquals(0x70DL, boot.canId); assertArrayEquals(byteArrayOf(0), boot.data) // COB-ID и DLC совпадают с физическим DEIF-профилем. + assertArrayEquals(byteArrayOf(5), model.poll(1000).single().data) // Self-start завершается через 1000 мс. + assertTrue(model.accept(0x201, bytes("0101300784030000"), nowMs = 1000)) // Измерение принимается через общий C-автомат. + assertTrue(model.poll(1000).isEmpty()); assertEquals(90.0, model.snapshot(1000).angle!!, 0.0) // Есть обновлённое показание, но отсутствует выдуманный ACK-PDO. + } // Нативная очередь останавливается при закрытии владельца. + } // Все события проверены на точных монотонных сроках. +} // Этот же класс теста подключается к Android sourceSets из templates. diff --git a/c/set-protocol/src/deif_xdi.c b/c/set-protocol/src/deif_xdi.c new file mode 100644 index 0000000..dc23a45 --- /dev/null +++ b/c/set-protocol/src/deif_xdi.c @@ -0,0 +1,185 @@ +#include "deif_xdi.h" /* Публичный ABI не зависит от Python, Kotlin, Qt или Android. */ +#include /* Фиксированные структуры копируются без динамической памяти. */ +#include /* Проверка конечности пользовательского масштаба предотвращает недопустимые показания. */ +#define DEIF_MAGIC 0x44454946U /* Метка DEIF отличает валидный caller-owned контекст. */ +#define DEIF_FIELDS 6U /* POWER, RPM, фактический угол, POWER%, RPM%, задание угла. */ +#define DEIF_QUEUE 16U /* Ограниченная очередь покрывает Boot-up, heartbeat и ответы без heap. */ +typedef struct { /* Привязка и последнее сообщение одного индикатора. */ + uint8_t selector[4]; /* SAM/DAM, индекс LE и подиндекс сохраняются в wire-порядке. */ + double scale; /* Множитель физической величины задаётся библиотекой прибора. */ + uint64_t seen; /* Монотонные миллисекунды последнего принятого объекта. */ + int32_t raw; /* Исходный I16 хранится без обратного округления показания. */ + unsigned bound, received, status; /* Привязка, наличие кадра и служебный статус I16. */ +} deif_binding; /* Внутренний layout не является частью публичного ABI. */ +typedef struct { /* Всё состояние принадлежит порту, часы и транспорт в ядре отсутствуют. */ + uint32_t magic, monitor_id; /* Метка контекста и точный CAN ID пассивного наблюдателя. */ + unsigned node, source, xdi, self_start, pdo, group, services; /* Профиль по DEIF 4189350066D. */ + unsigned active, nmt, heartbeat, accepted, brightness, palette, error, queued; /* Изменяемые коммуникационные параметры сеанса. */ + uint64_t started, last_hb, auto_at; /* Независимые сроки в монотонных миллисекундах. */ + deif_binding field[DEIF_FIELDS]; /* Каждый вход имеет собственные данные и срок свежести. */ + setp_deif_frame_t queue[DEIF_QUEUE]; /* Служебные кадры выдаются только один раз через poll. */ +} deif_state; /* Размер сообщает state_size, порты не повторяют эту структуру. */ +static const uint16_t bases[8] = {0x3420,0x3080,0x3000,0x3430,0x3090,0x3000,0x3500,0x3500}; /* Опубликованные семейства переменных и диммера. */ +static const uint8_t subs[8] = {2,2,2,2,2,7,2,3}; /* Фактическое значение, отдельное задание, яркость и палитра. */ +static deif_state *context(void *p) { /* Все публичные функции проверяют инициализацию состояния. */ + deif_state *s = (deif_state *)p; /* Порт выделяет выровненную память через uint64 либо direct ByteBuffer. */ + return s && s->magic == DEIF_MAGIC ? s : NULL; /* Невалидный указатель контекста не трактуется как работающий узел. */ +} /* Проверка не обращается к ОС. */ +static uint16_t le16(const uint8_t *p) { return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } /* Единственная реализация little-endian U16. */ +static void put16(uint8_t *p, uint16_t v) { p[0]=(uint8_t)v; p[1]=(uint8_t)(v>>8); } /* Обратное преобразование принадлежит тому же C-кодеку. */ +static void put32(uint8_t *p, uint32_t v) { unsigned i; for(i=0;i<4;i++) p[i]=(uint8_t)(v>>(8U*i)); } /* SDO и EMCY используют младший байт первым. */ +static unsigned raw_status(int32_t raw) { return raw == -32768 ? 1U : raw == 32766 ? 2U : raw == 32767 ? 3U : 0U; } /* §2.1.2: три зарезервированных значения I16. */ +static int address(uint32_t id, unsigned node, unsigned dam) { /* Проверка адреса применяется одинаково в обоих GUI. */ + if(!node || node>127U) return 0; /* Нулевой адрес не является источником или получателем MPDO. */ + return dam ? (id==0x200U+node || id==0x300U+node || id==0x400U+node || id==0x500U+node) : (id==0x200U+node || id==0x27FU); /* RPDO1…4 либо SAM с исключением service broadcast. */ +} /* Номер получателя не подменяет источник SAM. */ +int setp_deif_version(void) { return 1; } /* Независимая версия расширения ABI. */ +size_t setp_deif_state_size(void) { return sizeof(deif_state); } /* Клиент не зависит от внутренних паддингов структуры. */ +int setp_deif_catalog(unsigned f, int32_t *o) { /* Каталог является единственным источником числовых индексов. */ + if(f>=8U || !o) return 0; /* Неизвестное поле не создаёт фиктивный объект. */ + o[0]=bases[f]; o[1]=subs[f]; o[2]=(f==0U ? 127 : f<6U ? -1 : 0); return 1; /* 127 означает неизвестную физическую единицу POWER, прочие разрешения заданы в десятичной степени. */ +} /* Тексты и локализация остаются в GUI-портах. */ +int setp_deif_selector(unsigned f,unsigned node,unsigned instance,unsigned dam,uint8_t *o) { /* Формирует четыре байта привязки из каталога. */ + if(f>=8U || !o || node<1U || node>127U || instance<1U || instance>(f<6U?15U:9U) || dam>1U) return 0; /* Проверяет границы Node, экземпляра и сетевой группы. */ + o[0]=(uint8_t)(node|(dam?128U:0U)); put16(o+1,(uint16_t)(bases[f]+instance)); o[3]=subs[f]; return 1; /* Индекс и режим MPDO собираются только здесь. */ +} /* В портах нет копии wire-разметки. */ +int setp_deif_inspect(uint32_t id,const uint8_t *d,size_t n,unsigned flags,int32_t *o) { /* Коды ошибок сохраняют причину для локализованной диагностики. */ + unsigned i,node,index,sub,instance; int field=-1; /* Промежуточные поля ограничены размерами Classic CAN. */ + if(!o || (!d && n)) return -1; /* Отсутствующий вход не разыменовывается. */ + memset(o,0,12U*sizeof(*o)); if(flags) return -1; /* EXT и RTR не интерпретируются как XDi STD data frames. */ + if(id>=0x701U && id<=0x77FU) { /* Heartbeat и Boot-up имеют отдельный формат DLC1. */ + o[1]=(int32_t)(id-0x700U); if(n!=1U) return -2; o[10]=d[0]; o[0]=2; /* Сохраняем Node-ID и исходный NMT-байт даже при неизвестном коде. */ + return d[0]==0U || d[0]==4U || d[0]==5U || d[0]==127U ? 2 : -3; /* Toggle-бит node guarding не снимается автоматически. */ + } /* Переменные и диммер разбираются следующим общим путём. */ + if(id<0x201U || id>0x57FU) return 0; if(n!=8U) return -4; /* Неизвестный COB-ID отделён от неправильного DLC MPDO. */ + node=d[0]&127U; index=le16(d+1); sub=d[3]; instance=index&15U; /* Семейства переменных имеют по пятнадцать экземпляров. */ + o[1]=(int32_t)node; o[2]=(int32_t)index; o[3]=(int32_t)sub; o[4]=(int16_t)le16(d+4); o[6]=(int32_t)instance; o[8]=(d[0]&128U)!=0; o[9]=(d[6]==0U && d[7]==0U); /* Метаданные не требуют повторного endian-разбора в Python или Kotlin. */ + if(!address(id,node,(unsigned)o[8])) return -5; /* Включает согласование источника SAM с COB-ID. */ + for(i=0;i<6U;i++) if((index&0xFFF0U)==bases[i] && instance && (sub==2U || sub==7U)) { field=(int)i; break; } /* Известные переменные разрешают фактическое значение и задание. */ + if(index>=0x3501U && index<=0x3509U && (sub==2U || sub==3U)) { o[0]=3; o[5]=sub==2U?6:7; o[4]=d[4]; return 3; } /* Диммер имеет U8, а не I16. */ + if(field<0) return -6; o[0]=1; o[5]=field; o[7]=(int32_t)raw_status(o[4]); return 1; /* Служебный I16 не становится физическим измерением. */ +} /* Ненулевые старшие байты отмечаются отдельно, приёмник их отклонит. */ +int setp_deif_make(unsigned f,unsigned node,unsigned instance,int32_t v,uint32_t id,unsigned dam,setp_deif_frame_t *o) { /* Сборка данных, яркости и Color для всех платформ. */ + if(!id) id=0x200U+node; /* Нулевой аргумент выбирает исходный RPDO1 без копии формулы в портах. */ + if(!o || !address(id,node,dam) || (f<6U?(v< -32768 || v>32767):(f==6U?(v<0 || v>100):(f!=7U || v<0 || v>2)))) return 0; /* Значения проверяются до сужения разрядности. */ + memset(o,0,sizeof(*o)); o->can_id=id; o->dlc=8; if(!setp_deif_selector(f,node,instance,dam,o->data)) return 0; /* Неизвестное поле или экземпляр не создаёт частичный кадр. */ + if(f<6U) put16(o->data+4,(uint16_t)v); else o->data[4]=(uint8_t)v; return 1; /* Старшие байты всегда нулевые согласно §3.2.1. */ +} /* Передача готового кадра остаётся обязанностью транспорта. */ +int setp_deif_master(unsigned node,const int32_t *v,uint32_t id,unsigned dam,unsigned angle_subindex,setp_deif_frame_t *o) { /* Цикл MASTER использует единственный каталог и единственную сборку MPDO. */ + static const unsigned order[5]={2,1,4,0,3}; unsigned i,f; if(!v || !o || (angle_subindex!=2U && angle_subindex!=7U)) return 0; /* Подиндекс азимута выбирается явно, неизвестные коды не подставляются автоматически. */ + for(i=0;i<5U;i++) { f=i==0U && angle_subindex==7U?5U:order[i]; if(!setp_deif_make(f,node,1,v[i],id,dam,&o[i])) return 0; } return 5; /* Все кадры сохраняют один Node-ID, режим и COB-ID. */ +} /* Неуспешный цикл не должен передаваться портом частично. */ +int setp_deif_service(unsigned kind,unsigned node,unsigned value,setp_deif_frame_t *o) { /* Готовые служебные кадры не собираются повторно в GUI. */ + if(!o || node>127U || kind>1U) return 0; memset(o,0,sizeof(*o)); /* Границы проверяются до сужения байтов. */ + if(!kind) { if(!node || (value!=0U && value!=4U && value!=5U && value!=127U)) return 0; o->can_id=0x700U+node; o->dlc=1; o->data[0]=(uint8_t)value; } /* Boot-up и heartbeat своего CANopen-узла. */ + else { if(value!=1U && value!=2U && value!=128U && value!=129U && value!=130U) return 0; o->dlc=2; o->data[0]=(uint8_t)value; o->data[1]=(uint8_t)node; } return 1; /* NMT допускает broadcast 0 и передаёт два байта в COB-ID 0. */ +} /* Отправка физическому или локальному получателю остаётся за портом. */ +int setp_deif_angle_command(const setp_deif_frame_t *a,setp_deif_frame_t *o) { /* Перевод фактического азимута в независимый set-point использует тот же каталог. */ + int32_t m[12]; if(!a || setp_deif_inspect(a->can_id,a->data,a->dlc,0,m)!=1 || (m[2]&0xFFF0)!=0x3000) return 0; return setp_deif_make(5,(unsigned)m[1],(unsigned)m[6],m[4],a->can_id,(unsigned)m[8],o); /* Источник, экземпляр и RAW не вычисляются повторно в Python. */ +} /* Это второй отдельный CAN-кадр, не подмена фактического объекта. */ +int setp_deif_selector_info(const uint8_t *s,int32_t *o) { /* Общий разбор пользовательского селектора для всех редакторов. */ + if(!s || !o || !(s[0]&127U)) return 0; o[0]=s[0]&127U; o[1]=le16(s+1); o[2]=s[3]; o[3]=(s[0]&128U)!=0; return 1; /* Текст HEX остаётся форматом настроек, wire-геометрия находится в C. */ +} /* Неизвестные библиотечные индексы могут быть явно привязаны пользователем. */ +int setp_deif_readdress(const uint8_t *s,unsigned node,unsigned mode,uint8_t *o) { /* Перенос старого профиля не требует wire-масок в приложении. */ + if(!s || !o || !node || node>127U || mode>2U) return 0; memcpy(o,s,4); o[0]=(uint8_t)(node|(mode==2U?(s[0]&128U):(mode?128U:0U))); return 1; /* Индекс и подиндекс сохраняются побайтно, включая ручные объекты библиотеки. */ +} /* Адресный байт меняется единственным общим правилом. */ +int setp_deif_route(unsigned node,unsigned dam,uint32_t id,unsigned op,uint32_t *o) { /* Общая настройка COB-ID не смешивается с физическим каналом приложения. */ + if(!o || dam>1U || op>2U || (op==2U && (id<0x201U || id>0x57FU))) return 0; if(op==2U && (id!=0x27FU || dam)) node=id&127U; if(!node) node=1; if(node>127U) return 0; /* Legacy SAM 0x27F сохраняет явно выбранный источник. */ + if(!op) id=dam?(id/0x100U)*0x100U+node:(id==0x27FU?id:0x200U+node); o[0]=id; o[1]=node; o[2]=node|(dam?128U:0U); return 1; /* RPDO-база DAM сохраняется, SAM использует исходный диапазон XDi-net. */ +} /* Точный допустимый адрес проверяется кодеком перед отправкой. */ +int setp_deif_validate(uint32_t id,const uint8_t *d,size_t n,unsigned flags,unsigned slave) { /* Разделяет выход MASTER и события собственного SLAVE. */ + int32_t m[12]; int k; if(flags || (!d && n)) return 0; /* RTR/EXT запрещены в обоих маршрутах. */ + if(slave) { /* Сервер не может посылать запросы конфигурации другим узлам. */ + if(slave>127U) return 0; if(id==0x700U+slave && n==1U) return d[0]==0U || d[0]==4U || d[0]==5U || d[0]==127U; /* Только собственные NMT-состояния. */ + if(id==0x580U+slave && n==8U) return d[0]==0x43U || d[0]==0x47U || d[0]==0x4BU || d[0]==0x4FU || d[0]==0x60U || d[0]==0x80U; /* Только ответы expedited SDO либо abort. */ + if(id==0x80U+slave && n==8U) { static const uint8_t lost[8]={0,0x81,0x81,6,0,0,0,0}; static const uint8_t clear[8]={0}; return !memcmp(d,lost,8) || !memcmp(d,clear,8); } /* Data lost и сброс по Appendix 5. */ + return 0; /* Чужие идентификаторы и ответные PDO не разрешены. */ + } /* MASTER сохраняет отдельный ограниченный набор команд. */ + k=setp_deif_inspect(id,d,n,0,m); if(k==2) return d[0]==5U; if(k!=1 && k!=3) return 0; /* Обычный MASTER не передаёт NMT, SDO и Boot-up. */ + if(!m[9]) return 0; if(k==3) return d[5]==0U && (m[5]==6 ? d[4]<=100U : d[4]<=2U); return 1; /* Значения диммера проверяются как U8 с нулевым хвостом. */ +} /* Проверка не производит физический TX. */ +static void event(deif_state *s,uint32_t id,const uint8_t *d,unsigned n) { /* Очередь имеет явную ограниченную вместимость. */ + setp_deif_frame_t *f; if(s->queued>=DEIF_QUEUE) return; f=&s->queue[s->queued++]; memset(f,0,sizeof(*f)); f->can_id=id; f->dlc=n; memcpy(f->data,d,n); /* Один event соответствует одному готовому CAN-кадру. */ +} /* Порты регулярно выгружают очередь через poll. */ +int setp_deif_init(void *p,size_t size,unsigned node,unsigned source,unsigned xdi,unsigned self_start,unsigned pdo,unsigned group,unsigned services,uint32_t monitor_id) { /* Общий конструктор наблюдателя и серверного SLAVE. */ + deif_state *s=(deif_state *)p; unsigned f; uint8_t selector[4]; /* Селекторы строятся тем же общим каталогом. */ + if(!s || size(services?126U:127U) || group>9U || pdo<1U || pdo>4U || (services && (!node || node>(xdi?126U:127U) || (xdi && pdo==1U)))) return 0; /* Источник обычной рассылки не занимает сервисный Node 127; RPDO1 резервируется в XDi-net. */ + memset(s,0,sizeof(*s)); s->magic=DEIF_MAGIC; s->node=node; s->source=source; s->xdi=xdi; s->self_start=xdi||self_start; s->pdo=pdo; s->group=group; s->services=services; s->monitor_id=monitor_id?monitor_id:0x200U+source; /* Исходный CAN ID источника вычисляется в C, без копии формулы в Kotlin. */ + s->heartbeat=500; s->brightness=100; s->nmt=services?127U:5U; s->active=!services; /* Пассивный наблюдатель не выдаёт heartbeat и сразу принимает данные. */ + for(f=0;f=DEIF_FIELDS || !isfinite(scale)) return 0; /* Неверный масштаб не попадает в снимок индикатора. */ + b=&s->field[f]; bound=selector && (selector[0]||selector[1]||selector[2]||selector[3]); if(b->bound==bound && b->scale==scale && (!bound || !memcmp(b->selector,selector,4))) return 1; /* Повторная синхронизация порта не стирает принятые значения. */ + memset(b,0,sizeof(*b)); b->bound=bound; b->scale=scale; if(bound) memcpy(b->selector,selector,4); /* Новая привязка начинает собственный срок ожидания. */ + if(f==2U) { uint8_t cmd[4]; if(bound && (le16(selector+1)&0xFFF0U)==0x3000U) { memcpy(cmd,selector,4); cmd[3]=7; setp_deif_bind(s,5,cmd,scale); } else setp_deif_bind(s,5,NULL,scale); } return 1; /* Задание угла выводится отдельно даже при пассивном наблюдении. */ +} /* Выбор фактического или заданного объекта сохраняется в исходной привязке. */ +int setp_deif_default_angle(void *p,uint8_t *o,double *scale) { /* Миграция старой пустой привязки использует уже настроенную адресацию прибора. */ + deif_state *s=context(p); unsigned f,addr; if(!s || !o || !scale) return 0; addr=s->source; /* При отсутствии других полей применяется источник профиля. */ + for(f=0;ffield[f].bound) { addr=s->field[f].selector[0]; break; } /* SAM-источник либо DAM-получатель берётся без предположений UI. */ + *scale=0.1; return setp_deif_selector(2,addr&127U,1,(addr&128U)!=0,o); /* Стандартный азимут экземпляра 1 имеет разрешение 0,1°. */ +} /* Остальные пользовательские привязки не меняются. */ +int setp_deif_get_binding(void *p,unsigned f,uint8_t *o,double *scale) { /* Порт не содержит второй таблицы исходных коэффициентов. */ + deif_state *s=context(p); if(!s || f>=DEIF_FIELDS || !o || !scale) return 0; memcpy(o,s->field[f].selector,4); *scale=s->field[f].scale; return (int)s->field[f].bound; /* Публичный ABI выдаёт только селектор и скаляр масштаба. */ +} /* Внутренний layout deif_binding не раскрывается клиентам. */ +void setp_deif_reset_values(void *p) { /* Сброс данных не переключает коммуникационное состояние. */ + deif_state *s=context(p); unsigned f; if(!s) return; for(f=0;ffield[f].received=0; s->field[f].status=0; s->field[f].seen=0; s->field[f].raw=0; } /* Профиль и масштабы сохраняются. */ +} /* Этот путь используется при изменении маршрута наблюдателя. */ +int setp_deif_start(void *p,uint64_t now,unsigned reset_values) { /* NMT Reset communication сохраняет прикладные значения. */ + deif_state *s=context(p); uint8_t boot=0; if(!s) return 0; if(reset_values) setp_deif_reset_values(s); /* Reset node дополнительно очищает прикладную область. */ + s->active=1; s->nmt=s->services?127U:5U; s->accepted=0; s->queued=0; s->error=0; s->heartbeat=500; s->started=s->last_hb=now; s->auto_at=s->services && s->self_start?now+1000U:0; /* DEIF §1.8 и §1.10: 1000 мс self-start, 500 мс heartbeat. */ + if(s->services) event(s,0x700U+s->node,&boot,1); return 1; /* Наблюдатель не объявляет себя узлом сети. */ +} /* Включение само по себе не создаёт выдуманных измерений. */ +void setp_deif_stop(void *p) { deif_state *s=context(p); if(s) { s->active=0; s->queued=0; } } /* Выключение отменяет в том числе невыданные служебные кадры. */ +unsigned setp_deif_lost(void *p,uint64_t now) { /* Каждый используемый вход имеет независимый таймер. */ + deif_state *s=context(p); unsigned f,mask=0; if(!s || !s->active) return 0; /* Неактивный узел не генерирует ошибку Data lost. */ + for(f=0;f<5U;f++) if(s->field[f].bound) { uint64_t t=s->field[f].received?s->field[f].seen:s->started; if(f==2U && !s->field[2].received && s->field[5].received) t=s->field[5].seen; if(now>=t && now-t>=3000U) mask|=1U<raw=raw; b->seen=now; b->received=1; b->status=raw_status(raw); } /* Служебная ошибка отличается от отсутствия обновлений. */ +static int sdo(deif_state *s,const uint8_t *d,uint64_t now) { /* Явный ограниченный сервер expedited SDO без выдуманного полного EDS. */ + uint16_t idx=le16(d+1); unsigned sub=d[3],bytes=0,found_index=0,f; uint32_t value=0,abort=0; uint8_t out[8]={0}; /* Ответ всегда содержит исходный мультиплексор запроса. */ + memcpy(out+1,d+1,3); if(d[0]==0x80U) return 0; /* Клиентский abort не вызывает ответного abort. */ + if(idx==0x1000U || idx==0x1001U || idx==0x1017U || idx==0x1018U) found_index=1; /* Стандартные объекты объявлены явно. */ + if(idx==0x1000U && !sub) { bytes=4; value=0; } else if(idx==0x1001U && !sub) { bytes=1; value=s->error?0x81U:0U; } /* Тип устройства и error register по Appendix 1. */ + else if(idx==0x1017U && !sub) { bytes=2; value=s->heartbeat; } else if(idx==0x1018U && sub<=1U) { bytes=sub?4U:1U; value=sub?0x100000B2U:1U; } /* DEIF vendor ID опубликован; продукт и серийный номер не выдумываются. */ + for(f=0;ffield[f].bound && le16(s->field[f].selector+1)==idx) { found_index=1; if(s->field[f].selector[3]==sub) { bytes=2; value=s->field[f].received?(uint16_t)s->field[f].raw:0x7FFFU; } } /* До обновления I16 возвращается «данные недействительны». */ + if(d[0]!=0x40U && d[0]!=0x2FU && d[0]!=0x2BU && d[0]!=0x27U && d[0]!=0x23U) abort=0x05040001U; else if(!bytes) abort=found_index?0x06090011U:0x06020000U; /* Различаем неподдерживаемую команду, подиндекс и объект. */ + else if(d[0]==0x40U) { out[0]=(uint8_t)(0x43U|((4U-bytes)<<2)); put32(out+4,value); event(s,0x580U+s->node,out,8); return 1; } /* Upload возвращает фактическую ширину U8/U16/U32. */ + else if(idx!=0x1017U || sub) abort=0x06010002U; else if(d[0]!=0x2BU) abort=0x06070010U; /* Запись данного профиля разрешена только для U16 heartbeat producer. */ + else { value=le16(d+4); if(s->xdi && !value) abort=0x06090030U; else { s->heartbeat=value; s->last_hb=now; out[0]=0x60; event(s,0x580U+s->node,out,8); return 1; } } /* В XDi-net heartbeat обязателен, в CANopen ноль его отключает. */ + out[0]=0x80; put32(out+4,abort); event(s,0x580U+s->node,out,8); return 0; /* Неподдерживаемый запрос не меняет значения или NMT-состояние. */ +} /* На каждый запрос получается не более одного ответа. */ +int setp_deif_accept(void *p,uint32_t id,const uint8_t *d,size_t n,unsigned flags,uint64_t now) { /* Основной общий автомат приёма внешнего MASTER. */ + deif_state *s=context(p); int32_t m[12]; int kind,changed=0; unsigned f,dam; if(!s || !s->active || flags || (!d && n)) return 0; /* Неверный канал отфильтровывает порт, EXT/RTR — ядро. */ + if(s->auto_at && now>=s->auto_at) { s->nmt=5; s->auto_at=0; } /* Автозапуск действует и перед приёмом очередного кадра. */ + if(s->services && id==0 && n==2U && (!d[1] || d[1]==s->node)) { /* NMT адресует свой узел либо broadcast 0. */ + if(d[0]==129U || d[0]==130U) return setp_deif_start(s,now,d[0]==129U); /* Два вида сброса различаются сохранением прикладных данных. */ + if(d[0]==1U || d[0]==2U || d[0]==128U) { s->nmt=d[0]==1U?5U:d[0]==2U?4U:127U; s->auto_at=0; return 1; } return 0; /* Явная NMT-команда отменяет отложенный self-start. */ + } /* Остальные служебные кадры не являются измерениями. */ + if(s->services && id==0x600U+s->node && n==8U && (s->nmt==5U || s->nmt==127U)) return sdo(s,d,now); /* SDO доступен в Operational и Pre-operational. */ + if(s->nmt!=5U || n!=8U) return 0; kind=setp_deif_inspect(id,d,n,0,m); if(kind!=1 && kind!=3 && kind!=-6) return 0; /* Явная пользовательская привязка разрешает неизвестный каталогу I16, но не неверную адресацию. */ + dam=(unsigned)m[8]; if(dam) { if(s->node && (unsigned)m[1]!=s->node) return 0; if(!s->node && id!=s->monitor_id) return 0; if(s->services && id!=(s->pdo+1U)*0x100U+s->node) return 0; } /* Без заданного физического Node пассивный монитор сохраняет точную привязку CAN ID и селектора. */ + else if(s->services ? (!s->xdi || m[1]>=127) : id!=s->monitor_id) return 0; /* Пассивный монитор сохраняет точную настройку CAN ID, CANopen без XDi-net игнорирует SAM. */ + if(kind==3 && s->services && s->group && (unsigned)m[2]==0x3500U+s->group) { if(d[5]||d[6]||d[7] || ((m[3]==2 && d[4]>100U)||(m[3]==3 && d[4]>2U))) return 0; if(m[3]==2) s->brightness=d[4]; else s->palette=d[4]; s->accepted++; return 1; } /* Яркость и Color не продлевают свежесть измерений. */ + if(d[6]||d[7]) return 0; for(f=0;ffield[f].bound && !memcmp(s->field[f].selector+1,d+1,3) && ((dam && s->node) || s->field[f].selector[0]==d[0])) { store(&s->field[f],m[4],now); changed=1; } /* DAM без настроенного физического получателя не превращается в приём всех узлов сети. */ + if(changed) s->accepted++; return changed; /* Приём PDO не создаёт выдуманного ответного PDO. */ +} /* Словарь прикладных значений не зависит от способа доставки кадра. */ +size_t setp_deif_poll(void *p,uint64_t now,setp_deif_frame_t *o,size_t cap) { /* Таймеры используют только переданные портом монотонные часы. */ + deif_state *s=context(p); size_t count; uint8_t state; unsigned lost; if(!s || !s->active || !s->services) return 0; /* Пассивное наблюдение не передаёт ничего в сеть. */ + if(s->auto_at && now>=s->auto_at) { s->nmt=5; s->auto_at=0; } /* Стандартный self-start заканчивается через 1000 мс. */ + if(s->heartbeat && now>=s->last_hb && now-s->last_hb>=s->heartbeat) { state=(uint8_t)s->nmt; event(s,0x700U+s->node,&state,1); s->last_hb=now; } /* После задержки создаётся один актуальный heartbeat без пачки пропущенных тиков. */ + lost=setp_deif_lost(s,now)!=0; if(s->nmt==5U && lost!=s->error) { uint8_t emcy[8]={0}; if(lost) { emcy[1]=0x81; emcy[2]=0x81; emcy[3]=6; } event(s,0x80U+s->node,emcy,8); s->error=lost; } /* Appendix 5: Data lost 0x8100/0x81/0x06 и нулевой Error reset. */ + count=s->queuedqueued:cap; if(!o || !count) return 0; memcpy(o,s->queue,count*sizeof(*o)); s->queued-=(unsigned)count; memmove(s->queue,s->queue+count,s->queued*sizeof(*o)); return count; /* Непоместившиеся события сохраняются для следующего вызова. */ +} /* Владение выходным буфером остаётся у Python/JNI/MCU. */ +int setp_deif_read(void *p,unsigned f,uint64_t now,unsigned expiry,double *value,int64_t *m) { /* Возвращает данные без подмены ошибочного кода числом. */ + deif_state *s=context(p); deif_binding *b; unsigned flags=0; if(!s || f>=DEIF_FIELDS || !value || !m) return 0; b=&s->field[f]; /* Границы поля проверяются до доступа к массиву. */ + if(b->bound && b->received) { flags=1U; if(!b->status) flags|=2U; if(expiry && now>=b->seen && now-b->seen>expiry) flags|=4U; } /* Пассивный UI скрывает данные через пять секунд, сервер хранит последнее значение для мигания. */ + *value=b->raw*b->scale; m[0]=(int64_t)b->seen; m[1]=b->raw; m[2]=b->status; m[3]=flags; return (int)flags; /* Разрешение применяется в единственном общем ядре. */ +} /* Метаданные позволяют отличить invalid от устаревания и отсутствия кадра. */ +int setp_deif_angle(void *p,uint64_t now,unsigned expiry,double *v) { /* Единое правило выбора азимута для Desktop и Android. */ + deif_state *s=context(p); int64_t m[4]; unsigned f,kind; int flags; if(!s || !v) return 0; f=s->field[2].received?2U:5U; kind=f==5U || s->field[2].selector[3]==7U?2U:1U; /* До первого фактического кадра используется только принятое сетевое задание с явной пометкой. */ + flags=setp_deif_read(s,f,now,expiry,v,m); return (flags&2) && !(flags&4) ? (int)kind : 0; /* Ошибочное фактическое сообщение не заменяется старым заданием. */ +} /* Черновиков GUI в этом API нет. */ +int setp_deif_meta(void *p,int64_t *o) { /* Копирует скалярный снимок без раскрытия private-layout состояния. */ + deif_state *s=context(p); if(!s || !o) return 0; o[0]=s->active; o[1]=s->nmt; o[2]=(int64_t)s->started; o[3]=(int64_t)s->last_hb; o[4]=s->heartbeat; o[5]=s->accepted; o[6]=s->group; o[7]=s->brightness; o[8]=s->palette; o[9]=s->error; return 1; /* Индексы массива документированы в публичном заголовке. */ +} /* API пригоден для прямого буфера JNI и ctypes без платформенных зависимостей. */ diff --git a/c/set-protocol/src/set_signal.c b/c/set-protocol/src/set_signal.c index 96a0533..e6d80f8 100644 --- a/c/set-protocol/src/set_signal.c +++ b/c/set-protocol/src/set_signal.c @@ -33,9 +33,9 @@ static double evaluate(double t,const double *x,const double *y,size_t n, return (2*u*u*u-3*u*u+1)*y[i]+(u*u*u-2*u*u+u)*h*d[i] +(-2*u*u*u+3*u*u)*y[i+1]+(u*u*u-u*u)*h*d[i+1]; } -int set_signal_reconstruct(const double *input_x,const double *input_y,size_t count, - int method,unsigned degree,size_t output_count,int endpoint,double *out_x, - double *out_y,double *meta,double *work,size_t work_count) { +int set_signal_reconstruct_with_fit(const double *input_x,const double *input_y,size_t count, /* Общая подготовка данных обслуживает исходный и подключаемый решатели. */ + int method,unsigned degree,size_t output_count,int endpoint,double *out_x, /* Метод, степень и временная сетка сохраняют контракт существующего API. */ + double *out_y,double *meta,double *work,size_t work_count,set_signal_fit_fn fit) { /* NULL выбирает прежний МНК; другой callback получает уже нормированные данные. */ point *pairs; double *x,*y,*d,*h,*s,*q,*column; double coef[6]={0},r[6][6]={{0}},origin,span,scale=1,rmse=0; size_t i,j,k,n=0; unsigned pass; @@ -65,6 +65,10 @@ int set_signal_reconstruct(const double *input_x,const double *input_y,size_t co } if(method==SET_SIGNAL_POLYNOMIAL) { if(degree<1||degree>5||n<=degree) return 1; + if(fit) { /* Подключаемый решатель заменяет только вычисление коэффициентов МНК. */ + int status=fit(x,y,n,degree,coef); /* Передаём уникальные нормированные точки и массив до шести коэффициентов. */ + if(status) return status; /* Ошибка ранга или памяти возвращается явно, без скрытого перехода на другой решатель. */ + } else { /* Исходный алгоритм остаётся неизменным вариантом для сравнения и прошивок. */ for(j=0;j<=degree;++j) { double norm=0; for(i=0;i2) { @@ -112,6 +117,11 @@ int set_signal_reconstruct(const double *input_x,const double *input_y,size_t co meta[0]=(double)count; meta[1]=(double)n; meta[2]=sqrt(rmse)*scale; return isfinite(meta[2])?0:2; } +int set_signal_reconstruct(const double *input_x,const double *input_y,size_t count, /* Сохраняем прежний экспорт и поведение всех существующих клиентов. */ + int method,unsigned degree,size_t output_count,int endpoint,double *out_x, /* Параметры передаются без изменения единиц времени и амплитуды. */ + double *out_y,double *meta,double *work,size_t work_count) { /* Владение выходами и рабочим буфером по-прежнему остаётся у вызывающего. */ + return set_signal_reconstruct_with_fit(input_x,input_y,count,method,degree,output_count,endpoint,out_x,out_y,meta,work,work_count,NULL); /* NULL выбирает исходный двухпроходный МНК без зависимости от C++. */ +} /* Завершаем совместимую обёртку исходного C ABI. */ int set_signal_dac12(const double *volts,size_t count,double vref,uint16_t *codes) { size_t i; if(!volts||!codes||count<2||count>10000||!isfinite(vref)||vref<=0) return 1; diff --git a/c/set-protocol/tests/fixtures/deif-xdi-v1.tsv b/c/set-protocol/tests/fixtures/deif-xdi-v1.tsv new file mode 100644 index 0000000..3f8633e --- /dev/null +++ b/c/set-protocol/tests/fixtures/deif-xdi-v1.tsv @@ -0,0 +1,15 @@ +# COB-ID payload flags result RAW index subindex +201 0101300784030000 0 1 900 3001 7 +201 0101300284030000 0 1 900 3001 2 +201 0181300239FC0000 0 1 -967 3081 2 +201 0191300203FE0000 0 1 -509 3091 2 +201 01213402CEF70000 0 1 -2098 3421 2 +201 01313402D4FE0000 0 1 -300 3431 2 +30D 8D01300784030000 0 1 900 3001 7 +201 0101300784030000 1 -1 0 0 0 +201 0101300784030000 2 -1 0 0 0 +202 0101300784030000 0 -5 900 3001 7 +201 0181 0 -4 0 0 0 +701 05 0 2 0 0 0 +70D 00 0 2 0 0 0 +70D 7F 0 2 0 0 0 diff --git a/c/set-protocol/tests/test_deif_xdi.c b/c/set-protocol/tests/test_deif_xdi.c new file mode 100644 index 0000000..39b253c --- /dev/null +++ b/c/set-protocol/tests/test_deif_xdi.c @@ -0,0 +1,26 @@ +#include "deif_xdi.h" /* Эталонные векторы проверяют непосредственно единственное C-ядро. */ +#include /* Любое расхождение байтов или сроков делает тест неуспешным. */ +#include /* Файловый ввод нужен только хостовому тесту, не переносимому ядру. */ +#include /* Выравнивание контекста обеспечивает стандартный хостовый allocator. */ +#include /* Сравниваются точные CAN-последовательности. */ +int main(int argc,char **argv) { /* Один набор векторов используется также Python и Android/JVM. */ + FILE *input; char line[160],hex[17]; unsigned id,flags,index,sub,byte,i; int expected,raw; int32_t meta[12]; uint8_t data[8]; size_t n; void *state; double value; setp_deif_frame_t out[16]; /* Все размеры ограничены форматом Classic CAN и ABI. */ + assert(argc==2); input=fopen(argv[1],"r"); assert(input); /* Путь fixtures передаётся сборщиком без зависимости от cwd. */ + while(fgets(line,sizeof line,input)) { /* Таблица содержит положительные и ошибочные кадры. */ + if(line[0]=='#') continue; assert(sscanf(line,"%x %16s %u %d %d %x %x",&id,hex,&flags,&expected,&raw,&index,&sub)==7); /* Это чтение текстовой fixture, а не второй CAN-декодер. */ + n=strlen(hex)/2U; for(i=0;i None: import_library = build_dir / "setprotocol.lib" jni_flags = " ".join(f'/I"{path}"' for path in JNI_INCLUDES) command = ( - f'call "{vcvars}" && cl /nologo /W4 /std:c11 ' + f'call "{vcvars}" && cl /nologo /W4 /O2 /std:c11 ' # Оптимизируем исходный C-решатель, чтобы сравнение с оптимизированным Eigen не измеряло различие режимов компиляции. f'/DPCAN_ABI_BUILD_DLL /I"{INCLUDE}" {jni_flags} /LD {quoted_sources} ' f'/Fe"{output}" /link /IMPLIB:"{import_library}"' ) @@ -74,7 +74,7 @@ def _build_cc(output: Path, build_dir: Path) -> None: compiler = shutil.which("cc") or shutil.which("clang") or shutil.which("gcc") if compiler is None: raise SystemExit("C compiler was not found") - command = [compiler, "-std=c99", "-Wall", "-Wextra", "-Wpedantic", + command = [compiler, "-O2", "-std=c99", "-Wall", "-Wextra", "-Wpedantic", # Одинаковая оптимизация C99 и C++ делает время настольных вариантов сопоставимым. "-fPIC", "-shared", f"-I{INCLUDE}", *(f"-I{path}" for path in JNI_INCLUDES), *map(str, SOURCES), "-o", str(output), "-lm"] @@ -94,6 +94,7 @@ def main() -> int: SOURCES.extend([ ROOT / "ports" / "android" / "set_plot_jni.c", ROOT / "ports" / "android" / "setprotocol_jni.c", + ROOT / "ports" / "android" / "set_deif_jni.c", # JVM-тесты вызывают тот же DEIF-автомат, что Android NDK и ctypes. ]) output = args.output.resolve() output.parent.mkdir(parents=True, exist_ok=True) diff --git a/c/st7789/st7789_disabled.h b/c/st7789/st7789_disabled.h new file mode 100644 index 0000000..c2e770c --- /dev/null +++ b/c/st7789/st7789_disabled.h @@ -0,0 +1,6 @@ +#ifndef ST7789_DISABLED_H /* Защищает отключённый аппаратный интерфейс от повторного включения. */ +#define ST7789_DISABLED_H /* Позволяет общему main обслуживать одинаковый API на плате без подключённого дисплея. */ +#include /* Время общего опроса передаётся как 32-битное число миллисекунд. */ +static inline void ST7789_BoardInit(void) { } /* Профиль без дисплея не включает SPI и не занимает GPIO, сохраняя работу всех моделей DEIF. */ +static inline void ST7789_BoardPoll(uint32_t now_ms) { (void)now_ms; } /* Опрос без экрана не блокирует UART/CAN/USB и не требует графических исходников в прошивке. */ +#endif /* Завершает отключённый backend общего интерфейса дисплея. */ diff --git a/cpp/signal-eigen/README.md b/cpp/signal-eigen/README.md new file mode 100644 index 0000000..e58bb82 --- /dev/null +++ b/cpp/signal-eigen/README.md @@ -0,0 +1,50 @@ +# Альтернативный МНК Eigen QR + +Необязательный настольный модуль выполняет полиномиальный МНК через +`Eigen::ColPivHouseholderQR`. Исходный двухпроходный решатель остаётся вариантом +по умолчанию. Прошивки и основная SETProtocol DLL продолжают собираться как C99. + +Путь вызова: GUI → Python/ctypes → `setsignal_eigen` → общая подготовка +`set_signal.c` → callback Eigen → общие вычисление кривой и RMSE. +Сортировка, усреднение повторов X, нормировка, сетка, рабочий буфер и аннотации +формул совпадают у обоих вариантов. Порог ранга Eigen относительный: `1e-12`; +он может иначе классифицировать пограничные данные, чем исходная ортогонализация. +Модуль не зависит от Qt и не участвует в обмене с устройствами. + +| Файл | Назначение и зависимости | +| --- | --- | +| `signal_eigen.cpp` | Решатель QR и экспорт `set_signal_reconstruct_eigen`; C++14, Eigen, `set_signal.h` | +| `build.py` | Сборка DLL/SO, проверка и распаковка локального архива; Python 3.8+ и C/C++ компиляторы | +| `vendor/eigen-3.4.0.tar.gz` | Оригинальный архив зависимости, без изменений | +| `../../python/set_devices/signal_eigen.py` | Ленивый ctypes-загрузчик отдельного компонента | + +Зависимость: [Eigen 3.4.0, официальный архив](https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz). +SHA-256: `8586084f71f9bde545ee7fa6d00288b264a2b7ac3607b974e54d13e7162c1c72`. +Заголовки компилируются с `EIGEN_MPL2_ONLY`; `Eigen-COPYING.MPL2` копируется +рядом с библиотекой и включается в пакет SETGUI. Сборка не требует интернета. + +Из каталога SETGUI: + +```powershell +.venv/Scripts/python.exe third_party/templates/cpp/signal-eigen/build.py --output src/gui_desktop/native/setsignal_eigen.dll # Собираем 64-битный настольный компонент рядом с основной DLL. +``` + +Для 32-битного приложения добавьте `--arch x86`. Компилятор C обрабатывает +общий алгоритм отдельно от C++14-решателя. Windows-модуль использует статический +CRT и PE-подсистему 6.01; работоспособность на самой Windows 7 требует проверки +на соответствующей машине. Для Linux/macOS укажите имя `libsetsignal_eigen.so` +или `libsetsignal_eigen.dylib`. `scripts/build_exe.py` собирает и упаковывает +компонент автоматически, включая вариант Windows 7 x86. + +Контракт `set_signal_fit_fn` описан в `c/set-protocol/include/set_signal.h`: +callback получает уникальные нормированные X/Y, количество точек и степень 1…5, +возвращает коэффициенты по возрастанию степеней аргумента `2*x-1`. +Владение выходами остаётся у вызывающего; Eigen выделяет временные матрицы +только в настольном порте. Коды ошибок: 0 — успех, 1 — параметры, 2 — нечисловой +результат, 3 — недостаточный ранг, 5 — память/ошибка C++-решателя. +Исключения не пересекают C ABI. Общих изменяемых рабочих буферов нет. + +Загрузчик ищет компонент рядом с выбранной SETProtocol DLL. Переменная +`SETSIGNAL_EIGEN_LIBRARY` позволяет явно задать путь для тестов. Отсутствующая +библиотека вызывает понятную ошибку после выбора Eigen; скрытой замены +на исходный решатель нет. Используется в обработке графиков и генераторе SETGUI. diff --git a/cpp/signal-eigen/build.py b/cpp/signal-eigen/build.py new file mode 100644 index 0000000..45148fb --- /dev/null +++ b/cpp/signal-eigen/build.py @@ -0,0 +1,63 @@ +import argparse # Разбираем путь выходной библиотеки и целевую архитектуру настольной сборки. +import hashlib # Проверяем закреплённый архив Eigen перед использованием заголовков. +import os # Находим стандартный каталог установщика Visual Studio в Windows. +from pathlib import Path # Разрешаем пути независимо от текущего рабочего каталога сборки. +import platform # Выбираем расширение библиотеки и инструментарий целевой ОС. +import shutil # Находим доступный системный компилятор для Unix-подобных ОС. +import subprocess # Запускаем компиляторы с проверкой кода завершения. +import tarfile # Читаем заголовки и лицензии из проверенного архива без сетевого доступа. + +ROOT = Path(__file__).resolve().parent # Все исходники и закреплённая зависимость расположены рядом со скриптом. +CORE = ROOT.parents[1] / "c" / "set-protocol" # Подключаем исходный C99-алгоритм из того же репозитория, не создавая его копию. +SHA256 = "8586084f71f9bde545ee7fa6d00288b264a2b7ac3607b974e54d13e7162c1c72" # Контрольная сумма официального архива Eigen 3.4.0 из GitLab. + +def headers(directory): # Подготавливаем только необходимые заголовки и лицензии в каталоге конкретной сборки. + archive = ROOT / "vendor" / "eigen-3.4.0.tar.gz" # Закреплённый архив позволяет собирать EXE без скачивания зависимостей. + if hashlib.sha256(archive.read_bytes()).hexdigest() != SHA256: # Повреждённая или подменённая зависимость не должна попадать в бинарный модуль. + raise RuntimeError("Неверная SHA-256 архива Eigen 3.4.0") # Останавливаем сборку с явным указанием нарушенной проверки. + destination = directory / "eigen-3.4.0" # Раздельный каталог исключает пересечение разных целевых сборок. + with tarfile.open(archive, "r:gz") as source: # Читаем gzip-архив штатной библиотекой Python, совместимой с Python 3.8. + for member in source.getmembers(): # Рассматриваем каждый элемент, но не используем небезопасную полную распаковку архива. + parts = Path(member.name).parts[1:] # Удаляем единственный верхний каталог официального дистрибутива. + if not member.isfile() or not parts or any(part in ("..", "/", "\\") for part in parts): # Разрешаем только обычные файлы с безопасным относительным путём. + continue # Пропускаем ссылки, каталоги и элементы, способные выйти за корень распаковки. + if parts[0] != "Eigen" and not parts[0].startswith("COPYING"): # Для QR достаточно основного дерева Eigen и его лицензионных файлов. + continue # Примеры, тесты и неподдерживаемые модули не нужны при сборке приложения. + target = destination.joinpath(*parts) # Сохраняем исходное расположение внутренних include относительно корня Eigen. + target.resolve().relative_to(destination.resolve()) # Дополнительно проверяем итоговый абсолютный путь перед записью. + target.parent.mkdir(parents=True, exist_ok=True) # Создаём только каталог текущего безопасного файла. + with source.extractfile(member) as content: # Открываем содержимое обычного файла внутри проверенного архива. + target.write_bytes(content.read()) # Сохраняем оригинальные заголовки без изменения стороннего кода. + return destination # Возвращаем корень, который компилятор должен добавить в include-пути. + +def build(output, arch): # Собираем отдельный модуль, сохраняя основное C99-ядро без зависимости от C++. + output = output.resolve() # Абсолютный путь надёжен при смене рабочего каталога компилятора. + directory = output.parent / (".signal-eigen-" + arch) # Объектные файлы x86 и x64 не смешиваются. + directory.mkdir(parents=True, exist_ok=True) # Создаём каталог выходной библиотеки и промежуточных файлов. + include = headers(directory) # Проверяем архив и получаем локальные заголовки Eigen до запуска компилятора. + if platform.system() == "Windows": # На Windows используем тот же установленный MSVC, что основная DLL. + vswhere = Path(os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")) / "Microsoft Visual Studio/Installer/vswhere.exe" # Стандартный путь установщика соответствует основному сборщику SETGUI. + installation = subprocess.check_output([str(vswhere), "-latest", "-products", "*", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath"], text=True).strip() # Находим установку с компиляторами C/C++ для обеих архитектур. + if not installation: # Пустой ответ означает отсутствие подходящего инструментария. + raise RuntimeError("Не найдены Visual Studio C++ Build Tools") # Сообщаем причину вместо создания приложения без выбранного варианта Eigen. + vcvars = Path(installation) / "VC/Auxiliary/Build" / ("vcvars32.bat" if arch == "x86" else "vcvars64.bat") # Настраиваем среду именно под разрядность Python и EXE. + common = ["cl", "/nologo", "/O2", "/MT", "/DPCAN_ABI_BUILD_DLL", "/I" + str(CORE / "include")] # Оба варианта C и Eigen используют оптимизацию и статический CRT без новой зависимости от установленного runtime. + commands = [common + ["/std:c11", "/c", str(CORE / "src/set_signal.c"), "/Fo" + str(directory / "signal.obj")], common + ["/std:c++14", "/EHsc", "/I" + str(include), "/c", str(ROOT / "signal_eigen.cpp"), "/Fo" + str(directory / "eigen.obj")], ["link", "/nologo", "/DLL", "/MACHINE:" + arch.upper(), "/SUBSYSTEM:WINDOWS,6.01", "/OUT:" + str(output), str(directory / "signal.obj"), str(directory / "eigen.obj")]] # Отдельно компилируем C99 и C++, а PE-подсистему закрепляем на Windows 7 (6.01). + for command in commands: # Последовательные этапы используют только готовые объектные файлы предыдущих команд. + subprocess.run('call "%s" && %s' % (vcvars, subprocess.list2cmdline(command)), cwd=directory, shell=True, check=True) # Batch-настройка MSVC и компилятор выполняются в одном процессе cmd. + else: # Настольные Linux/macOS используют системные C/C++-компиляторы и тот же исходный алгоритм. + cc, cxx = shutil.which("cc"), shutil.which("c++") # C-исходник компилируем как C99, а Eigen исключительно как C++14. + if not cc or not cxx: # Обе стадии необходимы для сохранения языковой границы общего ядра. + raise RuntimeError("Нужны компиляторы C и C++") # Отсутствие инструментария не приводит к скрытому отключению Eigen. + subprocess.run([cc, "-O2", "-std=c99", "-fPIC", "-I" + str(CORE / "include"), "-c", str(CORE / "src/set_signal.c"), "-o", str(directory / "signal.o")], check=True) # Получаем позиционно-независимый объект оригинального C99-ядра. + subprocess.run([cxx, "-O2", "-std=c++14", "-fPIC", "-shared", "-I" + str(CORE / "include"), "-I" + str(include), str(ROOT / "signal_eigen.cpp"), str(directory / "signal.o"), "-o", str(output)], check=True) # Линкер C++ добавляет свою стандартную библиотеку к общему настольному модулю. + for name in ("COPYING.MPL2",): # Распространяем основной текст лицензии вместе с бинарным компонентом. + shutil.copyfile(include / name, output.parent / ("Eigen-" + name)) # Имя явно указывает, к какой встроенной библиотеке относится лицензия. + print(output) # Показываем точный путь успешно собранного компонента для журналов сборки. + +if __name__ == "__main__": # CLI используется как вручную, так и сборщиком EXE. + parser = argparse.ArgumentParser(description="Сборка альтернативного МНК Eigen QR") # Объясняем назначение отдельного настольного модуля. + parser.add_argument("--output", type=Path, required=True) # Вызывающий определяет выходной путь и расширение DLL/SO. + parser.add_argument("--arch", choices=("x86", "x64"), default="x64") # Windows 7 x86 явно выбирает 32-битный PE вместо значения по умолчанию. + arguments = parser.parse_args() # Проверяем обязательные параметры до работы с файловой системой. + build(arguments.output, arguments.arch) # Полностью выполняем сборку либо завершаем процесс исключением и ненулевым кодом. diff --git a/cpp/signal-eigen/signal_eigen.cpp b/cpp/signal-eigen/signal_eigen.cpp new file mode 100644 index 0000000..6508542 --- /dev/null +++ b/cpp/signal-eigen/signal_eigen.cpp @@ -0,0 +1,40 @@ +#define EIGEN_MPL2_ONLY // Ограничиваем подключаемые части Eigen лицензией MPL-2.0. +#include // Подключаем QR с выбором ведущего столбца для полиномиального МНК. +#include // Проверяем конечность вычисленных коэффициентов перед передачей в C. +#include // Перехватываем ошибку выделения памяти внутри границы C ABI. +#include "set_signal.h" // Используем общую подготовку точек, вычисление кривой и стабильный C ABI. + +static int eigen_fit(const double *x,const double *y,size_t count,unsigned degree,double *coefficients) { // Вычисляем только коэффициенты по уже нормированным уникальным точкам. + try { // Исключения C++ не должны пересекать границу ctypes или C-ядра. + Eigen::MatrixXd design(count,degree+1); // Матрица имеет одну строку на точку и до шести степеней, включая свободный член. + for(size_t i=0;i qr(design); // Используем отражения Хаусхолдера с перестановкой столбцов вместо собственной ортогонализации. + qr.setThreshold(1e-12); // Относительный порог ранга соответствует порядку допуска исходного решателя; он не является абсолютной погрешностью сигнала. + if(qr.rank()!=static_cast(degree+1)) return 3; // Отклоняем вырожденный базис, не выдавая неоднозначные коэффициенты за корректную кривую. + Eigen::Map values(y,count); // Читаем нормированные амплитуды из памяти C без дополнительного копирования входного вектора. + Eigen::VectorXd solution=qr.solve(values); // Находим минимум суммы квадратов без формирования нормальных уравнений AᵀA. + for(unsigned j=0;j<=degree;++j) { // Возвращаем степени в исходном порядке: Eigen отменяет перестановку столбцов при solve. + if(!std::isfinite(solution[j])) return 2; // Не разрешаем NaN или бесконечности попасть в оценку кривой и RMSE. + coefficients[j]=solution[j]; // Передаём коэффициент в буфер общего C-алгоритма вычисления полинома. + } // Весь выходной полином проверен до передачи управления C-ядру. + return 0; // Сообщаем общий для двух реализаций код успешного расчёта. + } catch(const std::bad_alloc &) { // Преобразуем нехватку памяти необязательного настольного решателя в детерминированный код. + return 5; // Код 5 обозначает невозможность выполнить расчёт, включая выделение матриц. + } catch(...) { // Защищаем потребителей C ABI от остальных исключений библиотеки C++. + return 5; // Возвращаем явную ошибку без подмены выбранного пользователем решателя. + } // Завершаем защиту границы между C++ и C. +} // Решатель не хранит глобальных данных и допускает независимые параллельные вызовы. + +extern "C" PCAN_ABI_API int set_signal_reconstruct_eigen( // Отдельный экспорт сохраняет возможность загрузить модуль без изменения основной DLL. + const double *x,const double *y,size_t count,int method,unsigned degree, // Формат точек и предел степени совпадают с исходным API. + size_t output_count,int endpoint,double *out_x,double *out_y, // Временная сетка и включение конечной точки рассчитываются общим C-ядром. + double *meta,double *work,size_t work_count) { // Метаданные и рабочая память сохраняют формат аннотаций формулы GUI. + if(method!=SET_SIGNAL_POLYNOMIAL) return 1; // Eigen доступен только для МНК; остальные методы не маскируются под альтернативный решатель. + return set_signal_reconstruct_with_fit(x,y,count,method,degree,output_count,endpoint,out_x,out_y,meta,work,work_count,eigen_fit); // Повторно используем C99-подготовку, обработку повторов, вычисление кривой и RMSE. +} // Завершаем экспорт с соглашением вызова C для x86 и x64. diff --git a/cpp/signal-eigen/vendor/eigen-3.4.0.tar.gz b/cpp/signal-eigen/vendor/eigen-3.4.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..20635de4fab2d4f1f66b5911b2317989a264f1e9 GIT binary patch literal 2705005 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

rgbQ7r92zL>! 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

H=yXQ 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

|2^*X-lj(8$1 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⪙C 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