generate method

String generate({
  1. String arch = 'NRF52',
  2. String? appFile,
  3. int? appVersion,
  4. int blVersion = 0,
  5. int blSettVersion = 0,
  6. int? customBootSettAddr,
  7. bool noBackup = true,
  8. int? backupAddress,
  9. ValidationType appValType = ValidationType.noValidation,
  10. ValidationType sdValType = ValidationType.noValidation,
  11. String? sdFile,
  12. Signing? signer,
})

Generate settings file from the provided data

Implementation

String generate({
  String arch = 'NRF52',
  String? appFile,
  int? appVersion,
  int blVersion = 0,
  int blSettVersion = 0,
  int? customBootSettAddr,
  bool noBackup = true,
  int? backupAddress,
  ValidationType appValType = ValidationType.noValidation,
  ValidationType sdValType = ValidationType.noValidation,
  String? sdFile,
  Signing? signer
}){
  logger?.verbose('Generating Settings');
  setArch(arch);
  late BLDFUSettingsStructV1 setts;
  late Uint8List appBootValidationBytes;

  if( customBootSettAddr != null){
    logger?.verbose('Setting custom boot address');
    blSettAddr = customBootSettAddr;
  }

  if (blSettVersion == 1){
    setts = BLDFUSettingsStructV1(blSettAddr,true);
  }
  else if(blSettVersion == 2){
    setts = BLDFUSettingsStructV2(blSettAddr);
  }
  else{
    throw("Unknown bootloader settings version");
  }

  logger?.verbose('Convertying bootloader version');
  blSettVersion = blSettVersion & 0xffffffff;
  blVersion = blVersion & 0xffffffff;

  logger?.verbose('Convertying application version');
  if (appVersion != null){
    appVersion = appVersion & 0xffffffff;
  }
  else{
    appVersion = 0x0 & 0xffffffff;
  }
  late int appValTypeInt;
  if (appFile != null){
    logger?.verbose('Generating application file perameters');
    //load application to find out size and CRC
    Uint8List appBin = NRFPackage.normalizeFirmware(appFile);

    //calculate application size and CRC32
    appSize = NRFPackage.calculateFileSize(appBin) & 0xffffffff;
    appCrc = NRFPackage.calculateCRC(CRCType.crc32, appBin) & 0xffffffff;
    bankCode = 0x1 & 0xffffffff;

    //Calculate Boot validation fields for app
    if (appValType == ValidationType.validateCrc){
      appValTypeInt = 1 & 0xffffffff;
      appBootValidationBytes = Struct.pack('<I', appCrc);
    }
    else if (appValType == ValidationType.validateSHA256){
      appValTypeInt = 2 & 0xffffffff;
      // Package.calculate_sha256_hash gives a reversed
      // digest. It need to be reversed back to a normal
      // sha256 digest.
      appBootValidationBytes = Uint8List.fromList(NRFPackage.calculateSHA256(appBin,FwType.application).reversed.toList());
    }
    else if (appValType == ValidationType.validateP256 && signer != null){
      appValTypeInt = 3 & 0xffffffff;
      appBootValidationBytes = NRFPackage.signFirmware(signer, appBin);
    }
    else{  //This also covers 'NO_VALIDATION' case
      appValTypeInt = 0 & 0xffffffff;
      appBootValidationBytes = Uint8List(0);
    }
  }
  else{
    logger?.verbose('No application file found');
    appSize = 0x0 & 0xffffffff;
    appCrc = 0x0 & 0xffffffff;
    bankCode = 0x0 & 0xffffffff;
    appValTypeInt = 0x0 & 0xffffffff;
    appBootValidationBytes = Uint8List(0);
  }

  late Uint8List sdBootValidationBytes;
  late int sdValTypeInt;
  if (sdFile != null){
    logger?.verbose('Generating softdevice file perameters');
    // Load SD to calculate CRC
    // Load SD hex file and remove MBR before calculating keys
    IntelHex ihSD = IntelHex.decodeRecord(sdFile);
    IntelHex ihSdNoMbr = IntelHex();
    ihSdNoMbr.merge(ihSD..setSubList(0x1000), Overlap.error);
    //ihSdNoMbr.write_hexFile(temp_sdFile);

    Uint8List sdBin = ihSdNoMbr.toBinArray();
    sdSize = NRFPackage.calculateFileSize(sdBin) & 0xffffffff;

    // Calculate Boot validation fields for SD
    if (sdValType == ValidationType.validateCrc){
      sdValTypeInt = 1 & 0xffffffff;
      int sdCrc = NRFPackage.calculateCRC(CRCType.crc32, sdBin) & 0xffffffff;
      sdBootValidationBytes = Struct.pack('<I', sdCrc);
    }
    else if (sdValType == ValidationType.validateSHA256){
      sdValTypeInt = 2 & 0xffffffff;
      // Package.calculate_sha256_hash gives a reversed
      // digest. It need to be reversed back to a normal
      // sha256 digest.
      sdBootValidationBytes = Uint8List.fromList(NRFPackage.calculateSHA256(sdBin,FwType.softdevice).reversed.toList());
    }
    else if (sdValType == ValidationType.validateP256 && signer != null){
      sdValTypeInt = 3 & 0xffffffff;
      sdBootValidationBytes = NRFPackage.signFirmware(signer, sdBin);
    }
    else{  // This also covers 'NO_VALIDATION_CASE'
      sdValTypeInt = 0 & 0xffffffff;
      sdBootValidationBytes = Uint8List(0);
    }
  }
  else{
    logger?.verbose('No softdevice file found');
    sdSize = 0x0 & 0xffffffff;
    sdValTypeInt = 0 & 0xffffffff;
    sdBootValidationBytes = Uint8List(0);
  }

  // additional hardcoded values
  bankLayout = 0x0 & 0xffffffff;
  bankCurrent = 0x0 & 0xffffffff;

  // Fill the entire settings page with 0's
  for(int offset = 0; offset < setts.bytesCount;offset++){ //offset in range(0, setts.bytesCount){
    ihex[blSettAddr + offset] = 0x00;
  }

  // Make sure the hex-file is 32bit-word-aligned
  int fillBytes = ((setts.bytesCount + 4 - 1) & ~(4 - 1)) - setts.bytesCount;
  for(int offset = setts.bytesCount; offset < setts.bytesCount + fillBytes; offset++){
    ihex[blSettAddr + offset] = 0xFF;
  }

  _addValueToHex(setts.settingsVersion, blSettVersion);
  _addValueToHex(setts.appVersion, appVersion);
  _addValueToHex(setts.blVersion, blVersion);
  _addValueToHex(setts.bankLayout, bankLayout);
  _addValueToHex(setts.bankCurrent, bankCurrent);
  _addValueToHex(setts.bankImgSize, appSize);
  _addValueToHex(setts.bankImgCrc, appCrc);
  _addValueToHex(setts.bankCode, bankCode);
  _addValueToHex(setts.sdSize, sdSize);

  bootValidationCrc = 0x0 & 0xffffffff;
  if (blSettVersion == 2){
    setts as BLDFUSettingsStructV2;
    _addValueToHex(setts.sdValidationType, sdValTypeInt, '<b');
    ihex.puts(setts.sdValidationBytes, sdBootValidationBytes);

    _addValueToHex(setts.appValidationType, appValTypeInt, '<b');
    ihex.puts(setts.appValidationBytes, appBootValidationBytes);

    bootValidationCrc = calculateCRC32FromHex(ihex,setts.sdValidationType,setts.lastAddress) & 0xffffffff;
    _addValueToHex(setts.bootValidationCrc, bootValidationCrc);
  }

  crc = calculateCRC32FromHex(ihex,blSettAddr+4,setts.initCmd - 1) & 0xffffffff;
  _addValueToHex(setts.crc, crc);

  if(backupAddress == null){
    backupAddress = blSettAddr - blSettBackupOffset;
  }
  else{
    logger?.verbose('Converting custom backup address');
    backupAddress = backupAddress;
  }

  if(!noBackup){
    logger?.verbose('Setting backup');
    for (int offset = 0; offset < setts.bytesCount;offset++){ //offset in range(0, setts.bytesCount):
      ihex[backupAddress + offset] = ihex[blSettAddr + offset];
    }
    for (int offset = setts.bytesCount; offset < setts.bytesCount + fillBytes; offset++){ //offset in range(setts.bytesCount, setts.bytesCount + fillBytes):
      ihex[backupAddress + offset] = 0xFF;
    }
  }

  logger?.verbose('Coverting data to Hex String');
  return ihex.bufferToHex();
}