80 lines
2.4 KiB
C
80 lines
2.4 KiB
C
/*
|
||
* Потоковый загрузчик по RS-485 с кадрированием, CRC32 и продолжением передачи. Автомат
|
||
* принимает части входного потока и вызывает операции Flash через порт; неполный кадр не
|
||
* является готовой командой.
|
||
*/
|
||
|
||
#ifndef RS485_BOOT_H
|
||
#define RS485_BOOT_H
|
||
|
||
#include <stdbool.h>
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#define RS485_BOOT_VERSION 1U
|
||
#define RS485_BOOT_MAX_PAYLOAD 512U
|
||
#define RS485_BOOT_MAX_FRAME (8U + RS485_BOOT_MAX_PAYLOAD + 4U)
|
||
#define RS485_BOOT_DATA_HEADER_SIZE 8U
|
||
#define RS485_BOOT_MAX_BLOCK (RS485_BOOT_MAX_PAYLOAD - RS485_BOOT_DATA_HEADER_SIZE)
|
||
|
||
typedef enum {
|
||
RS485_BOOT_IDLE = 0U,
|
||
RS485_BOOT_RECEIVING = 1U,
|
||
RS485_BOOT_READY = 2U,
|
||
RS485_BOOT_FAILED = 3U
|
||
} rs485_boot_state_t;
|
||
|
||
typedef enum {
|
||
RS485_BOOT_OK = 0U,
|
||
RS485_BOOT_INVALID_ARGUMENT = 1U,
|
||
RS485_BOOT_INVALID_LENGTH = 2U,
|
||
RS485_BOOT_BUSY = 5U,
|
||
RS485_BOOT_INTERNAL = 7U,
|
||
RS485_BOOT_UNSUPPORTED = 0x11U
|
||
} rs485_boot_result_t;
|
||
|
||
typedef struct {
|
||
uint32_t app_address;
|
||
uint32_t app_size;
|
||
uint16_t max_block_size;
|
||
} rs485_boot_config_t;
|
||
|
||
typedef struct {
|
||
bool (*transmit)(void *user, const uint8_t *data, uint16_t length);
|
||
bool (*erase)(void *user, uint32_t image_size);
|
||
bool (*write)(void *user, uint32_t offset, const uint8_t *data, uint16_t length);
|
||
bool (*read)(void *user, uint32_t offset, uint8_t *data, uint16_t length);
|
||
bool (*image_valid)(void *user, uint32_t image_size, uint32_t image_crc32);
|
||
void (*reboot)(void *user);
|
||
} rs485_boot_port_t;
|
||
|
||
typedef struct {
|
||
rs485_boot_config_t config;
|
||
rs485_boot_port_t port;
|
||
void *port_user;
|
||
uint8_t parser[RS485_BOOT_MAX_FRAME];
|
||
uint16_t parser_length;
|
||
uint8_t tx[RS485_BOOT_MAX_FRAME];
|
||
uint8_t scratch[32];
|
||
uint32_t image_size;
|
||
uint32_t image_crc32;
|
||
uint32_t next_offset;
|
||
uint32_t crc_errors;
|
||
rs485_boot_state_t state;
|
||
} rs485_boot_t;
|
||
|
||
bool rs485_boot_init(rs485_boot_t *boot, const rs485_boot_config_t *config,
|
||
const rs485_boot_port_t *port, void *port_user);
|
||
void rs485_boot_feed(rs485_boot_t *boot, const uint8_t *data, size_t length);
|
||
void rs485_boot_abort(rs485_boot_t *boot);
|
||
uint32_t rs485_boot_crc32(const uint8_t *data, size_t length);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif
|