Проект

Общее

Профиль

Протокол (Версия 20 — временная поддержка в версии 22) => Протокол (Версия 22)

Начиная с версии 2.0 ПО устройств поменялась и версия бинарного протокола взаимодействия с устройствами. И как следствие, поменялись структуры данных, с помощью которых шло взаимодействие, и коды некоторых команд.

Протокол взаимодействия приложения и устройств CAN-Hacker происходит по бинарному протоколу. Каждое пересылаемое сообщение начинается с заголовка:

typedef struct {
    uint8_t command;
    uint8_t sequence;
    uint8_t flags;
    uint8_t dSize;
} __attribute__((packed)) CommandHeader;

Однако для сообщений, используемых для работы с шинами данных используется заголовок немного другого вида:
typedef struct {
    uint8_t command;
    uint8_t sequence;
    uint16_t flags;
    uint16_t dSize;
} __attribute__((packed)) MsgCommandHeader;

В поле command отсылается команда для устройства. Диапазон команд от 0x01 до 0x7F.
Если устройство отвечает подтверждением выполнения команды, то в поле command выставляется старший бит для присланной команды. В поле sequence помещается порядковый номер запроса, поля flags и dSize сброшены в 0x00.
Если результатом выполнения команды является некий ответ, то в поле command будет выставлен номер команды из запроса. В поле sequence помещается порядковый номер запроса, поля flags и dSize будут заполнены исходя из формата ответа.
Исходя из ранее сказанного, поле sequence можно использовать для контроля обрабатываемых команд. Так же следует учесть, что для нумерации сообщений используется 2 счётчика сообщений. Первый используется для обработки команд от приложения к устройству, второй для контроля сообщений от устройства к приложению (например, сообщения с данными шины или с её состоянием, команды COMMAND_MESSAGE (0x40) и COMMAND_BUS_ERROR (0x48)).
Флаги в поле flags выставляются в зависимости от посылаемой команды.
В случае, если команда не поддерживается, то устройство присылает ответ, где в качестве команды будет значение 0xFF, в поле sequence порядковый номер запроса, а поля flags и dSize сброшены в 0x00.

Поддерживаемые команды

Синхронизация (COMMAND_SYNC 0xA5)

Информация об устройстве и управление

Нормально взаимодействие с устройством можно после отправки команды синхронизации (COMMAND_SYNC 0xA5) устройства.

Запрос идентификатора устройства (COMMAND_DEVICE_HARDWARE 0x05)
Запрос кода устройства (COMMAND_DEVICE_INFO 0x01)
Запрос внутренней версии ПО устройства (COMMAND_DEVICE_FIRMWARE 0x02)
Запрос серийного номера устройства (COMMAND_DEVICE_SERIAL 0x03)

Установка режима работы устройства (COMMAND_DEVICE_MODE 0x04)

Начать работу с устройством (COMMAND_DEVICE_OPEN 0x08)
Завершить работу с устройством (COMMAND_DEVICE_CLOSE 0x09)
Включение сбора статистики (COMMAND_DEVICE_STAT 0x0A)

Управление каналами

Работать с каналами взаимодействия с шиной можно после отправки устройства команды начала работы (COMMAND_DEVICE_OPEN 0x08).
Нумерация каналов зависит от выбранного режима работы устройства.
Номер канала задаётся в поле flags заголовка отправляемой команды. Поддерживается работа до 7 каналов.

enum FLAG_CHANNELS {
    FLAG_CHANNEL_1 = 0x20,
    FLAG_CHANNEL_2 = 0x40,
    FLAG_CHANNEL_3 = 0x60,
    FLAG_CHANNEL_4 = 0x80,
    FLAG_CHANNEL_5 = 0xA0,
    FLAG_CHANNEL_6 = 0xC0,
    FLAG_CHANNEL_7 = 0xE0
};

Настройка канала (COMMAND_CHANNEL_CONFIG 0x11)
Открытие канала (COMMAND_CHANNEL_OPEN 0x18)
Закрытие канала (COMMAND_CHANNEL_CLOSE 0x19)
Сброс канала (COMMAND_CHANNEL_RESET 0x1F)

Управление аппаратными фильтрами

Настройка фильтров возможна только после открытия канала соединения с шиной. При закрытии канала, фильтры сбрасываются.
Следует учесть, что в зависимости от типа устройства, настройка фильтров может отличаться.

Установить фильтр (COMMAND_FILTER_SET 0x21)
Сбросить фильтр (COMMAND_FILTER_CLEAR 0x22)

Управление пробросом сообщений между каналами

После открытия каналов связи с шинами, можно активировать проброс сообщений между однотипными каналами.

Включить проброс сообщений между каналами (COMMAND_GATEWAY_ON 0x31)
Выключить проброс сообщений между каналами (COMMAND_GATEWAY_OFF 0x32)
Выставить фильтр проброса сообщений между каналами (COMMAND_GATEWAY_FILTER_SET 0x33)
Сбросить фильтр проброса сообщений между каналами (COMMAND_GATEWAY_FILTER_CLEAR 0x34)
Сбросить все фильтры проброса сообщений между каналами (COMMAND_GATEWAY_ALL_CLEAR 0x35)

Взаимодействие с данными в шинах данных

После открытия канала шины данных, устройство начнёт приём данных из шины и отправку сообщений в шину.

Отправка данных в шину

Отправить сообщение в шину (COMMAND_MESSAGE 0x40)

Выставить ответ в шину (COMMAND_SLAVE_RESPONSE_SET 0x4A) для шины LIN
Выставить режим формирования ответа в шину (COMMAND_SLAVE_RESPONSE_MODE 0x4B) для шины LIN

Приём данных из шины

Получение сообщения из шины (COMMAND_MESSAGE 0x40)
Получение статуса шины (COMMAND_BUS_ERROR 0x48)

Список поддерживаемых команд

Синхронизация (COMMAND_SYNC 0xA5)

Единственная команда, которая не подпадает под стандарт. Используется для инициализации устройства в первоначальное состояние. Происходит закрытие каналов связи с шинами данных, сброс счётчиков и буферов данных. Работа с устройством всегда начинается с отправки данной команды.
Обратите внимание, что данная команда является константой и всегда посылается в одном и том же виде.

Пример

⇒ A5 00 A5 00
⇐ 5A 00 5A 00

Запрос идентификатора устройства (COMMAND_DEVICE_HARDWARE 0x05)

Возвращается идентификатор используемого устройства. Идентификатор зависит от аппаратной составляющей устройства.
В ответе используется структура:

enum HWIdentifiers {
    HW_CH30     = 0xFF, /* Old identifier for CAN-Hacker on F105 mcu with dual CAN channels and single LIN channel */
    HW_ODB_OLD  = 0x02, /* Old identifier for CAN-Hacker in ODB interface with single CAN channel and single LIN channel */
    HW_CH32     = 0x01, /* CAN-Hacker 3.2 on F105 mcu with dual CAN channels and single LIN channel */
    HW_ODB      = 0x04, /* CAN-Hacker in ODB interface on F105 mcu with single CAN channel and single LIN channel */
    HW_CHP      = 0x03, /* CAN-Hacker CH-P on F105 mcu with dual CAN channels and single LIN channel */
    HW_CH33     = 0x11, /* CAN-Hacker 3.3 on F407 mcu with dual CAN channels and single LIN channel */
    HW_CHPM03   = 0x13, /* CAN-Hacker CH-P on F407 mcu with dual CAN channels and single LIN channel */
    HW_ODB_FD   = 0x14, /* CAN-Hacker in ODB interface on G431 mcu with single CAN channel and single LIN channel */
    HW_FDL2     = 0x06  /* CAN-Hacker CH-P on G473 mcu with dual CAN channels and single LIN channel */
};

typedef struct {
    CommandHeader header;
    uint8_t hwId;
} __attribute__((packed)) DeviceIdentifier;

Все устройства делятся на группы CH-105/CH-407/CH-4FD.
CH-105 – В своей основе имеют контроллер F105.
CH-407 – В своей основе имеют контроллер F407.
CH-4FD – В своей основе имеют контроллер G4xx.

Запрос

Поле Значение
command 0x05
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Ответ

Поле Значение
header.command 0x05
header.sequence порядковый номер запроса
header.flags 0x00
header.dSize 0x01
hwId 1 байт типа устройства

Пример

⇒ 05 xx 00 00
⇐ 05 xx 00 01 03

Запрос кода устройства (COMMAND_DEVICE_INFO 0x01)

Возвращается тип используемого устройства. Например "CH-3.x", "CH-ODB" или "CH-P".

Запрос

Поле Значение
command 0x01
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Ответ

Поле Значение
command 0x01
sequence порядковый номер запроса
flags 0x00
dSize количество байт данных
data[] ответ

Пример
Получение кода устройства CH-P

⇒ 01 xx 00 00
⇐ 01 xx 00 04 43 48 2D 50

Запрос внутренней версии ПО устройства (COMMAND_DEVICE_FIRMWARE 0x02)

Возвращается в виде текста версия ПО записанного на устройство. Например "0.2.1".

Запрос

Поле Значение
command 0x02
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Ответ

Поле Значение
command 0x02
sequence порядковый номер запроса
flags 0x00
dSize количество байт данных
data[] ответ

Пример

⇒ 02 xx 00 00
⇐ 02 xx 00 05 30 2E 32 2E 31

Запрос серийного номера устройства (COMMAND_DEVICE_SERIAL 0x03)

Возвращается серийный номер устройства.
В ответе используется структура

typedef struct {
    CommandHeader header;
    uint8_t[8] serial;
} __attribute__((packed)) DeviceSerialNumber;

Запрос

Поле Значение
command 0x03
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Ответ

Поле Значение
header.command 0x03
header.sequence порядковый номер запроса
header.flags 0x00
header.dSize 0x08
serial 8 байт серийного номера

Пример
Получение серийного номера 000000000000002E

⇒ 03 xx 00 00
⇐ 03 xx 00 08 00 00 00 00 00 00 00 2E

Установка режима работы устройства (COMMAND_DEVICE_MODE 0x04)

Перед тем как начать работу с устройством, необходимо выставить его режим работы. Этот режим задаётся через задание значения в поле flags заголовка запроса.
Допускается использовать следующие значения:

enum FLAG_DEVICE_MODES {
    FLAG_DEVICE_MODE_FULL = 0x00,
    FLAG_DEVICE_MODE_CAN  = 0x01,
    FLAG_DEVICE_MODE_LIN  = 0x02
};

Следует учесть, что при выставлении режима работы FLAG_DEVICE_MODE_CAN, то остаются доступны для работы только каналы отвечающие за работу с CAN. Каналы для работы с LIN не доступны. При выставлении режима работы FLAG_DEVICE_MODE_LIN остаются доступны каналы работы только с LIN и их нумерация начинается с 1.

Запрос

Поле Значение
command 0x04
sequence порядковый номер запроса
flags режим работы устройства
dSize 0x00

Ответ

Поле Значение
command 0x84
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример

⇒ 04 xx 01 00
⇐ 84 xx 00 00

Начать работу с устройством (COMMAND_DEVICE_OPEN 0x08)

После посылки данной команды, можно формировать команды для настройки каналов взаимодействия с шинами данных.

Запрос

Поле Значение
command 0x08
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Ответ

Поле Значение
command 0x88
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример

⇒ 08 xx 00 00
⇐ 88 xx 00 00

Завершить работу с устройством (COMMAND_DEVICE_CLOSE 0x09)

Посылка данной команды автоматически закрывает все каналы работы с шинами данных.

Запрос

Поле Значение
command 0x09
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Ответ

Поле Значение
command 0x89
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример

⇒ 09 xx 00 00
⇐ 89 xx 00 00

Включение сбора статистики (COMMAND_DEVICE_STAT 0xA)

Сбор статистики по загрузке устройства, утилизации внутренних буферов позволяет определить, что является причиной потери данных при приёме/передачи данных. Для этого выводится загрузка процессора, приблизительный процент утилизации CAN-шин (не учитываются служебные биты), а также утилизация буфера приёма данных по USB, утилизация буферов на отправку в CAN-шины и буфер обработки данных.

Управление включением и выключением сбора статистики происходит с использованием выставления флага команде:

enum DEVICE_STAT {
    DEVICE_STAT_OFF  = 0x00,
    EDVICE_STAT_ON   = 0x01
};

После отправки команды на сбор статистики от устройства с интервалами раз в 1 секунду будет приходить статистика в виде набора структур. Данный набор и его последовательность зависят от используемого устройства. Первая структура будет CommandHeader, у которой в поле command будет значение 0x0A (COMMAND_DEVICE_STAT), sequence порядковый номер посылки, dSize будет содержать длину всех передаваемых данных. Ниже представлены возможные структуры, которые будет передавать устройство:

enum DEVICE_STAT_TYPE {
    DEVICE_STAT_CPU_IDLE          = 0x01,
    DEVICE_STAT_PROCESSING_BUFFER = 0x02,
    DEVICE_STAT_USB_BUFFER        = 0x03,
    DEVICE_STAT_CAN1_LOAD_N       = 0x11,
    DEVICE_STAT_CAN1_LOAD_D       = 0x21,
    DEVICE_STAT_CAN1_TX_BUFFER    = 0x31,
    DEVICE_STAT_CAN2_LOAD_N       = 0x12,
    DEVICE_STAT_CAN2_LOAD_D       = 0x22,
    DEVICE_STAT_CAN2_TX_BUFFER    = 0x32
};

typedef struct {              // Загрузка процессора = (1 - Value / MaxValue) * 100
    uint32_t DataType;        // DEVICE_STAT_CPU_IDLE          
    uint32_t MaxValue;        // Максимальное значение IDLE
    uint32_t Value;           // Текущее значение IDLE
} __attribute__((packed)) StatIdle;

typedef struct {              // Утилизация буферов
    uint32_t DataType;        // DEVICE_STAT_PROCESSING_BUFFER, DEVICE_STAT_USB_BUFFER, DEVICE_STAT_CAN1_TX_BUFFER, DEVICE_STAT_CAN2_TX_BUFFER
    uint32_t QueueSize;       // Общий размер буфера в записях
    uint32_t Utilization;     // Сколько записей в буфере
    uint32_t Lost;            // Сколько записей не было помещено в буфер из-за его переполнения
} __attribute__((packed)) StatBufferLoad;

typedef struct {              // Сколько бит передано в шину, без учёта служебных битов, с момента последней передачи статистики
    uint32_t DataType;        // DEVICE_STAT_CAN1_LOAD_N, DEVICE_STAT_CAN1_LOAD_D, DEVICE_STAT_CAN2_LOAD_N, DEVICE_STAT_CAN2_LOAD_D
    uint32_t Value;
} __attribute__((packed)) StatChannelLoad;

Запрос

Поле Значение
command 0x0A
sequence порядковый номер запроса
flags Значение из DEVICE_STAT
dSize 0x00

Ответ

Поле Значение
command 0x8A
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Включение сбора статистики

⇒ 0A xx 01 00
⇐ 8A xx 00 00

Пример статистики, отправляемой CH-P.FDL2

⇐ 0A xx 00 6C 01 00 00 00 00 F4 01 00 CA 85 01 00 02 00 00 00 08 00 00 00 01 00 00 00 00 00 00 00 03 00 00 00 30 00 00 00 02 00 00 00 00 00 00 00 31 00 00 00 80 01 00 00 05 00 00 00 00 00 00 00 11 00 00 00 5E CD 02 00 21 00 00 00 00 00 00 00 32 00 00 00 80 01 00 00 00 00 00 00 00 00 00 00 12 00 00 00 5E CD 02 00 22 00 00 00 00 00 00 00

Здесь:
  • StatIdle ( DataType = DEVICE_STAT_CPU_IDLE, MaxValue = 0x0001F400, Value = 0x000185CA ) = Load: 22
  • StatBufferLoad ( DataType = DEVICE_STAT_PROCESSING_BUFFER, QueueSize = 8, Utilization = 1, Lost = 0 )
  • StatBufferLoad ( DataType = DEVICE_STAT_USB_BUFFER, QueueSize = 48, Utilization = 2, Lost = 0 )
  • StatBufferLoad ( DataType = DEVICE_STAT_CAN1_TX_BUFFER, QueueSize = 384, Utilization = 5, Lost = 0 )
  • StatChannelLoad ( DataType = DEVICE_STAT_CAN1_LOAD_N, Value = 0x0002CD5E )
  • StatChannelLoad ( DataType = DEVICE_STAT_CAN1_LOAD_D, Value = 0 )
  • StatBufferLoad ( DataType = DEVICE_STAT_CAN2_TX_BUFFER, QueueSize = 384, Utilization = 0, Lost = 0 )
  • StatChannelLoad ( DataType = DEVICE_STAT_CAN2_LOAD_N, Value = 0x0002CD5E )
  • StatChannelLoad ( DataType = DEVICE_STAT_CAN2_LOAD_D, Value = 0 )

Настройка канала (COMMAND_CHANNEL_CONFIG 0x11)

Перед началом работы с каналом для взаимодействия с шиной данных, его необходимо настроить. В зависимости от типа канала доступен разный набор опций.
Общий список возможных опций для настройки:

enum FLAG_CHANNEL_CONFIGS {
    FLAG_CONFIG_BUS_SPEED      = 0x00,
    FLAG_CONFIG_BUS_SPEED_FD   = 0x01,
    FLAG_CONFIG_BUS_SPEED_M    = 0x02,
    FLAG_CONFIG_BUS_SPEED_FD_M = 0x03,
    FLAG_CONFIG_TERMINATOR     = 0x05,
    FLAG_CONFIG_PULL_UP        = 0x06,
    FLAG_CONFIG_CRC_MODE       = 0x07,
    FLAG_CONFIG_IDLE_DELAY     = 0x08,
    FLAG_CONFIG_MODE           = 0x09,
    FLAG_CONFIG_CAN_FRAME      = 0x0A
};

При отправке команды настройки канала в поле flags необходимо поместить одно из значений перечисления FLAG_CHANNELS и одно из значений FLAG_CHANNEL_CONFIGS.

Для настройки канала, ответственного за работу с шиной CAN, доступны следующие настройки: Для настройки канала, ответственного за работу с шиной LIN, доступны следующие настройки:

Задание скорости взаимодействия с шиной CAN (FLAG_CONFIG_BUS_SPEED 0x00)

Для настройки скорости канала устройства для работы с CAN шиной используется структура:

typedef struct {
    CommandHeader header;
    uint8_t speed;
} __attribute__((packed)) ChannelConfigureSpeed;

Здесь в поле speed заносится индекс скорости. На данный момент используется две таблицы скоростей.

Для устройств, которые могу работать с шиной CANFD, используется следующие индексы:

enum nominalCanBitrate {
    NOMINAL_BITRATE_10K = 0,
    NOMINAL_BITRATE_20K,
    NOMINAL_BITRATE_33_3K,
    NOMINAL_BITRATE_50K,
    NOMINAL_BITRATE_62_5K,
    NOMINAL_BITRATE_83_3K,
    NOMINAL_BITRATE_95_2K,
    NOMINAL_BITRATE_100K,
    NOMINAL_BITRATE_125K,
    NOMINAL_BITRATE_250K,
    NOMINAL_BITRATE_400K,
    NOMINAL_BITRATE_500K,
    NOMINAL_BITRATE_800K,
    NOMINAL_BITRATE_1000K,
};

Для взаимодействия с классической CAN шиной используются следующие индексы:
enum canBitrate {
    CAN_BITRATE_10K = 0,
    CAN_BITRATE_20K,
    CAN_BITRATE_33_3K,
    CAN_BITRATE_50K,
    CAN_BITRATE_62_5K,
    CAN_BITRATE_83_3K,
    CAN_BITRATE_95K,
    CAN_BITRATE_100K,
    CAN_BITRATE_125K,
    CAN_BITRATE_250K,
    CAN_BITRATE_400K,
    CAN_BITRATE_500K,
    CAN_BITRATE_800K,
    CAN_BITRATE_1000K
};

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_BUS_SPEED
header.dSize 0x01
speed значение из canBitrate или nominalCanBitrate, в зависимости от типа устройства

Ответ
Если запрос успешно обработан и значение индекса скорости в поле speed задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка CAN канала 2 на скорость 20Кбит.

⇒ 11 xx 40 01 01
⇐ 91 xx 00 00

Настройка CAN канала 2 с заданием неверного индекса скорости.

⇒ 11 xx 40 01 10
⇐ FF xx 00 00

Задание скорости передачи данных на шине CANFD (FLAG_CONFIG_BUS_SPEED_FD 0x01)

Для настройки скорости передачи данных канала устройства, подключенного к шине CANFD, используется структура:

typedef struct {
    CommandHeader header;
    uint8_t speed;
} __attribute__((packed)) ChannelConfigureSpeed;

Здесь в поле speed заносится индекс предзаданной скорости.

enum dataCanBitrate {
    DATA_BITRATE_500K = 0,
    DATA_BITRATE_1000K,
    DATA_BITRATE_2000K,
    DATA_BITRATE_4000K,
    DATA_BITRATE_5000K
};

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_BUS_SPEED_FD
header.dSize 0x01
speed значение из dataCanBitrate

Ответ
Если запрос успешно обработан и значение индекса скорости в поле speed задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка канала 2 на скорость данных 1000Кбит.

⇒ 11 xx 41 01 01
⇐ 91 xx 00 00

Настройка канала 2 с заданием неверного индекса скорости.

⇒ 11 xx 41 01 10
⇐ FF xx 00 00

Ручное задание скорости взаимодействия с шиной CAN (FLAG_CONFIG_BUS_SPEED_M 0x02)

Для ручного задания скорости канала устройства используется структура:

typedef struct {
    uint16_t Prescaler;
    uint16_t tqSeg1;
    uint16_t tqSeg2;
    uint16_t SyncJW;
} __attribute__((packed)) BusCustomBaudRate;

typedef struct {
    CommandHeader header;
    BusCustomBaudRate speed;
} __attribute__((packed)) ChannelConfigureCustomSpeed;

Для устройств, в названии которых есть идентификатор FD, расчёт ведётся исходя из частоты 120МГц, для остальных устройств из линейки CAN-Hacker расчёт ведётся исходя из скорости 36МГц.

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_BUS_SPEED_M
header.dSize 0x08
speed.Prescaler 2 байта
speed.tqSeg1 2 байта
speed.tqSeg2 2 байта
speed.SyncJW 2 байта

Ответ
Если запрос успешно обработан и значения полей структуры в поле speed заданы из диапазона допустимых величин.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка канала 1 на скорость 200Кбит с частотой CAN в 36МГц ( Prescaler = 10, tqSeg1 = 15, tqSeg2 = 2, SyncJW = 1 ).

⇒ 11 xx 22 08 0A 00 0F 00 02 00 01 00
⇐ 91 xx 00 00

Настройки канала 1 с заданием одного из полей неправильным значением ( например, SyncJW = 16384\0x4000 ).

⇒ 11 xx 22 08 0A 00 0F 00 02 00 00 40
⇐ FF xx 00 00

Ручное задание скорости передачи данных на шине CANFD (FLAG_CONFIG_BUS_SPEED_FD_M 0x03)

Для ручного задания скорости передачи данных канала устройства, подключенного к шине CANFD, используется структура:

typedef struct {
    uint16_t Prescaler;
    uint16_t tqSeg1;
    uint16_t tqSeg2;
    uint16_t SyncJW;
} __attribute__((packed)) BusCustomBaudRate;

typedef struct {
    CommandHeader header;
    BusCustomBaudRate speed;
} __attribute__((packed)) ChannelConfigureCustomSpeed;

Расчёт ведётся исходя из частоты 120МГц.

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_BUS_SPEED_M
header.dSize 0x08
speed.Prescaler 2 байта
speed.tqSeg1 2 байта
speed.tqSeg2 2 байта
speed.SyncJW 2 байта

Ответ
Если запрос успешно обработан и значения полей структуры в поле speed заданы из диапазона допустимых величин.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка канала 1 на скорость передачи данных в 2000Кбит с частотой CAN в 120МГц ( Prescaler = 6, tqSeg1 = 7, tqSeg2 = 2, SyncJW = 1 ).

⇒ 11 xx 23 08 06 00 07 00 02 00 01 00
⇐ 91 xx 00 00

Подключить терминирующий резистор (FLAG_CONFIG_TERMINATOR 0x05)

Некоторые устройства позволяют задействовать терминирующий резистор на 120Ом между линиями CAN-H и CAN-L. В таком случае используется данная настройка со следующей структурой обмена данных:

enum TERMINATOR_STATES {
    CAN_TERMINATOR_OFF  = 0x00,
    CAN_TERMINATOR_ON   = 0x01
};

typedef struct {
    CommandHeader header;
    uint8_t state;
} __attribute__((packed)) ChannelConfigureTerminator;

Данная настройка доступна для устройств с идентификаторами HW_CHP (0x03), HW_CHPM03 (0x13) и HW_FDL2 (0x06). Если устройство не поддерживает данную настройку, то ответ будет содержать 0xFF в поле с номером команды.

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_TERMINATOR
header.dSize 0x01
state значение из TERMINATOR_STATES

Ответ
Если запрос успешно обработан и значение состояния терминатора задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Подключение терминатора для канала 2.

⇒ 11 xx 45 01 01
⇐ 91 xx 00 00

Задание состояния терминатора для канала 2 с неправильным значением.

⇒ 11 xx 45 01 10
⇐ FF xx 00 00

Режим взаимодействия с шиной (FLAG_CONFIG_MODE 0x09)

Можно указать режим работы с CAN шиной: активный режим (Normal), когда доступен и приём и передача данных, или пассивный режим (Listen only), когда устройство только слушает шину данных. Для некоторых устройств доступен режим петли, когда канал не подключается к шине, а отправленные данные сразу попадают на вход.
Для настройки данного параметра используется следующая структура:

enum CHANNEL_MODES {
    MODE_NORMAL   = 0x00,
    MODE_LISTEN   = 0x01,
    MODE_LOOPBACK = 0x02
};

typedef struct {
    CommandHeader header;
    uint8_t mode;
} __attribute__((packed)) ChannelConfigureMode;

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_MODE
header.dSize 0x01
mode значение из CHANNEL_MODES

Ответ
Если запрос успешно обработан и значение режима работы канала задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Задание режима работы канала 1 в режиме только прослушивания шины

⇒ 11 xx 29 01 01
⇐ 91 xx 00 00

Задание режима работы канала 1 с неправильным значением.

⇒ 11 xx 29 01 05
⇐ FF xx 00 00

Задание скорости взаимодействия с шиной LIN (FLAG_CONFIG_BUS_SPEED 0x00)

Для настройки канала устройства используется структура:

typedef struct {
    CommandHeader header;
    uint8_t speed;
} __attribute__((packed)) ChannelConfigureSpeed;

Здесь в поле speed заносится индекс предзаданной скорости.
Доступны следующие значения:
enum LIN_BITRATE {
    LIN_BITRATE_2400 = 0,
    LIN_BITRATE_9600,
    LIN_BITRATE_10400,
    LIN_BITRATE_14400,
    LIN_BITRATE_15600,
    LIN_BITRATE_19200,
    LIN_BITRATE_20000,
    LIN_BITRATE_38400
};

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_BUS_SPEED
header.dSize 0x01
speed значение из LIN_BITRATE

Ответ
Если запрос успешно обработан и значение индекса скорости в поле speed задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка канала 3 на скорость 19200 бит.

⇒ 11 xx 60 01 05
⇐ 91 xx 00 00

Настройка канала 3 с заданием неверного индекса скорости.

⇒ 11 xx 60 01 10
⇐ FF xx 00 00

Ручное задание скорости взаимодействия с шиной LIN (FLAG_CONFIG_BUS_SPEED_M 0x02)

Для ручного задания скорости канала устройства используется структура:

typedef struct {
    uint16_t Prescaler;
    uint16_t tqSeg1;
    uint16_t tqSeg2;
    uint16_t SyncJW;
} __attribute__((packed)) BusCustomBaudRate;

typedef struct {
    CommandHeader header;
    BusCustomBaudRate speed;
} __attribute__((packed)) ChannelConfigureCustomSpeed;

ПРи задании пользовательской скорости учитывается значение поля Prescaler, в который и передаётся значение требуемой скорости. Остальные поля должны быть равны 0.

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_BUS_SPEED_M
header.dSize 0x08
speed.Prescaler 2 байта
speed.tqSeg1 2 байта
speed.tqSeg2 2 байта
speed.SyncJW 2 байта

Ответ
Если запрос успешно обработан и значения полей структуры в поле speed заданы из диапазона допустимых величин.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка LIN канала 1 на скорость 19200бит.

⇒ 11 xx 22 08 00 4B 00 00 00 00 00 00
⇐ 91 xx 00 00

Подтяжка шины данных (FLAG_CONFIG_PULL_UP 0x06)

Некоторые устройства позволяют подтягивать шину данных LIN к +12В. В таком случае используется данная настройка со следующей структурой обмена данных:

enum PULL_UP_STATES {
    LIN_PULL_UP_OFF  = 0x00,
    LIN_PULL_UP_ON   = 0x01
};

typedef struct {
    CommandHeader header;
    uint8_t state;
} __attribute__((packed)) ChannelConfigurePullUp;

Данная настройка доступна для устройств с идентификаторами HW_CHP (0x03), HW_CHPM03 (0x13) и HW_FDL2 (0x06). Если устройство не поддерживает данную настройку, то ответ будет содержать 0xFF в поле с номером команды.

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_PULL_UP
header.dSize 0x01
state значение из PULL_UP_STATES

Ответ
Если запрос успешно обработан и значение подтяжки задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Подтяжка шины данных к +12В для канала 3.

⇒ 11 xx 66 01 01
⇐ 91 xx 00 00

Задание подтяжки шины данных для канала 3 с неправильным значением.

⇒ 11 xx 66 01 10
⇐ FF xx 00 00

Задание режима расчёта контрольной суммы (FLAG_CONFIG_CRC_MODE 0x07)

Для каналов, отвечающих за работу с шиной LIN можно задать тип контрольной суммы, используемой для отправки данных в шину. Для данной настройки используется структура:

enum CRC_MODES {
    LIN_CRC_MODE_CLASSIC   = 0x00,
    LIN_CRC_MODE_ENCHANCED = 0x01
};

typedef struct {
    CommandHeader header;
    uint8_t mode;
} __attribute__((packed)) ChannelConfigureCRCMode;

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_CRC_MODE
header.dSize 0x01
mode значение из CRC_MODES

Ответ
Если запрос успешно обработан и значение вида контрольной суммы задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Задание расчёта классической контрольной суммы для канала 2.

⇒ 11 xx 47 01 00
⇐ 91 xx 00 00

Задание вида расчёта контрольной суммы для канала 2 с неправильным значением.

⇒ 11 xx 47 01 10
⇐ FF xx 00 00

Задержка обработки сигнала IDLE (FLAG_CONFIG_IDLE_DELAY 0x08)

Иногда случается, что при мониторинге взаимодействия Master и Slave устройства последнее отвечает с задержкой, большей чем предусматривает стандарт. Поэтому мы предусмотрели возможность установить задержку по обработке сигнала IDLE, возникающего на шине. Для настройки данного параметра используется структура:

enum LIN_IDLE_DELAY {
    LIN_IDLE_DELAY_None = 0,
    LIN_IDLE_DELAY_100us,
    LIN_IDLE_DELAY_200us,
    LIN_IDLE_DELAY_250us,
    LIN_IDLE_DELAY_500us,
    LIN_IDLE_DELAY_750us,
    LIN_IDLE_DELAY_1000us,
    LIN_IDLE_DELAY_1500us,
    LIN_IDLE_DELAY_2000us
};
typedef struct {
    CommandHeader header;
    uint8_t delay;
} __attribute__((packed)) ChannelConfigureIdleDelay;

Здесь в поле delay заносится значение индекса задержки.

Запрос

Поле Значение
header.command 0x11
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x + FLAG_CONFIG_IDLE_DELAY
header.dSize 0x01
delay значение из LIN_IDLE_DELAY

Ответ
Если запрос успешно обработан и значение индекса задержки в поле delay задано из допустимого диапазона значений.

Поле Значение
command 0x91
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка задержки обработки IDLE в канале 3 на 1000 микросекунд.

⇒ 11 xx 68 01 06
⇐ 91 xx 00 00

Настройка канала 3 с заданием неверного индекса задержки обработки IDLE.

⇒ 11 xx 68 01 10
⇐ FF xx 00 00

Открытие канала (COMMAND_CHANNEL_OPEN 0x18)

После настройки канала его можно открыть. После посылки данной команды начнётся обмен данными с шиной.

Запрос

Поле Значение
command 0x18
sequence порядковый номер запроса
flags FLAG_CHANNEL_x
dSize 0x00

Ответ

Поле Значение
command 0x98
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Открытие канала 1.

⇒ 18 xx 20 00
⇐ 98 xx 00 00

Попытка открытия канала 5, который не предусмотрен в устройстве.

⇒ 18 xx A0 00
⇐ FF xx 00 00

Закрытие канала (COMMAND_CHANNEL_OPEN 0x19)

Закрытие канала сбрасывает аппаратные фильтры, назначенные для закрываемого канала.

Запрос

Поле Значение
command 0x19
sequence порядковый номер запроса
flags FLAG_CHANNEL_x
dSize 0x00

Ответ

Поле Значение
command 0x99
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Закрытие канала 1.

⇒ 19 xx 20 00
⇐ 99 xx 00 00

Попытка закрытия канала 5, который не предусмотрен в устройстве.

⇒ 18 xx A0 00
⇐ FF xx 00 00

Сброс канала (COMMAND_CHANNEL_RESET 0x1F)

Сброс канала можно осуществить только для CAN и CANFD соединений. При этом происходит полный сброс с очисткой буферов на передачу и последующим восстановлением состояния ранее установленных фильтров. Следует учесть, что для устройств с поддержкой CANFD происходит сброс всех каналов вне зависимости от указанного канала.

Запрос

Поле Значение
command 0x1F
sequence порядковый номер запроса
flags FLAG_CHANNEL_x
dSize 0x00

Ответ

Поле Значение
command 0x9F
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Сброс канала 1.

⇒ 1F xx 20 00
⇐ 9F xx 00 00

Установить фильтр (COMMAND_FILTER_SET 0x21)

В зависимости от типа устройства реализуются разные механизмы по настройке фильтров.
Для устройств группы CH-105/CH-407 (2 CAN + 1 LIN) доступно: CAN – 14 фильтров (11/29 бит); LIN – 8 фильтров (8 бит).
Для устройств группы CH-105/CH-407 (CAN + LIN) доступно: CAN – 28 фильтров (11/29 бит); LIN – 8 фильтров (8 бит).
Для устройств группы CH-4FD (2 CAN + 1 LIN) доступно: CAN – 28 фильтров 11 бит + 8 фильтров 29 бит; LIN – 8 фильтров (8 бит).

Для установки фильтра используется структура:

enum FLAG_FILTER_TYPE {
    FLAG_FILTER_TYPE_29BIT   = 0x01
};

typedef struct {
    uint32_t number;
    uint32_t type;
    uint32_t id;
    uint32_t mask;
} __attribute__((packed)) FilterStruct;

typedef struct {
    CommandHeader header;
    FilterStruct filter;
} __attribute__((packed)) FilterSet;

Здесь в поле filter.number передаётся порядковый номер фильтра для канала. Нумерация идёт от 0. Канал задаётся в поле header.flag. В поле filter.type задаётся тип фильтра.

Запрос

Поле Значение
header.command 0x21
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x
header.dSize 0x10
filter.number порядковый номер фильтра для канала
filter.type тип фильтра из FLAG_FILTER_TYPE
filter.id идентификатор, по которому идёт фильтрация
filter.mask маска для отбрасывания битов, не участвующих в фильтрации

Ответ
Если запрос успешно обработан и номер фильтра задан из допустимого диапазона значений.

Поле Значение
command 0xA1
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Настройка фильтра 2 для второго канала для сообщения 11 бит для фильтрации сообщений с номерами 0x01* (0x010/0x7F0).

⇒ 21 xx 40 10 01 00 00 00 00 00 00 00 10 00 00 00 F0 07 00 00
⇐ A1 xx 00 00

Настройка канала 2 с заданием неверного индекса фильтра.

⇒ 21 xx 40 10 33 00 00 00 00 00 00 00 10 00 00 00 F0 07 00 00
⇐ FF xx 00 00

Сбросить фильтр (COMMAND_FILTER_CLEAR 0x22)

Как только на канал будут сброшены все фильтры, то канал работает на пропуск всех сообщений с шины.

Для сброса фильтра используется структура:

typedef struct {
    CommandHeader header;
    uint32_t number;
} __attribute__((packed)) FilterClear;

Здесь в поле number передаётся порядковый номер фильтра для канала. Нумерация идёт от 0. Канал фильтра задаётся в поле header.flag.

Запрос

Поле Значение
header.command 0x22
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x
header.dSize 0x04
number порядковый номер фильтра для канала

Ответ
Если запрос успешно обработан и номер фильтра задан из допустимого диапазона значений.

Поле Значение
command 0xA2
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Сброс фильтра 2 для второго канала.

⇒ 22 xx 40 04 01 00 00 00
⇐ A2 xx 00 00

Сброс фильтра канала 2 с заданием неверного индекса фильтра.

⇒ 22 xx 40 04 33 00 00 00
⇐ FF xx 00 00

Включить проброс сообщений между каналами (COMMAND_GATEWAY_ON 0x31)

Включение проброса сообщений между CAN и CANFD каналами устройства. Данную команду можно выполнить только после открытия двух каналов. При включении проброса между каналами мы можем указать между какими каналами осуществлять проброс и правило фильтрации по умолчанию (пропускать все сообщения кроме указанных в фильтре или блокировать все сообщения кроме указанных фильтре).
По сравнению с первой версией протокола здесь поменялись флаги, отвечающие за настройку проброса сообщений:

enum FLAG_GW_SRC_CHANNELS {
    FLAG_GW_SRC_CHANNEL_1 = 0x02,
    FLAG_GW_SRC_CHANNEL_2 = 0x04,
    FLAG_GW_SRC_CHANNEL_3 = 0x06,
    FLAG_GW_SRC_CHANNEL_4 = 0x08,
    FLAG_GW_SRC_CHANNEL_5 = 0x0A,
    FLAG_GW_SRC_CHANNEL_6 = 0x0C,
    FLAG_GW_SRC_CHANNEL_7 = 0x0E
};

enum FLAG_GW_DST_CHANNELS {
    FLAG_GW_DST_CHANNEL_1 = 0x20,
    FLAG_GW_DST_CHANNEL_2 = 0x40,
    FLAG_GW_DST_CHANNEL_3 = 0x60,
    FLAG_GW_DST_CHANNEL_4 = 0x80,
    FLAG_GW_DST_CHANNEL_5 = 0xA0,
    FLAG_GW_DST_CHANNEL_6 = 0xC0,
    FLAG_GW_DST_CHANNEL_7 = 0xE0
};

#define FLAG_GATEWAY_DEFAULT_ACCEPT = 0x01; // Если установить во флагах, то по умолчанию пробрасываем все сообщения.

Проброс можно включить между CAN и CANFD каналами. В итоге, если сообщение пробрасывается из CANFD в CAN, то длина сообщения обрезается под размер сообщения классического CAN. При пробросе сообщений из CAN в CANFD сообщение остаётся неизменным только к флагам отправки в CANFD добавляются флаги его настройки: FDF и BRS, если CANFD настроен с переключением скоростей.

Запрос

Поле Значение
command 0x31
sequence порядковый номер запроса
flags FLAG_GW_DST_CHANNEL_x — номер канала, в который будет происходить проброс сообщений; FLAG_GW_SRC_CHANNEL_x — номер канала, из которого будут обрабатываться сообщения; FLAG_GATEWAY_DEFAULT_ACCEPT
dSize 0x00

Ответ

Поле Значение
command 0xB1
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Включение проброса сообщений из канала 1 в канал 2.

⇒ 31 xx 43 00
⇐ B1 xx 00 00

Попытка включения проброса сообщений из несуществующего канала.

⇒ 31 xx A1 00
⇐ FF xx 00 00

Выключить проброс сообщений между каналами (COMMAND_GATEWAY_OFF 0x32)

Выключение проброса сообщений между CAN и CANFD каналами устройства.

Запрос

Поле Значение
command 0x32
sequence порядковый номер запроса
flags FLAG_GW_DST_CHANNEL_x + FLAG_GW_CSRC_HANNEL_x — номера каналов, между которыми отключить проброс сообщений
dSize 0x00

Ответ

Поле Значение
command 0xB1
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Выключение проброса сообщений из канала 1 в канал 2.

⇒ 32 xx 24 00
⇐ B2 xx 00 00

Попытка выключения проброса сообщений из несуществующего канала.

⇒ 32 xx A0 00
⇐ FF xx 00 00

Выставить фильтр проброса сообщений между каналами (COMMAND_GATEWAY_FILTER_SET 0x33)

В зависимости от настроек проброса сообщений между каналами выставляемые фильтры либо блокируют сообщения, либо пропускают. Для настройки фильтров используются те же структуры, что и для аппаратных фильтров: FilterSet и FilterStruct.
На данный момент можно задать фильтрацию по Id и маске. На каждое направление проброса можно задать по 32 записи с фильтрами сообщений.

Запрос

Поле Значение
header.command 0x33
header.sequence порядковый номер запроса
header.flags FLAG_GW_DST_CHANNEL_x + FLAG_GW_SRC_CHANNEL_x
header.dSize 0x10
filter.number порядковый номер фильтра для пары DST channel + SRC channel
filter.type тип фильтра из FLAG_FILTER_TYPE
filter.id идентификатор, по которому идёт фильтрация
filter.mask маска для отбрасывания битов, не участвующих в фильтрации

Сбросить фильтр проброса сообщений между каналами (COMMAND_GATEWAY_FILTER_CLEAR 0x34)

Структура сброса фильтра аналогична сбросу аппаратного фильтра.

Запрос

Поле Значение
header.command 0x34
header.sequence порядковый номер запроса
header.flags FLAG_GW_DST_CHANNEL_x + FLAG_GW_SRC_CHANNEL_x
header.dSize 0x04
number порядковый номер фильтра для канала

Сбросить все фильтры проброса сообщений между каналами (COMMAND_GATEWAY_ALL_CLEAR 0x35)

Вместо сброса фильтров проброса сообщений между каналами по одному, можно их сбросить сразу все, заполнив соответствующим образом структуру CommandHeader.

Запрос

Поле Значение
command 0x35
sequence порядковый номер запроса
flags FLAG_GW_DST_CHANNEL_x + FLAG_GW_SRC_CHANNEL_x
dSize 0x00

Отправить сообщение в шину (COMMAND_MESSAGE 0x40)

По сравнению с первой версией протокола данная команда претерпела ряд изменений в передаваемых данных устройству для передачи в шину данных. Теперь отправка сообщений происходит с использованием следующей структуры:

enum FLAG_MESSAGE_CHANNELS {
    FLAG_MESSAGE_CHANNEL_1 = 0x2000,
    FLAG_MESSAGE_CHANNEL_2 = 0x4000,
    FLAG_MESSAGE_CHANNEL_3 = 0x6000,
    FLAG_MESSAGE_CHANNEL_4 = 0x8000,
    FLAG_MESSAGE_CHANNEL_5 = 0xA000,
    FLAG_MESSAGE_CHANNEL_6 = 0xC000,
    FLAG_MESSAGE_CHANNEL_7 = 0xE000
};

#define FLAG_MESSAGE_CONFIRM_REQUIRED   0x0001U

// 29-bit message identifier
#define FLAG_MESSAGE_EXTID              0x00000001U
// Remote frame
#define FLAG_MESSAGE_RTR                0x00000002U
// CAN-FD frame
#define FLAG_MESSAGE_FDF                0x00000004U
// CAN-FD bit rate switch
#define FLAG_MESSAGE_BRS                0x00000008U
// CAN-FD Error status indicator
#define FLAG_MESSAGE_ESI                0x00000010U
// Block TX
#define FLAG_MESSAGE_BLOCK_TX           0x30000000U

typedef struct {
    uint32_t flags;                             // 4 bytes
    uint32_t msgID;                             // 4 bytes
    uint16_t dlc;                               // 2 bytes
    uint8_t  data[64];
} __attribute__((packed)) ToBusMessage;

typedef struct {
    MsgCommandHeader header;
    ToBusMessage message;
} __attribute__((packed)) SendMessage;

Если в поле message.dlc указывается длина передаваемых данных меньше 64 байт, то поле data может соответствовать количеству данных, указанных в message.dlc. Тогда header.dSize уменьшается на величину реально передаваемых данных.

Следует учесть, что по сравнению с первой версией протокола в header.flags указывается только номер канала из FLAG_MESSAGE_CHANNEL_x, через который будет происходить передача данных.
Для настройки формата передаваемых данных теперь используется поле message.flags. Следует учесть, что если для CAN шины в message.flags не выставить флаг FLAG_MESSAGE_BLOCK_TX, то устройство после отправки сообщения в шину вернёт его с соответствующим флагом.

Запрос

Поле Значение
header.command 0x40
header.sequence порядковый номер запроса
header.flags FLAG_MESSAGE_CHANNEL_x
header.dSize 0x0A - 0x4A
message.flags FLAG_MESSAGE_xxxx
message.msgID идентификатор отправляемого сообщения
message.dlc размер передаваемых данных в шину
message.data данные, передаваемые в шину

Ответ
Если выставлен флаг FLAG_MESSAGE_CONFIRM_REQUIRED в поле header.flags и запрос успешно обработан.

Поле Значение
command 0xC0
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Передача 4 байт данных в шину с 29 битным идентификатором сообщения 0x1FF00000.

⇒ 40 xx 00 20 0E 00 01 00 00 30 00 00 F0 1F 04 00 00 00 07 F0

Передача RTR запроса в шину с 11 битным идентификатором сообщения 0x2FF.

⇒ 40 xx 00 20 0A 00 02 00 00 30 FF 02 00 00 04 00

Выставить ответ в шину (COMMAND_SLAVE_RESPONSE_SET 0x4A)

Данная команда используется для выставления Slave ответа в LIN шине. Данная команда использует следующую структуру данных:

typedef struct {
    uint32_t msgID;
    uint8_t dlc;
    uint8_t data[8];
} __attribute__((packed)) ToBusMessage;

typedef struct {
    CommandHeader header;
    ToBusMessage slave;
} __attribute__((packed)) SlaveResponse;

Если в поле slave.dlc указывается длина передаваемых данных меньше 8 байт, то поле data может соответствовать количеству данных, указанных в slave.dlc. Тогда header.dSize уменьшается на величину реально передаваемых данных.
Здесь указывается для какого сообщения необходимо выставить Slave ответ. Идентификатор сообщения может быть как с выставленными битами защиты, так и со сброшенными.

Запрос

Поле Значение
header.command 0x4A
header.sequence порядковый номер запроса
header.flags FLAG_CHANNEL_x
header.dSize длина передаваемых данных
slave.msgID идентификатор отслеживаемого сообщения
slave.dlc размер передаваемых данных в шину
slave.data данные, передаваемые в шину

Ответ

Поле Значение
command 0xCA
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Если запрос не обработан.

Поле Значение
command 0xFF
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Необходимо при получении сообщения (биты защиты сброшены) передать 4 байта данных.

⇒ 4A xx 20 09 00 00 00 01 04 00 00 07 F0
⇐ СA xx 00 00

Выставить режим формирования ответа в шину (COMMAND_SLAVE_RESPONSE_MODE 0x4B)

Выставление режима формирования ответа в LIN-шину переводит устройство в целом в режим SLAVE. В итоге из панели передачи данных вы не сможете отправлять пакеты в LIN-шину. Режим работы задаётся выставлением в поле flags заголовка запроса соответствующего значения.
Возможные значения:

enum FLAG_LIN_SLAVE_MODES {
    FLAG_LIN_SLAVE_MODE_OFF = 0x00,
    FLAG_LIN_SLAVE_MODE_ON  = 0x01
};

Запрос

Поле Значение
command 0x4B
sequence порядковый номер запроса
flags FLAG_CHANNEL_x + FLAG_LIN_SLAVE_MODES
dSize 0x00

Ответ

Поле Значение
command 0xCB
sequence порядковый номер запроса
flags 0x00
dSize 0x00

Пример
Включение SLAVE режима для LIN-шины.

⇒ 4B xx 21 00
⇐ CB xx 00 00

Попытка выключения SLAVE режима на несуществующем LIN-канале.

⇒ 4B xx A0 00
⇐ FF xx 00 00

Получение сообщения из шины (COMMAND_MESSAGE 0x40)

Получение данных из шины происходит с использованием следующих структур:

enum FLAG_MESSAGE_CHANNELS {
    FLAG_MESSAGE_CHANNEL_1 = 0x2000,
    FLAG_MESSAGE_CHANNEL_2 = 0x4000,
    FLAG_MESSAGE_CHANNEL_3 = 0x6000,
    FLAG_MESSAGE_CHANNEL_4 = 0x8000,
    FLAG_MESSAGE_CHANNEL_5 = 0xA000,
    FLAG_MESSAGE_CHANNEL_6 = 0xC000,
    FLAG_MESSAGE_CHANNEL_7 = 0xE000
};

// 29-bit message identifier
#define FLAG_MESSAGE_EXTID              0x00000001U
// Remote frame
#define FLAG_MESSAGE_RTR                0x00000002U
// CAN-FD frame
#define FLAG_MESSAGE_FDF                0x00000004U
// CAN-FD bit rate switch
#define FLAG_MESSAGE_BRS                0x00000008U
// CAN-FD Error status indicator
#define FLAG_MESSAGE_ESI                0x00000010U
// LIN Master request
#define FLAG_MESSAGE_MR                 0x00000100U
// LIN Slave response
#define FLAG_MESSAGE_SR                 0x00000200U
// Classic CRC for LIN
#define FLAG_MESSAGE_CC                 0x00001000U
// Enhanced CRC for LIN
#define FLAG_MESSAGE_EC                 0x00002000U
// Error frame
#define FLAG_MESSAGE_EF                 0x01000000U
// RX
#define FLAG_MESSAGE_RX                 0x10000000U
// TX
#define FLAG_MESSAGE_TX                 0x20000000U

typedef struct {
    uint32_t flags;   // флаги сообщения
    uint32_t time;    // время получения сообщения из шины в микросекундах по внутренним часам устройства
    uint32_t crc;     // предполагаемая контрольная сумма сообщения. используется для LIN. в остальных случаях не определено.
    uint32_t msgID;
    uint16_t dlc;
    uint8_t data[64];
} __attribute__((packed)) BusMessage;

typedef struct {
    MsgCommandHeader header;
    BusMessage message;
} __attribute__((packed)) RcvMessage;

Если в поле message.dlc указывается длина передаваемых данных меньше 64 байт, то поле data может соответствовать количеству данных, указанных в message.dlc. Тогда header.dSize уменьшается на величину реально передаваемых данных.

Получение статуса шины (COMMAND_BUS_ERROR 0x48)

Данная команда от устройства возвращает статус шины в случае возникновения ошибки. Если в последствии ошибка на шине уходит, то приходит команда со статусом ошибки 0.
Команда со статусом шины может принимать следующие значения:

#define ERROR_CAN_STUFF                 0x00000001U
#define ERROR_CAN_FORMAT                0x00000002U
#define ERROR_LIN_FRAME                 0x00000002U
#define ERROR_CAN_ACK                   0x00000004U
#define ERROR_CAN_CRC                   0x00000008U
#define ERROR_CAN_TRANSMIT1             0x00000010U
#define ERROR_CAN_TRANSMIT0             0x00000020U
#define ERROR_BUS_OFF                   0x00000040U
#define ERROR_PASSIVE                   0x00000080U
#define ERROR_WARNING                   0x00000100U
#define ERROR_OVERFLOW                  0x00000200U
#define ERROR_DATA_STUFF                0x00010000U
#define ERROR_DATA_FORMAT               0x00020000U
#define ERROR_DATA_ACK                  0x00040000U
#define ERROR_DATA_CRC                  0x00080000U
#define ERROR_DATA_TRANSMIT1            0x00100000U
#define ERROR_DATA_TRANSMIT0            0x00200000U

typedef struct {
    CommandHeader header;
    uint32_t error;
} __attribute__((packed)) BusError;

В поле header.flags будет указан номер канала, для которого пришло данное сообщение.