/*
* dfu-programmer
*
* $Id: commands.c,v 1.6 2006/06/25 00:01:37 schmidtw Exp $
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "commands.h"
#include "arguments.h"
#include "intel_hex.h"
#include "atmel.h"
static int execute_erase( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
int result = 0;
if( 2 < debug ) {
fprintf( stderr, "%s: erase %d bytes\n", __FUNCTION__,
args.memory_size );
}
result = atmel_erase_flash( device, interface, ATMEL_ERASE_ALL );
if( 0 != result )
return result;
return atmel_blank_check( device, interface, 0, args.top_memory_address );
}
static int execute_flash( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
char *hex_data = NULL;
int usage = 0;
int retval = -1;
int result = 0;
char *buffer = NULL;
int i;
buffer = (char *) malloc( args.memory_size );
if( NULL == buffer ) {
fprintf( stderr, "Request for %d bytes of memory failed.\n",
args.memory_size );
goto error;
}
memset( buffer, 0, args.memory_size );
hex_data = intel_hex_to_buffer( args.com_flash_data.file,
args.memory_size, 0xff, &usage );
if( NULL == hex_data ) {
fprintf( stderr,
"Something went wrong with creating the memory image.\n" );
goto error;
}
if( 2 < debug ) {
fprintf( stderr, "%s: write %d/%d bytes\n", __FUNCTION__,
usage, args.memory_size );
}
result = atmel_flash( device, interface, 0, args.top_memory_address,
hex_data );
if( args.memory_size != result ) {
fprintf( stderr, "Error while flashing. (%d)\n", result );
goto error;
}
if( 0 == args.com_flash_data.suppress_validation ) {
fprintf( stderr, "Validating...\n" );
result = atmel_read_flash( device, interface, 0,
args.top_memory_address, buffer,
args.memory_size );
if( args.memory_size != result ) {
fprintf( stderr, "Error while validating.\n" );
goto error;
}
if( 0 != memcmp(hex_data, buffer, args.memory_size) ) {
fprintf( stderr, "Image did not validate.\n" );
goto error;
}
}
if( 0 == args.quiet ) {
fprintf( stderr, "%d bytes used (%.02f%%)\n", usage,
((float)(usage*100)/(float)(args.top_memory_address)) );
}
retval = 0;
error:
if( NULL != buffer ) {
free( buffer );
buffer = NULL;
}
if( NULL != hex_data ) {
free( hex_data );
hex_data = NULL;
}
return retval;
}
static int execute_start_app( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
return atmel_start_app( device, interface );
}
static int execute_get( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
struct atmel_device_info info;
char *message = NULL;
short value = 0;
int status;
int controller_error = 0;
if( device_8051 == args.device_type ) {
status = atmel_read_config_8051( device, interface, &info );
} else {
status = atmel_read_config_avr( device, interface, &info );
}
if( 0 != status ) {
fprintf( stderr, "Error reading %s config information.\n",
args.device_type_string );
return status;
}
switch( args.com_get_data.name ) {
case get_bootloader:
value = info.bootloaderVersion;
message = "Bootloader Version";
break;
case get_ID1:
value = info.bootID1;
message = "Device boot ID 1";
break;
case get_ID2:
value = info.bootID2;
message = "Device boot ID 2";
break;
case get_BSB:
value = info.bsb;
message = "Boot Status Byte";
if( device_8051 != args.device_type ) {
controller_error = 1;
}
break;
case get_SBV:
value = info.sbv;
message = "Software Boot Vector";
if( device_8051 != args.device_type ) {
controller_error = 1;
}
break;
case get_SSB:
value = info.ssb;
message = "Software Security Byte";
if( device_8051 != args.device_type ) {
controller_error = 1;
}
break;
case get_EB:
value = info.eb;
message = "Extra Byte";
if( device_8051 != args.device_type ) {
controller_error = 1;
}
break;
case get_manufacturer:
value = info.manufacturerCode;
message = "Manufacturer Code";
break;
case get_family:
value = info.familyCode;
message = "Family Code";
break;
case get_product_name:
value = info.productName;
message = "Product Name";
break;
case get_product_rev:
value = info.productRevision;
message = "Product Revision";
break;
case get_HSB:
value = info.hsb;
message = "Hardware Security Byte";
break;
}
if( 0 != controller_error ) {
fprintf( stderr, "%s requires 8051 based controller\n",
message );
return -1;
}
if( value < 0 ) {
fprintf( stderr, "The requested device info is unavailable.\n" );
return -2;
}
fprintf( stdout, "%s%s0x%02x (%d)\n",
((0 == args.quiet) ? message : ""),
((0 == args.quiet) ? ": " : ""),
value, value );
return 0;
}
static int execute_dump( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
int i = 0;
char *buffer = NULL;
buffer = (char *) malloc( (args.memory_size) );
if( NULL == buffer ) {
fprintf( stderr, "Request for %d bytes of memory failed.\n",
args.memory_size );
goto error;
}
if( 2 < debug ) {
fprintf( stderr, "%s: dump %d bytes\n", __FUNCTION__,
args.memory_size );
}
if( args.memory_size != atmel_read_flash(device, interface, 0,
args.top_memory_address, buffer,
args.memory_size) )
{
fprintf( stderr, "Error while validating.\n" );
return -1;
}
for( i = 0; i < args.memory_size; i++ ) {
fprintf( stdout, "%c", buffer[i] );
}
fflush( stdout );
error:
if( NULL != buffer ) {
free( buffer );
buffer = NULL;
}
return 0;
}
static int execute_configure( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
int value = args.com_configure_data.value;
int name = args.com_configure_data.name;
if( device_8051 != args.device_type ) {
fprintf( stderr, "target doesn't support configure operation.\n" );
return -1;
}
if( (0xff & value) != value ) {
fprintf( stderr, "Value to configure must be in range 0-255.\n" );
return -1;
}
if( 0 != atmel_set_config(device, interface, name, value) )
{
fprintf( stderr, "Configuration set failed.\n" );
return -1;
}
return 0;
}
static int execute_dnload( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
if( device_SAM7 != args.device_type || device_NEO1973 != args.device_type) {
fprintf( stderr, "target doesn't support dfu download operation.\n" );
return -1;
}
if ( 0 > sam7dfu_do_dnloa(device, interface, 256, /* FIXME */
args.com_flash_data.file) )
{
fprintf( stderr, "Download failed.\n" );
return -1;
}
}
static int execute_upload( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
if( device_SAM7 != args.device_type || device_NEO1973 != args.device_type) {
fprintf( stderr, "target doesn't support dfu upload operation.\n" );
return -1;
}
if ( 0 > sam7dfu_do_upload(device, interface, 256, /* FIXME */
args.com_flash_data.file) )
{
fprintf( stderr, "Upload failed.\n" );
return -1;
}
}
int execute_command( struct usb_dev_handle *device,
int interface,
struct programmer_arguments args )
{
switch( args.command ) {
case com_erase:
return execute_erase( device, interface, args );
case com_flash:
return execute_flash( device, interface, args );
case com_start_app:
return execute_start_app( device, interface, args );
case com_get:
return execute_get( device, interface, args );
case com_dump:
return execute_dump( device, interface, args );
case com_configure:
return execute_configure( device, interface, args );
case com_dnload:
return execute_dnload( device, interface, args );
case com_upload:
return execute_upload( device, interface, args );
default:
fprintf( stderr, "Not supported at this time.\n" );
}
return -1;
}