Пример #1
0
        static int Main(string[] args)
        {
            /* install global Exception handler
             * Won't do much more than pretify'ing the error messages but better
             * fail gracefully that terribly
             */
            System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;

            bool errors_encountered = false;

            CommandLineParser cmd_parser = new CommandLineParser();

            if (cmd_parser.parse_command_line(args) == false)
            {
                return(RETURN_INVALID_CMDLINE);
            }

            /****** SEED EROS Bdrige mode enable/disable requests */
            if (cmd_parser.bootloader_operations.Contains(CommandLineParser.en_bootloader_operations.SEEDEROS_BRIDGEENABLE))
            {
                return(EROS_EnableBridgeMode(ref cmd_parser));
            }

            if (cmd_parser.bootloader_operations.Contains(CommandLineParser.en_bootloader_operations.SEEDEROS_BRIDGEDISABLE))
            {
                return(EROS_DisableBridgeMode(ref cmd_parser));
            }

            /****** Emergency Erase Request
             *  Emergency Erase restores bootloader access in case of lost password, by wiping
             *  the full FLASH and EEPROM memory areas
             */
            if (cmd_parser.bootloader_operations.Contains(CommandLineParser.en_bootloader_operations.EMERGENCY_ERASE))
            {
                enEmergencyEraseConfirmResult eresult = ConfirmEmergencyErase(ref cmd_parser);

                if (eresult == enEmergencyEraseConfirmResult.ER_CONFIRMED)
                {
                    TSBInterfacing tsb = new TSBInterfacing(UpdateStatusOnScreen, AskQuestion_ToUser);
                    if (!tsb.EmergencyErase(cmd_parser.port_name, cmd_parser.baudrate_bps, cmd_parser.prewait_ms, cmd_parser.replytimeout_ms))
                    {
                        Console.WriteLine();
                        Console.WriteLine("> Error while performing Emergency Erase operation.");
                        return(RETURN_ERRORS_ENCOUNTERED);
                    }
                    else
                    {
                        return(0);
                    }
                }
                else if (eresult == enEmergencyEraseConfirmResult.ER_ERROR)
                {
                    return(RETURN_ERRORS_ENCOUNTERED);
                }
                else
                {
                    return(0);
                }
            }


            /********** Main cycle for multi-device bootloader operations
             *  We will cycle through the list of passwords supplied
             *  (or use empty password if none supplied)
             *
             *  On every iteration we will run the same operations but we will collect user
             *  options on each iteration (bc user may want different options for each
             *  device)
             */

            if (cmd_parser.bootloader_passwords.Count() == 0)
            {
                /* add a bogus entry with an empty password. Assuming user intends to start the session
                 * with no password. */
                cmd_parser.bootloader_passwords.Add("");
            }

            /* only advance to TSB if we have more commands lined up and requested at the command line */
            if (cmd_parser.bootloader_operations.Count == 0)
            {
                Console.WriteLine();
                Console.WriteLine("> No bootloader actions specified. Ending session");
                return(0);
            }


            foreach (string pwd in cmd_parser.bootloader_passwords)
            {
                TSBInterfacing tsb = new TSBInterfacing(UpdateStatusOnScreen, AskQuestion_ToUser);
                bool           activation_result = false;

                /* from TSB versions of 2020 onwards, we now have an operation timeout
                 *     which means the commands must get their complete input in a limited timespan
                 *
                 *    This means that, for setting password, timeout and/or magic bytes
                 *    we should ask the user for them beforehand so that they'r ready to go
                 *    If we wait for the user input while the sesison is active, the session
                 *    will likely timeout.
                 */
                TSBInterfacing.str_tsb_session_data new_user_data = default(TSBInterfacing.str_tsb_session_data);
                new_user_data.magic_bytes = new byte[2]; // we need to explicit allocate space for this

                if (pwd.Length > 0)
                {
                    if (cmd_parser.activation_mode == CommandLineParser.en_bootloader_activation_mode.COLD_BOOT)
                    {
                        Console.WriteLine();
                        Console.WriteLine("> Preparing to activate bootloader for device with password: {0}", pwd);
                        CollectUserOptions_AndUpdateCachedSessionData(ref cmd_parser, ref new_user_data);

                        activation_result = tsb.ActivateBootloaderFromColdStart(cmd_parser.port_name, cmd_parser.baudrate_bps, cmd_parser.prewait_ms, cmd_parser.replytimeout_ms, pwd, cmd_parser.verbose_output);
                    }
                    else
                    {
                        Console.WriteLine("ERROR: Bootloader passwords can only be specified when activating in 'cold' [boot] mode.");
                        return(RETURN_ERRORS_ENCOUNTERED);
                    }
                }
                else if (cmd_parser.activation_mode == CommandLineParser.en_bootloader_activation_mode.COLD_BOOT)
                {
                    Console.WriteLine();
                    Console.WriteLine("> Preparing to activate bootloader (no device password specified)");
                    CollectUserOptions_AndUpdateCachedSessionData(ref cmd_parser, ref new_user_data);

                    activation_result = tsb.ActivateBootloaderFromColdStart(cmd_parser.port_name, cmd_parser.baudrate_bps, cmd_parser.prewait_ms, cmd_parser.replytimeout_ms, pwd, cmd_parser.verbose_output);
                }
                else if (cmd_parser.activation_mode == CommandLineParser.en_bootloader_activation_mode.LIVE_VIA_DYNAMIXEL)
                {
                    if (cmd_parser.dynid < 0 || cmd_parser.dynid > 253)
                    {
                        Console.WriteLine("ERROR: 'live' bootloader activation mode was selected but the '-dynid' parameter was not given or is invalid. Please set a valid '-dynid' for 'live' activation mode.");
                        return(RETURN_ERRORS_ENCOUNTERED);
                    }

                    Console.WriteLine();
                    Console.WriteLine("> Preparing to activate bootloader 'live', on device with DynID {0}", cmd_parser.dynid);
                    CollectUserOptions_AndUpdateCachedSessionData(ref cmd_parser, ref new_user_data);

                    // baud after activation should not be hard coded as we may need to speak at higher bauds if going through the EROS board.
                    // timeout for bootloader activation must exceed the time set in the servo firmware.
                    activation_result = tsb.ActivateBootloaderFromDynamixel(cmd_parser.port_name, cmd_parser.baudrate_bps, 9600, (byte)cmd_parser.dynid, 3500, 6000, TSBInterfacing.en_dyn_protocol_version.DYNAMIXEL_1, cmd_parser.verbose_output);
                }

                if (activation_result == true)
                {
                    /* Bootloader is active. Print all bootloader information */
                    PrintDeviceInfo(tsb);

                    /*  check if the user asked to tag the file names.
                     *  This MUST be done here for the cases where we use multiple
                     *  passwords; in that case, we have sessins starting at different times
                     *  (initiated here) and also different passwords
                     */
                    string tag = string.Format("_{0:yyMMdd}_{0:HHmmss}", DateTime.Now);
                    if (pwd.Length > 0)
                    {
                        tag += string.Format("_{0}", pwd);
                    }

                    string eep_filename   = cmd_parser.eeprom_file_name;
                    string flash_filename = cmd_parser.flash_file_name;

                    if (cmd_parser.tag_eepromfilename_withdatetimepwd && !string.IsNullOrEmpty(cmd_parser.eeprom_file_name))
                    {
                        eep_filename = AddTagToFilename(cmd_parser.eeprom_file_name, tag);
                    }

                    if (cmd_parser.tag_flashfilename_withdatetimepwd && !string.IsNullOrEmpty(cmd_parser.flash_file_name))
                    {
                        flash_filename = AddTagToFilename(cmd_parser.flash_file_name, tag);
                    }


                    bool request_last_page_write = false;
                    /* loop through the various operations requested */
                    foreach (CommandLineParser.en_bootloader_operations bootloader_op in cmd_parser.bootloader_operations)
                    {
                        switch (bootloader_op)
                        {
                        case CommandLineParser.en_bootloader_operations.DISPLAY_DEVICE_INFO:
                            /* do nothing; when we activated TSB it already displayed the device info */
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_ERASE:
                            if (!tsb.EEProm_Erase())
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Erasing EEProm.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_WRITE:
                            if (!tsb.EEProm_Write(eep_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Writing EEPROM.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_VERIFY:
                            if (!tsb.EEProm_Verify(eep_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Verifying EEPROM.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_READ:
                            if (!tsb.EEProm_Read(eep_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Reading EEPROM.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_ERASE:
                            if (!tsb.Flash_Erase())
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Erasing Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_WRITE:
                            if (!tsb.Flash_Write(flash_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Writing Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_VERIFY:
                            if (!tsb.Flash_Verify(flash_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Verifying Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_READ:
                            if (!tsb.Flash_Read(flash_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Reading Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.PASSWORD_CHANGE:
                            tsb.session_data_.password = new_user_data.password;
                            request_last_page_write    = true;
                            break;

                        case CommandLineParser.en_bootloader_operations.TIMEOUT_CHANGE:
                            tsb.session_data_.timeout = new_user_data.timeout;
                            request_last_page_write   = true;
                            break;


                        case CommandLineParser.en_bootloader_operations.WRITE_MAGIC_BYTES:
                            tsb.session_data_.magic_bytes[0] = new_user_data.magic_bytes[0];
                            tsb.session_data_.magic_bytes[1] = new_user_data.magic_bytes[1];
                            request_last_page_write          = true;
                            break;

                        case CommandLineParser.en_bootloader_operations.PATCH_DAISY_CHAIN_BUG:
                            request_last_page_write = true;     // a simple last page write, applies the patch
                            break;

                        default:
                            Console.WriteLine("ERROR: Unknown Bootloader operation in function main()");
                            return(RETURN_UNKOWN_OPTION_IN_CASE);
                        }
                    }

                    // check if there are updated settings in last page, and commit them
                    if (request_last_page_write)
                    {
                        if (!tsb.LastPage_Write())
                        {
                            Console.WriteLine();
                            Console.WriteLine("> Error updating bootloader configuration data.");
                            Console.WriteLine("> (Daisy chain patch, Timeout, password and/or Magic bytes might not have been updated)");
                            errors_encountered = true;
                        }
                        request_last_page_write = false;
                    }

                    tsb.DeactivateBootloader();
                }
                else
                {
                    Console.WriteLine();
                    Console.WriteLine("> Could not activate bootloader for the selected device.");
                    Console.WriteLine("> Hint: Is password correct? Is BAUD rate correct?");
                    tsb.DeactivateBootloader();
                    errors_encountered = true;
                }
            }

            if (errors_encountered)
            {
                Console.WriteLine();
                Console.WriteLine("> Requested operations completed with errors. Please review the error messages above.");
                return(RETURN_ERRORS_ENCOUNTERED);
            }
            else
            {
                Console.WriteLine();
                Console.WriteLine("> All operations complete.");
                return(0);
            }
        }
Пример #2
0
        static int Main(string[] args)
        {
            /* install global Exception handler
             * Won't do much more than pretify'ing the error messages but better
             * fail gracefully that terribly
             */
            System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;

            bool errors_encountered = false;

            CommandLineParser cmd_parser = new CommandLineParser();

            if (cmd_parser.parse_command_line(args) == false)
            {
                return(RETURN_INVALID_CMDLINE);
            }

            /********************************
             * SEED EROS Bdrige mode enable/disable requests
             */

            /* SEED EROS Bridge Enable */
            if (cmd_parser.bootloader_operations.Contains(CommandLineParser.en_bootloader_operations.SEEDEROS_BRIDGEENABLE))
            {
                System.IO.Ports.SerialPort serial_port = new System.IO.Ports.SerialPort();

                serial_port.BaudRate = cmd_parser.baudrate_bps;
                serial_port.PortName = cmd_parser.port_name;
                serial_port.Encoding = Encoding.ASCII;

                try
                {
                    Console.WriteLine();
                    Console.WriteLine("> Seed Robotics Eros: Enabling bridge mode...");

                    serial_port.Open();
                    System.Threading.Thread.Sleep(cmd_parser.prewait_ms);

                    /* clear out any wrong/previous commands that might exist on the board buffer
                     * This ensures we're at a clean state of the command parser when we send the bridge enable command */
                    serial_port.Write("\r\n");
                    wait_for_reply(serial_port, cmd_parser.replytimeout_ms);
                    //System.Threading.Thread.Sleep(500); /* wait another 500ms to fully receive all comms */
                    serial_port.ReadExisting(); /* read and discard */

                    /* now send the actual command */
                    /* 20 = 4 + 16 (Int bus to USB with DTR reset) */
                    serial_port.Write("commbridge 20\r\n"); /* this command is specific to the EROS firmware CONSOLE; if you
                                                             * don't have a console on the port you are trying to open, this is
                                                             * not necessary;
                                                             * It bridges the USB interface to the Internal bus, using the
                                                             * a special bridge mode built for flashing the servos
                                                             * (it will auto reset the bus on Serial connect, uses a softserial library to
                                                             * cope with the device side of TSB weird timing, etc.) */

                    wait_for_reply(serial_port, cmd_parser.replytimeout_ms);

                    if (serial_port.BytesToRead < 1)
                    {
                        Console.WriteLine("ERROR");
                        Console.WriteLine("No reply from the Seed Eros device.");
                        Console.WriteLine("(Is this the Serial Port of the Seed Eros device? Is the device already in bridge mode?)");
                        return(RETURN_SEEDEROS_COMMAND_FAILED);
                    }
                    else
                    {
                        Console.Write("  < Reply: ");
                        while (serial_port.BytesToRead > 0)
                        {
                            Console.WriteLine(serial_port.ReadLine().ToString());
                        }
                    }

                    serial_port.Close();

                    return(0);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("ERROR");
                    Console.WriteLine(ex.Message);
                    Console.WriteLine();
                    Console.WriteLine("> Pre requisite command (SeedEros) failed. Ending session.");
                    return(RETURN_SEEDEROS_COMMAND_FAILED);
                }
            }

            /* SEED EROS Bridge Disable */
            if (cmd_parser.bootloader_operations.Contains(CommandLineParser.en_bootloader_operations.SEEDEROS_BRIDGEDISABLE))
            {
                System.IO.Ports.SerialPort serial_port = new System.IO.Ports.SerialPort();

                /* to exit bridge mode, we open and close the port at 1200 bps */
                serial_port.BaudRate = 1200;
                serial_port.PortName = cmd_parser.port_name;
                serial_port.Encoding = Encoding.ASCII;

                try
                {
                    Console.WriteLine();
                    Console.Write("> Seed Robotics Eros: Sending Host request to disable bridge mode...");

                    serial_port.Open();
                    serial_port.DtrEnable = true;       /* on Mono / .Net we apparently need to explicitly set DTR */

                    System.Threading.Thread.Sleep(800); /* wait a moment */

                    serial_port.Close();
                    System.Threading.Thread.Sleep(200); /* wait some other moment; just give Serial driver some spare time */

                    Console.WriteLine(" Done.\n");
                    Console.WriteLine("  ( If your firmware supports host request to exit bridge mode, the unit's LEDs should be back to white/three colours.");
                    Console.WriteLine("    If the LED colour hasn't changed, you need to manually power cycle your unit (including disconnecting the USB cable) to resume regular operation.)");

                    return(0);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("ERROR");
                    Console.WriteLine(ex.Message);
                    Console.WriteLine();
                    Console.WriteLine("> Post process command (SeedEros) failed.");
                    return(RETURN_SEEDEROS_COMMAND_FAILED);
                }
            }

            /* Emergency Erase Request
             * Emergency Erase restoresbootloader access in case of lost password, by wiping
             * the full FLASH and EEPROM memory areas
             */
            if (cmd_parser.bootloader_operations.Contains(CommandLineParser.en_bootloader_operations.EMERGENCY_ERASE))
            {
                if (cmd_parser.activation_mode != CommandLineParser.en_bootloader_activation_mode.COLD_BOOT)
                {
                    Console.WriteLine("ERROR: Emergency Erase can only be done in Cold [boot] activation mode.");
                    return(RETURN_ERRORS_ENCOUNTERED);
                }

                Console.WriteLine();
                Console.WriteLine("WARNING: Emergency Erase deletes all Application Flash");
                Console.WriteLine("and EEPROM data, as well as:");
                Console.WriteLine("  Timeout, Password and Magic Byte!");
                Console.WriteLine("No Firmware or EEPROM data will be left on the device after");
                Console.WriteLine("this operation.");
                Console.WriteLine("This creates a clean TSB configuration with default values.");
                Console.WriteLine();
                Console.WriteLine("IMPORTANT! An Emergency Erase DOES NOT target an individual");
                Console.WriteLine("device; if the device is connected on a BUS (Daisy chain),");
                Console.WriteLine("ALL the devices will perform the Emergency Erase.");
                Console.WriteLine();
                Console.WriteLine("This function should ONLY be used by experienced users.");
                Console.WriteLine();
                Console.Write("Do you fully understand the information above? (Y/n) ");
                if (!get_YesNo_reply())
                {
                    Console.WriteLine();
                    Console.WriteLine("Operation cancelled. Nothing was done.");
                    return(0);
                }
                Console.Write("Do you wish to continue? (Y/n) ");
                if (!get_YesNo_reply())
                {
                    Console.WriteLine();
                    Console.WriteLine("Operation cancelled. Nothing was done.");
                    return(0);
                }

                Console.WriteLine();

                TSBInterfacing tsb = new TSBInterfacing(UpdateStatusOnScreen, AskQuestion_ToUser);
                if (!tsb.EmergencyErase(cmd_parser.port_name, cmd_parser.baudrate_bps, cmd_parser.prewait_ms, cmd_parser.replytimeout_ms))
                {
                    Console.WriteLine();
                    Console.WriteLine("> Error while performing Emergency Erase operation.");
                    return(RETURN_ERRORS_ENCOUNTERED);
                }
                else
                {
                    return(0);
                }
            }


            /********** Main cycle for multi-device bootloader operations **************
             * /* Cycle through the passwords specified for the bootloader */
            if (cmd_parser.bootloader_passwords.Count() == 0)
            {
                /* add a bogus entry with an empty password. Assuming user intends to start the session
                 * with no password. */
                cmd_parser.bootloader_passwords.Add("");
            }

            /* only advance to TSB if we have more commands lined up and requested at the command line */
            if (cmd_parser.bootloader_operations.Count == 0 ||
                (cmd_parser.bootloader_operations.Count == 1 && cmd_parser.bootloader_operations.Contains(CommandLineParser.en_bootloader_operations.SEEDEROS_BRIDGEDISABLE)))
            {
                Console.WriteLine();
                Console.WriteLine("> No bootloader actions specified. Ending session");
                return(0);
            }


            foreach (string pwd in cmd_parser.bootloader_passwords)
            {
                TSBInterfacing tsb = new TSBInterfacing(UpdateStatusOnScreen, AskQuestion_ToUser);
                bool           activation_result = false;

                if (pwd.Length > 0)
                {
                    if (cmd_parser.activation_mode == CommandLineParser.en_bootloader_activation_mode.COLD_BOOT)
                    {
                        Console.WriteLine();
                        Console.WriteLine("> Activating bootloader for device with password: {0}", pwd);
                        Console.WriteLine();
                        activation_result = tsb.ActivateBootloaderFromColdStart(cmd_parser.port_name, cmd_parser.baudrate_bps, cmd_parser.prewait_ms, cmd_parser.replytimeout_ms, pwd);
                    }
                    else
                    {
                        Console.WriteLine("ERROR: Bootloader passwords can only be specified when activating in 'cold' [boot] mode.");
                        return(RETURN_ERRORS_ENCOUNTERED);
                    }
                }
                else if (cmd_parser.activation_mode == CommandLineParser.en_bootloader_activation_mode.COLD_BOOT)
                {
                    Console.WriteLine();
                    Console.WriteLine("> Activating bootloader (no device password specified)");
                    Console.WriteLine();
                    activation_result = tsb.ActivateBootloaderFromColdStart(cmd_parser.port_name, cmd_parser.baudrate_bps, cmd_parser.prewait_ms, cmd_parser.replytimeout_ms, pwd);
                }
                else if (cmd_parser.activation_mode == CommandLineParser.en_bootloader_activation_mode.LIVE_VIA_DYNAMIXEL)
                {
                    if (cmd_parser.dynid < 0 || cmd_parser.dynid > 253)
                    {
                        Console.WriteLine("ERROR: 'live' bootloader activation mode was selected but the '-dynid' parameter was not given or is invalid. Please set a valid '-dynid' for 'live' activation mode.");
                        return(RETURN_ERRORS_ENCOUNTERED);
                    }

                    Console.WriteLine();
                    Console.WriteLine("> Activating bootloader on 'live' device with Dynamixel ID {0}", cmd_parser.dynid);
                    Console.WriteLine();

                    // baud after activation should not be hard coded as we may need to speak at higher bauds if going through the EROS board.
                    // timeout for bootloader activation must exceed the time set in the servo firmware.
                    activation_result = tsb.ActivateBootloaderFromDynamixel(cmd_parser.port_name, cmd_parser.baudrate_bps, 9600, (byte)cmd_parser.dynid, 3500, 6000, TSBInterfacing.en_protocol_version.DYNAMIXEL_1);
                }


                /* build a new instance for every new device; this ensures variables and
                 * control structures come from a clean slate, which makes sense, since we're
                 * starting a whole new session
                 */


                if (activation_result == true)
                {
                    /* Bootloader is active. Print all bootloader information */
                    PrintDeviceInfo(tsb);

                    if (cmd_parser.patch_daisychain_bug)
                    {
                        if (tsb.session_data_.daisychain_patch_in_lastpage == false)
                        {
                            /* forcing a LastPageWrite will write the data with the necessary
                             * patches in place to cope with this bug */

                            Console.WriteLine();
                            Console.WriteLine("> Patching for daisy chain operation", pwd);
                            Console.WriteLine();

                            tsb.LastPage_Write();
                        }
                        else
                        {
                            Console.WriteLine();
                            Console.WriteLine("> Daisy chain patch is already applied", pwd);
                            Console.WriteLine();
                        }
                    }

                    /*  check if the user asked to tag the file names.
                     *  This MUST be done here for the cases where we use multiple
                     *  passwords; in that case, we have sessins starting at different times
                     *  (initiated here) and also different passwords
                     */
                    string tag = string.Format("_{0:yyMMdd}_{0:HHmmss}", DateTime.Now);
                    if (pwd.Length > 0)
                    {
                        tag += string.Format("_{0}", pwd);
                    }

                    string eep_filename   = cmd_parser.eeprom_file_name;
                    string flash_filename = cmd_parser.flash_file_name;

                    if (cmd_parser.tag_eepromfilename_withdatetimepwd && !string.IsNullOrEmpty(cmd_parser.eeprom_file_name))
                    {
                        eep_filename = AddTagToFilename(cmd_parser.eeprom_file_name, tag);
                    }

                    if (cmd_parser.tag_flashfilename_withdatetimepwd && !string.IsNullOrEmpty(cmd_parser.flash_file_name))
                    {
                        flash_filename = AddTagToFilename(cmd_parser.flash_file_name, tag);
                    }


                    /* loop through the various operations requested */
                    foreach (CommandLineParser.en_bootloader_operations bootloader_op in cmd_parser.bootloader_operations)
                    {
                        switch (bootloader_op)
                        {
                        case CommandLineParser.en_bootloader_operations.DISPLAY_DEVICE_INFO:
                            /* do nothing; when we activated TSB it already displayed the device info */
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_ERASE:
                            if (!tsb.EEProm_Erase())
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Erasing EEProm.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_WRITE:
                            if (!tsb.EEProm_Write(eep_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Writing EEPROM.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_VERIFY:
                            if (!tsb.EEProm_Verify(eep_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Verifying EEPROM.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.EEP_READ:
                            if (!tsb.EEProm_Read(eep_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Reading EEPROM.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_ERASE:
                            if (!tsb.Flash_Erase())
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Erasing Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_WRITE:
                            if (!tsb.Flash_Write(flash_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Writing Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_VERIFY:
                            if (!tsb.Flash_Verify(flash_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Verifying Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.FW_READ:
                            if (!tsb.Flash_Read(flash_filename))
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error Reading Flash.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.PASSWORD_CHANGE:
                            /* ask the user for a password */
                            Console.WriteLine();
                            Console.WriteLine("Please enter the new Password (max. {0} chars): ", TSBInterfacing.max_pwd_length);
                            string new_pwd = Console.ReadLine();

                            if (string.IsNullOrEmpty(new_pwd))
                            {
                                new_pwd = "";
                                Console.WriteLine("No password specified. The bootloader will be accessible without password.");
                            }
                            else if (new_pwd.Length > Tsbloader_adv.TSBInterfacing.max_pwd_length)
                            {
                                Console.WriteLine("ERROR: Password is too long. Maximum password length supported by this tool is {0} characters.", Tsbloader_adv.TSBInterfacing.max_pwd_length);
                                Console.WriteLine("> Password has not been changed.");
                            }
                            else
                            {
                                Console.WriteLine("New password will be set to: {0}", new_pwd);
                                Console.WriteLine("(if you lose your password, you may use the Emergency Erase option '-XXX')");
                            }

                            if (request_confirm())
                            {
                                tsb.session_data_.password = new_pwd;
                                if (!tsb.LastPage_Write())
                                {
                                    Console.WriteLine();
                                    Console.WriteLine("> Error writing bootloader configuration data.");
                                    errors_encountered = true;
                                }
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.TIMEOUT_CHANGE:
                            /* ask the user for a timeout */
                            int new_timeout_setting;
                            while (true)
                            {
                                Console.WriteLine();
                                Console.WriteLine("Current timeout is set to value {0}", tsb.session_data_.timeout);
                                Console.WriteLine("Please enter the new Timeout setting: ");
                                string new_timeout = Console.ReadLine();

                                if (string.IsNullOrEmpty(new_timeout))
                                {
                                    Console.WriteLine("Invalid timeout specified. Timeout must be number between {0} and 255.", MINIMUM_TIMEOUT_SETTING);
                                }
                                else
                                {
                                    if (!int.TryParse(new_timeout, out new_timeout_setting))
                                    {
                                        Console.WriteLine("Invalid timeout specified. Timeout must be number between {0} and 255.", MINIMUM_TIMEOUT_SETTING);
                                    }
                                    else if (new_timeout_setting < MINIMUM_TIMEOUT_SETTING || new_timeout_setting > 255)
                                    {
                                        Console.WriteLine("Invalid timeout value specified. Timeout must be number between {0} and 255.", MINIMUM_TIMEOUT_SETTING);
                                    }
                                    else
                                    {
                                        Console.WriteLine("New Timeout will be set to: {0}", new_timeout_setting);
                                        break;
                                    }
                                }
                            }

                            /* no need to confirm this one; save immediately */
                            tsb.session_data_.timeout = (byte)new_timeout_setting;
                            if (!tsb.LastPage_Write())
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error writing bootloader configuration data.");
                                errors_encountered = true;
                            }
                            break;

                        case CommandLineParser.en_bootloader_operations.WRITE_MAGIC_BYTES:
                            /* ask the user for the new magic bytes */
                            string[] s_magic_bytes_names = { "First", "Second" };

                            Console.WriteLine();
                            Console.WriteLine("Current Magic Bytes are set to [0x{0:X02}] [0x{1:X02}]", tsb.session_data_.magic_bytes[0], tsb.session_data_.magic_bytes[1]);

                            for (byte b = 0; b < 2; b++)
                            {
                                while (true)
                                {
                                    Console.WriteLine();
                                    Console.WriteLine("Enter the {0} Magic Byte, in HEX format (i.e. '0xA6', type 'A6', omitting the '0x'):", s_magic_bytes_names[b]);
                                    string magic_byte = Console.ReadLine();

                                    if (string.IsNullOrWhiteSpace(magic_byte))
                                    {
                                        Console.WriteLine("Empty Magic Byte specified; setting it to 0xFF");
                                        magic_byte = "FF";
                                    }

                                    int mb;
                                    try
                                    {
                                        // based on tips for parsing HEX here https://theburningmonk.com/2010/02/converting-hex-to-int-in-csharp/
                                        mb = int.Parse(magic_byte, System.Globalization.NumberStyles.HexNumber);

                                        if (mb > 255)
                                        {
                                            Console.WriteLine("ERROR: HEX number too big. Magic bytes are of BYTE type in range 0x0 to 0xFF.");
                                        }
                                        else
                                        {
                                            tsb.session_data_.magic_bytes[b] = (byte)mb;
                                            break;
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine("ERROR: Invalid HEX value. Magic bytes are set in HEX. Example: set to 0xA7, type 'A7' and ommit the '0x' part.");
                                    }
                                }
                            }

                            /* Save now */
                            Console.WriteLine("Magic Bytes will be set to: [0x{0:X02}] [0x{1:X02}]", tsb.session_data_.magic_bytes[0], tsb.session_data_.magic_bytes[1]);
                            if (!tsb.LastPage_Write())
                            {
                                Console.WriteLine();
                                Console.WriteLine("> Error writing bootloader configuration data.");
                                errors_encountered = true;
                            }
                            break;

                        default:
                            Console.WriteLine("ERROR: Unknown Bootloader operation in function main()");
                            return(RETURN_UNKOWN_OPTION_IN_CASE);
                        }
                    }

                    tsb.DeactivateBootloader();
                }
                else
                {
                    Console.WriteLine();
                    Console.WriteLine("> Could not activate bootloader for the selected device.");
                    tsb.DeactivateBootloader();
                    errors_encountered = true;
                }
            }



            if (errors_encountered)
            {
                Console.WriteLine();
                Console.WriteLine("> Requested operations completed with errors. Please review the error messages above.");
                return(RETURN_ERRORS_ENCOUNTERED);
            }
            else
            {
                Console.WriteLine();
                Console.WriteLine("> All operations complete.");
                return(0);
            }
        }