예제 #1
0
        /// <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);
            }
        }
예제 #2
0
 public bool Verify(IntelHexFile hex)
 {
     return(true);
 }
예제 #3
0
        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
        }