2   #define F_CPU 1000000UL /* 1 Mhz-Takt; hier richtigen Wert eintragen */ 
   5 #include "../firmware/spminterface.h" 
   6 #include "usbasploader.h" 
   8 // activate updaters full set of features 
   9 #ifndef CONFIG_UPDATER_REDUCEWRITES 
  10   #define CONFIG_UPDATER_REDUCEWRITES 
  13 #ifndef CONFIG_UPDATER_CLEANMEMCLEAR 
  14   #define CONFIG_UPDATER_CLEANMEMCLEAR 
  19 #include <avr/interrupt.h> 
  22 #include <avr/pgmspace.h> 
  26 #include <util/delay.h> 
  29 #define updater_pagefillcode    ((1<<SPMEN)) 
  30 #define updater_pageerasecode   ((1<<PGERS) | (1<<SPMEN)) 
  31 #define updater_pagewritecode   ((1<<PGWRT) | (1<<SPMEN)) 
  34 #include "../firmware/bootloaderconfig.h" 
  35 #if !HAVE_SPMINTEREFACE 
  36   #error "bootloader does not support updating itself! (HAVE_SPMINTEREFACE)" 
  39 // helpful definitions and makros //// 
  41 #ifndef NEW_BOOTLOADER_ADDRESS 
  42   #error "where should the new bootloader be positioned?" 
  47 #if (NEW_BOOTLOADER_ADDRESS != (funcaddr___bootloader__do_spm-(funcaddr___bootloader__do_spm % SPM_PAGESIZE))) 
  48   #warning the new bootloader seems to be located elsewhere, than the current one! 
  51 #ifndef NEW_SPM_ADDRESS 
  52   #warning I do not know where new "bootloader__do_spm" is located - assuming "NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE)" 
  53   #define NEW_SPM_ADDRESS (NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE)) 
  56 // TEMP_SPM supports up to 4 pages for "bootloader__do_spm"... 
  57 #define TEMP_SPM_NUMPAGE 4 
  58 #define TEMP_SPM_BLKSIZE (TEMP_SPM_NUMPAGE*SPM_PAGESIZE) 
  59 #ifndef TEMP_SPM_PAGEADR 
  60   #warning "TEMP_SPM_PAGEADR" is not defined explicitly - will choose END OF FLASH ! 
  61   #define TEMP_SPM_PAGEADR ((FLASHEND+1) - TEMP_SPM_BLKSIZE) 
  63 #define TEMP_SPM_ADDRESS ((TEMP_SPM_PAGEADR) + (funcaddr___bootloader__do_spm % SPM_PAGESIZE)) 
  66 #if (NEW_SPM_ADDRESS == funcaddr___bootloader__do_spm) 
  67   #define new_do_spm    do_spm 
  69 void new_do_spm(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
) { 
  70     __do_spm_Ex(flash_byteaddress
, spmcrval
, dataword
, NEW_SPM_ADDRESS 
>> 1); 
  74 void temp_do_spm(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
) { 
  75     __do_spm_Ex(flash_byteaddress
, spmcrval
, dataword
, TEMP_SPM_ADDRESS 
>> 1); 
  80 // some important consistency checks //// 
  82 //check if "NEW_BOOTLOADER_ADDRESS" is page-aligned 
  83 #if (NEW_BOOTLOADER_ADDRESS % SPM_PAGESIZE != 0)  
  84   #error "NEW_BOOTLOADER_ADDRESS" is not aligned to pages! 
  87 //check, if NEW_SPM_ADDRESS is an even address 
  88 #if ((NEW_SPM_ADDRESS % 2) != 0) 
  89   #error NEW_SPM_ADDRESS must be an even address, since it contains executable code! 
  94 //check, if TEMP_SPM somehow overlaps with old SPM 
  95 #if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= funcaddr___bootloader__do_spm) && (TEMP_SPM_ADDRESS <= (funcaddr___bootloader__do_spm + TEMP_SPM_BLKSIZE + SPM_PAGESIZE))) 
  96   #error TEMP_SPM_ADDRESS overlaps "funcaddr___bootloader__do_spm"! 
  99 //check, if TEMP_SPM somehow overlaps with new SPM 
 100 #if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= NEW_SPM_ADDRESS) && (TEMP_SPM_ADDRESS <= (NEW_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE))) 
 101   #error TEMP_SPM_ADDRESS overlaps "NEW_SPM_ADDRESS"! 
 104 //check, if TEMP_SPM_ADDRESS is an even address 
 105 #if ((TEMP_SPM_ADDRESS % 2) != 0) 
 106   #error TEMP_SPM_ADDRESS must be an even address, since it contains executable code! 
 109 //check, if TEMP_SPM_ADDRESS fits into flash 
 110 #if ((TEMP_SPM_PAGEADR + TEMP_SPM_BLKSIZE) > (FLASHEND+1)) 
 111   #error TEMP_SPM_ADDRESS exceeds flashend! 
 114 //check if size too low 
 115 #if (SIZEOF_new_firmware <= (TEMP_SPM_BLKSIZE + (NEW_SPM_ADDRESS - NEW_BOOTLOADER_ADDRESS))) 
 116   #error empty firmware! 
 119 //check if size too high 
 120 #if (SIZEOF_new_firmware > ((FLASHEND+1)-NEW_BOOTLOADER_ADDRESS)) 
 121   #error firmware too big! firmware does not fit into flash memory! 
 127  * in this case a near address 
 129 typedef uint32_t mypgm_addr_t
; 
 130 typedef void (*mypgm_spminterface
)(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
); 
 133 #       define  mymemcpy_PF mymemcpy_PF_far 
 134 void *mymemcpy_PF_far (void *dest
, mypgm_addr_t src
, size_t n
) { 
 135   uint8_t       *pagedata       
= (void*)dest
; 
 136   mypgm_addr_t   pageaddr       
= src
; 
 140     pagedata
[i
]=pgm_read_byte_far(pageaddr
); 
 147 #       define  mymemcpy_PF memcpy_PF  
 151 size_t mypgm_readpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
) { 
 152   size_t        result          
= (bufferbytesize 
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
; 
 153   size_t        pagesize        
= result 
>> 1; 
 154   uint16_t      *pagedata       
= (void*)buffer
; 
 155   mypgm_addr_t  pageaddr        
= byteaddress 
- (byteaddress 
% SPM_PAGESIZE
); 
 158   for (i
=0;i
<pagesize
;i
+=1) { 
 159     pagedata
[i
]=pgm_read_word_far(pageaddr
); 
 166 // replace it somehow with "memcpy_PF" in order to save some ops... 
 167 size_t mypgm_readpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
) { 
 168   size_t        result          
= (bufferbytesize 
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
; 
 169   mypgm_addr_t  pageaddr        
= byteaddress 
- (byteaddress 
% SPM_PAGESIZE
); 
 171   mymemcpy_PF((void*)buffer
, (uint_farptr_t
)pageaddr
, result
); 
 177 #ifdef CONFIG_UPDATER_REDUCEWRITES 
 178 size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
, mypgm_spminterface spmfunc
) { 
 179   size_t        result          
= (bufferbytesize 
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
; 
 180   size_t        pagesize        
= result 
>> 1; 
 181   uint16_t      *pagedata       
= (void*)buffer
; 
 182   mypgm_addr_t  pageaddr_bakup  
= byteaddress 
- (byteaddress 
% SPM_PAGESIZE
); 
 183   mypgm_addr_t  pageaddr        
= pageaddr_bakup
; 
 185   uint8_t       changed
=0, needs_erase
=0; 
 189   // just check, if page needs a rewrite or an erase... 
 190   for (i
=0;i
<pagesize
;i
+=1) { 
 191 #if (FLASHEND > 65535) 
 192     deeword
=pgm_read_word_far(pageaddr
); 
 194     deeword
=pgm_read_word(pageaddr
); 
 197     if (deeword 
!= pagedata
[i
]) changed
=1; 
 208      * ==> /(/x * y) ==> x + /y 
 210     deeword 
|= ~pagedata
[i
]; 
 211     if ((~deeword
) != 0) needs_erase
=1; 
 219       //do a page-erase, ATTANTION: flash only can be erased a limited number of times ! 
 220       spmfunc(pageaddr_bakup
, updater_pageerasecode
, 0); 
 223     // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!) 
 224     // now, fill the tempoary buffer 
 225     // ATTANTION: see comment on "do_spm" ! 
 226     pageaddr    
= pageaddr_bakup
; 
 227     for (i
=0;i
<pagesize
;i
+=1) { 
 228       spmfunc(pageaddr
, updater_pagefillcode
, pagedata
[i
]); 
 232     // so, now finally write the page to the FLASH 
 233     spmfunc(pageaddr_bakup
, updater_pagewritecode
, 0); 
 235     // no change - no write... 
 243 size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
, mypgm_spminterface spmfunc
) { 
 244   size_t        result          
= (bufferbytesize 
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
; 
 245   size_t        pagesize        
= result 
>> 1; 
 246   uint16_t      *pagedata       
= (void*)buffer
; 
 247   mypgm_addr_t  pageaddr_bakup  
= byteaddress 
- (byteaddress 
% SPM_PAGESIZE
); 
 248   mypgm_addr_t  pageaddr        
= pageaddr_bakup
; 
 252   //do a page-erase, ATTANTION: flash only can be erased a limited number of times ! 
 253   spmfunc(pageaddr_bakup
, updater_pageerasecode
, 0); 
 255   // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!) 
 256   // now, fill the tempoary buffer 
 257   // ATTANTION: see comment on "do_spm" ! 
 258   pageaddr      
= pageaddr_bakup
; 
 259   for (i
=0;i
<pagesize
;i
+=1) { 
 260     spmfunc(pageaddr
, updater_pagefillcode
, pagedata
[i
]); 
 264   // so, now finally write the page to the FLASH 
 265   spmfunc(pageaddr_bakup
, updater_pagewritecode
, 0); 
 271 // #pragma GCC diagnostic ignored "-Wno-pointer-to-int-cast" 
 275     uint8_t buffer
[SPM_PAGESIZE
]; 
 280     // check if firmware would change... 
 282     for (i
=0;i
<SIZEOF_new_firmware
;i
+=2) { 
 284 #if (FLASHEND > 65535) 
 285       a
=pgm_read_word_far((void*)&new_firmware
[i
]); 
 286       b
=pgm_read_word_far(NEW_BOOTLOADER_ADDRESS
+i
); 
 288       a
=pgm_read_word((void*)&new_firmware
[i
]); 
 289       b
=pgm_read_word(NEW_BOOTLOADER_ADDRESS
+i
); 
 299     // need to change the firmware... 
 303       // copy the current "bootloader__do_spm" to tempoary position via std. "bootloader__do_spm" 
 304       for (i
=0;i
<TEMP_SPM_BLKSIZE
;i
+=SPM_PAGESIZE
) { 
 305         mypgm_WRITEpage(TEMP_SPM_PAGEADR
+i
, buffer
, mypgm_readpage(funcaddr___bootloader__do_spm
+i
, buffer
, sizeof(buffer
)), do_spm
); 
 309       // start updating the firmware to "NEW_BOOTLOADER_ADDRESS" until at least "TEMP_SPM_BLKSIZE"-bytes after "NEW_SPM_ADDRESS" were written 
 310       // therefore use the tempoary "bootloader__do_spm" (since we most probably will overwrite the default do_spm) 
 311       for (i
=0;;i
+=SPM_PAGESIZE
) { 
 312 #ifdef CONFIG_UPDATER_CLEANMEMCLEAR 
 313         memset((void*)buffer
, 0xff, sizeof(buffer
)); 
 315         mymemcpy_PF((void*)buffer
, (uint_farptr_t
)((void*)&new_firmware
[i
]), ((SIZEOF_new_firmware
-i
)>sizeof(buffer
))?
sizeof(buffer
):(SIZEOF_new_firmware
-i
)); 
 317         mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS
+i
, buffer
, sizeof(buffer
), temp_do_spm
); 
 319         if ((NEW_BOOTLOADER_ADDRESS
+i
) > (NEW_SPM_ADDRESS
+TEMP_SPM_BLKSIZE
)) break; 
 323       // continue writeing the new_firmware after "NEW_SPM_ADDRESS+TEMP_SPM_BLKSIZE" this time use the "new_do_spm" 
 324       for (;i
<SIZEOF_new_firmware
;i
+=SPM_PAGESIZE
) { 
 325 #ifdef CONFIG_UPDATER_CLEANMEMCLEAR 
 326         memset((void*)buffer
, 0xff, sizeof(buffer
)); 
 328         mymemcpy_PF((void*)buffer
, (uint_farptr_t
)((void*)&new_firmware
[i
]), ((SIZEOF_new_firmware
-i
)>sizeof(buffer
))?
sizeof(buffer
):(SIZEOF_new_firmware
-i
)); 
 330         mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS
+i
, buffer
, sizeof(buffer
), new_do_spm
);