Skip to content

Commit 06d1f07

Browse files
authored
Merge pull request #10 from MrClock8163/connection-refactor
Connection refactor
2 parents 5061c76 + 4b22914 commit 06d1f07

File tree

6 files changed

+78
-82
lines changed

6 files changed

+78
-82
lines changed

src/geocompy/communication.py

Lines changed: 68 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414
from __future__ import annotations
1515

1616
from types import TracebackType
17-
from typing import Iterable
1817

19-
from serial import Serial, SerialException, SerialTimeoutException
18+
from serial import (
19+
Serial,
20+
SerialException,
21+
SerialTimeoutException,
22+
PARITY_NONE
23+
)
2024

2125

2226
class Connection:
@@ -27,16 +31,6 @@ class Connection:
2731
2832
"""
2933

30-
def __init__(self, name: str = ""):
31-
"""
32-
Parameters
33-
----------
34-
name : str, optional
35-
Descriptive name, by default ""
36-
37-
"""
38-
self.name: str = name
39-
4034
def is_open(self) -> bool:
4135
"""
4236
Checks if the communication channel is currently open.
@@ -88,32 +82,9 @@ def receive(self) -> str:
8882
"""
8983
raise NotImplementedError("interface does not implement 'receive'")
9084

91-
def exchange(self, cmds: Iterable[str]) -> list[str]:
85+
def exchange(self, cmd: str) -> str:
9286
"""
93-
Sends an arbitrary number of messages through the connection,
94-
and receives the corresponding responses.
95-
96-
Parameters
97-
----------
98-
cmds : Iterable[str]
99-
Collection of messages to send.
100-
101-
Returns
102-
-------
103-
list
104-
Responses to the sent messages.
105-
106-
Raises
107-
------
108-
NotImplementedError
109-
If the method is not implemented on the child class.
110-
111-
"""
112-
raise NotImplementedError("interface does not implement 'exchange'")
113-
114-
def exchange1(self, cmd: str) -> str:
115-
"""
116-
Sends a single message through the connection, and receives the
87+
Sends a message through the connection, and receives the
11788
corresponding response.
11889
11990
Parameters
@@ -135,6 +106,64 @@ def exchange1(self, cmd: str) -> str:
135106
raise NotImplementedError("interface does not implement 'exchange1'")
136107

137108

109+
def open_serial(
110+
port: str,
111+
*,
112+
speed: int = 9600,
113+
databits: int = 8,
114+
stopbits: int = 1,
115+
parity: str = PARITY_NONE,
116+
timeout: int = 15,
117+
eom: str = "\r\n",
118+
eoa: str = "\r\n"
119+
) -> SerialConnection:
120+
"""
121+
Constructs a SerialConnection with the given communication
122+
parameters.
123+
124+
Parameters
125+
----------
126+
port : str
127+
Name of the port to use (e.g. ``COM1`` or ``/dev/ttyUSB0``).
128+
speed : int, optional
129+
Communication speed (baud), by default 9600
130+
databits : int, optional
131+
Number of data bits, by default 8
132+
stopbits : int, optional
133+
Number of stop bits, by default 1
134+
parity : str, optional
135+
Parity bit behavior, by default PARITY_NONE
136+
timeout : int, optional
137+
Communication timeout threshold, by default 15
138+
eom : str, optional
139+
EndOfMessage sequence, by default ``"\\r\\n"``
140+
eoa : str, optional
141+
EndOfAnswer sequence, by default ``"\\r\\n"``
142+
143+
Returns
144+
-------
145+
SerialConnection
146+
147+
Examples
148+
--------
149+
150+
Opening a serial connection similar to a file:
151+
152+
>>> conn = open_serial("COM1", speed=19200, timeout=5)
153+
>>> # do operations
154+
>>> conn.close()
155+
156+
Using as a context manager:
157+
158+
>>> with open_serial("COM1", timeout=20) as conn:
159+
... conn.send("test")
160+
161+
"""
162+
serialport = Serial(port, speed, databits, parity, stopbits, timeout)
163+
wrapper = SerialConnection(serialport, eom=eom, eoa=eoa)
164+
return wrapper
165+
166+
138167
class SerialConnection(Connection):
139168
"""
140169
Connection wrapping an open serial port.
@@ -194,7 +223,6 @@ def __init__(
194223
be opened.
195224
196225
"""
197-
super().__init__("")
198226

199227
self._port: Serial = port
200228
self.eom: str = eom # end of message
@@ -293,40 +321,9 @@ def receive(self) -> str:
293321

294322
return answer.decode("ascii").removesuffix(self.eoa)
295323

296-
def exchange(self, cmds: Iterable[str]) -> list[str]:
297-
"""
298-
Writes an arbitrary number of messages to the serial line,
299-
and receives the corresponding responses, one pair at a time.
300-
301-
Parameters
302-
----------
303-
cmds : Iterable[str]
304-
Collection of messages to send.
305-
306-
Returns
307-
-------
308-
list
309-
Responses to the sent messages.
310-
311-
Raises
312-
------
313-
~serial.SerialException
314-
If the serial port is not open.
315-
~serial.SerialTimeoutException
316-
If the connection timed out before receiving the
317-
EndOfAnswer sequence for one of the responses.
318-
319-
"""
320-
answers: list[str] = []
321-
for item in cmds:
322-
self.send(item)
323-
answers.append(self.receive())
324-
325-
return answers
326-
327-
def exchange1(self, cmd: str) -> str:
324+
def exchange(self, cmd: str) -> str:
328325
"""
329-
Writes a single message to the serial line, and receives the
326+
Writes a message to the serial line, and receives the
330327
corresponding response.
331328
332329
Parameters

src/geocompy/dna/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def __init__(
140140

141141
for i in range(retry):
142142
try:
143-
reply = self._conn.exchange1("a")
143+
reply = self._conn.exchange("a")
144144
if reply == "?":
145145
break
146146
except Exception:
@@ -178,7 +178,7 @@ def setrequest(
178178
cmd = f"SET/{param:d}/{value:d}"
179179
comment = ""
180180
try:
181-
answer = self._conn.exchange1(cmd)
181+
answer = self._conn.exchange(cmd)
182182
except Exception:
183183
self._logger.error(format_exc())
184184
answer = DNAErrors.E_UNKNOWN.value
@@ -219,7 +219,7 @@ def confrequest(
219219
cmd = f"CONF/{param:d}"
220220
comment = ""
221221
try:
222-
answer = self._conn.exchange1(cmd)
222+
answer = self._conn.exchange(cmd)
223223
except Exception:
224224
self._logger.error(format_exc())
225225
answer = DNAErrors.E_UNKNOWN.value
@@ -269,7 +269,7 @@ def putrequest(
269269
cmd = f"PUT/{word:s}"
270270
comment = ""
271271
try:
272-
answer = self._conn.exchange1(cmd)
272+
answer = self._conn.exchange(cmd)
273273
except Exception:
274274
self._logger.error(format_exc())
275275
answer = DNAErrors.E_UNKNOWN.value
@@ -316,7 +316,7 @@ def getrequest(
316316
cmd = f"GET/{mode:s}/WI{wordindex:d}"
317317
comment = ""
318318
try:
319-
answer = self._conn.exchange1(cmd)
319+
answer = self._conn.exchange(cmd)
320320
except Exception:
321321
self._logger.error(format_exc())
322322
answer = DNAErrors.E_UNKNOWN.value
@@ -362,7 +362,7 @@ def request(
362362
"""
363363
comment = ""
364364
try:
365-
answer = self._conn.exchange1(cmd)
365+
answer = self._conn.exchange(cmd)
366366
except Exception:
367367
self._logger.error(format_exc())
368368
answer = DNAErrors.E_UNKNOWN.value

src/geocompy/tps1200p/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ def request(
338338

339339
cmd = f"%R1Q,{rpc}:{','.join(strparams)}"
340340
try:
341-
answer = self._conn.exchange1(cmd)
341+
answer = self._conn.exchange(cmd)
342342
except SerialTimeoutException:
343343
self._logger.error(format_exc())
344344
answer = (

src/geocompy/vivatps/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ def request(
355355

356356
cmd = f"%R1Q,{rpc}:{','.join(strparams)}"
357357
try:
358-
answer = self._conn.exchange1(cmd)
358+
answer = self._conn.exchange(cmd)
359359
except SerialTimeoutException:
360360
self._logger.error(format_exc())
361361
answer = (

tests/helpers_geocom.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class DummyGeoComConnection(Connection):
2828
def send(self, message: str):
2929
return
3030

31-
def exchange1(self, cmd: str) -> str:
31+
def exchange(self, cmd: str) -> str:
3232
if not self._CMD.match(cmd):
3333
return "%R1P,0,0:2"
3434

tests/helpers_gsionline.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ class DummyGsiOnlineConnection(Connection):
2626
)
2727

2828
def __init__(self, gsi16=False):
29-
super().__init__("")
3029
self._gsi16 = gsi16
3130

32-
def exchange1(self, cmd: str) -> str:
31+
def exchange(self, cmd: str) -> str:
3332
if self._CONF.match(cmd) and cmd != "CONF/0":
3433
if cmd == "CONF/137":
3534
return f"0137/{self._gsi16:04d}"

0 commit comments

Comments
 (0)