/* Shared SET USB boot dispatcher. The MCU wrapper supplies BOOT_* macros. */ #include "usb_setp_stream.h" #include 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; }