Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt. Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor. Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов. Обновить справочники устройств, проекты CCS и регрессионные проверки.
187 lines
8.1 KiB
C
187 lines
8.1 KiB
C
/*
|
|
* Автомат адресной загрузки прошивки по ProtoCAN с сессией, контрольной суммой и A/B-слотами.
|
|
* Приём блоков, проверка образа и активация разделены на этапы; операции Flash и метаданные
|
|
* слотов предоставляет платформа.
|
|
*/
|
|
|
|
#ifndef PCAN_BOOT_H
|
|
#define PCAN_BOOT_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
/* C28x has 16-bit addressable chars; wire octets use the low eight bits. */
|
|
#if defined(__TMS320C28XX__) || defined(PCAN_BOOT_WIDE_BYTES)
|
|
typedef unsigned int pcan_boot_byte_t;
|
|
#else
|
|
typedef uint8_t pcan_boot_byte_t;
|
|
#endif
|
|
|
|
#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_CMD_PING = 0x0CU,
|
|
PCAN_BOOT_CMD_CAPABILITIES = 0x0DU,
|
|
PCAN_BOOT_CMD_DEVICE_NAME = 0x0EU,
|
|
PCAN_BOOT_CMD_MEMORY_INFO = 0x0FU, /* Сохраняет существующий номер постраничного паспорта памяти. */
|
|
PCAN_BOOT_CMD_SELECT_MEMORY = 0x10U /* Выбирает 0=штатное хранилище, 1=внутренняя Flash до передачи метаданных. */
|
|
} 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_COMMITTED
|
|
} pcan_boot_state_t;
|
|
|
|
typedef struct {
|
|
uint32_t image_size;
|
|
uint32_t image_crc32;
|
|
uint32_t firmware_version;
|
|
uint16_t product_type;
|
|
pcan_boot_byte_t hardware_revision_min;
|
|
pcan_boot_byte_t hardware_revision_max;
|
|
} pcan_boot_manifest_t;
|
|
|
|
typedef struct {
|
|
pcan_boot_byte_t device_type;
|
|
pcan_boot_byte_t device_id;
|
|
uint16_t product_type;
|
|
pcan_boot_byte_t hardware_revision;
|
|
uint32_t firmware_version;
|
|
pcan_boot_byte_t active_slot;
|
|
/** 1 for an in-place/single-slot target, 2 for A/B. Zero keeps legacy A/B. */
|
|
pcan_boot_byte_t slot_count;
|
|
/** Writable image capacity. Zero uses PCAN_BOOT_SLOT_SIZE. */
|
|
uint32_t max_image_size;
|
|
pcan_boot_byte_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */
|
|
uint32_t session_timeout_ms; /**< 0 disables timeout for legacy ports. */
|
|
} pcan_boot_config_t;
|
|
|
|
typedef struct {
|
|
bool (*send)(void *user, uint32_t can_id, const pcan_boot_byte_t *data, pcan_boot_byte_t dlc);
|
|
bool (*erase_slot)(void *user, pcan_boot_byte_t slot);
|
|
bool (*write_slot)(void *user, pcan_boot_byte_t slot, uint32_t offset,
|
|
const pcan_boot_byte_t *data, pcan_boot_byte_t length);
|
|
bool (*authorize)(void *user, const pcan_boot_manifest_t *manifest);
|
|
bool (*verify_image)(void *user, pcan_boot_byte_t slot,
|
|
const pcan_boot_manifest_t *manifest);
|
|
/** A/B metadata, or optional single-slot activation after verification. */
|
|
bool (*set_pending_slot)(void *user, pcan_boot_byte_t slot,
|
|
const pcan_boot_manifest_t *manifest);
|
|
bool (*confirm_running_slot)(void *user);
|
|
void (*reboot)(void *user);
|
|
/** ENTER: 0 ready, 1 deferred ACK after reset, 2 denied. NULL = legacy ready. */
|
|
unsigned int (*enter_boot)(void *user, pcan_boot_byte_t session);
|
|
bool (*can_reboot)(void *user);
|
|
/** Eight-octet service response, addressed by command + page. */
|
|
bool (*service_info)(void *user, pcan_boot_byte_t command,
|
|
pcan_boot_byte_t page, pcan_boot_byte_t *out);
|
|
/** Optional precise result, replacing legacy boolean verify_image. */
|
|
pcan_boot_status_t (*verify_status)(void *user, pcan_boot_byte_t slot,
|
|
const pcan_boot_manifest_t *manifest);
|
|
pcan_boot_status_t (*select_memory)(void *user, pcan_boot_byte_t memory, pcan_boot_config_t *config); /* Необязательный порт явно переключает назначение образа до ERASE; старые порты возвращают INVALID_COMMAND. */
|
|
} 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;
|
|
pcan_boot_byte_t session_id;
|
|
pcan_boot_byte_t target_slot;
|
|
pcan_boot_byte_t last_status;
|
|
bool have_image;
|
|
bool have_compat;
|
|
uint32_t now_ms, last_activity_ms, discovery_at;
|
|
bool discovery_pending;
|
|
} 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 pcan_boot_byte_t *data, pcan_boot_byte_t dlc);
|
|
|
|
/** Call regularly with a wrapping monotonic millisecond clock. */
|
|
void pcan_boot_poll(pcan_boot_t *boot, uint32_t now_ms);
|
|
|
|
uint32_t pcan_boot_crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length); /* Общий потоковый CRC32 для readback аппаратных хранилищ; начальное состояние равно нулю. */
|
|
bool pcan_boot_report_busy(pcan_boot_t *boot, pcan_boot_byte_t command, uint32_t now_ms); /* Долгие аппаратные операции сообщают BUSY тем же codec и той же session, что обычный ответ. */
|
|
|
|
/** Переносимые операции с 29-битным ProtoCAN ID. */
|
|
uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route,
|
|
pcan_boot_byte_t device_type, pcan_boot_byte_t device_id,
|
|
pcan_boot_byte_t msg_type, uint16_t msg_body);
|
|
pcan_boot_byte_t pcan_boot_id_route(uint32_t can_id);
|
|
pcan_boot_byte_t pcan_boot_id_device_type(uint32_t can_id);
|
|
pcan_boot_byte_t pcan_boot_id_device_id(uint32_t can_id);
|
|
pcan_boot_byte_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 */
|