Перейти на компактные 12-словные записи v4 и сохранять 10 процентов банка после отключения. Добавить трёхсекундное ожидание роста ЗПТ и настраиваемый лимит пусков. Явно инициализировать состояние UART и гарантировать публикацию параметров EEPROM перед запуском Timer2. Сохранить воспроизводимые сборки, регрессионные проверки, документацию и обновлённые результаты сборки; исключить временные артефакты.
120 lines
12 KiB
C
120 lines
12 KiB
C
/* Дополнительная карта 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
|