/** * @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 /** Длина 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 */