Ejemplo n.º 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 override void Program(HexFile 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.CONFIG);

                // Not all devices provide CONFIG memory regions, as it is usually not desirable to program them anyway.
                if (configRegions.Count() == 0)
                {
                    throw new BootloaderException("Cannot program config words for this device (No CONFIG memory regions)");
                }

                foreach (var memoryRegion in configRegions)
                {
                    ProgramMemoryRegion(hexFile, memoryRegion);
                }
            }

            // Program everything else (PROGMEM, EEDATA)
            var dataRegions = memoryRegions.Where(r => r.Type != MemoryRegionType.CONFIG);

            // This shouldn't happen in a properly configured device, but show in case it does to prevent confusion
            if (dataRegions.Count() == 0)
            {
                throw new BootloaderException("Cannot program memory (No PROGMEM/EEDATA memory regions)");
            }

            foreach (var memoryRegion in dataRegions)
            {
                ProgramMemoryRegion(hexFile, memoryRegion);
            }
        }
Ejemplo n.º 2
0
        static void Main(string[] argv)
        {
            try
            {
                Args args = new Args();
                args.protocol = ProtocolType.HID;
                args.hexfile  = null;


                #region Command Line Arguments

                var p_main = new OptionSet()
                {
                    //{ "v|verbose", v => args.verbose = (v != null) },
                    //{ "d|debug", "Show debug information", v => args.debug = (v != null)},
                    { "h|help", v => args.showhelp = (v != null) },

                    { "n|no-verify", "Don't verify on program", v => args.noVerify = (v != null) },
                    { "c|program-configs", "Program configuration bits", v => args.programConfigs = (v != null) },
                    { "r|reset", "Reset device on completion", v => args.autoReset = (v != null) },

                    // Protocol selection

                    /*{ "auto", "Automatically scan for devices (default)", v=> {if (v!=null) args.protocol = ProtocolType.Auto;}},
                     * { "hid", "Use USB HID bootloader", v=> {if (v!=null) args.protocol = ProtocolType.HID;}},
                     * { "tcp", "Use TCP network bootloader", v=> {if (v!=null) args.protocol = ProtocolType.TCP;}},
                     * { "udp", "Use UDP network bootlaoder", v=> {if (v!=null) args.protocol = ProtocolType.UDP;}},
                     * { "serial", "Use Serial bootloader", v=> {if (v!=null) args.protocol = ProtocolType.Serial;}},*/
                };

                var p_hid = new OptionSet()
                {
                    //{ "default", v=>{}},
                    { "device=", "Optional VID/PID of the USB Device\neg. VID_04D8&PID_003C (default value)", v => args.hid.deviceId = v },
                };

                /*var p_network = new OptionSet() {
                 *  { "addr=", "IP Address", v => args.network.address = v },
                 *  { "port=", "Port", (int v) => args.network.port = v },
                 * };
                 * var p_serial = new OptionSet() {
                 *  { "port=", "COM Port", v => args.serial.port = v},
                 *  { "baud=", "Baud Rate", (int v) => args.serial.baud = v},
                 *  // TODO: could add an option for multiple serial protocols?
                 * };*/

                #endregion

                List <string> subargs = p_main.Parse(argv);
                List <string> extra   = subargs;

                #region Console Help

                if (args.showhelp) // --help
                {
                    ShowHelp(p_main, p_hid);
                    return;
                }

                #endregion

                #region Auto Protocol Scan

                // Try and search for devices automatically.
                // Order of search is: USB-HID, Serial, TCP, UDP
                // USB-HID uses the default DeviceID,
                // Serial uses common baud rates on all connected COM ports,
                // TCP/UDP looks for a broadcast from the device.
                if (args.protocol == ProtocolType.Auto)
                {
                    args.protocol = AutoProtocolScan();
                }

                #endregion

                #region Protocol Specific Argument Parsing

                // Parse protocol specific arguments for the specified protocol.
                // Does not apply for automatic scan, as parameters are determined automatically.
                // Also performs some basic verification of the parameters before doing anything with them.
                switch (args.protocol)
                {
                case ProtocolType.HID:
                    extra = p_hid.Parse(subargs);

                    // Validate Device ID format
                    if (args.hid.deviceId != null)
                    {
                        if (!Regex.Match(args.hid.deviceId, @"vid_[0-9a-f]{4}&pid_[0-9a-f]{4}", RegexOptions.IgnoreCase).Success)
                        {
                            throw new OptionException(String.Format("Invalid USB-HID Device ID '{0}'", args.hid.deviceId), "device");
                        }
                    }
                    break;

                case ProtocolType.TCP:
                case ProtocolType.UDP:
                    throw new NotImplementedException("TCP/UDP Bootloader is not implemented yet");
                    //extra = p_network.Parse(subargs);

                    //TODO: validate IP address/port if specified
                    break;

                case ProtocolType.Serial:
                    throw new NotImplementedException("Serial Bootloader is not implemented yet");
                    //extra = p_serial.Parse(subargs);

                    //TODO: validate COM port and baud rate if specified
                    //TODO: allow an auto com port?
                    break;
                }

                #endregion

                #region Un-named Argument Parsing

                // There are two un-named arguments, the first is the action to perform,
                // the second is a filename for the hex file to use (required for program/verify/read actions)

                // Must contain at least one extra parameter (action)
                if (extra.Count < 1)
                {
                    throw new OptionException("Must specify an action", "action");
                }
                args.action = (ProgrammerAction)Enum.Parse(typeof(ProgrammerAction), extra[0], true);

                // May contain a hexfile parameter (required for certain actions)
                if (args.action == ProgrammerAction.Program || args.action == ProgrammerAction.Read || args.action == ProgrammerAction.Verify)
                {
                    if (extra.Count < 2)
                    {
                        throw new OptionException("Must specify a hex file for this action", "hexfile");
                    }
                    args.hexfile = extra[1];
                }

                #endregion


                // Obtain a bootloader object for the given protocol, using polymorphism
                Bootloader bootloader = GetBootloaderObject(args);

                // Make sure the device is responding, and query it for device parameters
                bootloader.Query();
                Console.WriteLine("Found device");

                #region Action Execution

                // Run the specified action
                switch (args.action)
                {
                case ProgrammerAction.Scan:
                    // Do nothing, as we need to scan for the device anyway.
                    //TODO: Show address/port/baud/etc. if auto-scanning
                    break;

                case ProgrammerAction.Erase:
                    Console.WriteLine("Erasing program memory");
                    bootloader.Erase();
                    break;

                case ProgrammerAction.Read:
                {
                    Console.WriteLine("Reading program memory");
                    HexFile hexfile = bootloader.Read();
                    Console.WriteLine("Saved to '{0}'", args.hexfile);
                    //TODO: save hexfile
                }
                break;

                case ProgrammerAction.Program:
                {
                    HexFile hexfile = new HexFile(args.hexfile);
                    Console.WriteLine("Loaded HEX File '{0}' ({1} bytes)", args.hexfile, hexfile.Size);

                    if (hexfile.Size == 0)
                    {
                        throw new BootloaderException("Hex file is empty");
                    }

                    // Erase the device before programming (required)
                    Console.WriteLine("Erasing");
                    bootloader.Erase();

                    // Program the program memory, and optionally the config bits
                    Console.WriteLine("Programming");
                    bootloader.Program(hexfile, args.programConfigs);

                    // Optionally verify it was programmed correctly
                    if (!args.noVerify)
                    {
                        Console.WriteLine("Verifying");
                        bootloader.Verify(hexfile);
                    }
                    Console.WriteLine("Signing");
                    bootloader.SignFlash();
                }
                break;

                case ProgrammerAction.Verify:
                {
                    HexFile hexfile = new HexFile(args.hexfile);
                    Console.WriteLine("Verifying against '{0}'", args.hexfile);
                    bootloader.Verify(hexfile);
                }
                break;

                case ProgrammerAction.Reset:
                    Console.WriteLine("Resetting device");
                    bootloader.Reset();
                    break;

                case ProgrammerAction.Run:
                    Console.WriteLine("Running");
                    bootloader.Reset();     // TODO: implement
                    break;
                }

                // Reset after completing command
                if (args.autoReset && args.action != ProgrammerAction.Reset && args.action != ProgrammerAction.Run)
                {
                    Console.WriteLine("Resetting device");
                    bootloader.Reset();
                }

                #endregion

                //Console.WriteLine("Done.");
            }
#if !DEBUG
            /*catch (HidDeviceException e)
             * {
             *  Console.Error.WriteLine("HID Error: {0}", e.Message);
             * }*/
            catch (BootloaderException e)
            {
                Console.Error.WriteLine("Error: {0}", e.Message);
            }
            catch (OptionException e)
            {
                Console.Error.WriteLine("{0}", e.Message);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine();
                Console.Error.WriteLine(e);
                Console.Error.WriteLine();
            }
#endif
            finally
            {
#if DEBUG
                // Pause the console so we can see the output
                Console.ReadKey();
#endif
            }
        }
Ejemplo n.º 3
0
 public abstract void Program(HexFile hex, bool programConfigs = false);
Ejemplo n.º 4
0
 public abstract void Verify(HexFile hex);
Ejemplo n.º 5
0
        /// <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
        }
Ejemplo n.º 6
0
 public override void Verify(HexFile hex)
 {
     //throw new BootloaderException("Invalid byte at 0x{0:x}", 0);
 }
Ejemplo n.º 7
0
        static void Main(string[] argv)
        {
            try
            {
                Args args = new Args();
                args.protocol = ProtocolType.HID;
                args.hexfile = null;

                #region Command Line Arguments

                var p_main = new OptionSet() {
                    //{ "v|verbose", v => args.verbose = (v != null) },
                    //{ "d|debug", "Show debug information", v => args.debug = (v != null)},
                    { "h|help", v => args.showhelp = (v != null) },

                    { "n|no-verify", "Don't verify on program", v => args.noVerify = (v != null)},
                    { "c|program-configs", "Program configuration bits", v => args.programConfigs = (v != null)},
                    { "r|reset", "Reset device on completion", v => args.autoReset = (v != null)},

                    // Protocol selection
                    /*{ "auto", "Automatically scan for devices (default)", v=> {if (v!=null) args.protocol = ProtocolType.Auto;}},
                    { "hid", "Use USB HID bootloader", v=> {if (v!=null) args.protocol = ProtocolType.HID;}},
                    { "tcp", "Use TCP network bootloader", v=> {if (v!=null) args.protocol = ProtocolType.TCP;}},
                    { "udp", "Use UDP network bootlaoder", v=> {if (v!=null) args.protocol = ProtocolType.UDP;}},
                    { "serial", "Use Serial bootloader", v=> {if (v!=null) args.protocol = ProtocolType.Serial;}},*/
                };

                var p_hid = new OptionSet()
                {
                    //{ "default", v=>{}},
                    { "device=", "Optional VID/PID of the USB Device\neg. VID_04D8&PID_003C (default value)", v => args.hid.deviceId = v},
                };
                /*var p_network = new OptionSet() {
                    { "addr=", "IP Address", v => args.network.address = v },
                    { "port=", "Port", (int v) => args.network.port = v },
                };
                var p_serial = new OptionSet() {
                    { "port=", "COM Port", v => args.serial.port = v},
                    { "baud=", "Baud Rate", (int v) => args.serial.baud = v},
                    // TODO: could add an option for multiple serial protocols?
                };*/

                #endregion

                List<string> subargs = p_main.Parse(argv);
                List<string> extra = subargs;

                #region Console Help

                if (args.showhelp) // --help
                {
                    ShowHelp(p_main, p_hid);
                    return;
                }

                #endregion

                #region Auto Protocol Scan

                // Try and search for devices automatically.
                // Order of search is: USB-HID, Serial, TCP, UDP
                // USB-HID uses the default DeviceID,
                // Serial uses common baud rates on all connected COM ports,
                // TCP/UDP looks for a broadcast from the device.
                if (args.protocol == ProtocolType.Auto)
                {
                    args.protocol = AutoProtocolScan();
                }

                #endregion

                #region Protocol Specific Argument Parsing

                // Parse protocol specific arguments for the specified protocol.
                // Does not apply for automatic scan, as parameters are determined automatically.
                // Also performs some basic verification of the parameters before doing anything with them.
                switch (args.protocol)
                {
                    case ProtocolType.HID:
                        extra = p_hid.Parse(subargs);

                        // Validate Device ID format
                        if (args.hid.deviceId != null)
                        {
                            if (!Regex.Match(args.hid.deviceId, @"vid_[0-9a-f]{4}&pid_[0-9a-f]{4}", RegexOptions.IgnoreCase).Success)
                                throw new OptionException(String.Format("Invalid USB-HID Device ID '{0}'", args.hid.deviceId), "device");
                        }
                        break;

                    case ProtocolType.TCP:
                    case ProtocolType.UDP:
                        throw new NotImplementedException("TCP/UDP Bootloader is not implemented yet");
                        //extra = p_network.Parse(subargs);

                        //TODO: validate IP address/port if specified
                        break;

                    case ProtocolType.Serial:
                        throw new NotImplementedException("Serial Bootloader is not implemented yet");
                        //extra = p_serial.Parse(subargs);

                        //TODO: validate COM port and baud rate if specified
                        //TODO: allow an auto com port?
                        break;
                }

                #endregion

                #region Un-named Argument Parsing

                // There are two un-named arguments, the first is the action to perform,
                // the second is a filename for the hex file to use (required for program/verify/read actions)

                // Must contain at least one extra parameter (action)
                if (extra.Count < 1)
                    throw new OptionException("Must specify an action", "action");
                args.action = (ProgrammerAction)Enum.Parse(typeof(ProgrammerAction), extra[0], true);

                // May contain a hexfile parameter (required for certain actions)
                if (args.action == ProgrammerAction.Program || args.action == ProgrammerAction.Read || args.action == ProgrammerAction.Verify)
                {
                    if (extra.Count < 2)
                        throw new OptionException("Must specify a hex file for this action", "hexfile");
                    args.hexfile = extra[1];
                }

                #endregion

                // Obtain a bootloader object for the given protocol, using polymorphism
                Bootloader bootloader = GetBootloaderObject(args);

                // Make sure the device is responding, and query it for device parameters
                bootloader.Query();
                Console.WriteLine("Found device");

                #region Action Execution

                // Run the specified action
                switch (args.action)
                {
                    case ProgrammerAction.Scan:
                        // Do nothing, as we need to scan for the device anyway.
                        //TODO: Show address/port/baud/etc. if auto-scanning
                        break;

                    case ProgrammerAction.Erase:
                        Console.WriteLine("Erasing program memory");
                        bootloader.Erase();
                        break;

                    case ProgrammerAction.Read:
                        {
                            Console.WriteLine("Reading program memory");
                            HexFile hexfile = bootloader.Read();
                            Console.WriteLine("Saved to '{0}'", args.hexfile);
                            //TODO: save hexfile
                        }
                        break;

                    case ProgrammerAction.Program:
                        {
                            HexFile hexfile = new HexFile(args.hexfile);
                            Console.WriteLine("Loaded HEX File '{0}' ({1} bytes)", args.hexfile, hexfile.Size);

                            if (hexfile.Size == 0)
                                throw new BootloaderException("Hex file is empty");

                            // Erase the device before programming (required)
                            Console.WriteLine("Erasing");
                            bootloader.Erase();

                            // Program the program memory, and optionally the config bits
                            Console.WriteLine("Programming");
                            bootloader.Program(hexfile, args.programConfigs);

                            // Optionally verify it was programmed correctly
                            if (!args.noVerify)
                            {
                                Console.WriteLine("Verifying");
                                bootloader.Verify(hexfile);
                            }
                        }
                        break;

                    case ProgrammerAction.Verify:
                        {
                            HexFile hexfile = new HexFile(args.hexfile);
                            Console.WriteLine("Verifying against '{0}'", args.hexfile);
                            bootloader.Verify(hexfile);
                        }
                        break;

                    case ProgrammerAction.Reset:
                        Console.WriteLine("Resetting device");
                        bootloader.Reset();
                        break;

                    case ProgrammerAction.Run:
                        Console.WriteLine("Running");
                        bootloader.Reset(); // TODO: implement
                        break;
                }

                // Reset after completing command
                if (args.autoReset && args.action != ProgrammerAction.Reset && args.action != ProgrammerAction.Run)
                {
                    Console.WriteLine("Resetting device");
                    bootloader.Reset();
                }

                #endregion

                //Console.WriteLine("Done.");

            }
            #if !DEBUG
            /*catch (HidDeviceException e)
            {
                Console.Error.WriteLine("HID Error: {0}", e.Message);
            }*/
            catch (BootloaderException e)
            {
                Console.Error.WriteLine("Error: {0}", e.Message);
            }
            catch (OptionException e)
            {
                Console.Error.WriteLine("{0}", e.Message);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine();
                Console.Error.WriteLine(e);
                Console.Error.WriteLine();
            }
            #endif
            finally
            {
            #if DEBUG
                // Pause the console so we can see the output
                Console.ReadKey();
            #endif
            }
        }
Ejemplo n.º 8
0
 public abstract void Verify(HexFile hex);
Ejemplo n.º 9
0
 public abstract void Program(HexFile hex, bool programConfigs = false);