stm32/mboot: Update dfu state/status flags to better match standard.
This commit is contained in:
parent
03b1ed80e7
commit
b41d08cf15
96
ports/stm32/mboot/dfu.h
Normal file
96
ports/stm32/mboot/dfu.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017-2019 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STM32_MBOOT_DFU_H
|
||||
#define MICROPY_INCLUDED_STM32_MBOOT_DFU_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// DFU spec: https://www.usb.org/sites/default/files/DFU_1.1.pdf
|
||||
|
||||
#define DFU_XFER_SIZE (2048)
|
||||
|
||||
// DFU class requests
|
||||
enum {
|
||||
DFU_DETACH = 0,
|
||||
DFU_DNLOAD = 1,
|
||||
DFU_UPLOAD = 2,
|
||||
DFU_GETSTATUS = 3,
|
||||
DFU_CLRSTATUS = 4,
|
||||
DFU_GETSTATE = 5,
|
||||
DFU_ABORT = 6,
|
||||
};
|
||||
|
||||
// DFU States
|
||||
typedef enum {
|
||||
DFU_STATE_IDLE = 2,
|
||||
DFU_STATE_BUSY = 4,
|
||||
DFU_STATE_DNLOAD_IDLE = 5,
|
||||
DFU_STATE_MANIFEST = 7,
|
||||
DFU_STATE_UPLOAD_IDLE = 9,
|
||||
DFU_STATE_ERROR = 0xa,
|
||||
} dfu_state_t;
|
||||
|
||||
typedef enum {
|
||||
DFU_CMD_NONE = 0,
|
||||
DFU_CMD_EXIT = 1,
|
||||
DFU_CMD_UPLOAD = 7,
|
||||
DFU_CMD_DNLOAD = 8,
|
||||
} dfu_cmd_t;
|
||||
|
||||
// Error status flags
|
||||
typedef enum {
|
||||
DFU_STATUS_OK = 0x00, // No error condition is present.
|
||||
DFU_STATUS_ERROR_TARGET = 0x01, // File is not targeted for use by this device.
|
||||
DFU_STATUS_ERROR_FILE = 0x02, // File is for this device but fails some vendor-specific verification test.
|
||||
DFU_STATUS_ERROR_WRITE = 0x03, // Device is unable to write memory.
|
||||
DFU_STATUS_ERROR_ERASE = 0x04, // Memory erase function failed.
|
||||
DFU_STATUS_ERROR_CHECK_ERASED = 0x05, // Memory erase check failed.
|
||||
DFU_STATUS_ERROR_PROG = 0x06, // Program memory function failed.
|
||||
DFU_STATUS_ERROR_VERIFY = 0x07, // Programmed memory failed verification.
|
||||
DFU_STATUS_ERROR_ADDRESS = 0x08, // Cannot program memory due to received address that is out of range.
|
||||
DFU_STATUS_ERROR_NOTDONE = 0x09, // Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet.
|
||||
DFU_STATUS_ERROR_FIRMWARE = 0x0A, // Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations.
|
||||
DFU_STATUS_ERROR_VENDOR = 0x0B, // iString indicates a vendor-specific error.
|
||||
DFU_STATUS_ERROR_USBR = 0x0C, // Device detected unexpected USB reset signaling.
|
||||
DFU_STATUS_ERROR_POR = 0x0D, // Device detected unexpected power on reset.
|
||||
DFU_STATUS_ERROR_UNKNOWN = 0x0E, // Something went wrong, but the device does not know what it was.
|
||||
DFU_STATUS_ERROR_STALLEDPKT = 0x0F, // Device stalled an unexpected request.
|
||||
} dfu_status_t;
|
||||
|
||||
typedef struct _dfu_state_t {
|
||||
dfu_state_t state;
|
||||
dfu_cmd_t cmd;
|
||||
dfu_status_t status;
|
||||
uint8_t error;
|
||||
uint16_t wBlockNum;
|
||||
uint16_t wLength;
|
||||
uint32_t addr;
|
||||
uint8_t buf[DFU_XFER_SIZE] __attribute__((aligned(4)));
|
||||
} dfu_context_t;
|
||||
|
||||
static dfu_context_t dfu_context SECTION_NOZERO_BSS;
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_MBOOT_DFU_H
|
@ -33,6 +33,7 @@
|
||||
#include "storage.h"
|
||||
#include "i2cslave.h"
|
||||
#include "mboot.h"
|
||||
#include "dfu.h"
|
||||
|
||||
// Using polling is about 10% faster than not using it (and using IRQ instead)
|
||||
// This DFU code with polling runs in about 70% of the time of the ST bootloader
|
||||
@ -905,113 +906,80 @@ uint8_t i2c_slave_process_tx_byte(void) {
|
||||
/******************************************************************************/
|
||||
// DFU
|
||||
|
||||
#define DFU_XFER_SIZE (2048)
|
||||
|
||||
enum {
|
||||
DFU_DNLOAD = 1,
|
||||
DFU_UPLOAD = 2,
|
||||
DFU_GETSTATUS = 3,
|
||||
DFU_CLRSTATUS = 4,
|
||||
DFU_ABORT = 6,
|
||||
};
|
||||
|
||||
enum {
|
||||
DFU_STATUS_IDLE = 2,
|
||||
DFU_STATUS_BUSY = 4,
|
||||
DFU_STATUS_DNLOAD_IDLE = 5,
|
||||
DFU_STATUS_MANIFEST = 7,
|
||||
DFU_STATUS_UPLOAD_IDLE = 9,
|
||||
DFU_STATUS_ERROR = 0xa,
|
||||
};
|
||||
|
||||
enum {
|
||||
DFU_CMD_NONE = 0,
|
||||
DFU_CMD_EXIT = 1,
|
||||
DFU_CMD_UPLOAD = 7,
|
||||
DFU_CMD_DNLOAD = 8,
|
||||
};
|
||||
|
||||
typedef struct _dfu_state_t {
|
||||
int status;
|
||||
int cmd;
|
||||
uint16_t wBlockNum;
|
||||
uint16_t wLength;
|
||||
uint32_t addr;
|
||||
uint8_t buf[DFU_XFER_SIZE] __attribute__((aligned(4)));
|
||||
} dfu_state_t;
|
||||
|
||||
static dfu_state_t dfu_state SECTION_NOZERO_BSS;
|
||||
|
||||
static void dfu_init(void) {
|
||||
dfu_state.status = DFU_STATUS_IDLE;
|
||||
dfu_state.cmd = DFU_CMD_NONE;
|
||||
dfu_state.addr = 0x08000000;
|
||||
dfu_context.state = DFU_STATE_IDLE;
|
||||
dfu_context.cmd = DFU_CMD_NONE;
|
||||
dfu_context.addr = 0x08000000;
|
||||
}
|
||||
|
||||
static int dfu_process_dnload(void) {
|
||||
int ret = -1;
|
||||
if (dfu_state.wBlockNum == 0) {
|
||||
if (dfu_context.wBlockNum == 0) {
|
||||
// download control commands
|
||||
if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x41) {
|
||||
if (dfu_state.wLength == 1) {
|
||||
if (dfu_context.wLength >= 1 && dfu_context.buf[0] == 0x41) {
|
||||
if (dfu_context.wLength == 1) {
|
||||
// mass erase
|
||||
ret = do_mass_erase();
|
||||
} else if (dfu_state.wLength == 5) {
|
||||
} else if (dfu_context.wLength == 5) {
|
||||
// erase page
|
||||
uint32_t next_addr;
|
||||
ret = do_page_erase(get_le32(&dfu_state.buf[1]), &next_addr);
|
||||
ret = do_page_erase(get_le32(&dfu_context.buf[1]), &next_addr);
|
||||
}
|
||||
} else if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x21) {
|
||||
if (dfu_state.wLength == 5) {
|
||||
} else if (dfu_context.wLength >= 1 && dfu_context.buf[0] == 0x21) {
|
||||
if (dfu_context.wLength == 5) {
|
||||
// set address
|
||||
dfu_state.addr = get_le32(&dfu_state.buf[1]);
|
||||
dfu_context.addr = get_le32(&dfu_context.buf[1]);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
} else if (dfu_state.wBlockNum > 1) {
|
||||
} else if (dfu_context.wBlockNum > 1) {
|
||||
// write data to memory
|
||||
uint32_t addr = (dfu_state.wBlockNum - 2) * DFU_XFER_SIZE + dfu_state.addr;
|
||||
ret = do_write(addr, dfu_state.buf, dfu_state.wLength);
|
||||
uint32_t addr = (dfu_context.wBlockNum - 2) * DFU_XFER_SIZE + dfu_context.addr;
|
||||
ret = do_write(addr, dfu_context.buf, dfu_context.wLength);
|
||||
}
|
||||
if (ret == 0) {
|
||||
return DFU_STATUS_DNLOAD_IDLE;
|
||||
return DFU_STATE_DNLOAD_IDLE;
|
||||
} else {
|
||||
return DFU_STATUS_ERROR;
|
||||
return DFU_STATE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_handle_rx(int cmd, int arg, int len, const void *buf) {
|
||||
if (cmd == DFU_CLRSTATUS) {
|
||||
// clear status
|
||||
dfu_state.status = DFU_STATUS_IDLE;
|
||||
dfu_state.cmd = DFU_CMD_NONE;
|
||||
dfu_context.state = DFU_STATE_IDLE;
|
||||
dfu_context.cmd = DFU_CMD_NONE;
|
||||
dfu_context.status = DFU_STATUS_OK;
|
||||
dfu_context.error = 0;
|
||||
} else if (cmd == DFU_ABORT) {
|
||||
// clear status
|
||||
dfu_state.status = DFU_STATUS_IDLE;
|
||||
dfu_state.cmd = DFU_CMD_NONE;
|
||||
dfu_context.state = DFU_STATE_IDLE;
|
||||
dfu_context.cmd = DFU_CMD_NONE;
|
||||
dfu_context.status = DFU_STATUS_OK;
|
||||
dfu_context.error = 0;
|
||||
} else if (cmd == DFU_DNLOAD) {
|
||||
if (len == 0) {
|
||||
// exit DFU
|
||||
dfu_state.cmd = DFU_CMD_EXIT;
|
||||
dfu_context.cmd = DFU_CMD_EXIT;
|
||||
} else {
|
||||
// download
|
||||
dfu_state.cmd = DFU_CMD_DNLOAD;
|
||||
dfu_state.wBlockNum = arg;
|
||||
dfu_state.wLength = len;
|
||||
memcpy(dfu_state.buf, buf, len);
|
||||
dfu_context.cmd = DFU_CMD_DNLOAD;
|
||||
dfu_context.wBlockNum = arg;
|
||||
dfu_context.wLength = len;
|
||||
memcpy(dfu_context.buf, buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_process(void) {
|
||||
if (dfu_state.status == DFU_STATUS_MANIFEST) {
|
||||
if (dfu_context.state == DFU_STATE_MANIFEST) {
|
||||
do_reset();
|
||||
}
|
||||
|
||||
if (dfu_state.status == DFU_STATUS_BUSY) {
|
||||
if (dfu_state.cmd == DFU_CMD_DNLOAD) {
|
||||
dfu_state.cmd = DFU_CMD_NONE;
|
||||
dfu_state.status = dfu_process_dnload();
|
||||
if (dfu_context.state == DFU_STATE_BUSY) {
|
||||
if (dfu_context.cmd == DFU_CMD_DNLOAD) {
|
||||
dfu_context.cmd = DFU_CMD_NONE;
|
||||
dfu_context.state = dfu_process_dnload();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1019,32 +987,34 @@ static void dfu_process(void) {
|
||||
static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) {
|
||||
if (cmd == DFU_UPLOAD) {
|
||||
if (arg >= 2) {
|
||||
dfu_state.cmd = DFU_CMD_UPLOAD;
|
||||
uint32_t addr = (arg - 2) * max_len + dfu_state.addr;
|
||||
dfu_context.cmd = DFU_CMD_UPLOAD;
|
||||
uint32_t addr = (arg - 2) * max_len + dfu_context.addr;
|
||||
do_read(addr, len, buf);
|
||||
return len;
|
||||
}
|
||||
} else if (cmd == DFU_GETSTATUS && len == 6) {
|
||||
// execute command and get status
|
||||
switch (dfu_state.cmd) {
|
||||
switch (dfu_context.cmd) {
|
||||
case DFU_CMD_NONE:
|
||||
break;
|
||||
case DFU_CMD_EXIT:
|
||||
dfu_state.status = DFU_STATUS_MANIFEST;
|
||||
dfu_context.state = DFU_STATE_MANIFEST;
|
||||
break;
|
||||
case DFU_CMD_UPLOAD:
|
||||
dfu_state.status = DFU_STATUS_UPLOAD_IDLE;
|
||||
dfu_context.state = DFU_STATE_UPLOAD_IDLE;
|
||||
break;
|
||||
case DFU_CMD_DNLOAD:
|
||||
dfu_state.status = DFU_STATUS_BUSY;
|
||||
dfu_context.state = DFU_STATE_BUSY;
|
||||
break;
|
||||
default:
|
||||
dfu_context.state = DFU_STATE_BUSY;
|
||||
}
|
||||
buf[0] = 0;
|
||||
buf[1] = dfu_state.cmd; // TODO is this correct?
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = dfu_state.status;
|
||||
buf[5] = 0;
|
||||
buf[0] = dfu_context.status; // bStatus
|
||||
buf[1] = 0; // bwPollTimeout (ms)
|
||||
buf[2] = 0; // bwPollTimeout (ms)
|
||||
buf[3] = 0; // bwPollTimeout (ms)
|
||||
buf[4] = dfu_context.state; // bState
|
||||
buf[5] = dfu_context.error; // iString
|
||||
return 6;
|
||||
}
|
||||
return -1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user