iotsploit-drivers 0.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. iotsploit_drivers-0.0.6/PKG-INFO +53 -0
  2. iotsploit_drivers-0.0.6/README.md +28 -0
  3. iotsploit_drivers-0.0.6/pyproject.toml +33 -0
  4. iotsploit_drivers-0.0.6/src/iotsploit_drivers/__init__.py +1 -0
  5. iotsploit_drivers-0.0.6/src/iotsploit_drivers/esp32/__init__.py +0 -0
  6. iotsploit_drivers-0.0.6/src/iotsploit_drivers/esp32/drv_esp32.py +508 -0
  7. iotsploit_drivers-0.0.6/src/iotsploit_drivers/esp32/scpi_client.py +140 -0
  8. iotsploit_drivers-0.0.6/src/iotsploit_drivers/ft2232/__init__.py +0 -0
  9. iotsploit_drivers-0.0.6/src/iotsploit_drivers/ft2232/drv_ft2232.py +379 -0
  10. iotsploit_drivers-0.0.6/src/iotsploit_drivers/ft2232/protocol.py +168 -0
  11. iotsploit_drivers-0.0.6/src/iotsploit_drivers/greatfet/__init__.py +0 -0
  12. iotsploit_drivers-0.0.6/src/iotsploit_drivers/greatfet/drv_greatfet.py +365 -0
  13. iotsploit_drivers-0.0.6/src/iotsploit_drivers/greatfet/protocol.py +69 -0
  14. iotsploit_drivers-0.0.6/src/iotsploit_drivers/iotsploit_func_fpga/__init__.py +0 -0
  15. iotsploit_drivers-0.0.6/src/iotsploit_drivers/iotsploit_func_fpga/drv_iotsploit_fpga.py +405 -0
  16. iotsploit_drivers-0.0.6/src/iotsploit_drivers/jlink/__init__.py +0 -0
  17. iotsploit_drivers-0.0.6/src/iotsploit_drivers/jlink/drv_jlink.py +186 -0
  18. iotsploit_drivers-0.0.6/src/iotsploit_drivers/logic/__init__.py +5 -0
  19. iotsploit_drivers-0.0.6/src/iotsploit_drivers/logic/drv_logic.py +701 -0
  20. iotsploit_drivers-0.0.6/src/iotsploit_drivers/logic/protocol.py +526 -0
  21. iotsploit_drivers-0.0.6/src/iotsploit_drivers/socketcan/__init__.py +0 -0
  22. iotsploit_drivers-0.0.6/src/iotsploit_drivers/socketcan/drv_socketcan.py +290 -0
  23. iotsploit_drivers-0.0.6/src/iotsploit_drivers/ubertooth/__init__.py +1 -0
  24. iotsploit_drivers-0.0.6/src/iotsploit_drivers/ubertooth/drv_ubertooth.py +334 -0
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.3
2
+ Name: iotsploit-drivers
3
+ Version: 0.0.6
4
+ Summary: Official IoTSploit device driver package
5
+ License: GPL-3.0-or-later
6
+ Author: IoTSploit Team
7
+ Author-email: support@iotsploit.org
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: esptool (>=4.8)
16
+ Requires-Dist: iotsploit-core (>=0.0.6,<0.0.7)
17
+ Requires-Dist: pyftdi (>=0.55)
18
+ Requires-Dist: pylink-square (>=2.0)
19
+ Requires-Dist: pyserial (>=3.5)
20
+ Requires-Dist: python-can (>=4.5)
21
+ Requires-Dist: pyudev (>=0.24)
22
+ Requires-Dist: pyusb (>=1.2)
23
+ Description-Content-Type: text/markdown
24
+
25
+ # iotsploit-drivers
26
+
27
+ Official IoTSploit device driver package. Contains all built-in hardware drivers.
28
+
29
+ ## Included Drivers
30
+
31
+ | Driver | Module | Description |
32
+ |--------|--------|-------------|
33
+ | ESP32 | `iotsploit_drivers.esp32` | ESP32 device driver via SCPI |
34
+ | SocketCAN | `iotsploit_drivers.socketcan` | CAN bus driver via python-can |
35
+ | FT2232 | `iotsploit_drivers.ft2232` | FTDI FT2232 USB driver |
36
+ | GreatFET | `iotsploit_drivers.greatfet` | GreatFET One USB driver |
37
+ | Logic Analyzer | `iotsploit_drivers.logic` | Enxor logic analyzer driver |
38
+ | J-Link | `iotsploit_drivers.jlink` | SEGGER J-Link debug probe |
39
+ | Ubertooth | `iotsploit_drivers.ubertooth` | Ubertooth Bluetooth driver |
40
+ | FPGA | `iotsploit_drivers.iotsploit_func_fpga` | ECP5 FPGA driver |
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install iotsploit-drivers
46
+ ```
47
+
48
+ For development:
49
+
50
+ ```bash
51
+ pip install -e ./iotsploit-drivers
52
+ ```
53
+
@@ -0,0 +1,28 @@
1
+ # iotsploit-drivers
2
+
3
+ Official IoTSploit device driver package. Contains all built-in hardware drivers.
4
+
5
+ ## Included Drivers
6
+
7
+ | Driver | Module | Description |
8
+ |--------|--------|-------------|
9
+ | ESP32 | `iotsploit_drivers.esp32` | ESP32 device driver via SCPI |
10
+ | SocketCAN | `iotsploit_drivers.socketcan` | CAN bus driver via python-can |
11
+ | FT2232 | `iotsploit_drivers.ft2232` | FTDI FT2232 USB driver |
12
+ | GreatFET | `iotsploit_drivers.greatfet` | GreatFET One USB driver |
13
+ | Logic Analyzer | `iotsploit_drivers.logic` | Enxor logic analyzer driver |
14
+ | J-Link | `iotsploit_drivers.jlink` | SEGGER J-Link debug probe |
15
+ | Ubertooth | `iotsploit_drivers.ubertooth` | Ubertooth Bluetooth driver |
16
+ | FPGA | `iotsploit_drivers.iotsploit_func_fpga` | ECP5 FPGA driver |
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install iotsploit-drivers
22
+ ```
23
+
24
+ For development:
25
+
26
+ ```bash
27
+ pip install -e ./iotsploit-drivers
28
+ ```
@@ -0,0 +1,33 @@
1
+ [tool.poetry]
2
+ name = "iotsploit-drivers"
3
+ version = "0.0.6"
4
+ description = "Official IoTSploit device driver package"
5
+ authors = ["IoTSploit Team <support@iotsploit.org>"]
6
+ license = "GPL-3.0-or-later"
7
+ readme = "README.md"
8
+ packages = [{ include = "iotsploit_drivers", from = "src" }]
9
+
10
+ [tool.poetry.dependencies]
11
+ python = ">=3.10,<4.0"
12
+ iotsploit-core = "^0.0.6"
13
+ pyusb = ">=1.2"
14
+ python-can = ">=4.5"
15
+ pyserial = ">=3.5"
16
+ pyftdi = ">=0.55"
17
+ pylink-square = ">=2.0"
18
+ pyudev = ">=0.24"
19
+ esptool = ">=4.8"
20
+
21
+ [tool.poetry.plugins."iotsploit.device_drivers"]
22
+ drv_esp32 = "iotsploit_drivers.esp32.drv_esp32:ESP32Driver"
23
+ drv_socketcan = "iotsploit_drivers.socketcan.drv_socketcan:SocketCANDriver"
24
+ drv_ft2232 = "iotsploit_drivers.ft2232.drv_ft2232:FT2232Driver"
25
+ drv_greatfet = "iotsploit_drivers.greatfet.drv_greatfet:GreatFETDriver"
26
+ drv_jlink = "iotsploit_drivers.jlink.drv_jlink:JLinkAbility"
27
+ drv_ubertooth = "iotsploit_drivers.ubertooth.drv_ubertooth:UbertoothDriver"
28
+ drv_logic = "iotsploit_drivers.logic.drv_logic:EnxorLogicAnalyzerDriver"
29
+ drv_iotsploit_fpga = "iotsploit_drivers.iotsploit_func_fpga.drv_iotsploit_fpga:ECP5FPGADriver"
30
+
31
+ [build-system]
32
+ requires = ["poetry-core>=1.8.0"]
33
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1 @@
1
+ """Official IoTSploit device driver package."""
@@ -0,0 +1,508 @@
1
+ import logging
2
+ from typing import Optional, Dict, List
3
+ from iotsploit_core.domain.device import Device, DeviceType, SerialDevice
4
+ from iotsploit_core.core.base_plugin import BaseDeviceDriver
5
+ from .scpi_client import ScpiClient, ScpiSerialTransport
6
+ from iotsploit_core.core.tool_service import get_firmware_service
7
+ import time
8
+ import serial.tools.list_ports
9
+ from pathlib import Path
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class ESP32Driver(BaseDeviceDriver):
14
+ def __init__(self):
15
+ super().__init__()
16
+ self.transport = None
17
+ self.client = None
18
+ # Initialize firmware tool service
19
+ self.firmware_service = get_firmware_service()
20
+ # Define supported commands
21
+ self.supported_commands = {
22
+ "scan_wifi": "Scan for available WiFi networks",
23
+ "get_version": "Get device version",
24
+ "get_status": "Get device status",
25
+ "reset": "Reset the ESP32 device",
26
+ "start_wifi_monitor": "Start continuous WiFi monitoring",
27
+ "stop_wifi_monitor": "Stop continuous WiFi monitoring",
28
+ "flash_firmware": "Flash firmware to ESP32-S3 device",
29
+ "erase_flash": "Erase ESP32-S3 flash memory",
30
+ "get_chip_info": "Get ESP32-S3 chip information"
31
+ }
32
+
33
+ def get_auth_mode_str(self, auth_mode):
34
+ """Convert auth mode number to string description."""
35
+ auth_modes = {
36
+ 0: "OPEN",
37
+ 1: "WEP",
38
+ 2: "WPA_PSK",
39
+ 3: "WPA2_PSK",
40
+ 4: "WPA_WPA2_PSK",
41
+ 5: "WPA2_ENTERPRISE",
42
+ 6: "WPA3_PSK",
43
+ 7: "WPA2_WPA3_PSK"
44
+ }
45
+ return auth_modes.get(int(auth_mode), f"UNKNOWN({auth_mode})")
46
+
47
+ def _scan_wifi_networks(self) -> List[Dict]:
48
+ """Scan for WiFi networks and return formatted results."""
49
+ ap_list = self.client.query("WIFi:AP:LIST?", timeout=10.0)
50
+ if not ap_list or ap_list == "NO_AP_FOUND" or ap_list.startswith("ERROR"):
51
+ logger.info("No WiFi networks found or error response received from client")
52
+ return []
53
+
54
+ result = []
55
+ ap_entries = [ap for ap in ap_list.strip().split(';') if ap]
56
+ for ap in ap_entries:
57
+ try:
58
+ ssid, rssi, channel, auth = ap.split(',')
59
+ security = self.get_auth_mode_str(auth)
60
+ logger.info("Found WiFi Network: SSID: %s, RSSI: %s dBm, Channel: %s, Security: %s",
61
+ ssid, rssi, channel, security)
62
+ result.append({
63
+ "ssid": ssid,
64
+ "rssi": f"{rssi} dBm",
65
+ "channel": channel,
66
+ "security": security
67
+ })
68
+ except ValueError as e:
69
+ logger.error("Error parsing AP entry: %s - %s", ap, str(e))
70
+ return result
71
+
72
+ def _scan_impl(self) -> List[Device]:
73
+ """
74
+ Scan for available ESP32-S3 devices by checking all CP210x devices.
75
+ Returns the device with correct version number.
76
+ """
77
+ devices = []
78
+ # Find all CP210x devices
79
+ for port in serial.tools.list_ports.comports():
80
+ if "CP210" in port.description:
81
+ logger.info(f"Found CP210x device at {port.device}")
82
+ try:
83
+ # Try to connect and check version
84
+ temp_transport = ScpiSerialTransport(
85
+ port=port.device,
86
+ baudrate=115200,
87
+ timeout=1.0
88
+ )
89
+ temp_client = ScpiClient(temp_transport)
90
+ temp_client.connect()
91
+
92
+ try:
93
+ version = temp_client.get_version()
94
+ if version.strip() == "1.0.0":
95
+ logger.info(f"Found ESP32-S3 device at {port.device} with correct version")
96
+ devices.append(SerialDevice(
97
+ device_id="esp32s3_001",
98
+ name="ESP32-S3",
99
+ port=port.device,
100
+ baud_rate=115200,
101
+ attributes={
102
+ 'description': 'ESP32-S3 Development Board',
103
+ 'serial_number': port.serial_number,
104
+ 'chip': 'esp32s3'
105
+ }
106
+ ))
107
+ except Exception as e:
108
+ logger.debug(f"Not an ESP32-S3 device at {port.device}: {e}")
109
+
110
+ temp_client.close()
111
+ except Exception as e:
112
+ logger.debug(f"Failed to check device at {port.device}: {e}")
113
+ continue
114
+
115
+ if not devices:
116
+ logger.warning("No ESP32-S3 devices found")
117
+ return devices
118
+
119
+ def _initialize_impl(self, device: SerialDevice) -> bool:
120
+ """
121
+ Initialize the ESP32-S3 device using SCPI over serial.
122
+ """
123
+ if device.device_type != DeviceType.Serial:
124
+ raise ValueError("This plugin only supports serial devices")
125
+
126
+ logger.info(f"Initializing ESP32-S3 device on port {device.port}")
127
+ try:
128
+ self.transport = ScpiSerialTransport(
129
+ port=device.port,
130
+ baudrate=device.baud_rate,
131
+ timeout=1.0
132
+ )
133
+ self.client = ScpiClient(self.transport)
134
+ logger.info("ESP32-S3 device initialized successfully")
135
+ return True
136
+ except Exception as e:
137
+ logger.error(f"Failed to initialize ESP32-S3 device: {e}")
138
+ raise
139
+
140
+ def _connect_impl(self, device: SerialDevice) -> bool:
141
+ """
142
+ Connect to the ESP32-S3 device using SCPI client.
143
+ """
144
+ if not self.client:
145
+ logger.error("Device not initialized. Please initialize first.")
146
+ raise RuntimeError("Device not initialized")
147
+
148
+ try:
149
+ self.client.connect()
150
+ version = self.client.get_version()
151
+ status = self.client.get_status()
152
+ logger.info(f"ESP32-S3 device connected successfully. Version: {version}, Status: {status}")
153
+ return True
154
+ except Exception as e:
155
+ logger.error(f"Failed to connect to ESP32-S3 device: {e}")
156
+ raise
157
+
158
+ def _acquisition_loop(self):
159
+ """Continuous WiFi scanning loop."""
160
+ while self.is_acquiring.is_set():
161
+ try:
162
+ wifi_list = self._scan_wifi_networks()
163
+ # Send data through stream manager
164
+ if wifi_list:
165
+ for device_id in self._devices:
166
+ self.stream_wrapper.broadcast_data(device_id, {
167
+ "type": "wifi_scan",
168
+ "timestamp": time.time(),
169
+ "data": wifi_list
170
+ })
171
+ except Exception as e:
172
+ logger.error(f"Error in WiFi scanning loop: {e}")
173
+ time.sleep(5) # Scan every 5 seconds
174
+
175
+ # --- Optimized command dispatch below ---
176
+
177
+ def _handle_scan_wifi(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
178
+ wifi_list = self._scan_wifi_networks()
179
+ return {
180
+ "networks": wifi_list
181
+ }
182
+
183
+ def _handle_start_wifi_monitor(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
184
+ if not self.is_acquiring.is_set():
185
+ self.start_streaming(device)
186
+ return "WiFi monitoring started"
187
+
188
+ def _handle_stop_wifi_monitor(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
189
+ if self.is_acquiring.is_set():
190
+ self.stop_streaming(device)
191
+ return "WiFi monitoring stopped"
192
+
193
+ def _handle_get_version(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
194
+ return self.client.get_version()
195
+
196
+ def _handle_get_status(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
197
+ return self.client.get_status()
198
+
199
+ def _handle_reset(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
200
+ self.client.send_command("*RST")
201
+ return "Device reset successfully"
202
+
203
+ def _handle_flash_firmware(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
204
+ """
205
+ Flash firmware to ESP32-S3 device using ESP32Programmer
206
+ """
207
+ try:
208
+ # Check if esptool is available
209
+ if not self.firmware_service.esp32.is_tool_available('esptool'):
210
+ error_msg = "esptool is not available. Please install it: pip install esptool"
211
+ logger.error(error_msg)
212
+ return {"status": "error", "message": error_msg}
213
+
214
+ # Get firmware name from args or use default
215
+ firmware_name = args.get('firmware_name', 'esp32s3_wifi_penetration_tool') if args else 'esp32s3_wifi_penetration_tool'
216
+
217
+ # Try to get firmware from the centralized manifest
218
+ firmware_info = self.firmware_service.get_firmware_info(firmware_name)
219
+
220
+ if not firmware_info:
221
+ error_msg = f"Firmware '{firmware_name}' not found in manifest"
222
+ logger.error(error_msg)
223
+ return {"status": "error", "message": error_msg}
224
+
225
+ # Get flash options from firmware config
226
+ flash_options = firmware_info.get('flash_options', {})
227
+
228
+ # Get port, chip, and baud from args or flash options or defaults
229
+ port = args.get('port') if args else None
230
+ port = port or flash_options.get('port', '/dev/ttyACM2')
231
+
232
+ chip = args.get('chip') if args else None
233
+ chip = chip or flash_options.get('chip', 'esp32s3')
234
+
235
+ baud = args.get('baud') if args else None
236
+ baud = baud or flash_options.get('baud', '460800')
237
+
238
+ # Check if this firmware has a files array for multi-file flashing
239
+ if 'files' in flash_options:
240
+ # Use the files from the firmware configuration
241
+ files = flash_options['files']
242
+ logger.info(f"Using multi-file configuration from manifest: {len(files)} files")
243
+
244
+ # Verify all files exist
245
+ for file_entry in files:
246
+ file_path = file_entry['path']
247
+ if not Path(file_path).exists():
248
+ error_msg = f"Firmware file not found: {file_path}"
249
+ logger.error(error_msg)
250
+ return {"status": "error", "message": error_msg}
251
+
252
+ logger.info(f"Flashing ESP32-S3 firmware '{firmware_name}' to {port}...")
253
+ logger.info(f"Files to flash: {len(files)} files")
254
+
255
+ # Flash all files in one operation using the ESP32 programmer
256
+ result = self.firmware_service.esp32.flash_multi(
257
+ port=port,
258
+ files=files,
259
+ chip=chip,
260
+ baud=baud,
261
+ flash_mode=flash_options.get('flash_mode', 'dio'),
262
+ flash_freq=flash_options.get('flash_freq', '80m'),
263
+ flash_size=flash_options.get('flash_size', '2MB')
264
+ )
265
+ else:
266
+ # Single file flashing
267
+ firmware_path = firmware_info['path']
268
+ if not Path(firmware_path).exists():
269
+ error_msg = f"Firmware file not found: {firmware_path}"
270
+ logger.error(error_msg)
271
+ return {"status": "error", "message": error_msg}
272
+
273
+ logger.info(f"Flashing ESP32-S3 single firmware '{firmware_name}' to {port}...")
274
+
275
+ result = self.firmware_service.esp32.flash_single(
276
+ port=port,
277
+ firmware_path=firmware_path,
278
+ address=flash_options.get('address', '0x10000'),
279
+ chip=chip,
280
+ baud=baud
281
+ )
282
+
283
+ if result.success:
284
+ success_msg = f"ESP32-S3 firmware '{firmware_name}' flashed successfully in {result.execution_time:.2f}s"
285
+ logger.info(success_msg)
286
+ return {
287
+ "status": "success",
288
+ "message": success_msg,
289
+ "execution_time": result.execution_time,
290
+ "firmware_name": firmware_name
291
+ }
292
+ else:
293
+ error_msg = f"Failed to flash firmware '{firmware_name}': {result.stderr or 'Unknown error'}"
294
+ logger.error(error_msg)
295
+ return {
296
+ "status": "error",
297
+ "message": error_msg,
298
+ "return_code": result.return_code,
299
+ "stderr": result.stderr
300
+ }
301
+
302
+ except Exception as e:
303
+ error_msg = f"Error flashing ESP32-S3 firmware: {str(e)}"
304
+ logger.error(error_msg)
305
+ return {"status": "error", "message": error_msg}
306
+
307
+ def _handle_erase_flash(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
308
+ """
309
+ Erase ESP32-S3 flash memory using ESP32Programmer
310
+ """
311
+ try:
312
+ if not self.firmware_service.esp32.is_tool_available('esptool'):
313
+ error_msg = "esptool is not available. Please install it: pip install esptool"
314
+ logger.error(error_msg)
315
+ return {"status": "error", "message": error_msg}
316
+
317
+ # Get port from args or use default
318
+ port = args.get('port', '/dev/ttyACM2') if args else '/dev/ttyACM2'
319
+ chip = args.get('chip', 'esp32s3') if args else 'esp32s3'
320
+ baud = args.get('baud', '460800') if args else '460800'
321
+
322
+ logger.info(f"Erasing ESP32-S3 flash on {port}...")
323
+
324
+ result = self.firmware_service.esp32.erase_flash(
325
+ port=port,
326
+ chip=chip,
327
+ baud=baud
328
+ )
329
+
330
+ if result.success:
331
+ success_msg = f"ESP32-S3 flash erased successfully in {result.execution_time:.2f}s"
332
+ logger.info(success_msg)
333
+ return {
334
+ "status": "success",
335
+ "message": success_msg,
336
+ "execution_time": result.execution_time
337
+ }
338
+ else:
339
+ error_msg = f"Failed to erase flash: {result.stderr or 'Unknown error'}"
340
+ logger.error(error_msg)
341
+ return {
342
+ "status": "error",
343
+ "message": error_msg,
344
+ "return_code": result.return_code,
345
+ "stderr": result.stderr
346
+ }
347
+
348
+ except Exception as e:
349
+ error_msg = f"Error erasing ESP32-S3 flash: {str(e)}"
350
+ logger.error(error_msg)
351
+ return {"status": "error", "message": error_msg}
352
+
353
+ def _handle_get_chip_info(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
354
+ """
355
+ Get ESP32-S3 chip information using ESP32Programmer
356
+ """
357
+ try:
358
+ if not self.firmware_service.esp32.is_tool_available('esptool'):
359
+ error_msg = "esptool is not available. Please install it: pip install esptool"
360
+ logger.error(error_msg)
361
+ return {"status": "error", "message": error_msg}
362
+
363
+ # Get port from args or use default
364
+ port = args.get('port', '/dev/ttyACM2') if args else '/dev/ttyACM2'
365
+ baud = args.get('baud', '460800') if args else '460800'
366
+
367
+ logger.info(f"Getting ESP32-S3 chip info from {port}...")
368
+
369
+ result = self.firmware_service.esp32.get_chip_info(
370
+ port=port,
371
+ baud=baud
372
+ )
373
+
374
+ if result.success:
375
+ success_msg = f"ESP32-S3 chip info retrieved successfully"
376
+ logger.info(success_msg)
377
+ return {
378
+ "status": "success",
379
+ "message": success_msg,
380
+ "chip_info": result.stdout,
381
+ "execution_time": result.execution_time
382
+ }
383
+ else:
384
+ error_msg = f"Failed to get chip info: {result.stderr or 'Unknown error'}"
385
+ logger.error(error_msg)
386
+ return {
387
+ "status": "error",
388
+ "message": error_msg,
389
+ "return_code": result.return_code,
390
+ "stderr": result.stderr
391
+ }
392
+
393
+ except Exception as e:
394
+ error_msg = f"Error getting ESP32-S3 chip info: {str(e)}"
395
+ logger.error(error_msg)
396
+ return {"status": "error", "message": error_msg}
397
+
398
+ def _command_impl(self, device: SerialDevice, command: str, args: Optional[Dict] = None) -> Optional[str]:
399
+ """
400
+ Execute commands on the ESP32-S3 device using SCPI.
401
+ Uses a dictionary dispatch for cleaner code.
402
+ """
403
+ if not self.client and command != "flash_firmware":
404
+ logger.error("Cannot send command: ESP32-S3 device not connected")
405
+ raise RuntimeError("Device not connected")
406
+
407
+ command_map = {
408
+ "scan_wifi": self._handle_scan_wifi,
409
+ "start_wifi_monitor": self._handle_start_wifi_monitor,
410
+ "stop_wifi_monitor": self._handle_stop_wifi_monitor,
411
+ "get_version": self._handle_get_version,
412
+ "get_status": self._handle_get_status,
413
+ "reset": self._handle_reset,
414
+ "flash_firmware": self._handle_flash_firmware,
415
+ "erase_flash": self._handle_erase_flash,
416
+ "get_chip_info": self._handle_get_chip_info
417
+ }
418
+
419
+ try:
420
+ handler = command_map.get(command)
421
+ if handler is None:
422
+ logger.error(f"Unknown command: {command}")
423
+ return f"Unknown command: {command}"
424
+ return handler(device, args)
425
+ except Exception as e:
426
+ logger.error(f"Error executing command {command}: {e}")
427
+ raise
428
+
429
+ def _reset_impl(self, device: SerialDevice) -> bool:
430
+ """
431
+ Reset the ESP32-S3 device using SCPI *RST command.
432
+ """
433
+ try:
434
+ if self.client:
435
+ self.client.send_command("*RST")
436
+ logger.info("ESP32-S3 device reset successfully")
437
+ return True
438
+ return False
439
+ except Exception as e:
440
+ logger.error(f"Failed to reset ESP32-S3 device: {e}")
441
+ raise
442
+
443
+ def _close_impl(self, device: SerialDevice) -> bool:
444
+ """
445
+ Close the connection to the ESP32-S3 device.
446
+ """
447
+ try:
448
+ if self.is_acquiring.is_set():
449
+ self.stop_streaming(device)
450
+ if self.client:
451
+ self.client.close()
452
+ self.transport = None
453
+ self.client = None
454
+ logger.info("ESP32-S3 device closed successfully")
455
+ return True
456
+ except Exception as e:
457
+ logger.error(f"Failed to close ESP32-S3 device: {e}")
458
+ raise
459
+
460
+ def _setup_acquisition(self, device: Device):
461
+ """Setup for WiFi monitoring."""
462
+ logger.info(f"Setting up WiFi monitoring for device {device.device_id}")
463
+
464
+ def _cleanup_acquisition(self, device: Device):
465
+ """Cleanup after WiFi monitoring."""
466
+ logger.info(f"Cleaning up WiFi monitoring for device {device.device_id}")
467
+
468
+
469
+ if __name__ == "__main__":
470
+ logging.basicConfig(level=logging.INFO)
471
+
472
+ driver = ESP32Driver()
473
+ devices = driver.scan()
474
+
475
+ if devices:
476
+ test_device = devices[0]
477
+ print(f"ESP32-S3 Device Found: {test_device}")
478
+
479
+ try:
480
+ if driver.initialize(test_device):
481
+ if driver.connect(test_device):
482
+ print("Device connected successfully")
483
+
484
+ # Test flash firmware command
485
+ result = driver.command(test_device, "flash_firmware")
486
+ print(f"Flash firmware result: {result}")
487
+
488
+ # Start WiFi monitoring
489
+ result = driver.command(test_device, "start_wifi_monitor")
490
+ print(result)
491
+
492
+ # Let it run for 30 seconds
493
+ time.sleep(30)
494
+
495
+ # Stop WiFi monitoring
496
+ result = driver.command(test_device, "stop_wifi_monitor")
497
+ print(result)
498
+
499
+ if driver.close(test_device):
500
+ print("Device closed successfully")
501
+ else:
502
+ print("Failed to close device")
503
+ else:
504
+ print("Failed to connect to device")
505
+ except Exception as ex:
506
+ print(f"Error during device operation: {ex}")
507
+ else:
508
+ print("No ESP32-S3 devices found")