128 lines
5.8 KiB
C
128 lines
5.8 KiB
C
/**
|
||
* @file can_sensor.h
|
||
* @brief Портируемый транспорт SETTINGS для привязки DS18B20 к локации.
|
||
*
|
||
* Один Extended CAN-кадр содержит полную операцию. Поля локации находятся в
|
||
* Body идентификатора SETCAN, а восьмибайтовый ROM — в payload:
|
||
*
|
||
* @code
|
||
* Priority=1, DeviceType=0x7, DeviceID=0xF, MsgType=0xE (SETTINGS)
|
||
* Body[15:8] = номер сборки, Body[7:0] = позиция
|
||
* @endcode
|
||
*
|
||
* Запрос ПМ использует Route=0 (0x17FEZZYY), ответ прибора — Route=1
|
||
* (0x1FFEZZYY). DLC=0 означает GET, DLC=8 с ненулевым ROM — SET/REPLACE,
|
||
* DLC=8 с нулевым ROM — CLEAR. Успешный ответ возвращает текущий ROM с DLC=8,
|
||
* ошибка — однобайтовый код с DLC=1.
|
||
*/
|
||
|
||
#ifndef CAN_SENSOR_H
|
||
#define CAN_SENSOR_H
|
||
|
||
#include <stdint.h>
|
||
|
||
/** Длина ROM 1-Wire и максимального payload classic CAN. */
|
||
#define CAN_SENSOR_ID_SIZE 8U
|
||
#define CAN_SENSOR_MAX_DATA 8U
|
||
|
||
/** Назначенный проекту тип сообщения SETCAN SETTINGS. */
|
||
#define CAN_SENSOR_MSGTYPE_SETTINGS 0xEU
|
||
|
||
/** Маска полей SETCAN от Priority до MsgType; Body под маской не находится. */
|
||
#define CAN_SENSOR_HEADER_MASK 0x1FFF0000UL
|
||
#define CAN_SENSOR_BODY_MASK 0x0000FFFFUL
|
||
|
||
/** Базовые ID SETTINGS для выбранных DeviceType=0x7 и DeviceID=0xF. */
|
||
#define CAN_SENSOR_DEFAULT_TX_ID 0x1FFE0000UL
|
||
#define CAN_SENSOR_DEFAULT_RX_ID 0x17FE0000UL
|
||
|
||
/** Число попыток помещения кадра в почтовый ящик. */
|
||
#define CAN_SENSOR_DEFAULT_RETRIES 3U
|
||
|
||
/** Операции, полученные из направления, DLC и payload кадра. */
|
||
#define CAN_SENSOR_OPERATION_GET 0U
|
||
#define CAN_SENSOR_OPERATION_WRITE 1U
|
||
#define CAN_SENSOR_OPERATION_CLEAR 2U
|
||
#define CAN_SENSOR_OPERATION_RESPONSE 3U
|
||
#define CAN_SENSOR_OPERATION_ERROR 4U
|
||
#define CAN_SENSOR_OPERATION_INVALID 5U
|
||
|
||
/** Коды результата SETTINGS, передаваемые ответом с DLC=1. */
|
||
#define CAN_SENSOR_RESULT_OK 0x00U
|
||
#define CAN_SENSOR_RESULT_INVALID_DLC 0x01U
|
||
#define CAN_SENSOR_RESULT_INVALID_ROM_CRC 0x02U
|
||
#define CAN_SENSOR_RESULT_NOT_FOUND 0x03U
|
||
#define CAN_SENSOR_RESULT_ALREADY_ASSIGNED 0x04U
|
||
#define CAN_SENSOR_RESULT_EEPROM_ERROR 0x05U
|
||
#define CAN_SENSOR_RESULT_INVALID_LOCATION 0x06U
|
||
#define CAN_SENSOR_RESULT_BUSY 0x07U
|
||
|
||
/** Кадр CAN в форме, не зависящей от периферийного контроллера. */
|
||
typedef struct {
|
||
uint32_t id; /**< Расширенный идентификатор, 29 бит. */
|
||
uint8_t extended; /**< Для SETTINGS всегда 1. */
|
||
uint8_t length; /**< DLC, 0..8. */
|
||
uint8_t data[CAN_SENSOR_MAX_DATA]; /**< Payload. */
|
||
} CanSensor_Frame;
|
||
|
||
/** Разобранная команда или ответ SETTINGS. */
|
||
typedef struct {
|
||
uint8_t operation; /**< CAN_SENSOR_OPERATION_*. */
|
||
uint8_t request; /**< 1 — запрос Route=0, 0 — ответ Route=1. */
|
||
uint8_t assembly_serial; /**< Body[15:8], номер сборки Z. */
|
||
uint8_t position; /**< Body[7:0], позиция Y. */
|
||
uint8_t result; /**< Код ошибки для ERROR/INVALID. */
|
||
uint8_t id[CAN_SENSOR_ID_SIZE]; /**< ROM для WRITE/RESPONSE, нули для CLEAR. */
|
||
} CanSensor_Message;
|
||
|
||
/** Доступ переносимой части к CAN-контроллеру. */
|
||
typedef struct {
|
||
uint8_t (*send)(void *context, const CanSensor_Frame *frame);
|
||
uint8_t (*receive)(void *context, CanSensor_Frame *frame);
|
||
void *context;
|
||
} CanSensor_Io;
|
||
|
||
/** Базовые идентификаторы SETTINGS и режим транспорта. */
|
||
typedef struct {
|
||
uint32_t tx_id; /**< База ответа 0x1FFE0000, Body должен быть нулевым. */
|
||
uint32_t rx_id; /**< База запроса 0x17FE0000, Body должен быть нулевым. */
|
||
uint8_t extended; /**< 1 — Extended CAN ID. */
|
||
uint8_t retries; /**< Число попыток передачи. */
|
||
} CanSensor_Config;
|
||
|
||
/** Состояние транспорта и диагностические счётчики. */
|
||
typedef struct {
|
||
CanSensor_Io io;
|
||
CanSensor_Config config;
|
||
uint32_t sent_messages;
|
||
uint32_t send_errors;
|
||
uint32_t received_messages;
|
||
uint32_t dropped_frames;
|
||
} CanSensor;
|
||
|
||
void CanSensor_ConfigDefault(CanSensor_Config *config);
|
||
|
||
uint8_t CanSensor_Init(CanSensor *link, const CanSensor_Io *io,
|
||
const CanSensor_Config *config);
|
||
|
||
/** Собирает SETTINGS-кадр на базе tx_id или rx_id. */
|
||
uint8_t CanSensor_BuildFrame(const CanSensor_Config *config, CanSensor_Frame *frame,
|
||
uint8_t response, uint8_t position,
|
||
uint8_t assembly_serial, const uint8_t *data,
|
||
uint8_t length);
|
||
|
||
/** Передаёт успешный ответ с текущим ROM (DLC=8). */
|
||
uint8_t CanSensor_SendId(CanSensor *link, uint8_t position,
|
||
uint8_t assembly_serial, const uint8_t *id);
|
||
|
||
/** Передаёт ошибку SETTINGS (DLC=1). */
|
||
uint8_t CanSensor_SendError(CanSensor *link, uint8_t position,
|
||
uint8_t assembly_serial, uint8_t result);
|
||
|
||
uint8_t CanSensor_HandleFrame(CanSensor *link, const CanSensor_Frame *frame,
|
||
CanSensor_Message *out);
|
||
|
||
uint8_t CanSensor_Poll(CanSensor *link, CanSensor_Message *out);
|
||
|
||
#endif /* CAN_SENSOR_H */
|