11import  asyncio 
2+ import  binascii 
23import  logging 
34import  os 
45import  shlex 
56import  socket 
67import  typing  as  t 
8+ from  dataclasses  import  dataclass 
79
810from  pytest_embedded .log  import  DuplicateStdoutPopen 
911from  qemu .qmp  import  QMPClient 
1416    from  .app  import  QemuApp 
1517
1618
19+ @dataclass  
20+ class  QemuTarget :
21+     strap_mode : str 
22+     default_efuse : bytes 
23+ 
24+ 
25+ QEMU_TARGETS : dict [str , QemuTarget ] =  {
26+     'esp32' : QemuTarget (
27+         strap_mode = '0x0F' ,
28+         default_efuse = binascii .unhexlify (
29+             '00000000000000000000000000800000000000000000100000000000000000000000000000000000' 
30+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
31+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
32+             '00000000' 
33+         ),
34+     ),
35+     'esp32c3' : QemuTarget (
36+         strap_mode = '0x02' ,
37+         default_efuse = binascii .unhexlify (
38+             '00000000000000000000000000000000000000000000000000000000000000000000000000000c00' 
39+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
40+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
41+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
42+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
43+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
44+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
45+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
46+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
47+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
48+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
49+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
50+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
51+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
52+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
53+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
54+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
55+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
56+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
57+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
58+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
59+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
60+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
61+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
62+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
63+             '000000000000000000000000000000000000000000000000' 
64+         ),
65+     ),
66+     'esp32s3' : QemuTarget (
67+         strap_mode = '0x07' ,
68+         default_efuse = binascii .unhexlify (
69+             '00000000000000000000000000000000000000000000000000000000000000000000000000000c00' 
70+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
71+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
72+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
73+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
74+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
75+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
76+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
77+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
78+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
79+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
80+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
81+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
82+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
83+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
84+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
85+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
86+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
87+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
88+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
89+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
90+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
91+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
92+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
93+             '00000000000000000000000000000000000000000000000000000000000000000000000000000000' 
94+             '000000000000000000000000000000000000000000000000' 
95+         ),
96+     ),
97+ }
98+ 
99+ 
17100class  Qemu (DuplicateStdoutPopen ):
18101    """ 
19102    QEMU class 
@@ -26,9 +109,7 @@ class Qemu(DuplicateStdoutPopen):
26109    QEMU_DEFAULT_ARGS  =  '-nographic -machine esp32' 
27110    QEMU_DEFAULT_FMT  =  '-nographic -machine {}' 
28111
29-     QEMU_STRAP_MODE_FMT  =  '-global driver=esp32.gpio,property=strap_mode,value={}' 
30-     QEMU_SERIAL_TCP_FMT  =  '-serial tcp::{},server,nowait' 
31- 
112+     QEMU_STRAP_MODE_FMT  =  'driver={}.gpio,property=strap_mode,value={}' 
32113    QEMU_DEFAULT_QMP_FMT  =  '-qmp tcp:127.0.0.1:{},server,wait=off' 
33114
34115    def  __init__ (
@@ -37,6 +118,7 @@ def __init__(
37118        qemu_prog_path : str  |  None  =  None ,
38119        qemu_cli_args : str  |  None  =  None ,
39120        qemu_extra_args : str  |  None  =  None ,
121+         qemu_efuse_path : str  |  None  =  None ,
40122        app : t .Optional ['QemuApp' ] =  None ,
41123        ** kwargs ,
42124    ):
@@ -55,11 +137,28 @@ def __init__(
55137
56138        qemu_prog_path  =  qemu_prog_path  or  self .qemu_prog_name 
57139
140+         self .current_qemu_executable_path  =  qemu_prog_path 
141+         self .image_path  =  image_path 
142+         self .efuse_path  =  qemu_efuse_path 
143+ 
58144        if  qemu_cli_args :
59145            qemu_cli_args  =  qemu_cli_args .strip ('"' ).strip ("'" )
60146        qemu_cli_args  =  shlex .split (qemu_cli_args  or  self .qemu_default_args )
61147        qemu_extra_args  =  shlex .split (qemu_extra_args  or  '' )
62148
149+         if  self .efuse_path :
150+             logging .debug ('The eFuse file will be saved to: %s' , self .efuse_path )
151+             with  open (self .efuse_path , 'wb' ) as  f :
152+                 f .write (QEMU_TARGETS [self .app .target ].default_efuse )
153+             qemu_extra_args  +=  [
154+                 '-global' ,
155+                 self .QEMU_STRAP_MODE_FMT .format (self .app .target , QEMU_TARGETS [self .app .target ].strap_mode ),
156+                 '-drive' ,
157+                 f'file={ self .efuse_path }  ,if=none,format=raw,id=efuse' ,
158+                 '-global' ,
159+                 f'driver=nvram.{ self .app .target }  .efuse,property=drive,value=efuse' ,
160+             ]
161+ 
63162        self .qmp_addr  =  None 
64163        self .qmp_port  =  None 
65164
@@ -87,6 +186,49 @@ def __init__(
87186            ** kwargs ,
88187        )
89188
189+     def  execute_efuse_command (self , command : str ):
190+         import  espefuse 
191+         import  pexpect 
192+ 
193+         with  socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as  s :
194+             s .bind (('127.0.0.1' , 0 ))
195+             _ , available_port  =  s .getsockname ()
196+ 
197+         run_qemu_command  =  [
198+             '-nographic' ,
199+             '-machine' ,
200+             self .app .target ,
201+             '-drive' ,
202+             f'file={ self .image_path }  ,if=mtd,format=raw' ,
203+             '-global' ,
204+             self .QEMU_STRAP_MODE_FMT .format (self .app .target , QEMU_TARGETS [self .app .target ].strap_mode ),
205+             '-drive' ,
206+             f'file={ self .efuse_path }  ,if=none,format=raw,id=efuse' ,
207+             '-global' ,
208+             f'driver=nvram.{ self .app .target }  .efuse,property=drive,value=efuse' ,
209+             '-serial' ,
210+             f'tcp::{ available_port }  ,server,nowait' ,
211+         ]
212+         try :
213+             child  =  pexpect .spawn (self .current_qemu_executable_path , run_qemu_command )
214+             res  =  shlex .split (command )
215+             child .expect ('qemu' )
216+ 
217+             res  =  [r  for  r  in  res  if  r  !=  '--do-not-confirm' ]
218+             espefuse .main (
219+                 [
220+                     '--port' ,
221+                     f'socket://localhost:{ available_port }  ' ,
222+                     '--before' ,
223+                     'no_reset' ,
224+                     '--do-not-confirm' ,
225+                     * res ,
226+                 ]
227+             )
228+             self ._hard_reset ()
229+         finally :
230+             child .terminate ()
231+ 
90232    @property  
91233    def  qemu_prog_name (self ):
92234        if  self .app :
0 commit comments