Skip to content

Commit cee6816

Browse files
committed
Re-refactor UART classes.
1 parent ad84cc4 commit cee6816

File tree

3 files changed

+139
-101
lines changed

3 files changed

+139
-101
lines changed

adafruit_ble/uart.py

Lines changed: 8 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -28,81 +28,11 @@
2828
* Author(s): Dan Halbert for Adafruit Industries
2929
3030
"""
31-
from bleio import UUID, CharacteristicBuffer
32-
33-
34-
35-
36-
class UART:
37-
"""
38-
Common superclass for Nordic UART Service (NUS) clients or servers.
39-
Not for general use: use `UARTServer` and `UARTClient` for Peripheral and Central,
40-
respectively.
41-
42-
:param read_characteristic Characteristic: Characteristic to read from
43-
:param write_characteristic Characteristic: Characteristic to write to
44-
:param int timeout: the timeout in seconds to wait
45-
for the first character and between subsequent characters
46-
:param int buffer_size: buffer up to this many bytes.
47-
If more bytes are received, older bytes will be discarded.
48-
"""
49-
50-
NUS_SERVICE_UUID = UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
51-
"""Nordic UART Service UUID"""
52-
NUS_RX_CHAR_UUID = UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
53-
"""Nordic UART Service RX Characteristic UUID"""
54-
NUS_TX_CHAR_UUID = UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
55-
"""Nordic UART Service TX Characteristic UUID"""
56-
57-
def __init__(self, *, read_characteristic, write_characteristic, timeout=5.0, buffer_size=64):
58-
self._read_char = read_characteristic
59-
self._write_char = write_characteristic
60-
self._read_buffer = CharacteristicBuffer(self._read_char,
61-
timeout=timeout, buffer_size=buffer_size)
62-
63-
def read(self, nbytes=None):
64-
"""
65-
Read characters. If ``nbytes`` is specified then read at most that many bytes.
66-
Otherwise, read everything that arrives until the connection times out.
67-
Providing the number of bytes expected is highly recommended because it will be faster.
68-
69-
:return: Data read
70-
:rtype: bytes or None
71-
"""
72-
return self._read_buffer.read(nbytes)
73-
74-
def readinto(self, buf, nbytes=None):
75-
"""
76-
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
77-
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
78-
79-
:return: number of bytes read and stored into ``buf``
80-
:rtype: int or None (on a non-blocking error)
81-
"""
82-
return self._read_buffer.readinto(buf, nbytes)
83-
84-
def readline(self):
85-
"""
86-
Read a line, ending in a newline character.
87-
88-
:return: the line read
89-
:rtype: int or None
90-
"""
91-
return self._read_buffer.readline()
92-
93-
@property
94-
def in_waiting(self):
95-
"""The number of bytes in the input buffer, available to be read."""
96-
return self._read_buffer.in_waiting
97-
98-
def reset_input_buffer(self):
99-
"""Discard any unread characters in the input buffer."""
100-
self._read_buffer.reset_input_buffer()
101-
102-
def write(self, buf):
103-
"""Write a buffer of bytes."""
104-
# We can only write 20 bytes at a time.
105-
offset = 0
106-
while offset < len(buf):
107-
self._write_char.value = buf[offset:offset+20]
108-
offset += 20
31+
from bleio import UUID
32+
33+
NUS_SERVICE_UUID = UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
34+
"""Nordic UART Service UUID"""
35+
NUS_RX_CHAR_UUID = UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
36+
"""Nordic UART Service RX Characteristic UUID"""
37+
NUS_TX_CHAR_UUID = UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
38+
"""Nordic UART Service TX Characteristic UUID"""

adafruit_ble/uart_client.py

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
* Author(s): Dan Halbert for Adafruit Industries
2929
3030
"""
31-
from bleio import Characteristic, Central
32-
from .uart import UART
31+
from bleio import Central, CharacteristicBuffer
32+
from .uart import NUS_SERVICE_UUID, NUS_RX_CHAR_UUID, NUS_TX_CHAR_UUID
3333

34-
class UARTClient(UART):
34+
class UARTClient:
3535
"""
3636
Provide UART-like functionality via the Nordic NUS service.
3737
@@ -58,27 +58,88 @@ class UARTClient(UART):
5858
"""
5959

6060
def __init__(self, *, timeout=5.0, buffer_size=64):
61-
# Since we're remote we receive on tx and send on rx. The names
62-
# are from the point of view of the server.
63-
super().__init__(read_characteristic=Characteristic(UART.NUS_TX_CHAR_UUID),
64-
write_characteristic=Characteristic(UART.NUS_RX_CHAR_UUID),
65-
timeout=timeout, buffer_size=buffer_size)
66-
61+
self._buffer_size = buffer_size
62+
self._timeout = timeout
63+
self._read_char = self._write_char = self._read_buffer = None
6764
self._central = Central()
6865

69-
@property
70-
def connected(self):
71-
"""True if we are connected to a peripheral."""
72-
return self._central.connected
73-
7466
def connect(self, address, timeout):
7567
"""Try to connect to the peripheral at the given address.
7668
7769
:param bleio.Address address: The address of the peripheral to connect to
7870
:param float/int timeout: Try to connect for timeout seconds.
7971
"""
80-
self._central.connect(address, timeout, service_uuids=(UART.NUS_SERVICE_UUID,))
72+
self._central.connect(address, timeout, service_uuids=(NUS_SERVICE_UUID,))
73+
74+
# Connect succeeded. Get the remote characteristics we need, which were
75+
# found during discovery.
76+
77+
for characteristic in self._central.remote_services[0].characteristics:
78+
# Since we're remote we receive on tx and send on rx.
79+
# The names are from the point of view of the server.
80+
if characteristic.uuid == NUS_RX_CHAR_UUID:
81+
self._write_char = characteristic
82+
elif characteristic.uuid == NUS_TX_CHAR_UUID:
83+
self._read_char = characteristic
84+
if not self._write_char or not self._read_char:
85+
raise OSError("Remote UART missing needed characteristic")
86+
self._read_buffer = CharacteristicBuffer(self._read_char,
87+
timeout=self._timeout,
88+
buffer_size=self._buffer_size)
8189

8290
def disconnect(self):
8391
"""Disconnect from the peripheral."""
8492
self._central.disconnect()
93+
self._read_char = self._write_char = self._read_buffer = None
94+
95+
@property
96+
def connected(self):
97+
"""True if we are connected to a peripheral."""
98+
return self._central.connected
99+
100+
def read(self, nbytes=None):
101+
"""
102+
Read characters. If ``nbytes`` is specified then read at most that many bytes.
103+
Otherwise, read everything that arrives until the connection times out.
104+
Providing the number of bytes expected is highly recommended because it will be faster.
105+
106+
:return: Data read
107+
:rtype: bytes or None
108+
"""
109+
return self._read_buffer.read(nbytes)
110+
111+
def readinto(self, buf, nbytes=None):
112+
"""
113+
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
114+
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
115+
116+
:return: number of bytes read and stored into ``buf``
117+
:rtype: int or None (on a non-blocking error)
118+
"""
119+
return self._read_buffer.readinto(buf, nbytes)
120+
121+
def readline(self):
122+
"""
123+
Read a line, ending in a newline character.
124+
125+
:return: the line read
126+
:rtype: int or None
127+
"""
128+
return self._read_buffer.readline()
129+
130+
@property
131+
def in_waiting(self):
132+
"""The number of bytes in the input buffer, available to be read."""
133+
return self._read_buffer.in_waiting
134+
135+
def reset_input_buffer(self):
136+
"""Discard any unread characters in the input buffer."""
137+
self._read_buffer.reset_input_buffer()
138+
139+
def write(self, buf):
140+
"""Write a buffer of bytes."""
141+
# We can only write 20 bytes at a time.
142+
offset = 0
143+
while offset < len(buf):
144+
self._write_char.value = buf[offset:offset+20]
145+
offset += 20

adafruit_ble/uart_server.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828
* Author(s): Dan Halbert for Adafruit Industries
2929
3030
"""
31-
from bleio import Characteristic, Service, Peripheral
31+
from bleio import Characteristic, CharacteristicBuffer, Peripheral, Service
3232
from .advertising import ServerAdvertisement
33-
from .uart import UART
33+
from .uart import NUS_SERVICE_UUID, NUS_RX_CHAR_UUID, NUS_TX_CHAR_UUID
3434

35-
class UARTServer(UART):
35+
class UARTServer:
3636
"""
3737
Provide UART-like functionality via the Nordic NUS service.
3838
@@ -56,12 +56,12 @@ class UARTServer(UART):
5656
"""
5757

5858
def __init__(self, *, timeout=1.0, buffer_size=64, name=None):
59-
read_char = Characteristic(UART.NUS_RX_CHAR_UUID, write=True, write_no_response=True)
60-
write_char = Characteristic(UART.NUS_TX_CHAR_UUID, notify=True)
61-
super().__init__(read_characteristic=read_char, write_characteristic=write_char,
62-
timeout=timeout, buffer_size=buffer_size)
59+
self._read_char = Characteristic(NUS_RX_CHAR_UUID, write=True, write_no_response=True)
60+
self._write_char = Characteristic(NUS_TX_CHAR_UUID, notify=True)
61+
self._read_buffer = CharacteristicBuffer(self._read_char,
62+
timeout=timeout, buffer_size=buffer_size)
6363

64-
nus_uart_service = Service(UART.NUS_SERVICE_UUID, (read_char, write_char))
64+
nus_uart_service = Service(NUS_SERVICE_UUID, (self._read_char, self._write_char))
6565

6666
self._periph = Peripheral((nus_uart_service,), name=name)
6767
self._advertisement = ServerAdvertisement(self._periph)
@@ -81,3 +81,50 @@ def stop_advertising(self):
8181
def connected(self):
8282
"""True if someone connected to the server."""
8383
return self._periph.connected
84+
85+
def read(self, nbytes=None):
86+
"""
87+
Read characters. If ``nbytes`` is specified then read at most that many bytes.
88+
Otherwise, read everything that arrives until the connection times out.
89+
Providing the number of bytes expected is highly recommended because it will be faster.
90+
91+
:return: Data read
92+
:rtype: bytes or None
93+
"""
94+
return self._read_buffer.read(nbytes)
95+
96+
def readinto(self, buf, nbytes=None):
97+
"""
98+
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
99+
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
100+
101+
:return: number of bytes read and stored into ``buf``
102+
:rtype: int or None (on a non-blocking error)
103+
"""
104+
return self._read_buffer.readinto(buf, nbytes)
105+
106+
def readline(self):
107+
"""
108+
Read a line, ending in a newline character.
109+
110+
:return: the line read
111+
:rtype: int or None
112+
"""
113+
return self._read_buffer.readline()
114+
115+
@property
116+
def in_waiting(self):
117+
"""The number of bytes in the input buffer, available to be read."""
118+
return self._read_buffer.in_waiting
119+
120+
def reset_input_buffer(self):
121+
"""Discard any unread characters in the input buffer."""
122+
self._read_buffer.reset_input_buffer()
123+
124+
def write(self, buf):
125+
"""Write a buffer of bytes."""
126+
# We can only write 20 bytes at a time.
127+
offset = 0
128+
while offset < len(buf):
129+
self._write_char.value = buf[offset:offset+20]
130+
offset += 20

0 commit comments

Comments
 (0)