LCOV - code coverage report
Current view: top level - wibmod/src/WIB1 - WIB_Flash.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 236 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 9 0

            Line data    Source code
       1              : #include "wibmod/WIB1/WIB.hh"
       2              : #include "wibmod/WIB1/WIBException.hh"
       3              : #include "wibmod/WIB1/BNL_UDP_Exception.hh"
       4              : #include <fstream>
       5              : #include <assert.h>
       6              : #include <algorithm>
       7              : #define FLASH_TIMEOUT 400
       8              : 
       9              : #define MIN_LINE_LENGTH 10 
      10              : #define MAX_LINE_LENGTH 266
      11              : 
      12            0 : static void ParseIHexLine(std::string line, std::vector <uint8_t> &data, uint32_t &upperAddr){
      13            0 :   if(line.empty()){         
      14            0 :     BUException::WIB_FLASH_IHEX_ERROR e;
      15            0 :     e.Append("line is empty");
      16            0 :     throw e;
      17            0 :   }else if(line[0] != ':'){         
      18            0 :     BUException::WIB_FLASH_IHEX_ERROR e;
      19            0 :     e.Append("BAD Line in file - does not start with ':'");
      20            0 :     throw e;
      21            0 :   }else{
      22            0 :     line.erase(0,1);
      23              :   }      
      24            0 :   if(line.size()<MIN_LINE_LENGTH){         
      25            0 :     BUException::WIB_FLASH_IHEX_ERROR e;
      26            0 :     e.Append("BAD Line in file - incomplete intel hex format\n");
      27            0 :     throw e;
      28            0 :   }else if(line.size()>MAX_LINE_LENGTH){
      29            0 :     BUException::WIB_FLASH_IHEX_ERROR e;         
      30            0 :     e.Append("BAD Line in file - intel hex format not supported, contains too many characters\n");
      31            0 :     throw e;
      32            0 :   }else if (line.size()&1){         
      33            0 :     BUException::WIB_FLASH_IHEX_ERROR e;
      34            0 :     e.Append("BAD Line in file - uneven number of characters\n");
      35            0 :     throw e;
      36            0 :   }else {
      37            0 :     char const *entry = line.c_str();
      38            0 :     uint32_t line_sum = 0, byte_count = 0, address = 0, record_type = 0;
      39              : 
      40            0 :     uint32_t byte = 0;
      41            0 :     for(uint32_t iSum = 0; iSum < line.size(); iSum+=2){
      42            0 :       sscanf(entry+iSum, "%2x", &byte);
      43            0 :       line_sum += byte;
      44              :     }  
      45              :     //the content of the line is cancelled out through addition to its
      46              :     //two's complement which is the checksum if all data is intact
      47              : 
      48            0 :     if(0xFF&line_sum){
      49            0 :       line_sum = 0xFF & line_sum;
      50            0 :       BUException::WIB_FLASH_IHEX_ERROR e;            
      51            0 :       e.Append("BAD Line in file - content inconsistent with checksum.\n");
      52            0 :       throw e;
      53            0 :     } else{
      54            0 :       line_sum = 0;
      55              :     }  
      56              : 
      57            0 :     sscanf(entry,"%2x %4x %2x ", &byte_count, &address, &record_type);
      58            0 :     if(4 == record_type){
      59            0 :       upperAddr = 0;
      60            0 :       sscanf(entry+8,"%4x", &upperAddr);
      61            0 :       upperAddr = upperAddr << 16;
      62            0 :     } else if(0 == record_type){
      63            0 :       address = upperAddr+address;
      64            0 :       if(data.size() < (address+byte_count)){
      65            0 :         data.resize(address+byte_count,0xFF);
      66              :       }  
      67            0 :       for(uint32_t iAddr = 0; iAddr < byte_count; iAddr++){
      68            0 :         uint32_t tempData = 0;
      69            0 :         sscanf(entry+(iAddr*2)+8,"%02x",&tempData);
      70            0 :         data[address+iAddr] = (uint8_t)tempData;
      71              :       }  
      72              : 
      73              :     }  
      74              :   }  
      75            0 : }  
      76              : 
      77            0 :  void LoadIHexFile(std::vector <uint8_t>&data, const char* file){
      78            0 :    std::string line;
      79            0 :    std::ifstream datafile(file);
      80            0 :    uint32_t upperAddr = 0;
      81            0 :    if(datafile.is_open()){
      82            0 :      while(getline(datafile, line)){
      83            0 :        ParseIHexLine(line, data, upperAddr);
      84              :      }
      85              :    } else{
      86            0 :      BUException::WIB_FLASH_IHEX_ERROR e;      
      87            0 :      e.Append("Unable to open file ");
      88            0 :      e.Append(file);
      89            0 :      throw e;
      90            0 :    }
      91            0 :  }
      92              : 
      93            0 : static std::vector<uint32_t> firmwareFromIntelHexFile(std::string const & iHexFileName){
      94              :   //Ihex parser loads intel hex into a vector of bytes.
      95            0 :   std::vector<uint8_t> rawData;
      96            0 :   LoadIHexFile(rawData,iHexFileName.c_str());
      97              : 
      98              :   //We now need to convert it to a uint32_t 
      99              :   //This has the issue of what to do if we are off by 32bit boundary.
     100              :   //For now we'll just die so we don't have to deal with the issue. 
     101              :   //Make sure this is called before we erase the flash :-p
     102            0 :   if((rawData.size()&0x3) != 0x0){
     103            0 :     BUException::WIB_FLASH_IHEX_ERROR e;      
     104            0 :     e.Append("Flash data is not a multiple of 32bit words");
     105            0 :     throw e;
     106            0 :   }else if(0 == rawData.size()){
     107            0 :     BUException::WIB_FLASH_IHEX_ERROR e;      
     108            0 :     e.Append("Flash data is empty");
     109            0 :     throw e;
     110            0 :   }
     111              :   
     112              :   //Create a std::vector<uint32_t> and fill it with rawData;
     113            0 :   std::vector<uint32_t> ret;
     114            0 :   for(size_t iRawData = 0; iRawData < rawData.size();iRawData+=4){
     115              :     //Build the 32bit word
     116            0 :     uint32_t tempData = (rawData[iRawData + 0] <<  0 |
     117            0 :                          rawData[iRawData + 1] <<  8 |
     118            0 :                          rawData[iRawData + 2] << 16 |
     119            0 :                          rawData[iRawData + 3] << 24 );
     120            0 :     ret.push_back(tempData);      
     121              :   }
     122            0 :   return ret;
     123            0 : }
     124              :  
     125              : 
     126            0 : void WIB::ReadFlash(std::string const & fileName,uint8_t update_percentage){
     127            0 :   bool print_updates = false;
     128            0 :   if(update_percentage < 100){
     129            0 :     print_updates = true;
     130              :   }
     131            0 :   size_t update_delta = (update_percentage * float(16*1024*1024/4))/100;
     132            0 :   size_t next_update = update_delta;
     133              : 
     134            0 :   FILE * outFile = fopen(fileName.c_str(),"w");
     135            0 :   if(outFile == NULL){
     136            0 :     BUException::WIB_BAD_ARGS e;
     137            0 :     e.Append("Failed to create: ");
     138            0 :     e.Append(fileName);
     139            0 :     throw e;
     140            0 :   }
     141              : 
     142            0 :   if(print_updates){
     143            0 :     fprintf(stderr,"   Reading flash\n");
     144            0 :     fprintf(stderr,"   [");
     145            0 :     for(size_t i = 0; i < 100.0/update_percentage;i++){
     146            0 :       fprintf(stderr,"=");
     147              :     }
     148            0 :     fprintf(stderr,"]\n   [");
     149              :   }
     150              :   //program flash in groups of 64 32bit words (256 bytes)
     151            0 :   uint32_t address = 0;
     152              :   
     153            0 :   uint32_t blockRegMapAddress = GetItem("FLASH.DATA00")->address;
     154            0 :   size_t blockSize = 64;
     155              :   //set block size
     156            0 :   WriteWithRetry("FLASH.BYTE_COUNT",255);
     157              : 
     158            0 :   for(size_t iWord = 0; iWord < 16*1024*1024/4;){
     159            0 :     FlashCheckBusy();
     160              : 
     161              :     //Set adddress
     162            0 :     WriteWithRetry("FLASH.ADDRESS",address);
     163              :     //Start read
     164            0 :     WriteWithRetry("FLASH.RUN_COMMAND",0x5);
     165              :     
     166            0 :     FlashCheckBusy();
     167              :     
     168              :     //Readout the data
     169            0 :     for(size_t iWordRead = 0;iWordRead < blockSize;iWordRead++){
     170            0 :       fprintf(outFile,"0x%06X 0x%08X\n",uint32_t(iWord),ReadWithRetry(blockRegMapAddress+iWordRead));
     171            0 :       iWord++;
     172              :     }
     173              : 
     174              :         //    iWord+= blockSize;
     175            0 :     address+=blockSize*4;
     176              :     
     177            0 :     if(print_updates && (iWord > next_update)){
     178              :       //      printf("   % 3f%% done\n",float(iWord)/float(flashData.size()));
     179            0 :       fprintf(stderr,"=");
     180            0 :       next_update += update_delta;
     181              :     }
     182              :   }
     183            0 :   if(print_updates){
     184            0 :     printf("]\n");
     185            0 :     printf("   done\n");
     186              :   }
     187            0 :   fclose(outFile);
     188            0 : }
     189              : 
     190            0 : void WIB::EraseFlash(bool print_updates){
     191            0 :   if(print_updates){
     192            0 :     fprintf(stderr,"   Erase flash\n");
     193              :   }
     194            0 :   WriteWithRetry("FLASH.RUN_COMMAND",0x7);
     195            0 :   size_t iTimeout = FLASH_TIMEOUT;
     196            0 :   while(ReadWithRetry("FLASH.BUSY") && (iTimeout != 0)){
     197            0 :     iTimeout--;
     198            0 :     usleep(100000);
     199              :   }
     200            0 :   if(iTimeout == 0){
     201            0 :     BUException::WIB_FLASH_TIMEOUT e;
     202              :       //throw an exception
     203            0 :       e.Append("Program (erase): FLASH.BUSY");
     204            0 :       throw e;
     205              :     //throw an exception
     206            0 :   }
     207            0 : }
     208              : 
     209            0 : void WIB::ProgramFlash(std::string const & fileName,uint8_t update_percentage){
     210            0 :   WriteWithRetry("SYSTEM.SLOW_CONTROL_DND",1);
     211              : 
     212            0 :   bool print_updates = false;
     213            0 :   if(update_percentage < 100){
     214            0 :     print_updates = true;
     215              :   }
     216              : 
     217              :   //Load data and validate
     218            0 :   if(print_updates){
     219            0 :     fprintf(stderr,"   Reading file: %s\n",fileName.c_str());
     220              :   }
     221              :   //  std::vector<uint32_t> flashData = firmwareFromDumpFile(fileName);
     222            0 :   std::vector<uint32_t> flashData = firmwareFromIntelHexFile(fileName);
     223              : 
     224              :   //erase flash  
     225            0 :   EraseFlash(print_updates);
     226              : 
     227              :   //Load data into flash.
     228            0 :   WriteFlash(flashData,update_percentage);
     229              : 
     230              : 
     231              :   //Validate flash
     232            0 :   CheckFlash(flashData,update_percentage);
     233            0 :   WriteWithRetry("SYSTEM.SLOW_CONTROL_DND",0);
     234            0 : }
     235              : 
     236            0 : void WIB::WriteFlash(std::vector<uint32_t> flashData,uint8_t update_percentage){
     237              :   //Setup display if needed
     238            0 :   bool print_updates = false;
     239            0 :   if(update_percentage < 100){
     240            0 :     print_updates = true;
     241              :   }
     242            0 :   size_t update_delta = (update_percentage * float(flashData.size()))/100;
     243            0 :   size_t next_update = update_delta; 
     244            0 :   if(print_updates){
     245            0 :     fprintf(stderr,"   Programming flash\n");
     246            0 :     fprintf(stderr,"   [");
     247            0 :     for(size_t i = 0; i < 100.0/update_percentage;i++){
     248            0 :       fprintf(stderr,"=");
     249              :     }
     250            0 :     fprintf(stderr,"]\n   [");
     251              :   }
     252              : 
     253              : 
     254              :   //program flash in groups of 64 32bit words (256 bytes)
     255            0 :   uint32_t blockRegMapAddress = GetItem("FLASH.DATA00")->address;  //Address of first of 64 32bit words
     256            0 :   uint32_t flashAddress = 0; //Address in flash that we are writing to.
     257              : 
     258            0 :   for(size_t currentBlockStartIndex = 0; currentBlockStartIndex < flashData.size();){
     259            0 :     FlashCheckBusy();
     260              : 
     261              :     //Find size of this block to write (usually just 64 (256bytes)), but the last one might be smaller.
     262            0 :     size_t blockSize = std::min(size_t(64),flashData.size()-currentBlockStartIndex);
     263              :     //Set adddress
     264            0 :     WriteWithRetry("FLASH.ADDRESS",flashAddress);
     265              :     //set block size (in bytes and is 1 less than value; 0 means 1 byte, 255 means 256 bytes)
     266            0 :     WriteWithRetry("FLASH.BYTE_COUNT",(blockSize*sizeof(uint32_t))-1); 
     267              : 
     268              :     //Write block of data
     269            0 :     for(size_t iBlockWord = 0; iBlockWord < blockSize;iBlockWord++){
     270              :       //arg1: Address in WIB register map of this 32bit word
     271              :       //arg2: Data for this 32bit word reg map address in data vector
     272            0 :       WriteWithRetry(blockRegMapAddress               + iBlockWord,   
     273            0 :                      flashData[currentBlockStartIndex + iBlockWord]); 
     274              :     }
     275              :     //Do the block write
     276            0 :     WriteWithRetry("FLASH.RUN_COMMAND",0x1);
     277            0 :     currentBlockStartIndex += blockSize;
     278            0 :     flashAddress += blockSize*sizeof(uint32_t);
     279              :     
     280              :     //Update the screen if needed
     281            0 :     if(print_updates && (currentBlockStartIndex > next_update)){
     282            0 :       fprintf(stderr,"=");
     283            0 :       next_update += update_delta;
     284              :     }
     285              :   }
     286              :   //Update the screen if needed
     287            0 :   if(print_updates){
     288            0 :     fprintf(stderr,"]\n");
     289            0 :     fprintf(stderr,"   done\n");
     290              :   }
     291              : 
     292            0 : }
     293              : 
     294            0 : void WIB::CheckFlash(std::vector<uint32_t> flashData,uint8_t update_percentage){
     295            0 :   bool print_updates = false;
     296            0 :   if(update_percentage < 100){
     297            0 :     print_updates = true;
     298              :   }
     299            0 :   size_t update_delta = (update_percentage * float(16*1024*1024/4))/100;
     300            0 :   size_t next_update = update_delta;
     301              : 
     302            0 :   if(print_updates){
     303            0 :     fprintf(stderr,"   Checking flash\n");
     304            0 :     fprintf(stderr,"   [");
     305            0 :     for(size_t i = 0; i < 100.0/update_percentage;i++){
     306            0 :       fprintf(stderr,"=");
     307              :     }
     308            0 :     fprintf(stderr,"]\n   [");
     309              :   }
     310              :   //program flash in groups of 64 32bit words (256 bytes)
     311            0 :   uint32_t flashAddress = 0;  
     312            0 :   uint32_t blockRegMapAddress = GetItem("FLASH.DATA00")->address;
     313              : 
     314            0 :   for(size_t currentBlockStartIndex = 0; currentBlockStartIndex < 16*1024*1024/4;){
     315            0 :     FlashCheckBusy();
     316              : 
     317              :     //Find size of this block to write (usually just 64 (256bytes)), but the last one might be smaller.
     318            0 :     size_t blockSize = std::min(size_t(64),flashData.size()-currentBlockStartIndex);
     319              :     //Set adddress
     320            0 :     WriteWithRetry("FLASH.ADDRESS",flashAddress);
     321              :     //set block size (in bytes and is 1 less than value; 0 means 1 byte, 255 means 256 bytes)
     322            0 :     WriteWithRetry("FLASH.BYTE_COUNT",(blockSize*sizeof(uint32_t))-1); 
     323              :     //Start read
     324            0 :     WriteWithRetry("FLASH.RUN_COMMAND",0x5);
     325              : 
     326            0 :     FlashCheckBusy();
     327              : 
     328              :     //Check the data.
     329            0 :     for(size_t iBlockWord = 0;iBlockWord < blockSize;iBlockWord++){
     330              :       //flashData:     Address in WIB register map of this 32bit word
     331              :       //ReadWithRetry: Data from the flash for this word
     332            0 :       uint32_t dataRead;
     333            0 :       if((dataRead = ReadWithRetry(blockRegMapAddress + iBlockWord)) !=
     334            0 :          flashData[currentBlockStartIndex + iBlockWord]){
     335            0 :         BUException::WIB_FLASH_ERROR e; 
     336            0 :         char errorbuffer[] = "Error on index 0xXXXXXXXX: 0xXXXXXXXX != 0xXXXXXXXX";
     337            0 :         snprintf(errorbuffer,
     338              :                  strlen(errorbuffer),
     339              :                  "Error on index 0x%08X: 0x%08X != 0x%08X",
     340              :                  flashAddress,
     341              :                  dataRead,
     342            0 :                  flashData[currentBlockStartIndex + iBlockWord]);
     343            0 :         e.Append(errorbuffer);
     344            0 :         throw e;
     345            0 :       }
     346              :     }
     347            0 :     currentBlockStartIndex += blockSize;
     348            0 :     flashAddress += blockSize*sizeof(uint32_t);
     349              :     
     350            0 :     if(print_updates && (currentBlockStartIndex > next_update)){
     351            0 :       fprintf(stderr,"=");
     352            0 :       next_update += update_delta;
     353              :     }
     354              :   }
     355            0 :   if(print_updates){
     356            0 :     printf("]\n");
     357            0 :     printf("   Check passed\n");
     358              :   }  
     359            0 : }
     360              : 
     361              : 
     362            0 : void WIB::FlashCheckBusy(){
     363            0 :   size_t iTimeout = FLASH_TIMEOUT;
     364            0 :   while(ReadWithRetry("FLASH.BUSY") && (iTimeout != 0)){
     365            0 :     iTimeout--;
     366            0 :     usleep(10000);
     367              :   }
     368            0 :   if(iTimeout == 0){
     369            0 :     BUException::WIB_FLASH_TIMEOUT e;
     370              :     //throw an exception
     371            0 :     e.Append("Read: FLASH.BUSY");
     372            0 :     throw e;
     373            0 :   }
     374            0 : }
        

Generated by: LCOV version 2.0-1