1.. _execute-scripts-cmd:
2
3Execute Scripts
4===============
5
6The ``espefuse.py execute_scripts`` command executes scripts to burn at one time.
7
8Positional arguments:
9
10- ``scripts`` - it is special format of python scripts (receives list of files, like script1.py script2.py etc.).
11
12Optional arguments:
13
14- ``--index`` - integer index. It allows to retrieve unique data per chip from configfiles and then burn them (ex. CUSTOM_MAC, UNIQUE_ID).
15- ``--configfiles`` - List of configfiles with data (receives list of configfiles, like configfile1.py configfile2.py etc.).
16
17.. code-block:: none
18
19    > espefuse.py execute_scripts efuse_script1.py efuse_script2.py ...
20
21This command allows burning all needed efuses at one time based on your own python script and control issues during the burn process if so it will abort the burn process. This command has a few arguments:
22
23*  ``scripts`` is a list of scripts. The special format of python scripts can be executed inside ``espefuse.py``.
24*  ``--index`` integer index (it means the number of chip in the batch in the range 1 - the max number of chips in the batch). It allows to retrieve unique data per chip from configfiles and then burn them (ex. CUSTOM_MAC, UNIQUE_ID).
25*  ``--configfiles`` List of configfiles with data.
26
27Below you can see some examples of the script. This script file is run from ``espefuse.py`` as ``exec(open(file.name).read())`` it means that some functions and imported libs are available for using like ``os``. Please use only provided functions.
28If you want to use other libs in the script you can add them manually.
29
30Inside this script, you can call all commands which are available in CLI, see ``espefuse.py --help``. To run a efuse command you need to call ``espefuse(esp, efuses, args, 'burn_efuse DISABLE_DL_DECRYPT 1')``. This command will not burn eFuses immediately, the burn occurs at the end of all scripts.
31If necessary, you can call ``efuses.burn_all()`` which prompts ``Type 'BURN' (all capitals) to continue.``. To skip this check and go without confirmation just add the ``--do-not-confirm`` flag to the ``execute_scripts`` command.
32
33This command supports nesting. This means that one script can be called from another script (see the test case ``test_execute_scripts_nesting`` in ``esptool/test/test_espefuse.py``).
34
35.. code-block:: none
36
37    > espefuse.py execute_scripts efuse_script1.py --do-not-confirm
38
39Additionally, you can implement some checks based on the value of efuses. To get value of an efuse use ``efuses['FLASH_CRYPT_CNT'].get()``. Some eFuses have a dictionary to convert from a value to a human-readable as it looks in the table is printed by the ``summary`` command.
40See how it is done (for ESP32) for ``CODING_SCHEME`` when ``get_meaning()`` is called:
41
42* 0: ``NONE (BLK1-3 len=256 bits)``
43* 1: ``3/4 (BLK1-3 len=192 bits)``
44* 2: ``REPEAT (BLK1-3 len=128 bits) not supported``
45* 3: ``NONE (BLK1-3 len=256 bits)``
46
47.. code:: python
48
49    print("connected chip: %s, coding scheme %s" % (esp.get_chip_description(), efuses["CODING_SCHEME"].get_meaning()))
50    if os.path.exists("flash_encryption_key.bin"):
51        espefuse(esp, efuses, args, "burn_key flash_encryption flash_encryption_key.bin")
52    else:
53        raise esptool.FatalError("The 'flash_encryption_key.bin' file is missing in the project directory")
54
55    espefuse(esp, efuses, args, 'burn_efuse FLASH_CRYPT_CNT 0x7')
56
57    current_flash_crypt_cnt = efuses['FLASH_CRYPT_CNT'].get()
58    if current_flash_crypt_cnt in [0, 3]:
59        espefuse(esp, efuses, args, 'burn_efuse FLASH_CRYPT_CNT')
60
61    espefuse(esp, efuses, args, 'burn_efuse DISABLE_DL_ENCRYPT 1')
62
63    espefuse(esp, efuses, args, 'burn_efuse DISABLE_DL_DECRYPT 1')
64
65    espefuse(esp, efuses, args, 'burn_efuse DISABLE_DL_CACHE 1')
66
67    espefuse(esp, efuses, args, 'burn_efuse JTAG_DISABLE 1')
68    ...
69
70After ``efuses.burn_all()``, all needed efuses will be burnt to chip in order ``BLK_MAX`` to ``BLK_0``. This order prevents cases when protection is set before the value goes to a block. Please note this while developing your scripts.
71Upon completion, the new eFuses will be read back, and will be done some checks of written eFuses by ``espefuse.py``. In production, you might need to check that all written efuses are set properly, see the example below.
72
73The script `execute_efuse_script.py <https://github.com/espressif/esptool/blob/master/test/efuse_scripts/esp32xx/execute_efuse_script.py>`__ burns some efuses and checks them after reading back. To check read and write protection, ``is_readable()`` and ``is_writeable()`` are called.
74
75Burn Unique Data Per Chip
76^^^^^^^^^^^^^^^^^^^^^^^^^
77
78In case you are running the ``execute_scripts`` command from your production script, you may need to pass ``index`` to get the unique data for each chip from the ``configfiles`` (* .txt, * .json, etc.). The espefuse command will be like this, where ``{index}`` means the number of chip in the batch, you increment it by your own script in the range 1 - the max number of chips in the batch:
79
80.. code-block:: none
81
82    espefuse.py execute_scripts efuse_script2.py --do-not-confirm --index {index} --configfiles mac_addresses.json  unique_id.json
83
84The example of a script to burn custom_mac address and unique_id getting them from configfiles.
85
86.. code:: python
87
88    # efuse_script2.py
89
90    mac_addresses = json.load(args.configfiles[0])
91    unique_id = json.load(args.configfiles[1])
92
93    mac_val = mac_addresses[str(args.index)]
94    cmd = 'burn_custom_mac {}'.format(mac_val)
95    print(cmd)
96    espefuse(esp, efuses, args, cmd)
97
98    unique_id_val = unique_id[str(args.index)]
99    cmd = 'burn_efuse UNIQUE_ID {}'.format(unique_id_val)
100    print(cmd)
101    espefuse(esp, efuses, args, cmd)
102
103The example of a script to burn custom_mac address that generated right in the script.
104
105.. code:: python
106
107    # efuse_script2.py
108
109    step = 4
110    base_mac = '0xAABBCCDD0000'
111    mac = ''
112    for index in range(100):
113        mac = "{:012X}".format(int(base_mac, 16) + (args.index - 1) * step)
114        mac = ':'.join(mac[k] + mac [k + 1] for k in range(0, len(mac), 2))
115        break
116
117    cmd = 'burn_custom_mac mac'
118    print(cmd)
119    espefuse(esp, efuses, args, cmd)
120