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.
- iotsploit_drivers-0.0.6/PKG-INFO +53 -0
- iotsploit_drivers-0.0.6/README.md +28 -0
- iotsploit_drivers-0.0.6/pyproject.toml +33 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/__init__.py +1 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/esp32/__init__.py +0 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/esp32/drv_esp32.py +508 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/esp32/scpi_client.py +140 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/ft2232/__init__.py +0 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/ft2232/drv_ft2232.py +379 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/ft2232/protocol.py +168 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/greatfet/__init__.py +0 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/greatfet/drv_greatfet.py +365 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/greatfet/protocol.py +69 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/iotsploit_func_fpga/__init__.py +0 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/iotsploit_func_fpga/drv_iotsploit_fpga.py +405 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/jlink/__init__.py +0 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/jlink/drv_jlink.py +186 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/logic/__init__.py +5 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/logic/drv_logic.py +701 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/logic/protocol.py +526 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/socketcan/__init__.py +0 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/socketcan/drv_socketcan.py +290 -0
- iotsploit_drivers-0.0.6/src/iotsploit_drivers/ubertooth/__init__.py +1 -0
- 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."""
|
|
File without changes
|
|
@@ -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")
|