feat(protocan-boot): добавь прошивку приборов по CAN

This commit is contained in:
2026-08-29 17:11:53 +03:00
parent a1d2d05f42
commit d3bb634fb1
6 changed files with 927 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
#ifndef PCAN_BOOT_H
#define PCAN_BOOT_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PCAN_BOOT_VERSION 1U
#define PCAN_BOOT_BLOCK_SIZE 8U
#define PCAN_BOOT_BLOCK_COUNT 65536UL
#define PCAN_BOOT_SLOT_SIZE (PCAN_BOOT_BLOCK_COUNT * PCAN_BOOT_BLOCK_SIZE)
#define PCAN_BOOT_SLOT_NONE 0xFFU
#define PCAN_BOOT_MSG_CONTROL 0x9U
#define PCAN_BOOT_MSG_DATA_A 0xAU
#define PCAN_BOOT_MSG_DATA_B 0xBU
#define PCAN_BOOT_MSG_STATUS 0xCU
#define PCAN_BOOT_MSG_DISCOVERY 0xDU
#define PCAN_BOOT_ROUTE_FROM_PM 0U
#define PCAN_BOOT_ROUTE_FROM_DEVICE 1U
typedef enum {
PCAN_BOOT_CMD_IDENTIFY = 0x01U,
PCAN_BOOT_CMD_ENTER_BOOT = 0x02U,
PCAN_BOOT_CMD_BEGIN_IMAGE = 0x03U,
PCAN_BOOT_CMD_BEGIN_COMPAT = 0x04U,
PCAN_BOOT_CMD_ERASE = 0x05U,
PCAN_BOOT_CMD_VERIFY = 0x06U,
PCAN_BOOT_CMD_COMMIT = 0x07U,
PCAN_BOOT_CMD_CONFIRM = 0x08U,
PCAN_BOOT_CMD_REBOOT = 0x09U,
PCAN_BOOT_CMD_ABORT = 0x0AU,
PCAN_BOOT_CMD_QUERY_PROGRESS = 0x0BU
} pcan_boot_command_t;
typedef enum {
PCAN_BOOT_STATUS_OK = 0x00U,
PCAN_BOOT_STATUS_BUSY = 0x01U,
PCAN_BOOT_STATUS_INVALID_COMMAND = 0x02U,
PCAN_BOOT_STATUS_WRONG_DEVICE = 0x03U,
PCAN_BOOT_STATUS_WRONG_HARDWARE = 0x04U,
PCAN_BOOT_STATUS_INVALID_SIZE = 0x05U,
PCAN_BOOT_STATUS_CRC_ERROR = 0x06U,
PCAN_BOOT_STATUS_FLASH_ERROR = 0x07U,
PCAN_BOOT_STATUS_SEQUENCE_ERROR = 0x08U,
PCAN_BOOT_STATUS_SIGNATURE_ERROR = 0x09U,
PCAN_BOOT_STATUS_SESSION_ERROR = 0x0AU,
PCAN_BOOT_STATUS_VOLTAGE_ERROR = 0x0BU,
PCAN_BOOT_STATUS_INVALID_STATE = 0x0CU
} pcan_boot_status_t;
typedef enum {
PCAN_BOOT_STATE_IDLE = 0,
PCAN_BOOT_STATE_METADATA,
PCAN_BOOT_STATE_READY_TO_ERASE,
PCAN_BOOT_STATE_RECEIVING,
PCAN_BOOT_STATE_VERIFIED,
PCAN_BOOT_STATE_FAILED
} pcan_boot_state_t;
typedef struct {
uint32_t image_size;
uint32_t image_crc32;
uint32_t firmware_version;
uint16_t product_type;
uint8_t hardware_revision_min;
uint8_t hardware_revision_max;
} pcan_boot_manifest_t;
typedef struct {
uint8_t device_type;
uint8_t device_id;
uint16_t product_type;
uint8_t hardware_revision;
uint32_t firmware_version;
uint8_t active_slot;
uint8_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */
} pcan_boot_config_t;
typedef struct {
bool (*send)(void *user, uint32_t can_id, const uint8_t *data, uint8_t dlc);
bool (*erase_slot)(void *user, uint8_t slot);
bool (*write_slot)(void *user, uint8_t slot, uint32_t offset,
const uint8_t *data, uint8_t length);
bool (*authorize)(void *user, const pcan_boot_manifest_t *manifest);
bool (*verify_image)(void *user, uint8_t slot,
const pcan_boot_manifest_t *manifest);
bool (*set_pending_slot)(void *user, uint8_t slot,
const pcan_boot_manifest_t *manifest);
bool (*confirm_running_slot)(void *user);
void (*reboot)(void *user);
} pcan_boot_port_t;
typedef struct {
pcan_boot_config_t config;
pcan_boot_port_t port;
void *port_user;
pcan_boot_manifest_t manifest;
pcan_boot_state_t state;
uint32_t running_crc32;
uint32_t bytes_received;
uint16_t next_block;
uint8_t session_id;
uint8_t target_slot;
uint8_t last_status;
bool have_image;
bool have_compat;
} pcan_boot_t;
/** Инициализирует экземпляр. Все обязательные callbacks должны быть заданы. */
bool pcan_boot_init(pcan_boot_t *boot, const pcan_boot_config_t *config,
const pcan_boot_port_t *port, void *port_user);
/** Сбрасывает незавершённую сессию, не меняя конфигурацию и callbacks. */
void pcan_boot_abort(pcan_boot_t *boot);
/**
* Обрабатывает один Extended CAN-кадр.
* Возвращает true, если кадр принадлежал загрузочному сервису этого прибора.
*/
bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id,
const uint8_t *data, uint8_t dlc);
/** Переносимые операции с 29-битным ProtoCAN ID. */
uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route,
uint8_t device_type, uint8_t device_id,
uint8_t msg_type, uint16_t msg_body);
uint8_t pcan_boot_id_route(uint32_t can_id);
uint8_t pcan_boot_id_device_type(uint32_t can_id);
uint8_t pcan_boot_id_device_id(uint32_t can_id);
uint8_t pcan_boot_id_msg_type(uint32_t can_id);
uint16_t pcan_boot_id_msg_body(uint32_t can_id);
#ifdef __cplusplus
}
#endif
#endif /* PCAN_BOOT_H */