/* Параметры и обработчики Modbus после проверки CRC. Массив modbus * содержит обычные адреса 0..127, область 0x1000 обслуживает логгер. * EEPROM хранит параметры, но не является источником START/STOP: * при загрузке сохраняется последняя живая команда нагрузки. * Функции вызываются из main; EEPROM блокирует этот контекст. */ #include "DSP2833x_Device.h" // DSP2833x Headerfile Include File #include "package.h" #include "RS485.h" #include "crc16.h" #include "cntrl_adr.h" #include "bios_dsp.h" #include "message.h" #include "filter_bat2.h" #include "measure.h" #include "ADC.h" #include "peripher.h" #include "ecan.h" #include "pulto.h" #include "spise2p.h" #include "include/balsam167_eeprom_block.h" /* Использует общий с 167 контракт FC03: окно 0x8000..0xBFFF, до 120 слов AT25256B за запрос. */ #include "caliber.h" #include "log_to_mem.h" #include "firmware_info.h" /* Подключает адрес и границы неизменяемого паспорта 0x1200, совместимого с проверкой прошивки в 167. */ #include "../src/firmware_info_static.c" /* Собирает общие 12 слов firmware-info через include-путь firmware-info/include; как в 167, копии упаковщика в проекте нет. */ #include "DAC.h" int modbus[ANSWER_LEN+1]; unsigned int param[ANSWER_LEN+1]; void Default_params() { unsigned int i,def; int shkf_lo_edge[] = {300, // 380 300, // 38O 0, // 0 0, // 0 15, // 31 22, // 27 20, // 24 10, // 15 60}; // AD int bright[] = {10,8,6,8,6,8}; for(i=0;ibuffer[0] = CNTRL_ADDR; rs_arr->buffer[1] = function | 0x80; rs_arr->buffer[2] = error; crc = get_crc_16(0xFFFF, rs_arr->buffer, 3); rs_arr->buffer[3] = LOBYTE(crc); rs_arr->buffer[4] = HIBYTE(crc); rs_arr->flag_TIMEOUT_to_Send = true; RS_Send(rs_arr, rs_arr->buffer, 5); } void ReceiveCommandModbus3(RS_DATA *rs_arr) { unsigned int crc, Address_MB, Length_MB, i, value, saved = 0; // получили начальный адрес чтениа Address_MB = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3]; // получили количество слов данных Length_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; if (Address_MB >= BALSAM167_EEPROM_RTU_BASE) { /* Выделяет только верхнее окно EEPROM; старые регистры, логгер и паспорт обрабатываются прежним кодом ниже. */ if (!balsam167_eeprom_block_valid_profile(CMD_MODBUS_3, Address_MB, Length_MB, 0U)) { /* Профиль 0 сохраняет контракт 167 для 32 КиБ: запрещает пустой блок, более 120 слов, M95 и выход за конец окна. */ modbus_exception(rs_arr, CMD_MODBUS_3, 2U); /* Возвращает Illegal Data Address с CRC до любого обращения к SPI при неверном диапазоне. */ return; /* Не допускает перехода ошибочного запроса EEPROM к backend логгера или обычным регистрам. */ } /* Валидатор проверяет конец через вычитание, поэтому переполнение 16-битного адреса не разрешает чтение. */ Seeprom_read(Address_MB - BALSAM167_EEPROM_RTU_BASE, &rs_arr->buffer[3], Length_MB * 2U); /* Как в 167, SPI получает адрес в 16-битных словах и длину в октетах; IRQ остаются разрешены для автомата Timer2. */ for (i = Length_MB; i > 0U; --i) { /* Разворачивает прочитанные слова с конца в том же UART-буфере без нового массива и перезаписи ещё не обработанных слов. */ value = rs_arr->buffer[i + 2U]; /* Временное слово сохраняет оба SPI-октета до расширения одного элемента C28x в два октета RTU. */ rs_arr->buffer[i * 2U + 2U] = value & 0xFFU; /* Записывает младший октет слова после старшего, как требует физический дамп EEPROM в SETGUI. */ rs_arr->buffer[i * 2U + 1U] = (value >> 8) & 0xFFU; /* Маска 0xFF выделяет восемь бит линии из 16-битного unsigned int C28x. */ } /* Обратный обход корректен и для одного слова, и для максимального блока из 120 слов. */ rs_arr->buffer[0] = CNTRL_ADDR; /* Отвечает собственным адресом платы, сохраняя поддержку общего адреса 16 существующим приёмником. */ rs_arr->buffer[1] = CMD_MODBUS_3; /* Возвращает стандартную команду FC03 без введения отдельной команды BIOS или записи памяти. */ rs_arr->buffer[2] = Length_MB * 2U; /* Число полезных октетов находится в диапазоне 2..240 и помещается в одном октете RTU. */ crc = get_crc_16(0xFFFFU, rs_arr->buffer, Length_MB * 2U + 3U); /* Проверяет адрес, команду, длину и весь блок тем же Modbus CRC16, что остальные ответы прошивки. */ rs_arr->buffer[Length_MB * 2U + 3U] = LOBYTE(crc); /* Передаёт младший октет CRC первым в соответствии с Modbus RTU. */ rs_arr->buffer[Length_MB * 2U + 4U] = HIBYTE(crc); /* Завершает кадр старшим октетом CRC без устаревшего нулевого хвоста. */ rs_arr->flag_TIMEOUT_to_Send = true; /* Использует штатное управление таймаутом UART при отправке готового ответа из main. */ RS_Send(rs_arr, rs_arr->buffer, Length_MB * 2U + 5U); /* Отправляет ровно 5 служебных октетов плюс данные, максимум 245 элементов из существующего буфера на 400. */ return; /* Завершает только новый маршрут EEPROM, сохраняя прежние форматы остальных ответов FC03. */ } /* Новый маршрут не меняет PEEK, запись EEPROM, адреса параметров или драйвер SPI. */ if (!Length_MB || Length_MB > 125 || !((Address_MB < ANSWER_LEN && Length_MB <= ANSWER_LEN-Address_MB) || (Address_MB >= UMP_LOG_BASE && Address_MB <= UMP_LOG_BASE+15 && Length_MB <= UMP_LOG_BASE+16-Address_MB) || (Address_MB >= UMP_LOG_DATA && Address_MB < UMP_LOG_DATA+120 && Length_MB <= UMP_LOG_DATA+120-Address_MB) || (Address_MB == UMP_LOG_LIVE && Length_MB == 124) || /* Сохраняет точное прежнее 124-словное онлайн-окно логгера. */ firmware_info_range(Address_MB, Length_MB))) { /* Дополнительно разрешает только полное или частичное чтение двенадцати регистров паспорта. */ modbus_exception(rs_arr, CMD_MODBUS_3, 2); return; } ///////////////////////////////////////////////// // Отсылка /* Посчитали контрольную сумму перед самой посылкой */ rs_arr->buffer[0] = CNTRL_ADDR; rs_arr->buffer[1] = CMD_MODBUS_3; rs_arr->buffer[2] = Length_MB*2; /* Защищаем целостность одного снимка/блока; передача UART идёт уже * с разрешёнными прерываниями и не задерживает измерение/управление. */ if (Address_MB >= UMP_LOG_BASE && Address_MB < FIRMWARE_INFO_ADDRESS) saved = __disable_interrupts(); /* Неизменяемый паспорт не требует блокировки IRQ; целостность прежних снимков логгера сохраняется. */ for (i=0;i= FIRMWARE_INFO_ADDRESS) value = firmware_info_static_read(Address_MB - FIRMWARE_INFO_ADDRESS + i); /* После проверки диапазона читает только соответствующее слово статического паспорта, без обращения к логгеру. */ else value = Address_MB >= UMP_LOG_BASE ? ump_log_read(Address_MB+i) : (unsigned int)modbus[Address_MB+i]; /* Сохраняет прежнюю маршрутизацию и беззнаковое представление 16-битных слов технологической карты и логгера v4. */ rs_arr->buffer[3+i*2] = (value >> 8) & 0xFF; rs_arr->buffer[3+i*2+1] = value & 0xFF; } if (Address_MB >= UMP_LOG_BASE && Address_MB < FIRMWARE_INFO_ADDRESS) __restore_interrupts(saved); /* Возвращает сохранённую маску только для действительно защищённого снимка логгера. */ crc = 0xffff; crc = get_crc_16(crc, rs_arr->buffer, Length_MB*2+3); rs_arr->buffer[Length_MB*2+3] = LOBYTE(crc); rs_arr->buffer[Length_MB*2+4] = HIBYTE(crc); rs_arr->buffer[Length_MB*2+5] = 0; rs_arr->buffer[Length_MB*2+6] = 0; rs_arr->buffer[Length_MB*2+7] = 0; rs_arr->buffer[Length_MB*2+8] = 0; rs_arr->flag_TIMEOUT_to_Send=true; /* Расширение логгера отвечает точным кадром Modbus без хвостовых * нулей: они иначе попали бы в начало ответа следующего блока GUI. * Исторический формат технологических регистров оставлен прежним. */ RS_Send(rs_arr, rs_arr->buffer, Length_MB*2+(Address_MB >= UMP_LOG_BASE ? 5 : 8)); return; } void ReceiveCommandModbus6(RS_DATA *rs_arr) { unsigned int Address_MB, Data_MB, i; ///////////////////////////////////////////////// // Отсылка /* Отправлаем назад то же самое */ for (i=0;i<8;i++) rs_arr->buffer[i] = rs_arr->RS_Header[i]; // получили начальный адрес записи Address_MB = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3]; // получили слово данных Data_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; if (Address_MB >= FIRMWARE_INFO_ADDRESS && Address_MB < FIRMWARE_INFO_END) { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; } /* Как в контракте 167, запись в паспорт запрещена с Illegal Data Address и не достигает параметров или логгера. */ if (Address_MB >= UMP_LOG_BASE) { if (!ump_log_write(Address_MB, Data_MB)) { modbus_exception(rs_arr, CMD_MODBUS_6, 3); return; } } else if (Address_MB < ANSWER_LEN) { /* RS и CAN используют одну историю фронтов. Чередование каналов * не создаёт двух независимых повторных запусков. */ if (Address_MB == 127) { UMP_commands_write(Data_MB); ump_log_rs(); } else Modbus[Address_MB].all = Data_MB; } else { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; } rs_arr->flag_TIMEOUT_to_Send=true; RS_Send(rs_arr, rs_arr->buffer, Address_MB >= UMP_LOG_BASE ? 8 : 10); }