Files
templates/c/set-protocol/ports/stm32-usb-boot/boot_usb_protocol.inc

55 lines
2.7 KiB
C++

/* Shared SET USB boot dispatcher. The MCU wrapper supplies BOOT_* macros. */
#include "usb_setp_stream.h"
#include <string.h>
static setp_boot boot;
static bool reset_pending;
static uint32_t reset_at;
typedef struct { uint8_t *out; uint16_t size; uint32_t now; } reply_context;
void boot_protocol_init(void) { setp_boot_init(&boot,&BOOT_OPS,0,BOOT_APP_BASE,BOOT_APP_SIZE); }
void boot_protocol_poll(uint32_t now) {
if(reset_pending && (int32_t)(now-reset_at)>=0) BOOT_RESET();
}
static void dispatch(const setp_frame_t *r,void *user) {
reply_context *c=user;
uint8_t body[128]; uint16_t status=SETP_STATUS_OK; size_t n=0;
setp_frame_t response={0};
if((r->destination!=0 && r->destination!=BOOT_NODE) ||
(r->flags&(SETP_FLAG_RESPONSE|SETP_FLAG_EVENT))) return;
if(r->flags&(SETP_FLAG_ERROR|SETP_FLAG_MORE)) status=SETP_STATUS_INVALID_ARGUMENT;
else if(r->message_type>=SETP_MSG_FW_BEGIN && r->message_type<=SETP_MSG_FW_ACTIVATE) {
status=setp_boot_command(&boot,r->message_type,r->payload,r->payload_length);
if(!status && r->message_type==SETP_MSG_FW_STATUS)
n=setp_fw_status_encode(&boot.status,body+2,sizeof(body)-2);
if(!status && r->message_type==SETP_MSG_FW_ACTIVATE) {
reset_pending=true; reset_at=c->now+500;
}
} else if(r->payload_length) status=SETP_STATUS_INVALID_LENGTH;
else switch(r->message_type) {
case SETP_MSG_PING: setp_put_u32(body+2,c->now); n=4; break;
case SETP_MSG_DEVICE_INFO: {
static const uint8_t model[]=BOOT_MODEL;
const setp_device_info_t info={1,0,0,0x10000,3,0,sizeof(model)-1,model};
n=setp_device_info_encode(&info,body+2,sizeof(body)-2); break;
}
case SETP_MSG_CAPABILITIES: {
const setp_capabilities_t caps={1,SETP_MAX_PAYLOAD,
SETP_IFACE_MASK(SETP_IFACE_USB_CDC),SETP_FEATURE_FIRMWARE,0,0,0,0};
n=setp_capabilities_encode(&caps,body+2,sizeof(body)-2); break;
}
default: status=SETP_STATUS_UNSUPPORTED; break;
}
setp_put_u16(body,status); if(status) n=0;
response.flags=SETP_FLAG_RESPONSE|(status ? SETP_FLAG_ERROR : 0);
response.message_type=r->message_type; response.sequence=r->sequence;
response.source=BOOT_NODE; response.destination=r->source;
response.payload=body; response.payload_length=(uint16_t)(n+2);
c->size=(uint16_t)setp_frame_encode(&response,c->out,SETP_FRAME_MAX);
}
void usb_setp_reset(usb_setp_stream *s) { memset(s,0,sizeof(*s)); }
uint16_t usb_setp_feed(usb_setp_stream *s,uint8_t byte,uint32_t now,uint8_t *out) {
reply_context c={out,0,now};
if(now-s->last_byte>1000) setp_parser_reset(&s->parser);
s->last_byte=now; (void)setp_parser_feed(&s->parser,&byte,1,dispatch,&c);
return c.size;
}