Files
Balsam_167/Source/Internal/gas167.c
Andrey 1e911e5250 Обновить логгер УМП и исправить запуск UART и EEPROM
Перейти на компактные 12-словные записи v4 и сохранять 10 процентов банка после отключения. Добавить трёхсекундное ожидание роста ЗПТ и настраиваемый лимит пусков. Явно инициализировать состояние UART и гарантировать публикацию параметров EEPROM перед запуском Timer2. Сохранить воспроизводимые сборки, регрессионные проверки, документацию и обновлённые результаты сборки; исключить временные артефакты.
2026-10-12 12:25:41 +03:00

120 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Дополнительная карта GAS 167/v1 только для новой EEPROM M95M02. Русские пояснения сохранены в UTF-8. */
/* Подключает границы GAS и общий выбор EEPROM; при профиле 0 интерфейс GAS исключён. */
#include "gas167.h"
/* Весь дополнительный код включается только для физически установленной M95M02; вариант AT25256B не растёт. */
#if EEPROM_M95M02
/* Подключает тип платы dsk_LOAD и псевдонимы регистров, чтобы сохранять правила обычного Modbus. */
#include "package.h"
/* Использует существующие технологические регистры без копии массива и без добавления RAM. */
extern int modbus[];
/* Тип платы нужен для ограничений записи статусов и тайм-аута нагрузки. */
extern int Desk;
/* Вызывает штатную регистрацию изменения команды; нового регистратора GAS не создаёт. */
extern void ump_log_rs(void);
/* Постоянный дескриптор из восьми слов описывает карту 167/v1; область 0x5F00..0x5F07 доступна только для чтения. */
static const uint16_t gas167_info[GAS167_INFO_WORDS] = {
/* Слова 0..3: сигнатура GA/S1, версия профиля и номер проекта 167. */
0x4741U, 0x5331U, GAS167_PROFILE_VERSION, 167U,
/* Слова 4..7: база технологических регистров, число слов, маска RTU/CAN/FC06 и признак EEPROM M95M02 = 1; последний элемент описывает аппаратный профиль. */
GAS167_REG_BASE, GAS167_REG_COUNT, GAS167_CAPABILITIES, 1U
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
};
/* Проверяет одиночный адрес в двух непересекающихся диапазонах; весь блок дополнительно проверяет gas167_prepare. */
int gas167_contains(uint16_t address)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Беззнаковое 16-битное смещение проверяет 0x5000..0x507F: адрес ниже начала даёт большое смещение. */
return (uint16_t)(address - GAS167_REG_BASE) < GAS167_REG_COUNT ||
/* Аналогично проверяет 0x5F00..0x5F07; промежуток между диапазонами остаётся недоступным. */
(uint16_t)(address - GAS167_INFO_BASE) < GAS167_INFO_WORDS;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Записывает технологическое слово с теми же ограничениями, что и штатная функция Modbus FC06. */
static unsigned gas167_write(uint16_t offset, uint16_t value)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Правила записи совпадают со штатным Modbus: статусы защиты нельзя
* перезаписать, а недопустимый тайм-аут не позволяет обойти защиту. */
/* Состояние защиты 0x7C остаётся только для чтения; GAS-псевдоним лимита 0x507D допускает запись. */
if (Desk == dsk_LOAD && offset == 0x7CU) return 2;
/* Отклоняет нулевой лимит кодом Modbus 3 одинаково для RTU и служебного CAN; uint16_t ограничивает верхнюю границу 65535. */
if (Desk == dsk_LOAD && offset == 0x7DU && value == 0U) return 3;
/* Для сохраняемого тайм-аута CAN нагрузки применяется проверка диапазона независимо от транспорта. */
if (Desk == dsk_LOAD && offset == 0x52U &&
/* Значение 0 или больше 60000 мс недопустимо и возвращает код 3; защиту нельзя отключить такой записью. */
(value == 0U || value > 60000U)) return 3;
/* int C28x занимает одно слово регистра; чтение возвращает исходный uint16_t. */
/* Сохраняет 16-битный рисунок регистра: знаковый int C28x занимает ровно одно слово, чтение вернёт uint16_t. */
modbus[offset] = (int)value;
/* Запись слова команд 127 вызывает существующий хук регистратора, как обычный Modbus. */
if (offset == 127U) ump_log_rs();
/* Возвращает успех записи; исходное правило ошибок Modbus сохраняется. */
return 0;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Готовит FC03/FC06: value — число слов чтения или значение записи, address — глобальный словный адрес. */
unsigned gas167_prepare(unsigned function, uint16_t address, uint16_t value,
/* can включает парное чтение CAN; reply вмещает 124 слова, error получает код Modbus; вызывающий код удерживает краткую блокировку IRQ. */
int can, uint16_t *reply, unsigned *error)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Смещение адреса внутри выбранной области; uint16_t задаёт правила вычисления на границах 0xFFFF. */
uint16_t offset;
/* Индекс копирования и число доступных слов в выбранной области — 128 или 8. */
unsigned i, available;
/* Признак обращения к постоянному дескриптору вместо технологических регистров. */
int info;
/* Не разыменовывает отсутствующие выходные буферы; ответ сформировать нельзя. */
if (!reply || !error) return 0;
/* Сначала считает запрос успешным; последующие проверки задают конкретный код ошибки. */
*error = 0;
/* Выбирает дескриптор только для его восьми допустимых стартовых адресов. */
info = (uint16_t)(address - GAS167_INFO_BASE) < GAS167_INFO_WORDS;
/* Переводит глобальный адрес в индекс выбранной области без изменения штатных адресов Modbus. */
offset = (uint16_t)(address - (info ? GAS167_INFO_BASE : GAS167_REG_BASE));
/* Определяет границу выбранной области, чтобы следующий запрос не пересёк её конец. */
available = info ? GAS167_INFO_WORDS : GAS167_REG_COUNT;
/* GAS поддерживает только чтение FC03 и одиночную запись FC06; остальные функции возвращают исключение 1. */
if (function != 3U && function != 6U) *error = 1;
/* Отклоняет адрес вне выбранной области до любого чтения массива; исключение 2. */
else if (offset >= available) *error = 2;
/* Для FC06 длина не проверяется: value содержит записываемое слово. */
else if (function == 6U) {
/* Дескриптор запрещён для записи; технологическая область проходит проверку прав и тайм-аута. */
*error = info ? 2U : gas167_write(offset, value);
/* Чтение RTU допускает 1..124 слова; служебный CAN передаёт пары и поэтому требует чётную ненулевую длину. */
} else if (!value || value > GAS167_MAX_WORDS || (can && (value & 1U))) {
/* Неверная длина чтения получает исключение Modbus 3 без частичного ответа. */
*error = 3;
/* Проверяет остаток области через вычитание: запрос не выходит за границу, не оборачивается и не читает скрытый modbus[128]. */
} else if (value > available - offset) {
/* Пересечение конца области получает исключение Modbus 2; данные ещё не копировались. */
*error = 2;
/* Только полностью проверенный запрос попадает в ветвь копирования снимка. */
} else {
/* Проверяется весь блок до чтения: нельзя пересечь конец области,
* перейти через 0xFFFF или получить скрытое слово параметров. */
/* Копирует точно запрошенное число слов, не выполняя EEPROM I/O и не выделяя память. */
for (i = 0; i < value; ++i)
/* Берёт постоянное слово дескриптора либо сырой 16-битный регистр; согласованность обеспечена блокировкой вызывающего транспорта. */
reply[i] = info ? gas167_info[offset+i] : (uint16_t)modbus[offset+i];
/* Для успешного чтения возвращает фактическое число слов; транспорт сам строит RTU или CAN-кадры. */
return value;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Для записи либо ошибки сохраняет исходный адрес, используемый транспортом при формировании ответа. */
reply[0] = address;
/* Сохраняет исходное значение или длину рядом с адресом; массив ответа содержит два слова. */
reply[1] = value;
/* Возвращает двухсловный результат записи/ошибки; конкретный код ошибки остаётся в error. */
return 2;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Завершает код GAS, доступный только при EEPROM_M95M02=1. */
#endif