def create_device_cert_and_manifest():
    """AWS IoT EduKit MCU hardware device registration script
    Checkes environment is set correctly, generates ECDSA certificates,
    ensures all required python libraries are included, retrieves on-board 
    device certificate using the esp-cryptoauth library and utility, creates 
    an AWS IoT thing using the AWS CLI and Microchip Trust Platform Design Suite.
    """
    app_binary = 'sample_bins/secure_cert_mfg.bin'
    args = manifest_args(env.get("UPLOAD_PORT"))

    args.signer_cert = os.path.join(dest_folder, "signer_cert.crt")
    args.signer_privkey = os.path.join(dest_folder, "signer_key.pem")
    args.print_atecc608_type = False

    check_environment()
    generate_signer_certificate()

    esp = esptool.ESP32ROM(args.port, baud=115200)
    esp_hs.serial.load_app_stub(app_binary, esp)
    init_mfg = esp_hs.serial.cmd_interpreter()

    retval = init_mfg.wait_for_init(esp._port)
    if retval is not True:
        print("CMD prompt timed out.")
        exit(0)

    retval = init_mfg.exec_cmd(
        esp._port, "init {0} {1}".format(atecc608_i2c_sda_pin,
                                         atecc608_i2c_scl_pin))
    esp_hs.serial.esp_cmd_check_ok(
        retval, "init {0} {1}".format(atecc608_i2c_sda_pin,
                                      atecc608_i2c_scl_pin))
    os.makedirs(temp_folder, exist_ok=True)
    esp_hs.generate_manifest_file(esp, args, init_mfg)
 def connect(self):
     initial_baud = 115200 * 2
     if(self.chip_type == 'ESP32'):
         try:
             self.esp = esptool.ESP32ROM(self.port, initial_baud)
         except:
             if(DEBUG): print "ERROR!! The com port is occupied!!"
             return err_conn, "ERROR!! The com port is occupied!!"
     elif(self.chip_type == 'ESP8266'):
         try:
             self.esp = esptool.ESP8266ROM(self.port, initial_baud)
         except:
             if(DEBUG): print "ERROR!! The com port is occupied!!"
             return err_conn, "ERROR!! The com port is occupied!!"
     
     times = 3
     while True:
         try:
             if times-1>0:
                 self.esp.connect()
             else:
                 return err_conn, "ERROR!! sync to chip fail"
             break
         except:
             times -= 1
             pass
         
     return no_err, 'sync succ'
Esempio n. 3
0
def t_loadBin(esprftool, params):
    initial_baud = 115200
    esprftool._SignalTX.emit('sync...')
    esprftool._SignalLoadStatus.emit(4)
    esprftool._Signalprb.emit(0)
    if (params.chip_type == 'ESP32'):
        try:
            esp = esptool.ESP32ROM(params.port, initial_baud)
        except:
            print "ERROR!! The com port is occupied!!\n"
            esprftool._SignalTX.emit('ERROR!! The com port is occupied!!')
            return

    elif (params.chip_type == 'ESP8266'):
        try:
            esp = esptool.ESP8266ROM(params.port, initial_baud)
        except:
            print "ERROR!! The com port is occupied!!\n"
            esprftool._SignalTX.emit('ERROR!! The com port is occupied!!')
            return

    esprftool._SignalLoadStatus.emit(1)
    esp_mac = (00, 00, 00, 00, 00, 00)
    cus_mac = "00:00:00:00:00:00"
    print('%s: %s' % ("ESP_MAC", ':'.join(map(lambda x: '%02x' % x, esp_mac))))
    esprftool._SignalLoadStatus.emit(1)
    while True:
        try:
            esp.connect()
            break
        except:
            pass
    try:
        esprftool._SignalTX.emit('sync success')
        esp_mac = esp.read_mac()
        print 'esp_mac:%02x-%02x-%02x-%02x-%02x-%02x' % (esp_mac)
        esprftool._SignalTX.emit('esp_mac:%02x-%02x-%02x-%02x-%02x-%02x' %
                                 (esp_mac))
        esprftool._SignalLoadStatus.emit(2)

        if (params.esp_download_mode == 1):
            #print "load ram ..."
            load_ram(esp, params, esprftool)

        elif (params.esp_download_mode == 2):
            if not params.no_stub:
                esp = esp.run_stub()
            esp.change_baud(921600)
            #print "load flash ..."
            write_flash(esp, params, esprftool)
    except:
        esprftool._SignalLoadStatus.emit(4)
        esprftool._SignalTX.emit('load bin fail')
        return

    esprftool._SignalLoadStatus.emit(3)
Esempio n. 4
0
    def mesh_read_mac(self, str_port):
        esp = esptool.ESP32ROM(port=str_port, baud=115200)
        esp.connect()
        mac = esp.read_mac()

        def mac_to_str(mac):
            return ('%s' % (':'.join(map(lambda x: '%02x' % x, mac))))

        str_mac = mac_to_str(mac)
        return str_mac
Esempio n. 5
0
    def _create_esp_connection(self):
        '''Connect to ESP32. Child method.

        Need to indicate self.connecting=False when self.esp.connect() encounter
        an exception. No need to update self.connecting=True when connected
        as it is done Parent method.'''
        port = self.port.get()
        try:
            baud = self.baud.get()
        except tk.TclError as err:
            baud = esptool.ESPLoader.ESP_ROM_BAUD
            self.baud.set(baud)
            self.bauds.update_idletasks()

        try:
            if self.esp:
                self.esp._port.close()
            self.esp = esptool.ESP32ROM(
                port,
                baud,  #trace_enabled=True,
            )
            #Created attributes:
            # self.esp._port - Is an instance of serial.Serial() or a compatible object
            #                  see https://pythonhosted.org/pyserial/pyserial_api.html?highlight=setdtr#serial.Serial
            #                - It will close the defined serial port when self.esp._port is freed, i.e.
            #                  when tk.Tk() instance is destroyed.
            #                - set self.esp._port.baud
            # self.esp._slip_reader   - Is a generator to read SLIP packets from the
            #                           defined serial port in self.esp._port.
            # self.esp._trace_enabled - Denotes wheather tracing is activated.
            #                           For debugging. Default value is "False"
            # self.esp._last_trace    - stores time.time()
            self.esp.connect()
        except (esptool.FatalError, OSError) as err:
            self.esp._port.close()
            self._sop_for_not_connected()
            if "Failed to connect to ESP32: Timed out waiting for packet header" in err.__str__(
            ):
                self.status.set(ESP32Device.MSG2a
                                )  #Fail to Connect. Try another Baud value.
            else:
                self.status.set(
                    ESP32Device.MSG2
                )  #Fail to Connect. Hold down BOOT & click WRITE.'
            print(err)
        except SerialException as err:
            self.esp._port.close()
            self._sop_for_not_connected()
            print("{} ESP32 device is busy".format(port))
            self.status.set(ESP32Device.MSG1)
            print(err)
        else:
            pprint(self.esp.__dict__)
            print('esp is created & connected.\n')
Esempio n. 6
0
    def handler(self, *args, **kwargs):
        self.stop_receive()

        settings = self.port_inst.get_settings()

        rom = esptool.ESP32ROM(self.port_inst)
        rom.connect('hard_reset')
        esp = rom.run_stub()

        ret = func(self, esp, *args, **kwargs)

        self.port_inst.apply_settings(settings)
        self.start_receive()
        return ret
Esempio n. 7
0
    def get_mac(cls, app, port):
        """
        get MAC address via esptool

        :param app: application instance (to get tool)
        :param port: serial port as string
        :return: MAC address or None
        """
        try:
            esp = esptool.ESP32ROM(port)
            esp.connect()
            return esp.read_mac()
        except RuntimeError:
            return None
        finally:
            esp._port.close()
def main():
    """AWS IoT EduKit MCU hardware device registration script
    Checkes environment is set correctly, generates ECDSA certificates,
    ensures all required python libraries are included, retrieves on-board 
    device certificate using the esp-cryptoauth library and utility, creates 
    an AWS IoT thing using the AWS CLI and Microchip Trust Platform Design Suite.
    """
    app_binary = 'sample_bins/secure_cert_mfg.bin'
    parser = argparse.ArgumentParser(
        description='''Provision the Core2 for AWS IoT EduKit with 
        device_certificate and signer_certificate required for TLS authentication'''
    )

    parser.add_argument(
        "--port",
        '-p',
        dest='port',
        metavar='[port]',
        required=True,
        help='Serial comm port of the Core2 for AWS IoT EduKit device')

    args = parser.parse_args()

    args.signer_cert = "output_files/signer_cert.crt"
    args.signer_privkey = "output_files/signer_key.pem"
    args.print_atecc608_type = False
    check_environment()

    generate_signer_certificate()

    esp = esptool.ESP32ROM(args.port, baud=115200)
    esp_hs.serial.load_app_stub(app_binary, esp)
    init_mfg = esp_hs.serial.cmd_interpreter()

    retval = init_mfg.wait_for_init(esp._port)
    if retval is not True:
        print("CMD prompt timed out.")
        exit(0)

    retval = init_mfg.exec_cmd(
        esp._port, "init {0} {1}".format(atecc608_i2c_sda_pin,
                                         atecc608_i2c_scl_pin))
    esp_hs.serial.esp_cmd_check_ok(
        retval, "init {0} {1}".format(atecc608_i2c_sda_pin,
                                      atecc608_i2c_scl_pin))
    esp_hs.generate_manifest_file(esp, args, init_mfg)
    upload_manifest()
Esempio n. 9
0
    def get_mac(cls, port):
        """
        get MAC address via esptool

        :param port: serial port as string
        :return: MAC address or None
        """
        esp = None
        try:
            esp = esptool.ESP32ROM(port)
            esp.connect()
            return esp.read_mac()
        except RuntimeError:
            return None
        finally:
            if esp:
                # do hard reset after use esptool
                esp.hard_reset()
                esp._port.close()
Esempio n. 10
0
    def handler(self, *args, **kwargs):
        self.stop_receive()

        settings = self.port_inst.get_settings()

        try:
            rom = esptool.ESP32ROM(self.port_inst)
            rom.connect('hard_reset')
            esp = rom.run_stub()

            ret = func(self, esp, *args, **kwargs)
            # do hard reset after use esptool
            esp.hard_reset()
        finally:
            # always need to restore port settings
            self.port_inst.apply_settings(settings)

        self.start_receive()

        return ret
    def setUp(self):
        # reset and zero efuses
        serialport.dtr = False
        serialport.rts = True
        time.sleep(0.05)
        serialport.rts = False
        time.sleep(0.05)
        serialport.dtr = True

        # connect & verify efuses are really zero
        self.esp = esptool.ESP32ROM(serialport)
        self.esp.connect('no_reset')  # takes ~7 seconds
        self.efuses = espefuse.EspEfuses(self.esp)

        # Check every efuse is zero (~1 second)
        for efuse in self.efuses:
            val = efuse.get_raw()
            BAD_EFUSE_MSG = "Efuse %s not all zeroes - either this is a real ESP32 chip (VERY BAD, read top of file), or the reset is not erasing all efuses correctly." % efuse.register_name
            try:
                self.assertEqual(b'\x00' * len(val), val, BAD_EFUSE_MSG)
            except TypeError:
                self.assertEqual(0, val, BAD_EFUSE_MSG)
Esempio n. 12
0
def get_secret_key(port, esptool):
    """
    Generate Secret Key

    :param port: Serial Port
    :type port: str

    :param esptool: esptool module
    :type esptool: module

    :return: Secret Key on Success
    :rtype: str
    """
    esp = esptool.ESP32ROM(port)
    esp.connect('default_reset')
    for (name, idx, read_addr, _, _) in BLOCKS:
        addrs = range(read_addr, read_addr + 32, 4)
        secret = "".join(["%08x" % esp.read_reg(addr) for addr in addrs[0:4]])
        secret = secret[6:8]+secret[4:6]+secret[2:4]+secret[0:2] +\
            secret[14:16]+secret[12:14]+secret[10:12]+secret[8:10] +\
            secret[22:24]+secret[20:22]+secret[18:20]+secret[16:18] +\
            secret[30:32]+secret[28:30]+secret[26:28]+secret[24:26]
    return secret
Esempio n. 13
0
 def valid_key_present(self):
     esp = esptool.ESP32ROM(serialport)
     esp.connect()
     efuses, _ = espefuse.get_efuses(esp=esp)
     blk1_rd_en = efuses["BLOCK1"].is_readable()
     return not blk1_rd_en
Esempio n. 14
0
def main():
    parser = argparse.ArgumentParser(
        description='''Provision the ESPWROOM32SE device with
        device_certificate and signer_certificate required for TLS authentication'''
    )

    parser.add_argument(
        "--flash",
        dest='bin_path',
        default='/sample_bins/secure_cert_mfg.bin',
        metavar='relative/path/to/bins',
        help=
        'relative path(from secure_cert_mfg.py) to binary to be flashed on the ESP device'
    )

    parser.add_argument(
        '--signer-cert',
        dest='signer_cert',
        default='sample_certs/sample_signer_cert.pem',
        metavar='relative/path/to/signer_cert.pem',
        help='relative path(from secure_cert_mfg.py) to signer certificate.')

    parser.add_argument(
        '--signer-cert-private-key',
        dest='signer_privkey',
        default='sample_certs/sample_signer_key.pem',
        metavar='relative/path/to/signer-priv-key',
        help=
        'relative path(from secure_cert_mfg.py) to signer certificate private key'
    )

    parser.add_argument("--pwd",
                        '--password',
                        dest='password',
                        metavar='[password]',
                        help='the password associated with the private key')

    parser.add_argument("--port",
                        '-p',
                        dest='port',
                        metavar='[port]',
                        required=True,
                        help='uart com port to which ESP device is connected')

    parser.add_argument(
        "--type",
        "--print-atecc608a-type",
        dest='print_atecc608a_type',
        action='store_true',
        help='print type of atecc608a chip connected to your ESP device')

    parser.add_argument(
        "--valid-for-years",
        dest='nva_years',
        default=40,
        type=int,
        help=
        'number of years for which device cert is valid (from current year), default = 40'
    )
    args = parser.parse_args()
    esp = esptool.ESP32ROM(args.port, baud=115200)
    hs.serial.load_app_stub(args.bin_path, esp)
    init_mfg = hs.serial.cmd_interpreter()

    retval = init_mfg.wait_for_init(esp._port)
    if retval is not True:
        print("CMD prompt timed out.")
        exit(0)

    retval = init_mfg.exec_cmd(esp._port, "init")
    hs.serial.esp_cmd_check_ok(retval, "init")

    if "TrustCustom" in retval[1]['Return']:
        print("ATECC608A chip is of type TrustCustom")
        provision_trustcustom_device(esp, args, init_mfg)
    elif "Trust&Go" in retval[1]['Return']:
        print("ATECC608A chip is of type Trust&Go")
        hs.manifest.generate_manifest_file(esp, args, init_mfg)
    elif "TrustFlex" in retval[1]['Return']:
        print("ATECC608A chip is of type TrustFlex")
        hs.manifest.generate_manifest_file(esp, args, init_mfg)
    else:
        print("Invalid type")
        exit(0)
Esempio n. 15
0
def main():
    parser = argparse.ArgumentParser(
        description='espefuse.py v%s - ESP32 efuse get/set tool' %
        esptool.__version__,
        prog='espefuse')

    parser.add_argument('--port',
                        '-p',
                        help='Serial port device',
                        default=os.environ.get('ESPTOOL_PORT',
                                               esptool.ESPLoader.DEFAULT_PORT))

    parser.add_argument('--before',
                        help='What to do before connecting to the chip',
                        choices=['default_reset', 'no_reset', 'esp32r1'],
                        default='default_reset')

    parser.add_argument(
        '--do-not-confirm',
        help=
        'Do not pause for confirmation before permanently writing efuses. Use with caution.',
        action='store_true')

    subparsers = parser.add_subparsers(
        dest='operation',
        help='Run espefuse.py {command} -h for additional help')

    subparsers.add_parser('dump', help='Dump raw hex values of all efuses')
    subparsers.add_parser('summary',
                          help='Print human-readable summary of efuse values')

    p = subparsers.add_parser('burn_efuse',
                              help='Burn the efuse with the specified name')
    p.add_argument('efuse_name',
                   help='Name of efuse register to burn',
                   choices=[efuse[0] for efuse in EFUSES])
    p.add_argument('new_value',
                   help='New value to burn (not needed for flag-type efuses',
                   nargs='?',
                   type=esptool.arg_auto_int)

    p = subparsers.add_parser(
        'read_protect_efuse',
        help='Disable readback for the efuse with the specified name')
    p.add_argument('efuse_name',
                   help='Name of efuse register to burn',
                   choices=[
                       efuse[0] for efuse in EFUSES if efuse[6] is not None
                   ])  # only allow if read_disable_bit is not None

    p = subparsers.add_parser(
        'write_protect_efuse',
        help='Disable writing to the efuse with the specified name')
    p.add_argument('efuse_name',
                   help='Name of efuse register to burn',
                   choices=[efuse[0] for efuse in EFUSES])

    p = subparsers.add_parser(
        'burn_key',
        help=
        'Burn a 256-bit AES key to EFUSE BLK1,BLK2 or BLK3 (flash_encryption, secure_boot).'
    )
    p.add_argument(
        '--no-protect-key',
        help='Disable default read- and write-protecting of the key. ' +
        'If this option is not set, once the key is flashed it cannot be read back or changed.',
        action='store_true')
    p.add_argument(
        '--force-write-always',
        help=
        "Write the key even if it looks like it's already been written, or is write protected. "
        +
        "Note that this option can't disable write protection, or clear any bit which has already been set.",
        action='store_true')
    p.add_argument(
        'block',
        help='Key block to burn. "flash_encryption" is an alias for BLK1, ' +
        '"secure_boot" is an alias for BLK2.',
        choices=["secure_boot", "flash_encryption", "BLK1", "BLK2", "BLK3"])
    p.add_argument('keyfile',
                   help='File containing 256 bits of binary key data',
                   type=argparse.FileType('rb'))

    p = subparsers.add_parser(
        'set_flash_voltage',
        help=
        'Permanently set the internal flash voltage regulator to either 1.8V, 3.3V or OFF. '
        +
        'This means GPIO12 can be high or low at reset without changing the flash voltage.'
    )
    p.add_argument('voltage',
                   help='Voltage selection',
                   choices=['1.8V', '3.3V', 'OFF'])

    args = parser.parse_args()
    print('espefuse.py v%s' % esptool.__version__)
    if args.operation is None:
        parser.print_help()
        parser.exit(1)

    # each 'operation' is a module-level function of the same name
    operation_func = globals()[args.operation]

    esp = esptool.ESP32ROM(args.port)
    esp.connect(args.before)

    # dict mapping register name to its efuse object
    efuses = [EfuseField.from_tuple(esp, efuse) for efuse in EFUSES]
    operation_func(esp, efuses, args)
Esempio n. 16
0
def main():
    parser = argparse.ArgumentParser(
        description='espefuse.py v%s - ESP32 efuse get/set tool' %
        esptool.__version__,
        prog='espefuse')

    parser.add_argument(
        '--baud',
        '-b',
        help='Serial port baud rate used when flashing/reading',
        type=arg_auto_int,
        default=os.environ.get('ESPTOOL_BAUD', esptool.ESPLoader.ESP_ROM_BAUD))

    parser.add_argument('--port',
                        '-p',
                        help='Serial port device',
                        default=os.environ.get('ESPTOOL_PORT',
                                               esptool.ESPLoader.DEFAULT_PORT))

    parser.add_argument(
        '--before',
        help='What to do before connecting to the chip',
        choices=['default_reset', 'no_reset', 'esp32r1', 'no_reset_no_sync'],
        default='default_reset')

    parser.add_argument(
        '--do-not-confirm',
        help=
        'Do not pause for confirmation before permanently writing efuses. Use with caution.',
        action='store_true')

    def add_force_write_always(p):
        p.add_argument(
            '--force-write-always',
            help=
            "Write the efuse even if it looks like it's already been written, or is write protected. "
            +
            "Note that this option can't disable write protection, or clear any bit which has already been set.",
            action='store_true')

    subparsers = parser.add_subparsers(
        dest='operation',
        help='Run espefuse.py {command} -h for additional help')

    subparsers.add_parser('dump', help='Dump raw hex values of all efuses')
    p = subparsers.add_parser(
        'summary', help='Print human-readable summary of efuse values')
    p.add_argument('--format',
                   help='Select the summary format',
                   choices=['summary', 'json'],
                   default='summary')
    p.add_argument('--file',
                   help='File to save the efuse summary',
                   type=argparse.FileType('w'),
                   default=sys.stdout)

    p = subparsers.add_parser('burn_efuse',
                              help='Burn the efuse with the specified name')
    p.add_argument('efuse_name',
                   help='Name of efuse register to burn',
                   choices=[efuse[0] for efuse in EFUSES])
    p.add_argument('new_value',
                   help='New value to burn (not needed for flag-type efuses',
                   nargs='?',
                   type=esptool.arg_auto_int)

    p = subparsers.add_parser(
        'read_protect_efuse',
        help='Disable readback for the efuse with the specified name')
    p.add_argument('efuse_name',
                   help='Name of efuse register to burn',
                   choices=[
                       efuse[0] for efuse in EFUSES if efuse[6] is not None
                   ])  # only allow if read_disable_bit is not None

    p = subparsers.add_parser(
        'write_protect_efuse',
        help='Disable writing to the efuse with the specified name')
    p.add_argument('efuse_name',
                   help='Name of efuse register to burn',
                   choices=[efuse[0] for efuse in EFUSES])

    p = subparsers.add_parser(
        'burn_key',
        help=
        'Burn a 256-bit AES key to EFUSE BLK1,BLK2 or BLK3 (flash_encryption, secure_boot).'
    )
    p.add_argument(
        '--no-protect-key',
        help='Disable default read- and write-protecting of the key. ' +
        'If this option is not set, once the key is flashed it cannot be read back or changed.',
        action='store_true')
    add_force_write_always(p)
    p.add_argument(
        'block',
        help='Key block to burn. "flash_encryption" is an alias for BLK1, ' +
        '"secure_boot" is an alias for BLK2.',
        choices=["secure_boot", "flash_encryption", "BLK1", "BLK2", "BLK3"])
    p.add_argument('keyfile',
                   help='File containing 256 bits of binary key data',
                   type=argparse.FileType('rb'))

    p = subparsers.add_parser(
        'burn_block_data',
        help="Burn non-key data to EFUSE BLK1, BLK2 or BLK3. " +
        " Don't use this command to burn key data for Flash Encryption or Secure Boot, "
        + "as the byte order of keys is swapped (use burn_key).")
    p.add_argument('--offset',
                   '-o',
                   help='Byte offset in the efuse block',
                   type=int,
                   default=0)
    add_force_write_always(p)
    p.add_argument('block',
                   help='Efuse block to burn.',
                   choices=["BLK1", "BLK2", "BLK3"])
    p.add_argument('datafile',
                   help='File containing data to burn into the efuse block',
                   type=argparse.FileType('rb'))

    p = subparsers.add_parser(
        'set_flash_voltage',
        help=
        'Permanently set the internal flash voltage regulator to either 1.8V, 3.3V or OFF. '
        +
        'This means GPIO12 can be high or low at reset without changing the flash voltage.'
    )
    p.add_argument('voltage',
                   help='Voltage selection',
                   choices=['1.8V', '3.3V', 'OFF'])

    p = subparsers.add_parser(
        'adc_info',
        help='Display information about ADC calibration data stored in efuse.')

    p = subparsers.add_parser(
        'burn_custom_mac',
        help='Burn a 48-bit Custom MAC Address to EFUSE BLK3.')
    p.add_argument(
        'mac',
        help=
        'Custom MAC Address to burn given in hexadecimal format with bytes separated by colons'
        + ' (e.g. AB:CD:EF:01:02:03).',
        type=mac_int)

    p = subparsers.add_parser('get_custom_mac',
                              help='Prints the Custom MAC Address.')

    args = parser.parse_args()
    print('espefuse.py v%s' % esptool.__version__)
    if args.operation is None:
        parser.print_help()
        parser.exit(1)

    # each 'operation' is a module-level function of the same name
    operation_func = globals()[args.operation]

    esp = esptool.ESP32ROM(args.port, baud=args.baud)
    esp.connect(args.before)

    # dict mapping register name to its efuse object
    efuses = EspEfuses(esp)
    operation_func(esp, efuses, args)
Esempio n. 17
0
def main():
    parser = argparse.ArgumentParser(
        description='efuse722.py v%s - Chip 7.2.2 efuse get/set tool' %
        esptool.__version__,
        prog='espefuse')

    parser.add_argument('--port',
                        '-p',
                        help='Serial port device',
                        default=os.environ.get('ESPTOOL_PORT',
                                               esptool.ESPLoader.DEFAULT_PORT))

    parser.add_argument('--before',
                        help='What to do before connecting to the chip',
                        choices=['default_reset', 'no_reset', 'esp32r1'],
                        default='default_reset')

    subparsers = parser.add_subparsers(
        dest='operation',
        help='Run espefuse.py {command} -h for additional help')

    subparsers.add_parser('dump', help='Dump raw hex values of all efuses')

    subparsers.add_parser('summary', help='Summary of all known efuse values')

    p = subparsers.add_parser('burn_efuse',
                              help='Burn the efuse with the specified name')
    p.add_argument('efuse_name',
                   help='Name of efuse register to burn',
                   choices=[efuse[0] for efuse in BLK0_EFUSES])
    p.add_argument('value',
                   help='New value to burn',
                   type=esptool.arg_auto_int)

    p = subparsers.add_parser(
        'burn_key', help='Burn the key block with the specified name')
    p.add_argument('file',
                   help='File to write (must be 32 bytes long)',
                   type=argparse.FileType('rb'))
    p.add_argument('key_block',
                   help='Number of key block to burn',
                   type=int,
                   choices=range(0, 7))
    p.add_argument('purpose', help='Purpose to set)', choices=KEY_PURPOSES)

    p = subparsers.add_parser(
        'burn_key_digest',
        help='Parse a RSA public key and burn the digest to key efuse block')
    p.add_argument('file',
                   help='Key file to digest (PEM format)',
                   type=argparse.FileType('r'))
    p.add_argument('key_block',
                   help='Number of key block to burn',
                   type=int,
                   choices=range(0, 7))
    p.add_argument('purpose', help='Purpose to set)', choices=KEY_PURPOSES)

    args = parser.parse_args()

    # each 'operation' is a module-level function of the same name
    operation_func = globals()[args.operation]

    esp = esptool.ESP32ROM(args.port)
    esp.connect(args.before)

    operation_func(esp, args)