host_dfu_task.c

Go to the documentation of this file.
00001 /*This file is prepared for Doxygen automatic documentation generation.*/
00013 
00014 /* Copyright (c) 2009 Atmel Corporation. All rights reserved.
00015  *
00016  * Redistribution and use in source and binary forms, with or without
00017  * modification, are permitted provided that the following conditions are met:
00018  *
00019  * 1. Redistributions of source code must retain the above copyright notice,
00020  * this list of conditions and the following disclaimer.
00021  *
00022  * 2. Redistributions in binary form must reproduce the above copyright notice,
00023  * this list of conditions and the following disclaimer in the documentation
00024  * and/or other materials provided with the distribution.
00025  *
00026  * 3. The name of Atmel may not be used to endorse or promote products derived
00027  * from this software without specific prior written permission.
00028  *
00029  * 4. This software may only be redistributed and used in connection with an Atmel
00030  * AVR product.
00031  *
00032  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
00033  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00034  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND
00035  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
00036  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00037  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00038  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00039  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00040  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00041  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00042  */
00043 
00044 //_____  I N C L U D E S ___________________________________________________
00045 
00046 #include "config.h"
00047 #include "conf_usb.h"
00048 
00049 #include "modules/file_system/fat.h"
00050 #include "modules/file_system/fs_com.h"
00051 #include "modules/file_system/navigation.h"
00052 #include "modules/file_system/file.h"
00053 #include "modules/file_system/nav_utils.h"
00054 
00055 #include "host_dfu_task.h"
00056 #include "modules/usb/host_chap9/usb_host_task.h"
00057 #include "modules/usb/host_chap9/usb_host_enum.h"
00058 #include "lib_mcu/usb/usb_drv.h"
00059 #include "lib_mcu/flash/flash.h"
00060 
00061 
00062 //_____ M A C R O S ________________________________________________________
00063 
00064 
00065 #ifndef LOG_STR_CODE
00066 #define LOG_STR_CODE(str)
00067 #else
00068 U8 code log_dfu_connect[]="DFU Connected";
00069 #endif
00070 
00071 
00072 //_____ D E C L A R A T I O N S ____________________________________________
00073 
00074 
00075 U8  dfu_connected=0;
00076 
00077 static U8 buf[MAX_DATA_PER_RECORD];
00078 static U8 prog_buf[MAX_DATA_PER_RECORD+FLASH_PAGE_SIZE];
00079 static U8 check_buf[MAX_DATA_PER_RECORD+FLASH_PAGE_SIZE];
00080 static   U8 dfu_status;
00081 
00082 static   U16 end_addr;
00083 static   U16 start_addr;
00084 static   U8 pgm_index=0;
00085 static   U8 pgm_nb_data=0;
00086 
00087 
00088 U8 code firmware_name[]=FIRMWARE_NAME;
00089 
00096 void host_dfu_task_init(void)
00097 {
00098    Joy_init();
00099    Leds_init();
00100    dfu_connected=0;
00101 }
00102 
00109 void host_dfu_task(void)
00110 {
00111    if(Is_host_ready())    //Enumeration successfull, device is operationnal
00112    {
00113       if(Is_new_device_connection_event())        //New device connected and enumerated...
00114       {
00115          // Check host is connected to ATMEL bootloader
00116          if(Get_VID()==ATMEL_VID && Get_PID()==AT90DFU_PID)
00117          {
00118             LOG_STR_CODE(log_dfu_connect);
00119             dfu_connected=1;
00120             Led1_on();
00121          }
00122          else
00123          {
00124             dfu_connected=0;
00125          }
00126       }
00127       if(dfu_connected)
00128       {
00129          if(Is_joy_up()||Is_joy_left())
00130          {
00131             nav_reset();
00132             nav_drive_set(0);
00133             if(nav_partition_mount())
00134             {
00135                if(goto_code_name((U8 code *)firmware_name,FALSE,TRUE))
00136                {
00137                   Led0_on();
00138                   Dfu_erase();
00139                   Led0_off();
00140                   dfu_load_hex();
00141                }
00142             }
00143          }
00144       }
00145    }
00146 
00147    //Device disconnection...
00148    if(Is_device_disconnection_event())
00149    {
00150       dfu_connected=0;
00151       Led1_off();
00152    }
00153 }
00154 
00161 U8 dfu_load_hex(void)
00162 {
00163    U8 record_type;
00164    U16 addr;
00165    U8 nb_data;
00166    U8 i;
00167    U8 stop=0;
00168 
00169    dfu_status=TRUE;
00170    file_open(FOPEN_MODE_R); // Open hex firmware file
00171    while (file_eof()==FALSE)
00172    {
00173       i=file_getc();
00174       while(i!=RECORD_MARK)
00175       {
00176          i=file_getc();
00177          if(file_eof())
00178          {
00179             stop=1;
00180             break;
00181          }
00182       }
00183       if(stop) break;
00184       // Build the hex record information from file
00185       nb_data=ascii_to_bin(file_getc());
00186       nb_data=nb_data<<4;
00187       nb_data+=ascii_to_bin(file_getc());
00188       addr=ascii_to_bin(file_getc());
00189       addr=addr<<4;
00190       addr+=ascii_to_bin(file_getc());
00191       addr=addr<<4;
00192       addr+=ascii_to_bin(file_getc());
00193       addr=addr<<4;
00194       addr+=ascii_to_bin(file_getc());
00195       record_type=ascii_to_bin(file_getc());
00196       record_type=record_type<<4;
00197       record_type+=ascii_to_bin(file_getc());
00198       for(i=0;i<nb_data;i++)
00199       {
00200          buf[i]=ascii_to_bin(file_getc());
00201          buf[i]=buf[i]<<4;
00202          buf[i]+=ascii_to_bin(file_getc());
00203       }
00204       // Decode record type
00205       switch(record_type)
00206       {
00207          case DATA_RECORD:
00208             if(addr!=end_addr+1 && pgm_index!=0) //None consecutive addr, first flush previous buffer
00209             {
00210                dfu_flush_prog();
00211             }
00212             // Add new data to prog buffer
00213             for(i=0;i<nb_data;i++)
00214             {
00215                prog_buf[pgm_index]=buf[i];
00216                pgm_index++;
00217             }
00218             // Update nb of data to load
00219             pgm_nb_data+=nb_data;
00220             // Compute last byte add to load
00221             if(pgm_nb_data>nb_data)
00222             {  // Data exist in buffer
00223                end_addr=end_addr+nb_data;
00224             }
00225             else // first load
00226             {
00227                end_addr=addr+nb_data-1;
00228                start_addr=addr;
00229             }
00230             //If enough data flush prog buffer
00231             if(pgm_index>=10*MAX_DATA_PER_RECORD)
00232             {
00233                dfu_flush_prog();
00234             }
00235             break;
00236          case PAGE_RECORD:
00237             if(pgm_index) // Prog buffer not empty ?
00238             {
00239                dfu_flush_prog();  // Then flush it
00240             }
00241             Dfu_set_page(buf[1]); // Send page change frame
00242          default:  //Ignore all other record types
00243             break;
00244       }
00245    }
00246    // Remaining data in buffer before quit?
00247    if(pgm_index>0)
00248    {
00249       dfu_flush_prog();
00250    }
00251    file_close();
00252    Led0_off();
00253    return dfu_status;
00254 }
00255 
00264 void dfu_prog(U16 start,U16 end,U8 *buf)
00265 {
00266    U8 i;
00267    U16 j;
00268    U8 padding;
00269 
00270    data_stage[0]=0x01;
00271    data_stage[1]=0;
00272    data_stage[2]=MSB(start);
00273    data_stage[3]=LSB(start);
00274    data_stage[4]=MSB(end);
00275    data_stage[5]=LSB(end);
00276    for(i=6;i<32;i++)
00277    {
00278       data_stage[i]=0;
00279    }
00280    padding=start%32;
00281    j=padding;
00282    while(j)
00283    {
00284       data_stage[i]=0x00;
00285       i++; j--;
00286    }
00287    j=end-start+1;
00288    while(j)
00289    {
00290       data_stage[i]=*buf;
00291       buf++;
00292       j--;i++;
00293    }
00294    Dfu_download(32+end-start+1+padding);
00295 }
00296 
00297 void dfu_read(U16 start,U16 end,U8 *buf)
00298 {
00299    U16 j;
00300    U16 i;
00301 
00302    data_stage[0]=0x03;
00303    data_stage[1]=0;
00304    data_stage[2]=MSB(start);
00305    data_stage[3]=LSB(start);
00306    data_stage[4]=MSB(end);
00307    data_stage[5]=LSB(end);
00308    Dfu_download(6);
00309    i=end-start+1;
00310    Dfu_upload(i);
00311    for(j=0;j<i;j++)
00312    {
00313       *buf=data_stage[j];
00314       buf++;
00315    }
00316 }
00317 
00318 void dfu_flush_prog(void)
00319 {
00320    U8 i;
00321    // All buffer in the same flash memory page ?
00322    if( MSB(start_addr)== MSB(end_addr))
00323    {
00324       dfu_prog(start_addr,end_addr,prog_buf);
00325    }
00326    else // No, program in two times
00327    {
00328       i=(end_addr%FLASH_PAGE_SIZE);
00329       dfu_prog(start_addr,end_addr-i-1,prog_buf);
00330       dfu_prog(end_addr-i,end_addr,&prog_buf[pgm_nb_data-i-1]);
00331    }
00332    // Verify on the fly...
00333    dfu_read(start_addr,end_addr,check_buf);
00334    for(i=0;i<pgm_nb_data;i++)
00335    {
00336       if(prog_buf[i]!=check_buf[i])
00337       {
00338          Leds_on();
00339          dfu_status=FALSE;
00340       }
00341    }
00342    Led0_toggle();
00343    pgm_index=0;
00344    pgm_nb_data=0;
00345 }
00346 
00347 U8 ascii_to_bin (U8 b)
00348 {
00349 b|='a'-'A'; // to_lower: '0'=>'0', 'A'=>'a', 'a'=>'a'
00350 return ( (b <= '9') ? (b-'0') : (b+10-'a') );
00351 }
00352 

Generated on Wed Sep 23 09:49:34 2009 for ATMEL by  doxygen 1.5.3