/// <summary> /// Program the target device with the provided hexfile /// </summary> /// <param name="hexFile">Hexfile containing data to program</param> /// <param name="programConfigs">If true, will attempt to program config words (WARNING: programming invalid config words could brick the device!)</param> public void Program(IntelHexFile hexFile, bool programConfigs = false) { // Program config words first to minimise the risk that the MCU // is reset during programming, thus leaving the MCU in a state // that can't be booted. if (programConfigs) { var configRegions = _memoryRegions.Where(r => r.Type == MemoryRegionType.ConfigBits); // Not all devices provide CONFIG memory regions, as it is usually not desirable to program them anyway. if (!configRegions.Any()) { throw new ArgumentException("Cannot program config words for this device (No CONFIG memory regions)", nameof(hexFile)); } foreach (var memoryRegion in configRegions) { ProgramMemoryRegion(hexFile, memoryRegion); } } // Program everything else (PROGMEM, EEDATA) var dataRegions = _memoryRegions.Where(r => r.Type == MemoryRegionType.Flash); // This shouldn't happen in a properly configured device, but show in case it does to prevent confusion if (!dataRegions.Any()) { throw new ArgumentException("Cannot program memory (No PROGMEM/EEDATA memory regions)", nameof(hexFile)); } _totalFlashSize = dataRegions.Sum(r => r.Size); FlashCount = 0; foreach (var memoryRegion in dataRegions) { ProgramMemoryRegion(hexFile, memoryRegion); } }
public bool Verify(IntelHexFile hex) { return(true); }
private void ProgramMemoryRegion(IntelHexFile hexFile, MemoryRegionStruct memoryRegion) { using (var pipe = HidDevice.Open()) { byte currentByteInAddress = 1; bool skippedBlock = false; // Obtain the data related to the current memory region var regionData = hexFile.MapMemory(memoryRegion.Address, memoryRegion.Size, _bytesPerAddress); int j = 0; // While the current address is less than the end address uint address = memoryRegion.Address; uint endAddress = memoryRegion.Address + memoryRegion.Size; while (address < endAddress) { // Prepare command ProgramDeviceStruct myCommand = new ProgramDeviceStruct { ReportID = 0, Command = BootloaderCommand.Program, Address = address }; myCommand.Data = new byte[ProgramPacketDataSize]; // If a block consists of all 0xFF, then there is no need to write the block // as the erase cycle will have set everything to 0xFF bool skipBlock = true; byte i; for (i = 0; i < _bytesPerPacket; i++) { byte data = regionData[j++]; myCommand.Data[i + (myCommand.Data.Length - _bytesPerPacket)] = data; if (data != 0xFF) { // We can skip a block if all bytes are 0xFF. // Bytes are also ignored if it is byte 4 of a 3 word instruction on PIC24 (bytesPerAddress=2, currentByteInAddress=2, even address) if ((_bytesPerAddress != 2) || ((address % 2) == 0) || (currentByteInAddress != 2)) { // Then we can't skip this block of data skipBlock = false; } } if (currentByteInAddress == _bytesPerAddress) { // If we haven't written enough bytes per address to be at the next address address++; currentByteInAddress = 1; } else { // If we haven't written enough bytes to fill this address currentByteInAddress++; } //If we have reached the end of the memory region, then we // need to pad the data at the end of the packet instead // of the front of the packet so we need to shift the data // to the back of the packet. if (address >= endAddress) { byte n; i++; int len = myCommand.Data.Length; for (n = 0; n < len; n++) { if (n < i) { // Move it from where it is to the back of the packet, thus shifting all of the data down. myCommand.Data[len - n - 1] = myCommand.Data[i + (len - _bytesPerPacket) - n - 1]; } else { myCommand.Data[len - n - 1] = 0x00; } } // Break out of the for loop now that all the data has been padded out. break; } } //end for // Use the counter to determine how many bytes were written myCommand.BytesPerPacket = i; //If the block was all 0xFF then we can just skip actually programming // this device. Otherwise enter the programming sequence if (!skipBlock) { //If we skipped one block before this block then we may need // to send a proramming complete command to the device before // sending the data for this command. if (skippedBlock) { SendCommandPacket(pipe, new BootloaderCommandStruct { ReportID = 0, Command = BootloaderCommand.ProgramComplete }); //since we have now indicated that the programming is complete // then we now mark that we haven't skipped any blocks skippedBlock = false; } SendCommandPacket(pipe, myCommand); FlashCount += ProgramPacketDataSize; } else { // We are skipping the block skippedBlock = true; FlashCount += ProgramPacketDataSize; } } //end while // All data for this region has been programmed SendCommandPacket(pipe, new BootloaderCommandStruct { ReportID = 0, Command = BootloaderCommand.ProgramComplete }); ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(0, null)); } //end using }