1+ import bluetooth
2+ import random
3+ import struct
4+ import time
5+ from ble_advertising import advertising_payload
6+
7+ from micropython import const
8+
9+ _IRQ_CENTRAL_CONNECT = const (1 )
10+ _IRQ_CENTRAL_DISCONNECT = const (2 )
11+ _IRQ_GATTS_WRITE = const (3 )
12+ _IRQ_MTU_EXCHANGED = const (21 )
13+
14+ _FLAG_READ = const (0x0002 )
15+ _FLAG_WRITE_NO_RESPONSE = const (0x0004 )
16+ _FLAG_WRITE = const (0x0008 )
17+ _FLAG_NOTIFY = const (0x0010 )
18+
19+ _UART_UUID = bluetooth .UUID ("6E400001-B5A3-F393-E0A9-E50E24DCCA9E" )
20+ _UART_TX = (
21+ bluetooth .UUID ("6E400003-B5A3-F393-E0A9-E50E24DCCA9E" ),
22+ _FLAG_READ | _FLAG_NOTIFY ,
23+ )
24+ _UART_RX = (
25+ bluetooth .UUID ("6E400002-B5A3-F393-E0A9-E50E24DCCA9E" ),
26+ _FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE ,
27+ )
28+ _UART_SERVICE = (
29+ _UART_UUID ,
30+ (_UART_TX , _UART_RX ),
31+ )
32+
33+ _PREFERRED_MTU = const (517 )
34+ _DEFAULT_MTU = const (23 )
35+
36+ class BLEBasePeripheral :
37+ def __init__ (self , ble , name = "ESP32S3" ):
38+ self ._ble = ble
39+ self ._ble .active (True )
40+ self ._ble .config (mtu = _PREFERRED_MTU )
41+ self ._ble .irq (self ._irq )
42+ ((self ._handle_tx , self ._handle_rx ),) = self ._ble .gatts_register_services ((_UART_SERVICE ,))
43+ self ._connections = set ()
44+ self ._mtu = _DEFAULT_MTU
45+ self ._write_callback = None
46+ self ._payload = advertising_payload (name = name )
47+ self ._name = name
48+ self ._advertise ()
49+
50+ def _irq (self , event , data ):
51+ # Track connections so we can send notifications.
52+ if event == _IRQ_CENTRAL_CONNECT :
53+ conn_handle , _ , _ = data
54+ print ("Connected to" , conn_handle )
55+ self ._connections .add (conn_handle )
56+ elif event == _IRQ_CENTRAL_DISCONNECT :
57+ conn_handle , _ , _ = data
58+ print ("Disconnected from " , conn_handle )
59+ self ._connections .remove (conn_handle )
60+ # Start advertising again to allow a new connection.
61+ self ._advertise ()
62+ elif event == _IRQ_MTU_EXCHANGED :
63+ conn_handle , mtu = data
64+ self ._mtu = mtu
65+ print ("Packet size agreed:" , mtu , "bytes" )
66+ elif event == _IRQ_GATTS_WRITE :
67+ conn_handle , value_handle = data
68+ value = self ._ble .gatts_read (value_handle )
69+ if value_handle == self ._handle_rx and self ._write_callback :
70+ self ._write_callback (value )
71+
72+ def send (self , data ):
73+ for conn_handle in self ._connections :
74+ self ._ble .gatts_notify (conn_handle , self ._handle_tx , data )
75+
76+ def is_connected (self ):
77+ return len (self ._connections ) > 0
78+
79+ def _advertise (self , interval_us = 100000 ):
80+ print ("Advertising as" , self ._name )
81+ self ._ble .gap_advertise (interval_us , adv_data = self ._payload )
82+
83+ def on_write (self , callback ):
84+ self ._write_callback = callback
85+
86+ def max_bytes (self ):
87+ # 3 bytes of every packet are used by Bluetooth itself.
88+ return self ._mtu - 3
0 commit comments