src/dfu-programmer/src/stm32.c
/** dfu-programmer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
//___ I N C L U D E S ________________________________________________________
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#include <errno.h>
#include "dfu-bool.h"
#include "dfu-device.h"
#include "config.h"
#include "arguments.h"
#include "dfu.h"
#include "stm32.h"
#include "util.h"
//___ M A C R O S ( P R I V A T E ) ________________________________________
#define STM32_DEBUG_THRESHOLD 50
#define STM32_TRACE_THRESHOLD 55
#define DEBUG(...) dfu_debug( __FILE__, __FUNCTION__, __LINE__, STM32_DEBUG_THRESHOLD, __VA_ARGS__ )
#define TRACE(...) dfu_debug( __FILE__, __FUNCTION__, __LINE__, STM32_TRACE_THRESHOLD, __VA_ARGS__ )
#define STM32_MAX_TRANSFER_SIZE 0x0800 /* 2048 */
#define STM32_MIN_SECTOR_BOUND 0x4000 /* 16 kb */
#define STM32_OTP_BYTES_SIZE 528 /* number of OTP bytes (0x210) */
#define STM32_OPTION_BYTES_SIZE 16 /* number option bytes */
#define SET_ADDR_PTR 0x21
#define ERASE_CMD 0x41
#define READ_UNPROTECT 0x92
#define GET_CMD 0x00
//___ T Y P E D E F S ( P R I V A T E ) ____________________________________
//___ P R O T O T Y P E S ( P R I V A T E ) ________________________________
static inline int32_t stm32_get_status( dfu_device_t *device );
/* run dfu_get_status to get the current status
* retrn 0 on status OK, -1 on status req fail, -2 on bad status
*/
static int32_t stm32_set_address_ptr( dfu_device_t *device, uint32_t address );
/* @brief set the address pointer to a certain address
* @param the address to set
* @retrn 0 on success, negative on failure
*/
static int32_t stm32_write_block( dfu_device_t *device,
size_t xfer_len,
uint8_t *buffer );
/* flash the contents of memory into a block of memory. it is assumed that
* the appropriate page has already been selected. start and end are the
* start and end addresses of the flash data. returns 0 on success,
* positive dfu error code if one is obtained, or negative if communitcation
* with device fails.
*/
static int32_t stm32_read_block( dfu_device_t *device,
size_t xfer_len,
uint8_t *buffer );
/* read a block of memory, assumes address pointer is already set
*/
static inline void print_progress( intel_buffer_info_t *info,
uint32_t *progress );
/* calculate how many progress indicator steps to print and print them
* update progress value
*/
static int32_t stm32_erase( dfu_device_t *device, uint8_t *command,
uint8_t command_length, dfu_bool quiet );
/* erase, erase page, and read unprotect all share this functionality
* although with different commands
*/
//___ V A R I A B L E S ______________________________________________________
extern int debug; /* defined in main.c */
/* FIXME : these should be read from usb device descriptor because they are
* device specififc */
static const uint32_t stm32_sector_addresses[] = {
0x08000000, /* sector 0, 16 kb */
0x08004000, /* sector 1, 16 kb */
0x08008000, /* sector 2, 16 kb */
0x0800C000, /* sector 3, 16 kb */
0x08010000, /* sector 4, 64 kb */
0x08020000, /* sector 5, 128 kb */
0x08040000, /* sector 6, 128 kb */
0x08060000, /* sector 7, 128 kb */
0x08080000, /* sector 8, 128 kb */
0x080A0000, /* sector 9, 128 kb */
0x080C0000, /* sector 10, 128 kb */
0x080E0000, /* sector 11, 128 kb */
0x1FFF0000, /* system memory, 30 kb */
0x1FFF7800, /* OTP area, 528 bytes */
0x1FFFC000, /* Option bytes, 16 bytes */
};
//___ F U N C T I O N S ( P R I V A T E ) __________________________________
static inline int32_t stm32_get_status( dfu_device_t *device ) {
dfu_status_t status;
if( 0 == dfu_get_status(device, &status) ) {
if( status.bStatus == DFU_STATUS_OK ) {
DEBUG( "Status OK\n" );
} else {
DEBUG( "Status %s not OK, use DFU_CLRSTATUS\n",
dfu_status_to_string(status.bStatus) );
dfu_clear_status( device );
return -2;
}
} else {
DEBUG( "DFU_GETSTATUS request failed\n" );
return -1;
}
return 0;
}
static int32_t stm32_set_address_ptr( dfu_device_t *device, uint32_t address ) {
TRACE( "%s( 0x%X )\n", __FUNCTION__, address );
const uint8_t length = 5;
int32_t status;
uint8_t command[] = {
(uint8_t) SET_ADDR_PTR,
(uint8_t) address & 0xFF, /* address LSB */
(uint8_t) (address>>8) & 0xFF,
(uint8_t) (address>>16) & 0xFF,
(uint8_t) (address>>24) & 0xFF /* address MSB */
};
/* check dfu status for okay to send */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d getting status on start\n", status);
return -1;
}
dfu_set_transaction_num( 0 ); /* set wValue to zero */
if( length != dfu_download(device, length, command) ) {
DEBUG( "dfu_download failed\n" );
return -2;
}
/* call dfu get status to trigger command */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d triggering %s\n", status, __FUNCTION__);
return -3;
}
/* check command success */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d: %s unsuccessful\n", status, __FUNCTION__);
return -4;
}
return 0;
}
static int32_t stm32_write_block( dfu_device_t *device,
size_t xfer_len,
uint8_t *buffer ) {
TRACE( "%s( %p, %u, %p )\n", __FUNCTION__, device, xfer_len, buffer );
int32_t status;
/* check input args */
if( (NULL == device) || (NULL == buffer) ) {
DEBUG( "ERROR: Invalid arguments, device/buffer pointer is NULL.\n" );
return -1;
} else if ( xfer_len > STM32_MAX_TRANSFER_SIZE ) {
DEBUG( "ERROR: 0x%X byte message > MAX TRANSFER SIZE (0x%X).\n",
xfer_len, STM32_MAX_TRANSFER_SIZE );
return -1;
} else if ( xfer_len < 1 ) {
DEBUG( "ERROR: xfer_len is %u\n", xfer_len );
return -1;
}
if( xfer_len != dfu_download(device, xfer_len, buffer) ) {
DEBUG( "dfu_download failed\n" );
return -3;
}
/* call dfu get status to trigger command */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d triggering %s\n", status, __FUNCTION__);
return -3;
}
/* check that the command was successfully executed */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d: %s unsuccessful\n", status, __FUNCTION__);
return -4;
}
return 0;
}
static int32_t stm32_read_block( dfu_device_t *device,
size_t xfer_len,
uint8_t *buffer ) {
TRACE( "%s( %p, %u, %p )\n", __FUNCTION__, device, xfer_len, buffer );
int32_t result;
if( buffer == NULL ) {
DEBUG("ERROR: buffer ptr is NULL\n");
return -1;
} else if( xfer_len > STM32_MAX_TRANSFER_SIZE ) {
/* this could cause a read problem */
DEBUG("ERROR: transfer size %d exceeds max %d.\n",
xfer_len, STM32_MAX_TRANSFER_SIZE );
return -1;
}
/* check status before read */
if( (result = stm32_get_status(device)) ) {
DEBUG("Status Error %d before read\n", result );
return -2;
}
result = dfu_upload( device, xfer_len, buffer );
if( result < 0) {
dfu_status_t status;
DEBUG( "ERROR: dfu_upload result: %d\n", result );
if( 0 == dfu_get_status(device, &status) ) {
DEBUG( "Error Status %s, state %s\n",
dfu_status_to_string(status.bStatus),
dfu_state_to_string(status.bState) );
if( status.bStatus == DFU_STATUS_ERROR_VENDOR ) {
/* status = dfuERROR and state = errVENDOR */
DEBUG("Device is read protected\n");
return STM32_READ_PROT_ERROR;
}
} else {
DEBUG("DFU GET_STATUS fail\n");
}
dfu_clear_status( device );
return result;
}
return 0;
}
static inline void print_progress( intel_buffer_info_t *info,
uint32_t *progress ) {
if ( !(debug > STM32_DEBUG_THRESHOLD) ) {
while ( ((info->block_end - info->data_start + 1) * 32) > *progress ) {
fprintf( stderr, ">" );
*progress += info->data_end - info->data_start + 1;
}
}
}
static int32_t stm32_erase( dfu_device_t *device, uint8_t *command,
uint8_t command_length, dfu_bool quiet ) {
int32_t status;
dfu_set_transaction_num( 0 ); /* set wValue to zero */
if( command_length != dfu_download(device, command_length, command) ) {
if( !quiet ) fprintf( stderr, "ERROR\n" );
DEBUG( "dfu_download failed\n" );
return UNSPECIFIED_ERROR;
}
/* call dfu get status to trigger command */
if( (status = stm32_get_status(device)) ) {
if( !quiet ) fprintf( stderr, "ERROR\n" );
DEBUG("Error %d triggering %s\n", status, __FUNCTION__);
return UNSPECIFIED_ERROR;
}
/* check status again for erase status, this can take a while */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d: %s unsuccessful\n", status, __FUNCTION__);
if( !quiet ) fprintf( stderr, "ERROR\n" );
return UNSPECIFIED_ERROR;
} else {
if( !quiet ) fprintf( stderr, "DONE\n" );
}
return SUCCESS;
}
//___ F U N C T I O N S ______________________________________________________
int32_t stm32_erase_flash( dfu_device_t *device, dfu_bool quiet ) {
TRACE( "%s( %p, %s )\n", __FUNCTION__, device, quiet ? "ture" : "false" );
uint8_t command[] = { ERASE_CMD };
uint8_t length = 1;
if( !quiet ) {
fprintf( stderr, "Erasing flash... " );
DEBUG("\n");
}
return stm32_erase( device, command, length, quiet );
}
int32_t stm32_page_erase( dfu_device_t *device, uint32_t address,
dfu_bool quiet ) {
TRACE( "%s( %p, 0x%X, %s )\n", __FUNCTION__, device, address,
quiet ? "ture" : "false" );
uint8_t length = 5;
uint8_t command[5] = {
ERASE_CMD,
(uint8_t) (0xff & address), // page LSB
(uint8_t) (0xff & ((address)>>8)),
(uint8_t) (0xff & ((address)>>16)),
(uint8_t) (0xff & ((address)>>24)) // page MSB
};
return stm32_erase( device, command, length, quiet );
}
int32_t stm32_start_app( dfu_device_t *device, dfu_bool quiet ) {
TRACE( "%s( %p )\n", __FUNCTION__, device );
int32_t status;
/* set address pointer (jump target) to start address */
if( (status = stm32_set_address_ptr( device, STM32_FLASH_OFFSET )) ) {
DEBUG("Error setting address pointer\n");
return UNSPECIFIED_ERROR;
}
/* check dfu status for ok to send */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d getting status on start\n", status);
return UNSPECIFIED_ERROR;
}
if( !quiet ) fprintf( stderr, "Launching program... \n" );
dfu_set_transaction_num( 0 ); /* set wValue to zero */
if( 0 != dfu_download(device, 0, NULL) ) {
if( !quiet ) fprintf( stderr, "ERROR\n" );
DEBUG( "dfu_download failed\n" );
return UNSPECIFIED_ERROR;
}
/* call dfu get status to trigger command */
if( (status = stm32_get_status(device)) ) {
DEBUG("Error %d triggering %s\n", status, __FUNCTION__);
return UNSPECIFIED_ERROR;
}
return SUCCESS;
}
int32_t stm32_read_flash( dfu_device_t *device, intel_buffer_in_t *buin,
const uint8_t mem_segment, const dfu_bool quiet ) {
TRACE( "%s( %p, %p, %u, %s )\n", __FUNCTION__, device, buin,
mem_segment, ((true == quiet) ? "true" : "false"));
uint8_t reset_address_flag; // reset address offset required
uint32_t address_offset; // keep record of sent progress as bytes * 32
uint16_t xfer_size = 0; // the size of a transfer
uint8_t mem_section = 0; // tracks the current memory page
uint32_t progress = 0; // used to indicate progress
int32_t status;
int32_t retval = UNSPECIFIED_ERROR; // the return value for this function
if( (NULL == buin) || (NULL == device) ) {
DEBUG( "invalid arguments.\n" );
if( !quiet )
fprintf( stderr, "Program Error, use debug for more info.\n" );
return ARGUMENT_ERROR;
}
if( !quiet ) {
if( debug <= STM32_DEBUG_THRESHOLD ) {
/* NOTE: From here on we should go to finally on error */
fprintf( stderr, "[================================] " );
}
fprintf( stderr, "Reading 0x%X bytes...\n",
buin->info.data_end - buin->info.data_start + 1 );
if( debug <= STM32_DEBUG_THRESHOLD ) {
/* NOTE: From here on we should go to finally on error */
fprintf( stderr, "[" );
}
}
/* read the data */
buin->info.block_start = buin->info.data_start;
reset_address_flag = 0;
address_offset = buin->info.block_start;
while( buin->info.block_start <= buin->info.data_end ) {
if( reset_address_flag ) {
address_offset = buin->info.block_start;
if( (status = stm32_set_address_ptr(device,
STM32_FLASH_OFFSET + address_offset)) ) {
DEBUG("Error setting address 0x%X\n", address_offset);
retval = UNSPECIFIED_ERROR;
goto finally;
}
dfu_set_transaction_num( 2 ); /* sets block offset 0 */
reset_address_flag = 0;
}
// find end value for the current transfer
buin->info.block_end = buin->info.block_start + STM32_MAX_TRANSFER_SIZE - 1;
mem_section = buin->info.block_start / STM32_MIN_SECTOR_BOUND;
if( buin->info.block_end / STM32_MIN_SECTOR_BOUND > mem_section ) {
buin->info.block_end = STM32_MIN_SECTOR_BOUND * mem_section - 1;
}
if( buin->info.block_end > buin->info.data_end ) {
buin->info.block_end = buin->info.data_end;
}
xfer_size = buin->info.block_end - buin->info.block_start + 1;
if( xfer_size != STM32_MAX_TRANSFER_SIZE ) {
DEBUG("xfer_size change, need addr reset\n");
reset_address_flag = 1;
}
if( (status = stm32_read_block( device, xfer_size,
&buin->data[buin->info.block_start] )) ) {
DEBUG( "Error reading block 0x%X to 0x%X: err %d.\n",
buin->info.block_start, buin->info.block_end, status );
retval = ( status == -10 ) ? DEVICE_ACCESS_ERROR : FLASH_READ_ERROR;
/* read protect error code in read_block is -10 */
goto finally;
}
buin->info.block_start = buin->info.block_end + 1;
if( reset_address_flag == 0 && (buin->info.block_start !=
(STM32_MAX_TRANSFER_SIZE * (dfu_get_transaction_num() - 2))
+ address_offset) ) {
DEBUG("block start & address mismatch, reset req\n");
reset_address_flag = 1;
}
if( !quiet ) print_progress( &buin->info, &progress );
}
retval = SUCCESS;
finally:
if ( !quiet ) {
if( SUCCESS == retval ) {
if ( debug <= STM32_DEBUG_THRESHOLD ) {
fprintf( stderr, "] " );
}
fprintf( stderr, "SUCCESS\n" );
} else {
if ( debug <= STM32_DEBUG_THRESHOLD ) {
fprintf( stderr, " X ");
}
fprintf( stderr, "ERROR\n" );
if( retval==DEVICE_ACCESS_ERROR )
fprintf( stderr,
"Memory access error, use debug for more info.\n" );
else if( retval==FLASH_READ_ERROR )
fprintf( stderr,
"Memory read error, use debug for more info.\n" );
}
}
return retval;
}
int32_t stm32_write_flash( dfu_device_t *device, intel_buffer_out_t *bout,
const dfu_bool eeprom, const dfu_bool force, const dfu_bool quiet ) {
TRACE( "%s( %p, %p, %s, %s )\n", __FUNCTION__, device, bout,
((true == eeprom) ? "true" : "false"),
((true == quiet) ? "true" : "false") );
uint32_t i;
uint32_t progress = 0; // keep record of sent progress as bytes * 32
uint32_t address_offset; // keep record of sent progress as bytes * 32
uint8_t reset_address_flag; // reset address offset required
uint16_t xfer_size = 0; // the size of a transfer
uint8_t mem_section = 0; // tracks the current memory page
int32_t retval = UNSPECIFIED_ERROR; // the return value for this function
uint8_t buffer[STM32_MAX_TRANSFER_SIZE]; // buffer holding out data
int32_t status;
/* check arguments */
if( (NULL == device) || (NULL == bout) ) {
DEBUG( "ERROR: Invalid arguments, device/buffer pointer is NULL.\n" );
if( !quiet )
fprintf( stderr, "Program Error, use debug for more info.\n" );
return ARGUMENT_ERROR;
} else if( bout->info.valid_start > bout->info.valid_end ) {
DEBUG( "ERROR: No valid target memory, end 0x%X before start 0x%X.\n",
bout->info.valid_end, bout->info.valid_start );
if( !quiet )
fprintf( stderr, "Program Error, use debug for more info.\n" );
return BUFFER_INIT_ERROR;
}
/* for each page with data, fill unassigned values on the page with 0xFF
* bout->data[0] always aligns with a flash page boundary irrespective
* of where valid_start is located */
if( 0 != intel_flash_prep_buffer( bout ) ) {
if( !quiet )
fprintf( stderr, "Program Error, use debug for more info.\n" );
return BUFFER_INIT_ERROR;
}
/* determine the limits of where actual data resides in the buffer */
bout->info.data_start = UINT32_MAX;
for( i = 0; i < bout->info.total_size; i++ ) {
if( bout->data[i] <= UINT8_MAX ) {
bout->info.data_end = i;
if( bout->info.data_start == UINT32_MAX )
bout->info.data_start = i;
}
}
/* debug info about data limits */
DEBUG("Flash available from 0x%X to 0x%X, 0x%X bytes.\n",
bout->info.valid_start, bout->info.valid_end,
bout->info.valid_end - bout->info.valid_start + 1); // bytes inclusive so +1
DEBUG("Data start @ 0x%X; %uB p 0x%X + 0x%X offset.\n",
bout->info.data_start, bout->info.page_size,
bout->info.data_start / bout->info.page_size,
bout->info.data_start % bout->info.page_size);
DEBUG("Data end @ 0x%X; %uB p 0x%X + 0x%X offset.\n",
bout->info.data_end, bout->info.page_size,
bout->info.data_end / bout->info.page_size,
bout->info.data_end % bout->info.page_size);
DEBUG("Totals: 0x%X bytes, %u %uB pages.\n",
bout->info.data_end - bout->info.data_start + 1,
bout->info.data_end / bout->info.page_size \
- bout->info.data_start/bout->info.page_size + 1,
bout->info.page_size );
/* more error checking */
if( (bout->info.data_start < bout->info.valid_start) ||
(bout->info.data_end > bout->info.valid_end) ) {
DEBUG( "ERROR: Data exists outside of the valid target flash region.\n" );
if( !quiet )
fprintf( stderr, "Hex file error, use debug for more info.\n" );
return BUFFER_INIT_ERROR;
} else if( bout->info.data_start == UINT32_MAX ) {
DEBUG( "ERROR: No valid data to flash.\n" );
if( !quiet )
fprintf( stderr, "Hex file error, use debug for more info.\n" );
return BUFFER_INIT_ERROR;
}
if( !quiet ) {
if( debug <= STM32_DEBUG_THRESHOLD ) {
/* NOTE: from here on we should run finally block */
fprintf( stderr, "[================================] " );
}
fprintf( stderr, "Programming 0x%X bytes...\n",
bout->info.data_end - bout->info.data_start + 1 );
if( debug <= STM32_DEBUG_THRESHOLD ) {
/* NOTE: from here on we need to run finally block */
fprintf( stderr, "[" );
}
}
/* program the data */
bout->info.block_start = bout->info.data_start;
reset_address_flag = 1;
while( bout->info.block_start <= bout->info.data_end ) {
if( reset_address_flag ) {
address_offset = bout->info.block_start;
if( (status = stm32_set_address_ptr(device,
STM32_FLASH_OFFSET + address_offset)) ) {
DEBUG("Error setting address 0x%X\n", address_offset);
retval = DEVICE_ACCESS_ERROR;
goto finally;
}
dfu_set_transaction_num( 2 ); /* sets block offset 0 */
reset_address_flag = 0;
}
/* find end address (info.block_end) for data section to write */
mem_section = bout->info.block_start / STM32_MIN_SECTOR_BOUND;
for( i = 0, bout->info.block_end = bout->info.block_start;
bout->info.block_end <= bout->info.data_end;
bout->info.block_end++, i++ ) {
xfer_size = bout->info.block_end - bout->info.block_start + 1;
// check if the current value is valid
if( bout->data[bout->info.block_end] > UINT8_MAX ) break;
// check if the current data packet is too big
if( xfer_size > STM32_MAX_TRANSFER_SIZE ) break;
// check if the current data value is outside of the memory sector
if( bout->info.block_end / STM32_MIN_SECTOR_BOUND - mem_section ) break;
buffer[i] = (uint8_t) bout->data[bout->info.block_end];
}
bout->info.block_end--; // bout->info.block_end was one step beyond the last data value to flash
xfer_size = bout->info.block_end - bout->info.block_start + 1;
if( xfer_size != STM32_MAX_TRANSFER_SIZE ) {
DEBUG("xfer_size %u not max %u, need addr reset\n",
xfer_size, STM32_MAX_TRANSFER_SIZE);
reset_address_flag = 1;
}
/* write the data */
DEBUG("Program data block: 0x%X to 0x%X, 0x%X bytes.\n",
bout->info.block_start, bout->info.block_end, xfer_size);
if( (status = stm32_write_block( device, xfer_size, buffer )) ) {
DEBUG( "Error flashing the block: err %d.\n", status );
retval = FLASH_WRITE_ERROR;
goto finally;
}
// incrment bout->info.block_start to the next valid address
for( bout->info.block_start = bout->info.block_end + 1;
bout->info.block_start <= bout->info.data_end;
bout->info.block_start++ ) {
if( (bout->data[bout->info.block_start] <= UINT8_MAX) ) break;
} // bout->info.block_start is now on the first valid data for the next segment
if( reset_address_flag == 0 && (bout->info.block_start !=
(STM32_MAX_TRANSFER_SIZE * (dfu_get_transaction_num() - 2))
+ address_offset) ) {
DEBUG("block start does not match addr, reset req\n");
reset_address_flag = 1;
}
// display progress in 32 increments (if not hidden)
if ( !quiet ) print_progress( &bout->info, &progress );
}
retval = SUCCESS;
finally:
if ( !quiet ) {
if( SUCCESS == retval ) {
if ( debug <= STM32_DEBUG_THRESHOLD ) {
fprintf( stderr, "] " );
}
fprintf( stderr, "SUCCESS\n" );
} else {
if ( debug <= STM32_DEBUG_THRESHOLD ) {
fprintf( stderr, " X ");
}
fprintf( stderr, "ERROR\n" );
if( retval==DEVICE_ACCESS_ERROR )
fprintf( stderr,
"Memory access error, use debug for more info.\n" );
else if( retval==FLASH_WRITE_ERROR )
fprintf( stderr,
"Memory write error, use debug for more info.\n" );
}
}
return retval;
}
int32_t stm32_get_commands( dfu_device_t *device ) {
TRACE("%s( %p )\n", __FUNCTION__, device);
int32_t result;
uint8_t i;
const size_t xfer_len = 80;
uint8_t buffer[xfer_len];
/* check status before read */
if( (result = stm32_get_status(device)) ) {
DEBUG("Status Error %d before read\n", result );
return UNSPECIFIED_ERROR;
}
dfu_set_transaction_num( 0 );
result = dfu_upload( device, xfer_len, buffer );
if( result < 0) {
dfu_status_t status;
DEBUG( "dfu_upload result: %d\n", result );
result = UNSPECIFIED_ERROR;
if( 0 == dfu_get_status(device, &status) ) {
if( status.bStatus == DFU_STATUS_OK ) {
DEBUG("DFU Status OK, state %d\n", status.bState);
} else if( status.bStatus == DFU_STATUS_ERROR_VENDOR ) {
DEBUG("Device is read protected\n");
/* status = dfuERROR and state = errVENDOR */
result = DEVICE_ACCESS_ERROR;
} else {
DEBUG("Unknown error status %d / state %d\n",
status.bStatus, status.bState );
}
} else {
DEBUG("DFU GET_STATUS fail\n");
}
dfu_clear_status( device );
return result;
}
fprintf( stdout, "There are %d commands:\n", result );
for( i = 0; i < result; i++ ) {
fprintf( stdout, " 0x%02X\n", buffer[i] );
}
return SUCCESS;
}
int32_t stm32_get_configuration( dfu_device_t *device ) {
TRACE("%s( %p )\n", __FUNCTION__, device);
int32_t status;
uint8_t i;
uint8_t buffer[STM32_OPTION_BYTES_SIZE];
if( (status = stm32_set_address_ptr(device,
stm32_sector_addresses[mem_st_option_bytes])) ) {
DEBUG("Error (%d) setting address 0x%X\n",
status, stm32_sector_addresses[mem_st_option_bytes]);
return UNSPECIFIED_ERROR;
}
if( (status = stm32_read_block(device, STM32_OPTION_BYTES_SIZE, buffer)) ) {
DEBUG("Error (%d) reading option buffer block\n", status );
return FLASH_READ_ERROR;
}
fprintf( stdout, "There are %d option bytes:\n", STM32_OPTION_BYTES_SIZE );
fprintf( stdout, "0x%02X", buffer[0] );
for( i = 1; i < STM32_OPTION_BYTES_SIZE; i++ ) {
fprintf( stdout, ", 0x%02X", buffer[i] );
}
fprintf( stdout, "\n" );
return SUCCESS;
}
int32_t stm32_read_unprotect( dfu_device_t *device, dfu_bool quiet ) {
TRACE( "%s( %p, %s )\n", __FUNCTION__, device, quiet ? "ture" : "false" );
uint8_t command[] = { READ_UNPROTECT };
uint8_t length = 1;
if( !quiet ) {
fprintf( stderr, "Read Unprotect, Erasing flash... " );
DEBUG("\n");
}
return stm32_erase( device, command, length, quiet );
}
// vim: shiftwidth=2