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 //_____ D E C L A R A T I O N S ____________________________________________
00072 
00073 
00074 U8  dfu_connected=0;
00075 
00076 static   U8 buf[MAX_DATA_PER_RECORD];
00077 static   U8 prog_buf[MAX_DATA_PER_RECORD+FLASH_PAGE_SIZE];
00078 static   U8 check_buf[MAX_DATA_PER_RECORD+FLASH_PAGE_SIZE];
00079 static   U8 dfu_status;
00080 
00081 static   U16 end_addr;
00082 static   U16 start_addr;
00083 static   U8 pgm_index=0;
00084 static   U8 pgm_nb_data=0;
00085 
00086 
00087 U8 code firmware_name[]=FIRMWARE_NAME;
00088 
00095 void host_dfu_task_init(void)
00096 {
00097    Joy_init();
00098    Leds_init();
00099    dfu_connected=0;
00100 }
00101 
00108 void host_dfu_task(void)
00109 {
00110    if(Is_host_ready())    //Enumeration successfull, device is operationnal
00111    {
00112       if(Is_new_device_connection_event())        //New device connected and enumerated...
00113       {
00114          // Check host is connected to ATMEL bootloader
00115          if(Get_VID()==ATMEL_VID && Get_PID()==AT90DFU_PID)
00116          {
00117             LOG_STR_CODE(log_dfu_connect);
00118             dfu_connected=1;
00119             Led2_on();
00120          }
00121          else
00122          {
00123             dfu_connected=0;
00124          }
00125       }
00126       if(dfu_connected)
00127       {
00128          if(Is_joy_up()||Is_joy_left())
00129          {
00130             nav_reset();
00131             nav_drive_set(0);
00132             if(nav_partition_mount())
00133             {
00134                if(goto_code_name((U8 code *)firmware_name,FALSE,FALSE))
00135                {
00136                   Led0_on();
00137                   Dfu_erase();
00138                   Led0_off();
00139                   dfu_load_hex();
00140                }
00141             }
00142          }
00143       }
00144    }
00145 
00146    //Device disconnection...
00147    if(Is_device_disconnection_event())
00148    {
00149       dfu_connected=0;
00150       Led2_off();
00151    }
00152 }
00153 
00160 U8 dfu_load_hex(void)
00161 {
00162    U8 record_type;
00163    U16 addr;
00164    U8 nb_data;
00165    U8 i;
00166    U8 stop=0;
00167 
00168    dfu_status=TRUE;
00169    file_open(FOPEN_MODE_R); // Open hex firmware file
00170    while (file_eof()==FALSE)
00171    {
00172       i=file_getc();
00173       while(i!=RECORD_MARK)
00174       {
00175          i=file_getc();
00176          if(file_eof())
00177          {
00178             stop=1;
00179             break;
00180          }
00181       }
00182       if(stop) break;
00183       // Build the hex record information from file
00184       nb_data=ascii_to_bin(file_getc());
00185       nb_data=nb_data<<4;
00186       nb_data+=ascii_to_bin(file_getc());
00187       addr=ascii_to_bin(file_getc());
00188       addr=addr<<4;
00189       addr+=ascii_to_bin(file_getc());
00190       addr=addr<<4;
00191       addr+=ascii_to_bin(file_getc());
00192       addr=addr<<4;
00193       addr+=ascii_to_bin(file_getc());
00194       record_type=ascii_to_bin(file_getc());
00195       record_type=record_type<<4;
00196       record_type+=ascii_to_bin(file_getc());
00197       for(i=0;i<nb_data;i++)
00198       {
00199          buf[i]=ascii_to_bin(file_getc());
00200          buf[i]=buf[i]<<4;
00201          buf[i]+=ascii_to_bin(file_getc());
00202       }
00203       // Decode record type
00204       switch(record_type)
00205       {
00206          case DATA_RECORD:
00207             if(addr!=end_addr+1 && pgm_index!=0) //None consecutive addr, first flush previous buffer
00208             {
00209                dfu_flush_prog();
00210             }
00211             // Add new data to prog buffer
00212             for(i=0;i<nb_data;i++)
00213             {
00214                prog_buf[pgm_index]=buf[i];
00215                pgm_index++;
00216             }
00217             // Update nb of data to load
00218             pgm_nb_data+=nb_data;
00219             // Compute last byte add to load
00220             if(pgm_nb_data>nb_data)
00221             {  // Data exist in buffer
00222                end_addr=end_addr+nb_data;
00223             }
00224             else // first load
00225             {
00226                end_addr=addr+nb_data-1;
00227                start_addr=addr;
00228             }
00229             //If enough data flush prog buffer
00230             if(pgm_index>=10*MAX_DATA_PER_RECORD)
00231             {
00232                dfu_flush_prog();
00233             }
00234             break;
00235          case PAGE_RECORD:
00236             if(pgm_index) // Prog buffer not empty ?
00237             {
00238                dfu_flush_prog();  // Then flush it
00239             }
00240             Dfu_set_page(buf[1]); // Send page change frame
00241          default:  //Ignore all other record types
00242             break;
00243       }
00244    }
00245    // Remaining data in buffer before quit?
00246    if(pgm_index>0)
00247    {
00248       dfu_flush_prog();
00249    }
00250    file_close();
00251    Led0_off();
00252    return dfu_status;
00253 }
00254 
00263 void dfu_prog(U16 start,U16 end,U8 *buf)
00264 {
00265    U8 i;
00266    U16 j;
00267    U8 padding;
00268 
00269    data_stage[0]=0x01;
00270    data_stage[1]=0;
00271    data_stage[2]=MSB(start);
00272    data_stage[3]=LSB(start);
00273    data_stage[4]=MSB(end);
00274    data_stage[5]=LSB(end);
00275    for(i=6;i<32;i++)
00276    {
00277       data_stage[i]=0;
00278    }
00279    padding=start%32;
00280    j=padding;
00281    while(j)
00282    {
00283       data_stage[i]=0x00;
00284       i++; j--;
00285    }
00286    j=end-start+1;
00287    while(j)
00288    {
00289       data_stage[i]=*buf;
00290       buf++;
00291       j--;i++;
00292    }
00293    Dfu_download(32+end-start+1+padding);
00294 }
00295 
00296 void dfu_read(U16 start,U16 end,U8 *buf)
00297 {
00298    U16 j;
00299    U16 i;
00300 
00301    data_stage[0]=0x03;
00302    data_stage[1]=0;
00303    data_stage[2]=MSB(start);
00304    data_stage[3]=LSB(start);
00305    data_stage[4]=MSB(end);
00306    data_stage[5]=LSB(end);
00307    Dfu_download(6);
00308    i=end-start+1;
00309    Dfu_upload(i);
00310    for(j=0;j<i;j++)
00311    {
00312       *buf=data_stage[j];
00313       buf++;
00314    }
00315 }
00316 
00317 void dfu_flush_prog(void)
00318 {
00319    U8 i;
00320    // All buffer in the same flash memory page ?
00321    if( MSB(start_addr)== MSB(end_addr))
00322    {
00323       dfu_prog(start_addr,end_addr,prog_buf);
00324    }
00325    else // No, program in two times
00326    {
00327       i=(end_addr%FLASH_PAGE_SIZE);
00328       dfu_prog(start_addr,end_addr-i-1,prog_buf);
00329       dfu_prog(end_addr-i,end_addr,&prog_buf[pgm_nb_data-i-1]);
00330    }
00331    // Verify on the fly...
00332    dfu_read(start_addr,end_addr,check_buf);
00333    for(i=0;i<pgm_nb_data;i++)
00334    {
00335       if(prog_buf[i]!=check_buf[i])
00336       {
00337          Leds_on();
00338          dfu_status=FALSE;
00339       }
00340    }
00341    Led0_toggle();
00342    pgm_index=0;
00343    pgm_nb_data=0;
00344 }
00345 
00346 U8 ascii_to_bin (U8 b)
00347 {
00348 b|='a'-'A'; // to_lower: '0'=>'0', 'A'=>'a', 'a'=>'a'
00349 return ( (b <= '9') ? (b-'0') : (b+10-'a') );
00350 }
00351 

Generated on Wed Sep 23 09:33:17 2009 for ATMEL by  doxygen 1.5.3