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 % 233 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 9 0

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

Generated by: LCOV version 2.0-1