提交 b41d08cf 编写于 作者: A Andrew Leech 提交者: Damien George

stm32/mboot: Update dfu state/status flags to better match standard.

上级 03b1ed80
/*
* 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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册