Merge origin/ump-v4 into main
Combine Flash CAN updates, signal processing and HOPE pin fixes with current Modbus/GAS, STM32 ports and CCS release exports. Resolve protocol, documentation and Qt conflicts; deduplicate Android JNI sources and include gauge/IGBT sources in host builds.
This commit is contained in:
+42
-15
@@ -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,13 +80,16 @@ 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 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)
|
||||
@@ -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),
|
||||
|
||||
@@ -20,6 +20,7 @@ class CanBootTarget:
|
||||
hardware_min: int = 0
|
||||
hardware_max: int = 255
|
||||
session_id: int = 1
|
||||
memory: str = "eeprom" # Назначение выбирается явно; старые вызовы сохраняют EEPROM A/B и прежний wire-протокол.
|
||||
|
||||
def __post_init__(self):
|
||||
if not 0 <= self.device_type <= 7 or not 0 <= self.device <= 15:
|
||||
@@ -30,6 +31,10 @@ class CanBootTarget:
|
||||
raise ValueError("Неверный диапазон аппаратных ревизий")
|
||||
if not 1 <= self.session_id <= 255:
|
||||
raise ValueError("Session ID должен быть 1…255")
|
||||
if self.memory not in ("eeprom", "flash", "stm32") or self.memory == "flash" and self.product_type != 0x2833: # F28335 требует отдельного подтверждения выбора Flash; STM32 использует штатный односекционный поток.
|
||||
raise ValueError("Внутренняя Flash по CAN доступна только для F28335 / Product Type 0x2833") # Ошибка назначения обнаруживается до первого CAN-кадра.
|
||||
if self.memory == "stm32" and self.product_type != 0: # BOOT CANdle G474VET6 публикует Product Type 0 в своём аппаратном профиле.
|
||||
raise ValueError("CANdle G474VET6 требует Product Type 0") # Не допускает случайную передачу образа с ранее выбранным типом платы Бальзам.
|
||||
|
||||
|
||||
class CanBootTransfer:
|
||||
@@ -41,6 +46,19 @@ class CanBootTransfer:
|
||||
raise ValueError("F28335 M95M02 A/B: образ не должен превышать 130560 байт")
|
||||
if not 0 <= image.version <= 0xFFFFFFFF:
|
||||
raise ValueError("Версия образа вне диапазона u32")
|
||||
if target.memory == "stm32": # Односекционная Flash G474 проверяется до первой команды ENTER_BOOT.
|
||||
from set_devices.mcu_profiles import CANDLE_G474_BOOT # Размер приложения и адрес векторов берутся из общего профиля платы.
|
||||
profile = CANDLE_G474_BOOT # Границы соответствуют 32 КиБ BOOT и 480 КиБ приложения STM32G474VET6.
|
||||
if not 8 <= len(image.data) <= profile["app_size"]: # Первые восемь байтов содержат SP и Reset_Handler; запись не должна выходить за Flash.
|
||||
raise ValueError("CANdle G474VET6: приложение должно занимать 8…491520 байт") # Ошибка обнаруживается до стирания целевого приложения.
|
||||
sp, pc = struct.unpack_from("<II", image.data) # Таблица векторов ARM Cortex-M хранит два 32-битных little-endian адреса.
|
||||
if sp & 7 or not profile["stack_base"] < sp <= profile["stack_end"]: # MSP выровнен на восемь байтов и входит в те же 80 КиБ SRAM, которые разрешает валидатор штатного BOOT CANdle.
|
||||
raise ValueError("CANdle G474VET6: неверный начальный указатель стека") # Случайный BIN не рассматривается как приложение ARM.
|
||||
if not pc & 1 or not profile["app_base"] <= (pc & ~1) < profile["app_base"] + len(image.data): # Thumb-вектор должен указывать внутрь приложения, слинкованного для 0x08008000.
|
||||
raise ValueError("CANdle G474VET6: нужен образ приложения для 0x08008000") # BOOT-образ 0x08000000 и приложение USB BOOT RB не принимаются.
|
||||
if target.memory == "flash": # Flash принимает тот же подписанный SCI8, что существующий RS Flash, с защищённым сектором A.
|
||||
from .f28335_flash import parse_sci8 # Повторно использует общий валидатор FAB1, адресов и CRC без отдельной реализации в клиенте.
|
||||
parse_sci8(image.data) # Обычный RAM BIN и образ с аппаратным boot отвергаются до входа в загрузчик.
|
||||
self.image, self.target = image, target
|
||||
self.stage = "enter"
|
||||
self.next_block = 0
|
||||
@@ -50,6 +68,8 @@ class CanBootTransfer:
|
||||
|
||||
@property
|
||||
def response_timeout_ms(self):
|
||||
if self.target.memory == "flash" and self.stage == "commit": # TI erase/program/verify выполняются синхронно после полной проверки staging.
|
||||
return 180000 # Даёт до 180 секунд на штатную запись и итоговую CRC, как действующий RS Flash-клиент.
|
||||
return 15000 if self.stage in ("enter", "verify", "commit") else 1500
|
||||
|
||||
@property
|
||||
@@ -88,7 +108,7 @@ class CanBootTransfer:
|
||||
if not self.accepts(frame):
|
||||
return [], ""
|
||||
command = ProtoCanId.parse(frame.can_id).body & 255
|
||||
expected_command = {"enter": 2, "image": 3, "compat": 4, "erase": 5,
|
||||
expected_command = {"enter": 2, "memory": 16, "image": 3, "compat": 4, "erase": 5, # Ответ выбора назначения принимается только на собственном этапе.
|
||||
"data": 0, "verify": 6, "commit": 7, "reboot": 9}.get(self.stage)
|
||||
# Позднее подтверждение предыдущего этапа нельзя применять к новому:
|
||||
# оно не продвигает автомат и не считается ошибкой текущего запроса.
|
||||
@@ -99,7 +119,10 @@ class CanBootTransfer:
|
||||
return [], "Загрузчик занят"
|
||||
if status not in (0, 8) or (status == 8 and self.stage != "data"):
|
||||
raise RuntimeError(f"ProtoCAN Boot: ошибка 0x{status:02X}")
|
||||
if self.stage == "enter":
|
||||
if self.stage == "enter" and self.target.memory == "flash": # Старый загрузчик должен явно подтвердить поддержку новой цели до передачи образа.
|
||||
self.stage = "memory" # Сначала требует ACK SELECT_MEMORY, затем начнёт обычные метаданные.
|
||||
return self._control(16, b"\x01"), "Выбор внутренней Flash F28335" # DLC=1 и значение 1 означают внутреннюю Flash; значение 0 зарезервировано за штатной EEPROM.
|
||||
if self.stage in ("enter", "memory"): # EEPROM сохраняет прежний переход, Flash переходит только после подтверждённого выбора памяти.
|
||||
self.stage = "image"
|
||||
return self._control(3, struct.pack("<II", len(self.image.data), self.image.crc32)), "Передача метаданных"
|
||||
if self.stage == "image":
|
||||
@@ -110,7 +133,7 @@ class CanBootTransfer:
|
||||
if slot not in (0, 1):
|
||||
raise RuntimeError("ProtoCAN Boot: неверный слот")
|
||||
self.slot, self.stage = slot, "erase"
|
||||
return self._control(5), "Стирание неактивного слота"
|
||||
return self._control(5), ("Подготовка временного слота" if self.target.memory == "flash" else "Стирание приложения STM32" if self.target.memory == "stm32" else "Стирание неактивного слота") # F28335 готовит staging, STM32 стирает единственный слот, EEPROM сохраняет штатное поведение A/B.
|
||||
if self.stage in ("erase", "data"):
|
||||
total = (len(self.image.data) + 7) // 8
|
||||
# The final index of a 512 KiB image wraps the u16 status field.
|
||||
@@ -132,11 +155,15 @@ class CanBootTransfer:
|
||||
return self._window(), "Передача блоков ProtoCAN Boot"
|
||||
if self.stage == "verify":
|
||||
self.stage = "commit"
|
||||
return self._control(7), "Активация образа"
|
||||
return self._control(7), "Запись и проверка внутренней Flash" if self.target.memory == "flash" else "Активация образа" # Для Flash COMMIT означает реальный вызов TI API и публикацию FAB1 последней стадией.
|
||||
if self.stage == "commit":
|
||||
self.stage = "reboot"
|
||||
return self._control(9), "Перезапуск прибора"
|
||||
self.stage, self.finished = "finished", True
|
||||
if self.target.memory == "stm32": # У односекционного STM32 нет EEPROM-кандидата и механизма пробного запуска A/B.
|
||||
return [], "Flash STM32 записана и проверена; прибор перезапускается" # Успех сообщается после ACK VERIFY, COMMIT и REBOOT обычного протокола.
|
||||
if self.target.memory == "flash": # Flash не выдаётся за EEPROM-кандидата, которому требуется trial/CONFIRM.
|
||||
return [], "Внутренняя Flash записана и проверена; прибор перезапускается" # Успех возможен только после итогового ACK COMMIT и ACK REBOOT.
|
||||
if self.target.product_type == 0x2833:
|
||||
return [], "Образ принят; после перезапуска приложение подтвердит пробный запуск"
|
||||
return [], "Прошивка ProtoCAN Boot завершена"
|
||||
|
||||
@@ -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 ещё не обслуживает'}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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()
|
||||
@@ -662,11 +664,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(res: Decoded) -> None: # Единый тип 0x5 разбирается по номеру функции, а не по прежним трём MsgType.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user