esp32_bluetooth_classic_sni.../libs/ESP32BTDriver.py
Matheus Eduardo Garbelini c1fc3f84e3 Step 1 Update
2021-09-06 09:45:23 +08:00

197 lines
6.1 KiB
Python
Executable file

import binascii
import os
import sys
import pty
import subprocess
import serial
import tty
import time
import ctypes
import serial.tools.list_ports
from threading import Thread
from binascii import hexlify, unhexlify
from colorama import Fore
from time import sleep
from firmware import reset_firmware
class ConnectionStatus(ctypes.LittleEndianStructure):
_fields_ = [
("clock", ctypes.c_uint32, 8 * 4),
("channel", ctypes.c_uint8, 8),
("ptt", ctypes.c_uint8, 1),
("role", ctypes.c_uint8, 1),
("custom_lmp", ctypes.c_uint8, 1),
("retry_flag", ctypes.c_uint8, 1),
("intercept_req", ctypes.c_uint8, 1),
("tx_encrypted", ctypes.c_uint8, 1),
("rx_encrypted", ctypes.c_uint8, 1),
("is_eir", ctypes.c_uint8, 1),
]
def getdict(self):
return dict((f, getattr(self, f)) for f, _, _ in self._fields_)
# USB Serial commands
ESP32_CMD_DATA_RX = b'\xA7'
ESP32_CMD_DATA_TX = b'\xBB'
ESP32_CMD_CHECKSUM_ERROR = b'\xA8'
ESP32_CMD_CONFIG_AUTO_EMPTY_PDU = b'\xA9'
ESP32_CMD_CONFIG_ACK = b'\xAA'
ESP32_CMD_CONFIG_LOG_TX = b'\xCC'
ESP32_CMD_LOG = b'\x7F'
ESP32_CMD_RESET = b'\x86'
ESP32_CMD_VERSION = b'\xEE'
ESP32_CMD_ENABLE_LMP_SNIFFING = b'\x81'
ESP32_CMD_SET_BDADDR = b'\x87'
ESP32_CMD_DISABLE_POLL_NULL = b'\x89'
# HCI Codes to bridge
H4_NONE = b'\x00'
H4_CMD = b'\x01'
H4_ACL = b'\x02'
H4_SCO = b'\x03'
H4_EVT = b'\x04'
H4_EVT_HW_ERROR = b'\x10'
# Driver class
class ESP32BTDriver:
event_counter = 0
direction = None
version = None
status = None # type: ConnectionStatus
serial_bridge = None
serial_bridge_name = None
serial_hci_thread = None
serial_baudrate = 921600
serial_portname = None
# Constructor ------------------------------------
def __init__(self, port_name=None, baudrate=921600, reset_board=True,
debug=False):
self.serial_portname = port_name
self.serial_baudrate = baudrate
if reset_board:
# Reset ESP32 board to endure clean session
self.reset_firmware()
self.serial = serial.Serial(
port_name, baudrate, rtscts=0, xonxoff=0, timeout=1)
self.get_version()
os.system("setserial %s low_latency >/dev/null" %
(self.serial_portname))
master, slave = pty.openpty()
self.serial_bridge_name = os.ttyname(slave)
self.serial_bridge = master
tty.setraw(master)
tty.setraw(slave)
print(Fore.GREEN + 'HCI Bridge started on ' + os.ttyname(slave))
self.serial_hci_thread = Thread(target=self.hci_handler)
self.serial_hci_thread.daemon = True
self.serial_hci_thread.start()
def close(self):
print('ESP32 Driver closed')
def reset_firmware(self, wait_reset=True, soft_reset=False):
if soft_reset is False:
try:
import serial
except:
print("[ERROR] pyserial module not found, installing now via pip...")
os.system(sys.executable +
' -m pip install pyserial --upgrade')
os.sync()
# We should have pyserial installed here
import serial
ser = serial.Serial(self.serial_portname, self.serial_baudrate,
rtscts=False, dsrdtr=False)
ser.rts = True
ser.dtr = True
ser.dtr = False
ser.dtr = True
ser.close()
ser = None
print('[!] Reset Done! EN pin toggled HIGH->LOW->HIGH')
else:
self.serial.write(ESP32_CMD_RESET + bytearray([0x86, 0xAA]))
if wait_reset:
print('[!] Waiting 0.8s...')
sleep(0.8)
# UART functions ---------------------------
def get_version(self):
self.serial.write(ESP32_CMD_VERSION)
version_string = self.serial.readline()
if version_string and len(version_string):
self.version = version_string.decode('utf-8').split('\n')[0]
print("[ESP32BT] Firmware version: " + self.version)
else:
raise Exception(
"Version not received. Make sure to flash ESP32BT firmware")
def enable_sniffing(self, val):
self.serial.write(ESP32_CMD_ENABLE_LMP_SNIFFING + bytearray([val]))
def disable_poll_null(self, val):
self.serial.write(ESP32_CMD_DISABLE_POLL_NULL + bytearray([val]))
self.serial.read(1)
def set_bdaddr(self, value):
addr = unhexlify(''.join(value.split(':')[::-1]))
self.serial.write(ESP32_CMD_SET_BDADDR + addr)
def hci_handler(self):
while True:
c = os.read(self.serial_bridge, 1)
self.serial.write(c)
def receive(self):
cmd = self.serial.read(1)
if cmd == H4_EVT:
opcode = self.serial.read(1)
length = self.serial.read(1)
payload = self.serial.read(ord(length))
os.write(self.serial_bridge, H4_EVT + opcode + length + payload)
elif cmd == H4_ACL:
opcode = self.serial.read(2)
length = self.serial.read(2)
payload = self.serial.read(length[0] | (length[1] << 8))
os.write(self.serial_bridge, H4_ACL + opcode + length + payload)
elif cmd == H4_CMD: # Should not happen
opcode = self.serial.read(2)
length = self.serial.read(1)
if len(length):
payload = self.serial.read(ord(length))
os.write(self.serial_bridge, H4_CMD +
opcode + length + payload)
# Receive BT packets
elif cmd == ESP32_CMD_DATA_RX or cmd == ESP32_CMD_DATA_TX:
raw_sz = self.serial.read(2)
sz = raw_sz[0] | (raw_sz[1] << 8)
data = self.serial.read(sz)
checksum = self.serial.read(1)
# Check data checksum
if (checksum and (sum(data) & 0xFF) == ord(checksum)):
self.status = ConnectionStatus(*data[0:6])
self.direction = (1 if cmd == ESP32_CMD_DATA_RX else 0)
return data
return None