Ika Shouyu Poppoyaki - LPC82x supported

Dependencies:   MODSERIAL mbed

Fork of ika_shouyu_poppoyaki by Tedd OKANO

main.cpp

Committer:
okano
Date:
2013-09-12
Revision:
19:7a7381e78025
Parent:
18:b401da200216
Child:
20:98d7b5878e3e

File content as of revision 19:7a7381e78025:

/**
 *  Sample of ISP operation for NXP MCUs
 *
 *  @author  Tedd OKANO
 *  @version 0.8
 *  @date    Sep-2013
 *  
 *  This program programs MCU flash memory through UART. It uses 
 *  "In-System Programming (ISP)" interface in target MCU (NXP LPC micro-
 *  controllers).
 *  
 *  The ISP is done by PC and serial cable normally. The ISP protocol is 
 *  executed software on a PC. The software reads a data file and transfers
 *  the data with the ISP protocol. 
 *  This program does same process of that. The mbed perform the function like 
 *  "FlashMagic" and "lpc21isp".
 *  (This program not just copies the binary but also insert 4 byte checksum at 
 *  address 0x1C.)
 *  
 *  This program currently supports LPC1114(LPC1114FN28/102 - DIP28-ARM) and 
 *  LPC810(LPC810M021FN8 - DIP8-ARM).
 */

#include    "mbed.h"
#include    "target_table.h"

BusOut          leds( LED4, LED3, LED2, LED1 );
DigitalOut      reset_pin( p26 );
DigitalOut      isp_pin( p25 );
Serial          pc ( USBTX,USBRX );
LocalFileSystem local( "local" );
Ticker          success;


#if 0
Serial          target( p28, p27 );
#else
#define MODSERIAL_DEFAULT_RX_BUFFER_SIZE 512
#define MODSERIAL_DEFAULT_TX_BUFFER_SIZE 512 
#include "MODSERIAL.h"
MODSERIAL       target( p28, p27 ); //
#endif



#define     ENTER_TO_ISP_MODE   0
#define     NO_ISP_MODE         1
#define     STR_BUFF_SIZE       64

#define     SOURCE_FILE         "/local/bin"

//  "ISP_BAUD_RATE" is baud rate for ISP operation

#define     ISP_BAUD_RATE       115200
//#define     ISP_BAUD_RATE       57600
//#define     ISP_BAUD_RATE       9600

//  "TARGET_OPERATION_BAUD_RATE" is baud rate for USB-serial bridge operation after 
//  ISP completion. 
//  if the target application uses serial(UART) and you use the bridge feature, 
//  please set this value correctly. 

#define     TARGET_OPERATION_BAUD_RATE  9600

int     error_state         = 0;

int     file_size( FILE *fp );
void    reset_target( int isp_pin_state );
int     try_and_check( char *command, char *expected_return_str, int mode );
int     try_and_check2( char *command, char *expected_return_str, int mode );
void    print_command( char *command );
void    print_result( int r );
char    read_byte( void );
void    erase_sectors( int last_sector );
int     write_uuencoded_data( FILE *fp, int ram_size, int sector_size, unsigned int  );
int     write_binary_data( FILE *fp, int ram_size, int sector_size, unsigned int ram_start );
int     verify_binary_data( FILE *fp );
void    initialize_uue_table( void );
long    bin2uue( char *bin, char *str, int size );
int     get_flash_writing_size( int ram_size, unsigned int ram_start );
void    add_isp_checksum( char *b );
void    send_RAM_transfer_checksum( int checksum );
void    put_string( char *s );
void    put_binary( char *b, int size );
void    get_string( char *s );
int     get_binary( char *b, int length );
void    success_indicator();


#pragma diag_suppress 1293  //  surpressing a warning message of "assignment in condition" ;)


int main()
{
    FILE            *fp;
    char            str_buf0[ STR_BUFF_SIZE ];
    char            str_buf1[ STR_BUFF_SIZE ];
    int             data_size;
    int             last_sector;
    target_param    *tpp;

    printf( "\r\n\r\n\r\nmbed ISP program : programming LPC device from mbed\r\n" );

    target.baud( ISP_BAUD_RATE );

    reset_target( ENTER_TO_ISP_MODE );

    try_and_check( "?", "Synchronized", 0 );

    try_and_check2( "Synchronized\r\n", "OK", 0 );
    try_and_check2( "12000\r\n", "OK", 0 );
    try_and_check2( "U 23130\r\n", "0", 0 );
    try_and_check2( "A 0\r\n", "0", 0 );

    try_and_check( "K\r\n", "0", 0 );
    get_string( str_buf0 );
    get_string( str_buf1 );

    printf( "    result of \"K\" = %s %s\r\n", str_buf0, str_buf1 );

    try_and_check( "J\r\n", "0", 0 );
    get_string( str_buf0 );

    printf( "    result of \"J\" = %s\r\n", str_buf0 );

    tpp  = find_target_param( str_buf0 );
    printf( "  target device found : type       = \"%s\"\r\n",   tpp->type_name );
    printf( "                        ID         = 0x%08X\r\n", tpp->id );
    printf( "                        RAM size   = %10d bytes\r\n", tpp->ram_size );
    printf( "                        flash size = %10d bytes\r\n", tpp->flash_size );

    printf( "  opening file: \"%s\"\r\n", SOURCE_FILE );

    if ( NULL == (fp    = fopen( SOURCE_FILE, "rb" )) ) {
        error( "couldn't open source file" );
        return ( 1 );
    }

    data_size   = file_size( fp );
    last_sector = data_size / tpp->sector_size;

    printf( "  data size = %d bytes, it takes %d secotrs in flash area\r\n", data_size, last_sector + 1 );
    printf( "  resetting target\r\n" );

    erase_sectors( last_sector );

    if ( tpp->write_type == BINARY )
        write_binary_data( fp, tpp->ram_size, tpp->sector_size, tpp->ram_start_address );
    else // UUENCODE
        write_uuencoded_data(  fp, tpp->ram_size, tpp->sector_size, tpp->ram_start_address );

    fclose( fp );

    printf( "\r\n  %s\r\n\r\n",
            error_state ?
            "** The data could not be written :(" :
            "** The data has been written successflly :)"
          );
    
    if ( error_state )
        error( "  ** ISP failed\r\n" );

#define AUTO_PROGRAM_START
#ifdef  AUTO_PROGRAM_START
    target.baud( TARGET_OPERATION_BAUD_RATE );

    reset_target( NO_ISP_MODE );
    printf( "  ** The program in flash has been started!!\r\n" );
#endif

    printf( "     (now the mbed is working in \"serial through mode\")\r\n\r\n" );

    success.attach( &success_indicator, 0.1 );

    while (1) {

        if ( pc.readable() ) {
            target.putc( pc.getc() );
        }

        if ( target.readable() ) {
            pc.putc( target.getc() );
        }

    }
}


int file_size( FILE *fp )
{
    int     size;

    fseek( fp, 0, SEEK_END ); // seek to end of file
    size    = ftell( fp );       // get current file pointer
    fseek( fp, 0, SEEK_SET ); // seek back to beginning of file

    return size;
}


void reset_target( int isp_pin_state )
{
    reset_pin   = 1;
    isp_pin     = isp_pin_state;
    wait_ms( 100 );
    
    reset_pin   = 0;
    wait_ms( 100 );
    
    reset_pin   = 1;
    wait_ms( 100 );
}


int try_and_check( char *command, char *expected_return_str, int mode )
{
    char    rtn_str[ STR_BUFF_SIZE ];
    int     result  = 1;

    print_command( command );
    put_string( command );

    get_string( rtn_str );
    print_result( result  = strcmp( expected_return_str, rtn_str ) );

    if ( result && !mode )
        error( "command failed\r\n" );

    error_state |= result;

    return ( result );
}


int try_and_check2( char *command, char *expected_return_str, int mode )
{
    char    rtn_str[ STR_BUFF_SIZE ];
    int     result  = 1;

    print_command( command );
    put_string( command );

    get_string( rtn_str );  // just readout echoback
    get_string( rtn_str );
    print_result( result  = strcmp( expected_return_str, rtn_str ) );

    if ( result && !mode )
        error( "command failed\r\n" );

    error_state |= result;

    return ( result );
}


void print_command( char *command )
{
    char    s[ STR_BUFF_SIZE ];
    char    *pos;

    strcpy( s, command );

    if ( pos    = strchr( s, '\r' ) )
        *pos    = '\0';

    if ( pos    = strchr( s, '\n' ) )
        *pos    = '\0';

    printf( "  command-\"%s\" : ", s );
}


void print_result( int r )
{
    printf( "%s\r\n", r ? "Fail" : "Pass" );
}


char read_byte( void )
{
    while ( !target.readable() )
        ;

    return ( target.getc() );
}


void erase_sectors( int last_sector )
{
    char    command_str[ STR_BUFF_SIZE ];

    sprintf( command_str, "P 0 %d\r\n", last_sector );
    try_and_check( command_str, "0", 0 );

    *(command_str)  = 'E';
    try_and_check( command_str, "0", 0 );
}

#define     BYTES_PER_LINE      45
char        uue_table[ 64 ];

int write_uuencoded_data( FILE *fp, int ram_size, int sector_size, unsigned int ram_start )
{
    char    command_str[ STR_BUFF_SIZE ];
    long    checksum        = 0;
    int     total_size      = 0;
    int     size;

    int     flash_writing_size;
    int     lines_per_transfer;
    int     transfer_size;

    char    *b;

    initialize_uue_table();

    flash_writing_size  = get_flash_writing_size( ram_size, ram_start );
    lines_per_transfer  = ((flash_writing_size / BYTES_PER_LINE) + 1);
    transfer_size       = (((flash_writing_size + 11) / 12) * 12);

    //  char    b[ transfer_size ]; // this can be done in mbed-compiler. but I should do it in common way

    if ( NULL == (b = (char *)malloc( transfer_size * sizeof( char ) )) )
        error( "malloc error happened\r\n" );

    for ( int i = flash_writing_size; i < transfer_size; i++ )
        b[ i ]  = 0;    //  this is not neccesary but just stuffing stuffing bytes

    while ( size    = fread( b, sizeof( char ), flash_writing_size, fp ) ) {

        if ( !total_size ) {
            //  overwriting 4 bytes data for address=0x1C
            //  there is a slot for checksum that is checked in (target's) boot process
            add_isp_checksum( b );
        }

        sprintf( command_str, "W %ld %ld\r\n", ram_start, transfer_size );
        try_and_check( command_str, "0", 0 );

        for ( int i = 0; i < lines_per_transfer; i++ ) {

            checksum   += bin2uue( b + (i * BYTES_PER_LINE), command_str, i == (lines_per_transfer - 1) ? (transfer_size % BYTES_PER_LINE) : BYTES_PER_LINE );

            //  printf( "  data -- %02d %s\r", i, command_str );

            put_string( command_str );

            if ( !((i + 1) % 20) ) {
                send_RAM_transfer_checksum( checksum );
                checksum   = 0;
            }
        }

        send_RAM_transfer_checksum( checksum );
        checksum   = 0;

        sprintf( command_str, "P %d %d\r\n", total_size / sector_size, total_size / sector_size );
        try_and_check( command_str, "0", 0 );

        sprintf( command_str, "C %d %d %d\r\n", total_size, ram_start, flash_writing_size );
        try_and_check( command_str, "0", 0 );

        total_size  += size;
    }

    try_and_check( "G 0 T\r\n", "0", 0 );
    free( b );

    return ( total_size );
}


int write_binary_data( FILE *fp, int ram_size, int sector_size, unsigned int ram_start )
{
    char    command_str[ STR_BUFF_SIZE ];
    int     total_size      = 0;
    int     size;
    int     flash_writing_size;
    char    *b;

    flash_writing_size  = 256;

    if ( NULL == (b     = (char *)malloc( flash_writing_size * sizeof( char ) )) )
        error( "malloc error happened\r\n" );

    printf( "\r\n  ==== flash writing ====\r\n" );

    while ( size    = fread( b, sizeof( char ), flash_writing_size, fp ) ) {

        if ( !total_size ) {
            //  overwriting 4 bytes data for address=0x1C
            //  there is a slot for checksum that is checked in (target's) boot process
            add_isp_checksum( b );
        }

        sprintf( command_str, "W %ld %ld\r\n", ram_start, flash_writing_size );
        try_and_check( command_str, "0", 0 );

        put_binary( b, flash_writing_size );
        put_string( "\r\n" );

        sprintf( command_str, "P %d %d\r\n", total_size / sector_size, total_size / sector_size );
        try_and_check( command_str, "0", 0 );

        sprintf( command_str, "C %d %d %d\r\n", total_size, ram_start, flash_writing_size );
        try_and_check( command_str, "0", 0 );

        total_size  += size;
        //printf( "  total %d bytes transferred\r", total_size );

    }

    free( b );

    verify_binary_data( fp );

    return ( total_size );
}


int verify_binary_data( FILE *fp )
{
    char    command_str[ STR_BUFF_SIZE ];
    int     read_size   = 0;
    int     size;
    int     flash_reading_size;
    char    *bf;
    char    *br;
    int     error_flag  = 0;
    unsigned long   checksum        = 0;
    unsigned long   checksum_count  = 0;

    fseek( fp, 0, SEEK_SET ); // seek back to beginning of file

    flash_reading_size  = 128;

    if ( NULL == (bf    = (char *)malloc( flash_reading_size * sizeof( char ) )) )
        error( "malloc error happened (in verify process, file data buffer)\r\n" );

    if ( NULL == (br    = (char *)malloc( flash_reading_size * sizeof( char ) )) )
        error( "malloc error happened (in verify process, read data buffer)\r\n" );


    printf( "\r\n  ==== flash reading and verifying ====\r\n" );

    while ( size    = fread( bf, sizeof( char ), flash_reading_size, fp ) ) {

        if ( read_size < 0x20 ) {
            for ( int i = 0; i < flash_reading_size; i += 4 ) {

                if ( checksum_count == 7 ) {
                    checksum    = 0xFFFFFFFF - checksum + 1;
                    *((unsigned int *)(bf + i)) = checksum;
                  //printf( "\r\n\r\n  -- calculated checksum    : 0x%08X\r\n", checksum );
                } else {
                    checksum    += *((unsigned int *)(bf + i));
                }
                
                checksum_count++;
            }
        }


        sprintf( command_str, "R %ld %ld\r\n", read_size, size );
//        try_and_check( command_str, "0", MODE_SILENT );
        try_and_check( command_str, "0", 0 );

        get_binary( br, 1 );
        get_binary( br, size );

        for ( int i = 0; i < size; i++ ) {
//            printf( "   %s 0x%02X --- 0x%02X\r\n", (*(bf + i) != *(br + i)) ? "***" : "   ", *(bf + i), *(br + i) );
            if ( (*(bf + i) != *(br + i)) ) {
//                printf( "   %s 0x%02X --- 0x%02X\r\n", (*(bf + i) != *(br + i)) ? "***" : "   ", *(bf + i), *(br + i) );
                error_flag++;
            }
        }

        if ( error_flag )
            break;
            
        read_size   += size;

//        printf( "  total %d bytes read\r\n", read_size );
    }
    
    error_state |= error_flag;

    printf( "  total %d bytes read\r", read_size );
    printf( "  verification result : \"%s\"\r\n", error_flag ? "Fail" : "Pass" );

    free( bf );
    free( br );

    return ( read_size );
}


void initialize_uue_table( void )
{
    int     i;

    uue_table[0] = 0x60;           // 0x20 is translated to 0x60 !

    for (i = 1; i < 64; i++) {
        uue_table[i] = (char)(0x20 + i);
    }
}


long bin2uue( char *bin, char *str, int size )
{
    unsigned long   v;
    long            checksum    = 0;
    int             strpos      = 0;

    *(str + strpos++) = ' ' + size;

    for ( int i = 0; i < size; i += 3 ) {
        checksum    += *(bin + i + 0) + *(bin + i + 1) + *(bin + i + 2);
        v   = (*(bin + i + 0) << 16) | (*(bin + i + 1) << 8) | (*(bin + i + 2) << 0);
        *(str + strpos++) = uue_table[ (v >> 18) & 0x3F ];
        *(str + strpos++) = uue_table[ (v >> 12) & 0x3F ];
        *(str + strpos++) = uue_table[ (v >>  6) & 0x3F ];
        *(str + strpos++) = uue_table[ (v >>  0) & 0x3F ];
    }
    *(str + strpos++) = '\n';
    *(str + strpos++) = '\0';

    return checksum;
}


int get_flash_writing_size( int ram_size, unsigned int ram_start )
{
    int flash_writing_size[]    = {
        4096,
        1024,
        512,
        256
    };
    int     available_size;
    int     i;

    available_size  = ram_size - (ram_start & 0xFFFF);

    for ( i = 0; i < sizeof( flash_writing_size ) / sizeof( int ); i++ ) {
        if ( flash_writing_size[ i ] < available_size )
            break;
    }

    return ( flash_writing_size[ i ] );
}


void add_isp_checksum( char *b )
{
    //  see http://www.lpcware.com/content/nxpfile/lpc177x8x-checksum-insertion-program

    unsigned int    *p;
    unsigned int    cksum   = 0;

    p  = (unsigned int *)b;

    for ( int i = 0; i < 7; i++ ) {
        cksum   += *p++;
    }

    printf( "  -- value at checksum slot : 0x%08X\r\n", *p );

    *p  = 0xFFFFFFFF - cksum + 1;
    printf( "  -- calculated checksum    : 0x%08X\r\n", *p );

    printf( "     new checksum will be used to program flash\r\n" );
}


void send_RAM_transfer_checksum( int checksum )
{
    char    command[ 16 ];

    sprintf( command, "%d\n", checksum );
    try_and_check( command, "OK", 0 );
}


void put_string( char *s )
{
    char            c;
    static int      i   = 0;

    while ( c = *s++ ) {
        target.putc( c );
        leds    = i++ & 0x1;
    }
}


void put_binary( char *b, int size )
{
    for ( int i = 0; i < size; i++ )
        target.putc( *b++ );
}


Timeout timeout;

int timeout_flag    = 0;

void set_flag()
{
    timeout_flag    = 1;
}


void get_string( char *s )
{
    int     i   = 0;
    char    c   = 0;
    timeout_flag    = 0;

    timeout.attach( &set_flag, 1 );

    do {
        do {
            if ( target.readable() ) {
                c  = target.getc();

                if ( ( c == '\n') || (c == '\r') )
                    break;

                *s++    = c;
                i++;
            }

            if ( timeout_flag )
                return;
        } while ( 1 );
    } while ( !i );

    *s  = '\0';
}


int get_binary( char *b, int length )
{
    int i;

    timeout_flag    = 0;
    timeout.attach( &set_flag, 1 );

    for ( i = 0; i < length; i++ ) {
        if ( target.readable() )
            *b++    = target.getc();

        if ( timeout_flag )
            return ( i );
    }

    return ( i );
}


void success_indicator()
{
    static int  i   = 0;
    
    leds    = 0x1 << (i++ & 0x3);
}