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 }
/// <summary> /// Program the target PIC memory region using the provided hex file /// </summary> /// <param name="hexFile">Hexfile containing data to program</param> /// <param name="memoryRegion">The target memory region to program</param> private void ProgramMemoryRegion(HexFile hexFile, MemoryRegionStruct memoryRegion) { using (var WriteFile = HidDevice.GetWriteFile()) { byte currentByteInAddress = 1; bool skippedBlock = false; // Obtain the data related to the current memory region var regionData = hexFile.GetMemoryRegion(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 { WindowsReserved = 0, Command = PROGRAM_DEVICE, Address = address }; myCommand.Data = new byte[PROGRAM_PACKET_DATA_SIZE]; // 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 <BootloaderCommandStruct>(new BootloaderCommandStruct { WindowsReserved = 0, Command = PROGRAM_COMPLETE }); //since we have now indicated that the programming is complete // then we now mark that we haven't skipped any blocks skippedBlock = false; } // Write the packet data! /*string debug = ""; * foreach (byte b in myCommand.Data) * debug += b.ToString("x2") + " "; * Console.WriteLine(">>> USB OUT Packet >>>\n{0}", debug);*/ SendCommandPacket <ProgramDeviceStruct>(myCommand); } else { // We are skipping the block skippedBlock = true; } }//end while // All data for this region has been programmed SendCommandPacket <BootloaderCommandStruct>(new BootloaderCommandStruct { WindowsReserved = 0, Command = PROGRAM_COMPLETE }); }//end using }