First commit

This commit is contained in:
Dave Lacey
2011-07-07 20:15:51 +01:00
commit 02b07ed9f3
70 changed files with 15434 additions and 0 deletions

1
module_dfu/README Normal file
View File

@@ -0,0 +1 @@
Code providing firmware upgrade over USB.

View File

@@ -0,0 +1,46 @@
# This file describes how this module will affect the application
# using it. The file is included in the Makefile of the main application.
#
# The module contributes to the build of the application by extending
# the following variables:
#
# SOURCE_DIRS - directories with source files to be included in the build
# INCLUDE_DIRS - directories to be added to the include path during the build
# LIB_DIRS - directories containing libraries to be linked into the build
#
# Note that all the source files in each directory in SOURCE_DIRS
# will be compiled (you do not need to name the files individually).
#
MODULE_DIRS = src
SOURCE_DIRS += $(MODULE_DIRS)
INCLUDE_DIRS += $(MODULE_DIRS)
# You can change the flags of a set of files using the SET_XCC_[lang]_FLAGS
# functions. The first argument is a list of directories and the
# second argument is the value to set the compile flags to. e.g.
#
# $(call SET_XCC_C_FLAGS, mydir1 mydir2, $(XCC_FLAGS) -g -O3)
ifeq ($(ARCH_G),)
ARCH_FLAG = -D ARCH_L
else
ARCH_FLAG = -D ARCH_G
endif
$(call SET_XCC_C_FLAGS, $(MODULE_DIRS) $(XCC_FLAGS) $(ARCH_FLAG) -g -O3)
$(call SET_XCC_XC_FLAGS, $(MODULE_DIRS), $(XCC_FLAGS) $(ARCH_FLAG) -fsubword-select -g -O3)
# You can change the flags of an individual file by setting the
# XCC_FLAGS_[filename] variable. e.g.
#
# XCC_FLAGS_myfile.xc = $(XCC_FLAGS) -fsubword-select
# You can exclude particular files from the build even if they occur
# within SOURCE_DIRS by adding the file name (with no path) to the
# EXCLUDE_FILES variable e..g
#
# EXCLUDE_FILES += myfile.xc
#

View File

@@ -0,0 +1 @@
Code providing firmware upgrade over USB.

188
module_dfu/src/dfu.h Normal file
View File

@@ -0,0 +1,188 @@
#ifndef DFU_VENDOR_ID
#define DFU_VENDOR_ID 0x20B1
#endif
//#ifndef DFU_PRODUCT_ID
//#define DFU_PRODUCT_ID 0x0003
//#error DFU_PRODUCT_ID not defined!
//#endif
#ifndef PID_DFU
#error PID_DFU not defined!
#endif
#ifndef DFU_BCD_DEVICE
#warning DFU_BCD_DEVICE NOT DEFINED
#define DFU_BCD_DEVICE 0x0000
#endif
#ifndef DFU_SERIAL_STR_INDEX
#error DFU_SERIAL_STR_INDEX NOT DEFINED!
//#define DFU_SERIAL_STR_INDEX 0x00
#endif
#ifndef DFU_PRODUCT_INDEX
#error DFU_PROFUCT_INDEX NOT DEFINED!
//#define DFU_PRODUCT_INDEX 0x1
#endif
#ifndef DFU_MANUFACTURER_INDEX
#error DFU_MANUFACTURING_INDEX NOT DEFINED!
//#define DFU_MANUFACTURER_INDEX 0x2
#endif
unsigned char DFUdevDesc[] = {
18, /* 0 bLength : Size of descriptor in Bytes (18 Bytes) */
1, /* 1 bdescriptorType */
0, /* 2 bcdUSB */
2, /* 3 bcdUSB */
0x00, /* 4 bDeviceClass: See interface */
0x00, /* 5 bDeviceSubClass: See interface */
0, /* 6 bDeviceProtocol: See interface */
64, /* 7 bMaxPacketSize */
(DFU_VENDOR_ID & 0xFF), /* 8 idVendor */
(DFU_VENDOR_ID >> 8), /* 9 idVendor */
(PID_DFU & 0xFF), /* 10 idProduct */
(PID_DFU >> 8), /* 11 idProduct */
(DFU_BCD_DEVICE & 0xFF), /* 12 bcdDevice : Device release number */
(DFU_BCD_DEVICE >> 8), /* 13 bcdDevice : Device release number */
DFU_MANUFACTURER_INDEX, /* 14 iManufacturer : Index of manufacturer string */
DFU_PRODUCT_INDEX, /* 15 iProduct : Index of product string descriptor */
DFU_SERIAL_STR_INDEX, /* 16 iSerialNumber : Index of serial number decriptor */
0x01 /* 17 bNumConfigurations : Number of possible configs */
};
unsigned char DFUcfgDesc[] = {
/* Standard USB device descriptor */
0x09, /* 0 bLength */
CONFIGURATION, /* 1 bDescriptorType */
0x1b, /* 2 wTotalLength */
0x00, /* 3 wTotalLength */
1, /* 4 bNumInterface: Number of interfaces*/
0x01, /* 5 bConfigurationValue */
0x00, /* 6 iConfiguration */
0xC0, /* 7 bmAttributes */
0x32, /* 8 bMaxPower */
/* Standard DFU class interface descriptor */
0x09, /* 0 bLength : Size of this descriptor, in bytes. (field size 1 bytes) */
0x04, /* 1 bDescriptorType : INTERFACE descriptor. (field size 1 bytes) */
0x00, /* 2 bInterfaceNumber : Index of this interface. (field size 1 bytes) */
0x00, /* 3 bAlternateSetting : Index of this setting. (field size 1 bytes) */
0x00, /* 4 bNumEndpoints : 0 endpoints. (field size 1 bytes) */
0xFE, /* 5 bInterfaceClass : AUDIO. (field size 1 bytes) */
0x01, /* 6 bInterfaceSubclass : AUDIO_CONTROL. (field size 1 bytes) */
0x02, /* 7 bInterfaceProtocol : Unused. (field size 1 bytes) */
0x00, /* 8 iInterface : Unused. (field size 1 bytes) */
#if 0
/* DFU 1.0 Standard DFU class functional descriptor */
0x07,
0x21,
0x07,
0xFA,
0x00,
0x40,
0x00
#else
/* DFU 1.1 Run-Time DFU Functional Descriptor */
0x09, /* 0 Size */
0x21, /* 1 bDescriptorType : DFU FUNCTIONAL */
0x07, /* 2 bmAttributes */
0xFA, /* 3 wDetachTimeOut */
0x00, /* 4 wDetachTimeOut */
0x40, /* 5 wTransferSize */
0x00, /* 6 wTransferSize */
0x10, /* 7 bcdDFUVersion */
0x01, /* 7 bcdDFUVersion */
#endif
};
unsigned char DFUoSpeedCfgDesc[] =
{
/* Standard USB device descriptor */
0x09, /* 0 bLength */
OTHER_SPEED_CONFIGURATION, /* 1 bDescriptorType */
0x1b, /* 2 wTotalLength */
0x00, /* 3 wTotalLength */
1, /* 4 bNumInterface: Number of interfaces*/
0x01, /* 5 bConfigurationValue */
0x00, /* 6 iConfiguration */
0xC0, /* 7 bmAttributes */
0x32, /* 8 bMaxPower */
/* Standard DFU class interface descriptor */
0x09, /* 0 bLength : Size of this descriptor, in bytes. (field size 1 bytes) */
0x04, /* 1 bDescriptorType : INTERFACE descriptor. (field size 1 bytes) */
0x00, /* 2 bInterfaceNumber : Index of this interface. (field size 1 bytes) */
0x00, /* 3 bAlternateSetting : Index of this setting. (field size 1 bytes) */
0x00, /* 4 bNumEndpoints : 0 endpoints. (field size 1 bytes) */
0xFE, /* 5 bInterfaceClass : AUDIO. (field size 1 bytes) */
0x01, /* 6 bInterfaceSubclass : AUDIO_CONTROL. (field size 1 bytes) */
0x02, /* 7 bInterfaceProtocol : Unused. (field size 1 bytes) */
0x00, /* 8 iInterface : Unused. (field size 1 bytes) */
/* DFU 1.1 Run-Time DFU Functional Descriptor */
0x09, /* 0 Size */
0x21, /* 1 bDescriptorType : DFU FUNCTIONAL */
0x07, /* 2 bmAttributes */
0xFA, /* 3 wDetachTimeOut */
0x00, /* 4 wDetachTimeOut */
0x40, /* 5 wTransferSize */
0x00, /* 6 wTransferSize */
0x10, /* 7 bcdDFUVersion */
0x01, /* 7 bcdDFUVersion */
};
unsigned char DFUdevQualDesc[] =
{
10, /* 0 bLength : Size of descriptor in Bytes (18 Bytes) */
DEVICE_QUALIFIER, /* 1 bdescriptorType */
0, /* 2 bcdUSB */
2, /* 3 bcdUSB */
0xfe, /* 4 bDeviceClass */
1, /* 5 bDeviceSubClass */
0, /* 6 bDeviceProtocol */
64, /* 7 bMaxPacketSize */
0x01, /* 8 bNumConfigurations : Number of possible configs */ \
0x00 /* 9 bReserved (must be zero) */ \
};
int DFUReportResetState(chanend ?c_user_cmd);
int DFUDeviceRequests(XUD_ep c_ep0_out, XUD_ep &?ep0_in, SetupPacket &sp, chanend ?c_user_cmd, unsigned int altInterface, unsigned int user_reset);
// Overload the USB user command handler if present
extern unsigned int flash_programmer(unsigned int cmd, unsigned int request_data[16]);
void user_cmd_handler(unsigned int cmd, chanend ?c_user_cmd) {
if (!isnull(c_user_cmd)) {
unsigned int request_data_len = 0;
unsigned int request_data[16];
unsigned int return_data_len = 0;
int i = 0;
// Read request data length
request_data_len = inuint(c_user_cmd);
// Read request data
for (i = 0; i < request_data_len; i++) {
request_data[i] = inuint(c_user_cmd);
}
return_data_len = flash_programmer(cmd, request_data);
outuint(c_user_cmd, return_data_len);
if (return_data_len) {
for (i = 0; i < return_data_len/4; i++) {
outuint(c_user_cmd, request_data[i]);
}
}
}
}

460
module_dfu/src/dfu.xc Normal file
View File

@@ -0,0 +1,460 @@
#include <xs1.h>
#include <platform.h>
#include <print.h>
#include "xud.h"
#ifdef ARCH_G
#include "XUD_USB_Defines.h"
#else
#include "usb.h"
#endif
#include "dfu_types.h"
#include "flash_programmer.h"
static int DFU_state = STATE_APP_IDLE;
static int DFU_status = DFU_OK;
static timer DFUTimer;
static unsigned int DFUTimerStart = 0;
static unsigned int DFUResetTimeout = 100000000; // 1 second default
static int DFU_flash_connected = 0;
static unsigned int subPagesLeft = 0;
extern int DFU_reset_override;
void temp() {
asm(".linkset DFU_reset_override, _edp.bss");
asm(".globl DFU_reset_override");
}
static int DFU_OpenFlash(chanend ?c_user_cmd)
{
if (!DFU_flash_connected)
{
unsigned int cmd_data[16];
HandleUserDeviceRequest(FLASH_CMD_INIT, 1, 0, cmd_data, c_user_cmd);
DFU_flash_connected = 1;
}
return 0;
}
static int DFU_CloseFlash(chanend ?c_user_cmd) {
if (DFU_flash_connected) {
unsigned int cmd_data[16];
HandleUserDeviceRequest(FLASH_CMD_DEINIT, 1, 0, cmd_data, c_user_cmd);
DFU_flash_connected = 0;
}
return 0;
}
static int DFU_Detach(unsigned int timeout, chanend ?c_user_cmd) {
if (DFU_state == STATE_APP_IDLE) {
DFU_state = STATE_APP_DETACH;
DFU_OpenFlash(c_user_cmd);
// Setup DFU timeout value
DFUResetTimeout = timeout * 100000;
// Start DFU reset timer
DFUTimer :> DFUTimerStart;
} else {
DFU_state = STATE_DFU_ERROR;
}
return 0;
}
static int DFU_Dnload(unsigned int request_len, unsigned int block_num, unsigned int request_data[16], chanend ?c_user_cmd) {
unsigned int fromDfuIdle = 0;
// Get DFU packets here, sequence is
// DFU_DOWNLOAD -> DFU_DOWNLOAD_SYNC
// GET_STATUS -> DFU_DOWNLOAD_SYNC (flash busy) || DFU_DOWNLOAD_IDLE
// REPEAT UNTIL DFU_DOWNLOAD with 0 length -> DFU_MANIFEST_SYNC
DFU_OpenFlash(c_user_cmd);
switch (DFU_state) {
case STATE_DFU_IDLE:
case STATE_DFU_DOWNLOAD_IDLE:
break;
default:
DFU_state = STATE_DFU_ERROR;
return 0;
}
if ((DFU_state == STATE_DFU_IDLE) && (request_len == 0)) {
DFU_state = STATE_DFU_ERROR;
return 0;
} else if (DFU_state == STATE_DFU_IDLE) {
fromDfuIdle = 1;
} else {
fromDfuIdle = 0;
}
if (request_len == 0) {
// Host signalling complete download
int i = 0;
unsigned int cmd_data[16];
if (subPagesLeft) {
unsigned int subPagePad[16] = {0};
for (i = 0; i < subPagesLeft; i++) {
HandleUserDeviceRequest(FLASH_CMD_WRITE_PAGE_DATA, 1, 64, subPagePad, c_user_cmd);
}
}
cmd_data[0] = 2; // Terminate write
HandleUserDeviceRequest(FLASH_CMD_WRITE_PAGE, 1, 4, cmd_data, c_user_cmd);
DFU_state = STATE_DFU_MANIFEST_SYNC;
} else {
unsigned int i = 0;
unsigned int flash_cmd = 0;
unsigned int flash_page_index = 0;
unsigned int cmd_data[16];
if (fromDfuIdle)
{
unsigned s = 0;
#if 0
/* Flash lib does erase on add image */
// Erase flash on first block
HandleUserDeviceRequest(FLASH_CMD_ERASE_ALL, 1, 0, cmd_data, c_user_cmd);
#endif
#if 0
/* Delay should not be required. Erase now blocking call */
DFUTimer :> s;
DFUTimer when timerafter(s + 25000000) :> s; // Wait for flash erase
#endif
}
// Program firmware, STATE_DFU_DOWNLOAD_BUSY not currently used
if (!(block_num % 4)) {
cmd_data[0] = !fromDfuIdle; // 0 for first page, 1 for other pages.
HandleUserDeviceRequest(FLASH_CMD_WRITE_PAGE, 1, 4, cmd_data, c_user_cmd);
subPagesLeft = 4;
}
for (i = 0; i < 16; i++) {
cmd_data[i] = request_data[i];
}
HandleUserDeviceRequest(FLASH_CMD_WRITE_PAGE_DATA, 1, 64, cmd_data, c_user_cmd);
subPagesLeft--;
DFU_state = STATE_DFU_DOWNLOAD_SYNC;
}
return 0;
}
static int DFU_Upload(unsigned int request_len, unsigned int block_num, unsigned int request_data[16], chanend ?c_user_cmd) {
unsigned int cmd_data[16];
unsigned int firstRead = 0;
// Start at flash address 0
// Keep reading flash pages until read_page returns 1 (address out of range)
// Return terminating upload packet at this point
DFU_OpenFlash(c_user_cmd);
switch (DFU_state) {
case STATE_DFU_IDLE:
case STATE_DFU_UPLOAD_IDLE:
break;
default:
DFU_state = STATE_DFU_ERROR;
return 0;
}
//printintln(request_len);
if ((DFU_state == STATE_DFU_IDLE) && (request_len == 0)) {
DFU_state = STATE_DFU_ERROR;
return 0;
} else if (DFU_state == STATE_DFU_IDLE) {
firstRead = 1;
subPagesLeft = 0;
}
if (!subPagesLeft) {
cmd_data[0] = !firstRead;
// Read page
HandleUserDeviceRequest(FLASH_CMD_READ_PAGE, 0, 4, cmd_data, c_user_cmd);
subPagesLeft = 4;
// If address out of range, terminate!
if (cmd_data[0] == 1) {
subPagesLeft = 0;
// Back to idle state, upload complete
DFU_state = STATE_DFU_IDLE;
return 0;
}
}
// Read page data
HandleUserDeviceRequest(FLASH_CMD_READ_PAGE_DATA, 0, 0, request_data, c_user_cmd);
subPagesLeft--;
DFU_state = STATE_DFU_UPLOAD_IDLE;
return 64;
}
static int DFU_GetStatus(unsigned int request_len, unsigned int request_data[16], chanend ?c_user_cmd) {
unsigned int timeout = 0;
request_data[0] = timeout << 8 | (unsigned char)DFU_status;
switch (DFU_state) {
case STATE_DFU_MANIFEST:
case STATE_DFU_MANIFEST_WAIT_RESET:
DFU_state = STATE_DFU_ERROR;
break;
case STATE_DFU_DOWNLOAD_BUSY:
// If download completes -> DFU_DOWNLOAD_SYNC
// Currently all transactions are synchronous so no busy state
break;
case STATE_DFU_DOWNLOAD_SYNC:
DFU_state = STATE_DFU_DOWNLOAD_IDLE;
break;
case STATE_DFU_MANIFEST_SYNC:
// Check if complete here
DFU_state = STATE_DFU_IDLE;
break;
default:
break;
}
request_data[1] = DFU_state;
return 6;
}
static int DFU_ClrStatus(void) {
if (DFU_state == STATE_DFU_ERROR) {
DFU_state = STATE_DFU_IDLE;
} else {
DFU_state = STATE_DFU_ERROR;
}
return 0;
}
static int DFU_GetState(unsigned int request_len, unsigned int request_data[16], chanend ?c_user_cmd) {
request_data[0] = DFU_state;
switch (DFU_state) {
case STATE_DFU_DOWNLOAD_BUSY:
case STATE_DFU_MANIFEST:
case STATE_DFU_MANIFEST_WAIT_RESET:
DFU_state = STATE_DFU_ERROR;
break;
default:
break;
}
return 1;
}
static int DFU_Abort(void) {
DFU_state = STATE_DFU_IDLE;
return 0;
}
// Tell the DFU state machine that a USB reset has occured
int DFUReportResetState(chanend ?c_user_cmd) {
unsigned int inDFU = 0;
unsigned int currentTime = 0;
if (DFU_reset_override == 0x11042011) {
unsigned int cmd_data[16];
inDFU = 1;
DFU_state = STATE_DFU_IDLE;
return inDFU;
}
switch(DFU_state) {
case STATE_APP_DETACH:
case STATE_DFU_IDLE:
DFU_state = STATE_DFU_IDLE;
DFUTimer :> currentTime;
if (currentTime - DFUTimerStart > DFUResetTimeout) {
DFU_state = STATE_APP_IDLE;
//printintln(currentTime - DFUTimerStart);
//printintln(DFUResetTimeout);
inDFU = 0;
} else {
inDFU = 1;
}
break;
case STATE_APP_IDLE:
case STATE_DFU_DOWNLOAD_SYNC:
case STATE_DFU_DOWNLOAD_BUSY:
case STATE_DFU_DOWNLOAD_IDLE:
case STATE_DFU_MANIFEST_SYNC:
case STATE_DFU_MANIFEST:
case STATE_DFU_MANIFEST_WAIT_RESET:
case STATE_DFU_UPLOAD_IDLE:
case STATE_DFU_ERROR:
inDFU = 0;
DFU_state = STATE_APP_IDLE;
break;
default:
DFU_state = STATE_DFU_ERROR;
inDFU = 1;
break;
}
if (!inDFU) {
DFU_CloseFlash(c_user_cmd);
}
return inDFU;
}
int XMOS_DFU_RevertFactory(chanend ?c_user_cmd) {
unsigned int cmd_data[16];
unsigned s = 0;
DFU_OpenFlash(c_user_cmd);
HandleUserDeviceRequest(FLASH_CMD_ERASE_ALL, 1, 0, cmd_data, c_user_cmd);
DFUTimer :> s;
DFUTimer when timerafter(s + 25000000) :> s; // Wait for flash erase
return 0;
}
int XMOS_DFU_SelectImage(unsigned int index, chanend ?c_user_cmd) {
// Select the image index for firmware update
return 0;
}
int XMOS_DFU_SaveState()
{
return 0;
}
int XMOS_DFU_LoadState()
{
return 0;
}
int DFUDeviceRequests(XUD_ep ep0_out, XUD_ep &?ep0_in, SetupPacket &sp, chanend ?c_user_cmd, unsigned int altInterface, unsigned int user_reset) {
unsigned int return_data_len = 0;
unsigned int data_buffer_len = 0;
unsigned int data_buffer[17];
unsigned int reset_device_after_ack = 0;
if(sp.bmRequestType.Direction == BM_REQTYPE_DIRECTION_OUT)
{ // Host to device
if (sp.wLength)
#ifdef ARCH_G
data_buffer_len = XUD_GetBuffer_(ep0_out, 0, (data_buffer, unsigned char[]));
#else
data_buffer_len = XUD_GetBuffer(ep0_out, (data_buffer, unsigned char[]));
#endif
}
// Map Standard DFU commands onto device level firmware upgrade mechanism
switch (sp.bRequest) {
case DFU_DETACH:
return_data_len = DFU_Detach(sp.wValue, c_user_cmd);
break;
case DFU_DNLOAD:
return_data_len = DFU_Dnload(sp.wLength, sp.wValue, data_buffer, c_user_cmd);
break;
case DFU_UPLOAD:
return_data_len = DFU_Upload(sp.wLength, sp.wValue, data_buffer, c_user_cmd);
break;
case DFU_GETSTATUS:
return_data_len = DFU_GetStatus(sp.wLength, data_buffer, c_user_cmd);
break;
case DFU_CLRSTATUS:
return_data_len = DFU_ClrStatus();
break;
case DFU_GETSTATE:
return_data_len = DFU_GetState(sp.wLength, data_buffer, c_user_cmd);
break;
case DFU_ABORT:
return_data_len = DFU_Abort();
break;
/* XMOS Custom DFU requests */
case XMOS_DFU_RESETDEVICE:
reset_device_after_ack = 1;
return_data_len = 0;
break;
case XMOS_DFU_REVERTFACTORY:
return_data_len = XMOS_DFU_RevertFactory(c_user_cmd);
break;
case XMOS_DFU_RESETINTODFU:
reset_device_after_ack = 1;
DFU_reset_override = 0x11042011;
return_data_len = 0;
break;
case XMOS_DFU_RESETFROMDFU:
reset_device_after_ack = 1;
DFU_reset_override = 0;
return_data_len = 0;
break;
case XMOS_DFU_SELECTIMAGE:
return_data_len = XMOS_DFU_SelectImage(sp.wValue, c_user_cmd);
break;
case XMOS_DFU_SAVESTATE:
/* Save passed state to flash */
return_data_len = XMOS_DFU_SaveState();
break;
case XMOS_DFU_RESTORESTATE:
/* Restore saved state from flash */
return_data_len = XMOS_DFU_LoadState();
break;
default:
break;
}
if (sp.bmRequestType.Direction == BM_REQTYPE_DIRECTION_IN && sp.wLength != 0) { // Device to host
#ifdef ARCH_G
XUD_DoGetRequest(ep0_out, 0, (data_buffer, unsigned char[]), return_data_len, return_data_len);
#else
XUD_DoGetRequest(ep0_out, ep0_in, (data_buffer, unsigned char[]), return_data_len, return_data_len);
#endif
} else {
#ifdef ARCH_G
XUD_DoSetRequestStatus(ep0_out, 0);
#else
XUD_DoSetRequestStatus(ep0_in, 0);
#endif
}
// If device reset requested, handle after command acknowledgement
if (reset_device_after_ack)
{
if (!user_reset)
{
unsigned int cmd_data[16];
HandleUserDeviceRequest(FLASH_CMD_REBOOT, 1, 0, cmd_data, c_user_cmd);
}
else
{
return 1;
}
}
return 0;
}

View File

@@ -0,0 +1,48 @@
// Default Command requests (from Spec)
#define DFU_DETACH 0
#define DFU_DNLOAD 1
#define DFU_UPLOAD 2
#define DFU_GETSTATUS 3
#define DFU_CLRSTATUS 4
#define DFU_GETSTATE 5
#define DFU_ABORT 6
// XMOS Alternate Setting Command Requests
#define XMOS_DFU_RESETDEVICE 0xf0
#define XMOS_DFU_REVERTFACTORY 0xf1
#define XMOS_DFU_RESETINTODFU 0xf2
#define XMOS_DFU_RESETFROMDFU 0xf3
#define XMOS_DFU_SELECTIMAGE 0xf4
#define XMOS_DFU_SAVESTATE 0xf5
#define XMOS_DFU_RESTORESTATE 0xf6
// DFU States
#define STATE_APP_IDLE 0x00
#define STATE_APP_DETACH 0x01
#define STATE_DFU_IDLE 0x02
#define STATE_DFU_DOWNLOAD_SYNC 0x03
#define STATE_DFU_DOWNLOAD_BUSY 0x04
#define STATE_DFU_DOWNLOAD_IDLE 0x05
#define STATE_DFU_MANIFEST_SYNC 0x06
#define STATE_DFU_MANIFEST 0x07
#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
#define STATE_DFU_UPLOAD_IDLE 0x09
#define STATE_DFU_ERROR 0x0a
// DFU error conditions
#define DFU_OK 0x00 // No error condition is present.
#define DFU_errTARGET 0x01 // File is not targeted for use by this device.
#define DFU_errFILE 0x02 // File is for this device but fails some vendor-specific verification test.
#define DFU_errWRITE 0x03 // Device is unable to write memory.
#define DFU_errERASE 0x04 // Memory erase function failed.
#define DFU_errCHECK_ERASED 0x05 // Memory erase check failed.
#define DFU_errPROG 0x06 // Program memory function failed.
#define DFU_errVERIFY 0x07 // Programmed memory failed verification.
#define DFU_errADDRESS 0x08 // Cannot program memory due to received address that is out of range.
#define DFU_errNOTDONE 0x09 // Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet.
#define DFU_errFIRMWARE 0x0A // Devices firmware is corrupt. It cannot return to run-time (non-DFU) operations
#define DFU_errVENDOR 0x0B // iString indicates a vendor-specific error.
#define DFU_errUSBR 0x0C // Device detected unexpected USB reset signaling.
#define DFU_errPOR 0x0D // Device detected unexpected power on reset.
#define DFU_errUNKNOWN 0x0E // Something went wrong, but the device does not know what it was
#define DFU_errSTALLEDPKT 0x0F // Device stalled an unexpected request.

218
module_dfu/src/flash_interface.c Executable file
View File

@@ -0,0 +1,218 @@
#include <xs1.h>
#include <flash.h>
#include <flashlib.h>
#include <print.h>
#include <string.h>
#include <xclib.h>
#ifndef FLASH_MAX_UPGRADE_SIZE
#ifdef ARCH_G
#define FLASH_MAX_UPGRADE_SIZE 128 * 1024 // 128K default
#else
//#define FLASH_MAX_UPGRADE_SIZE 64 * 1024 // 64K default
#define FLASH_MAX_UPGRADE_SIZE 128 * 1024 // 64K default
#endif
#endif
#if 1
#define FLASH_ERROR() do { printstr("Error: line: "); printintln(__LINE__); __builtin_trap(); } while(0)
#else
#define FLASH_ERROR() do {} while(0)
#endif
static int flash_device_open = 0;
static fl_BootImageInfo factory_image;
static fl_BootImageInfo upgrade_image;
static int upgrade_image_valid = 0;
static int current_flash_subpage_index = 0;
static unsigned char current_flash_page_data[256];
int flash_cmd_enable_ports() __attribute__ ((weak));
int flash_cmd_enable_ports() {
return 0;
}
int flash_cmd_disable_ports() __attribute__ ((weak));
int flash_cmd_disable_ports() {
return 0;
}
int flash_cmd_init(void) {
fl_BootImageInfo image;
if (!flash_device_open) {
if (flash_cmd_enable_ports());
flash_device_open = 1;
}
if (!flash_device_open)
return 0;
// Disable flash protection
fl_setProtection(0);
if (fl_getFactoryImage(&image) != 0) {
return 0;
}
factory_image = image;
if (fl_getNextBootImage(&image) == 0) {
upgrade_image_valid = 1;
upgrade_image = image;
}
return 0;
}
int flash_cmd_deinit(void) {
if (!flash_device_open)
return 0;
flash_cmd_disable_ports();
flash_device_open = 0;
return 0;
}
int flash_cmd_read_page(unsigned char *data) {
if (!upgrade_image_valid) {
*(unsigned int *)data = 1;
return 4;
}
if (*(unsigned int *)data == 0) {
fl_startImageRead(&upgrade_image);
}
current_flash_subpage_index = 0;
if (fl_readImageRead(current_flash_page_data) == 0) {
*(unsigned int *)data = 0;
} else {
*(unsigned int *)data = 1;
}
return 4;
}
int flash_cmd_read_page_data(unsigned char *data) {
unsigned char *page_data_ptr = &current_flash_page_data[current_flash_subpage_index * 64];
memcpy(data, page_data_ptr, 64);
current_flash_subpage_index++;
return 64;
}
#if 0
static int roundUpToSectorBoundary(unsigned address)
{
unsigned curAddress = 0;
unsigned numSectors = fl_getNumSectors();
unsigned i;
for (i = 0; i < numSectors; i++) {
curAddress += fl_getSectorSize(i);
if (curAddress >= address)
return curAddress;
}
return address;
}
#endif
static void begin_write()
{
int result;
// TODO this will take a long time. To minimise the amount of time spent
// paused on this operation it would be preferable to move to this to a
// seperate command, e.g. start_write.
do {
result = fl_startImageAdd(&factory_image, FLASH_MAX_UPGRADE_SIZE, 0);
} while (result > 0);
if (result < 0)
FLASH_ERROR();
}
static int pages_written = 0;
int flash_cmd_write_page(unsigned char *data) {
unsigned int flag = *(unsigned int *)data;
//printstr("flash_cmd_write_page(");
//printint(flag);
//printstr(")\n");
if (upgrade_image_valid) {
return 0;
}
switch (flag) {
case 0:
// First page.
begin_write();
pages_written = 0;
// fallthrough
case 1:
// Do nothing.
break;
case 2:
// Termination.
if (fl_endWriteImage() != 0)
FLASH_ERROR();
// Sanity check
fl_BootImageInfo image = factory_image;
if (fl_getNextBootImage(&image) != 0)
FLASH_ERROR();
break;
}
current_flash_subpage_index = 0;
return 0;
}
static int isAllOnes(unsigned char page[256])
{
unsigned i;
for (i = 0; i < 256; i++) {
if (page[i] != 0xff)
return 0;
}
return 1;
}
int flash_cmd_write_page_data(unsigned char *data) {
unsigned char *page_data_ptr = &current_flash_page_data[current_flash_subpage_index * 64];
//printstr("flash_cmd_write_page_data()\n");
if (upgrade_image_valid) {
return 0;
}
if (current_flash_subpage_index >= 4) {
return 0;
}
memcpy(page_data_ptr, data, 64);
current_flash_subpage_index++;
if (current_flash_subpage_index == 4) {
if (isAllOnes(data))
FLASH_ERROR();
if (fl_writeImagePage(current_flash_page_data) != 0)
FLASH_ERROR();
pages_written++;
}
return 0;
}
int flash_cmd_erase_all(void) {
if (upgrade_image_valid) {
if (fl_deleteImage(&upgrade_image) != 0)
FLASH_ERROR();
upgrade_image_valid = 0;
}
return 0;
}
int flash_cmd_reboot(void) {
unsigned int pllVal;
read_sswitch_reg(0, 6, &pllVal);
write_sswitch_reg(0, 6, pllVal);
return 0;
}

View File

@@ -0,0 +1,33 @@
#ifndef _flash_interface_h_
#define _flash_interface_h_
int flash_cmd_init(void);
/**
* Prepare to write a page of a new upgrade image.
* The first word of data should be set to 0 if it is the first page,
* 1 for all other pages and 2 to terminate the write (no further data is sent).
*/
int flash_cmd_write_page(unsigned char []);
/**
* Provide upgrade image data. flash_cmd_write_page() must be called previously.
* Once a page of data has been provided it is written to the device.
*/
int flash_cmd_write_page_data(unsigned char []);
/**
* Read a page of data from the upgrade image.
* If the first word of data is 0 the page is read from the start of the
* upgrade image, otherwise the next page in the image will be read.
* On return the first word of data is written with 1 if there is nothing to
* read and 0 otherwise.
*/
int flash_cmd_read_page(unsigned char []);
/**
* Get data previously read by flash_cmd_read_page().
*/
int flash_cmd_read_page_data(unsigned char []);
int flash_cmd_erase_all(void);
int flash_cmd_reboot(void);
int flash_cmd_init(void);
int flash_cmd_deinit(void);
#endif /*_flash_interface_h_*/

View File

@@ -0,0 +1,14 @@
#define FLASH_CMD_WRITE_PAGE 0xf1
#define FLASH_CMD_READ_PAGE 0xf2
#define FLASH_CMD_WRITE_PAGE_DATA 0xf3
#define FLASH_CMD_READ_PAGE_DATA 0xf4
#define FLASH_CMD_ERASE_ALL 0xf5
#define FLASH_CMD_REBOOT 0xf6
#define FLASH_CMD_INIT 0xf7
#define FLASH_CMD_DEINIT 0xf8
unsigned int flash_programmer(unsigned int cmd, unsigned int request_data[16]);
int HandleUserDeviceRequest(unsigned int cmd, unsigned int to_device,
unsigned int request_size, unsigned int request_data[16],
chanend ?c_user_cmd);

View File

@@ -0,0 +1,82 @@
#include <xs1.h>
#include <print.h>
#include "flash_interface.h"
#include "flash_programmer.h"
unsigned int flash_programmer(unsigned int cmd, unsigned int request_data[16]) {
unsigned int return_data_len = 0;
switch (cmd) {
case FLASH_CMD_WRITE_PAGE:
return_data_len = flash_cmd_write_page((request_data, unsigned char[64]));
break;
case FLASH_CMD_READ_PAGE:
return_data_len = flash_cmd_read_page((request_data, unsigned char[64]));
break;
case FLASH_CMD_WRITE_PAGE_DATA:
return_data_len = flash_cmd_write_page_data((request_data, unsigned char[64]));
break;
case FLASH_CMD_READ_PAGE_DATA:
return_data_len = flash_cmd_read_page_data((request_data, unsigned char[64]));
break;
case FLASH_CMD_ERASE_ALL:
return_data_len = flash_cmd_erase_all();
break;
case FLASH_CMD_REBOOT:
return_data_len = flash_cmd_reboot();
break;
case FLASH_CMD_INIT:
return_data_len = flash_cmd_init();
break;
case FLASH_CMD_DEINIT:
return_data_len = flash_cmd_deinit();
break;
default:
break;
}
return return_data_len;
}
int HandleUserDeviceRequest(unsigned int cmd, unsigned int to_device,
unsigned int request_size, unsigned int request_data[16],
chanend ?c_user_cmd) {
unsigned int return_data_len = 0;
if (isnull(c_user_cmd)) {
return_data_len = flash_programmer(cmd, request_data);
} else {
int i = 0;
outuint(c_user_cmd, cmd);
outuint(c_user_cmd, request_size/4);
if (request_size) {
// Send request data to user cmd handler
for (i = 0; i < request_size/4; i++) {
outuint(c_user_cmd, request_data[i]);
}
}
return_data_len = inuint(c_user_cmd);
if (return_data_len) {
// Get response data from user cmd handler
for (i = 0; i < return_data_len/4; i++) {
request_data[i] = inuint(c_user_cmd);
}
}
}
return return_data_len;
}