#include "balsam_can.h" #include #include static uint16_t get_be16(const uint8_t *data) { return (uint16_t)(((uint16_t)data[0] << 8) | data[1]); } static size_t copy_name(const char *name, char *output, size_t output_size) { size_t length = strlen(name); if ((output != NULL) && (output_size != 0U)) { size_t copied = length < output_size - 1U ? length : output_size - 1U; memcpy(output, name, copied); output[copied] = '\0'; } return length; } static size_t indexed_name(const char *prefix, unsigned index, char *output, size_t output_size) { int length; if ((output == NULL) || (output_size == 0U)) { char scratch[64]; length = snprintf(scratch, sizeof scratch, "%s %u", prefix, index); } else { length = snprintf(output, output_size, "%s %u", prefix, index); } return length > 0 ? (size_t)length : 0U; } int balsam_can_is_id(uint32_t can_id) { uint32_t relative = (can_id & 0x1FFFFFFFUL) - BALSAM_CAN_BASE_ID; return relative < BALSAM_CAN_NODE_COUNT || (relative >= BALSAM_CAN_DATA_OFFSET && relative < BALSAM_CAN_DATA_OFFSET + BALSAM_CAN_NODE_COUNT); } int balsam_can_decode(uint32_t can_id, const uint8_t *data, size_t size, balsam_can_frame_t *output) { uint32_t relative; uint16_t header; if ((data == NULL) || (output == NULL)) return -1; can_id &= 0x1FFFFFFFUL; if (!balsam_can_is_id(can_id)) return 0; if (size != BALSAM_CAN_DLC) return -2; 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); header = get_be16(data); output->present_mask = (uint8_t)((header >> 13) & 0x07U); output->start_address = (uint16_t)(header & 0x1FFFU); output->values[0] = get_be16(&data[2]); output->values[1] = get_be16(&data[4]); output->values[2] = get_be16(&data[6]); return 1; } const char *balsam_can_device_name(uint8_t device) { static const char *const names[BALSAM_CAN_NODE_COUNT] = { "Трансформатор 1", "Трансформатор 2", "Силовой блок 1", "Силовой блок 2", "УМП 1", "УМП 2", "Двигатель", "ВЭП", "Задатчик", "Узел 10", "Узел 11", "Узел 12", "Терминал" }; return (device >= 1U && device <= BALSAM_CAN_NODE_COUNT) ? names[device - 1U] : "Неизвестный узел"; } size_t balsam_can_register_name(uint8_t device, uint16_t address, char *output, size_t output_size) { 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) return indexed_name("Показания T°", address - 0x17U, output, output_size); if ((device == 1U || device == 2U) && address >= 0x30U && address <= 0x43U) return indexed_name("Аварийная уставка T°", address - 0x2FU, output, output_size); if ((device == 1U || device == 2U) && address >= 0x48U && address <= 0x5BU) return indexed_name("Предупредительная уставка T°", address - 0x47U, output, output_size); if ((device == 3U || device == 4U) && address < 16U) return indexed_name("Диагностика T°", address + 1U, output, output_size); if ((device == 3U || device == 4U) && address >= 0x18U && address <= 0x27U) return indexed_name("Показания T°", address - 0x17U, output, output_size); if ((device == 3U || device == 4U) && address == 0x28U) return copy_name("Действующее Uвх1", output, output_size); if ((device == 3U || device == 4U) && address == 0x29U) return copy_name("Амплитудное Uвх1", output, output_size); if ((device == 3U || device == 4U) && address == 0x2AU) return copy_name("Действующее Uвх2", output, output_size); if ((device == 3U || device == 4U) && address == 0x2BU) return copy_name("Амплитудное Uвх2", output, output_size); if ((device == 5U || device == 6U) && address == 0U) return copy_name("Диагностика Utr a", output, output_size); if ((device == 5U || device == 6U) && address == 1U) return copy_name("Диагностика Utr c", output, output_size); if ((device == 5U || device == 6U) && address == 2U) return copy_name("Диагностика Itr a", output, output_size); if ((device == 5U || device == 6U) && address == 3U) return copy_name("Диагностика Itr c", output, output_size); if ((device == 5U || device == 6U) && address == 0x18U) return copy_name("Действующее Utr", output, output_size); if ((device == 5U || device == 6U) && address == 0x19U) return copy_name("Амплитудное Utr", output, output_size); if ((device == 5U || device == 6U) && address == 0x1AU) return copy_name("Действующее Itr", output, output_size); if ((device == 5U || device == 6U) && address == 0x1BU) return copy_name("Амплитудное Itr", output, output_size); if ((device == 5U || device == 6U) && address == 0x1CU) return copy_name("Ток СИФУ, задание (mA*10)", output, output_size); if ((device == 5U || device == 6U) && address == 0x1DU) return copy_name("Ток СИФУ, обратная связь (mA*10)", output, output_size); if (device == 7U && address < 8U) return indexed_name("Диагностика T°", address + 1U, output, output_size); if (device == 7U && address >= 0x18U && address <= 0x1FU) return indexed_name("Показания T°", address - 0x17U, output, output_size); if (device == 8U) { static const char *const vep_names[] = { "Диагностика 380В Ф1", "Диагностика 380В Ф2", "Диагностика 31В Ф1", "Диагностика 31В Ф2", "Диагностика 31В UC1", "Диагностика 31В UC2", "Диагностика 24В ПУ", "Диагностика 27В ФА", "Диагностика 24В ПК", "Диагностика 15В ДР", "Диагностика +24В ДТ", "Диагностика -24В ДТ", "Диагностика 24В ПМУ", "Диагностика T° 1", "Диагностика T° 2" }; static const char *const vep_values[] = { "Показания 380В Ф1", "Показания 380В Ф2", "Показания 31В Ф1", "Показания 31В Ф2", "Показания 31В UC1", "Показания 31В UC2", "Показания 24В ПУ", "Показания 27В ФА", "Показания 24В ПК", "Показания 15В ДР", "Показания +24В ДТ", "Показания -24В ДТ", "Показания 24В ПМУ", "Показания T° 1", "Показания T° 2" }; if (address < sizeof vep_names / sizeof vep_names[0]) return copy_name(vep_names[address], output, output_size); if (address >= 0x18U && address < 0x18U + sizeof vep_values / sizeof vep_values[0]) return copy_name(vep_values[address - 0x18U], output, output_size); if (address == 0x10U) return copy_name("Дискретные датчики (14 бит)", output, output_size); } if (device == 9U && address == 0U) return copy_name("Обороты ГЭД, об/мин", output, output_size); if (device == 9U && address == 1U) return copy_name("Обороты ГВ, об/мин", output, output_size); if (device == 9U && address == 2U) return copy_name("Лампы (8 бит)", output, output_size); if (device == 9U && address == 3U) return copy_name("Диоды (16 бит)", output, output_size); if (device == 9U && address == 0x10U) return copy_name("Кнопки (12 бит)", output, output_size); if (address == 0x16U) return copy_name("Дискретные входы / кнопки", output, output_size); if (address == 0x17U) return copy_name("Состояние джамперов", output, output_size); if (address == 0x60U) return copy_name("Период быстрого CAN-цикла", output, output_size); if (address == 0x61U) return copy_name("Период медленного CAN-цикла", output, output_size); if (address == 0x62U) return copy_name("Яркость индикации", output, output_size); if (address == 0x63U) return copy_name("Период опроса OWEN", output, output_size); if (address == 0x7EU) return copy_name("Последний режим", output, output_size); if (address == 0x7FU) return copy_name("Команды", output, output_size); return copy_name("", output, output_size); }