183 lines
9.1 KiB
C
183 lines
9.1 KiB
C
#include "balsam_can.h"
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
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);
|
||
}
|