Repository navigation
Expand file tree
/
Copy pathdevice.py
More file actions
134 lines (110 loc) · 3.87 KB
/
Copy pathdevice.py
File metadata and controls
134 lines (110 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""Base abstractions for addressed devices connected to the controller."""
class BaseDevice:
"""Abstract interface for an addressed controller device."""
def send_command(self):
"""Send a device command.
Raises
------
NotImplementedError
Always raised by the base implementation.
"""
raise NotImplementedError
def translate_response(self):
"""Translate a controller response into device values.
Raises
------
NotImplementedError
Always raised by the base implementation.
"""
raise NotImplementedError
class DeviceWithAddress(BaseDevice):
"""Base device that prefixes commands with a controller address."""
def __init__(self, controller, address="0", debug=False):
"""Initialize an addressed device.
Parameters
----------
controller : BaseSerialController
Controller used for serial communication.
address : str, default="0"
Device address used in outgoing commands.
debug : bool, default=False
Whether to print parsed response details.
"""
super().__init__()
# the controller object which services the COM port
self.controller = controller
self.address = address
self.debug = debug
def dict_command(self, dict_source, req="get_position", data=""):
"""Generates the GET commands from get_ cmd dictionary.
Parameters
----------
req : str, optinal
Name of request
data : str
Parameters to be sent after address and request
Returns
-------
status : tuple
(code, addr, data)
"""
if req in dict_source:
instruction = dict_source[req]
print(instruction)
else:
print(f"Invalid Command: {req}")
return None
status = self.send_command(instruction, message=data)
return status
def send_command(self, instruction, message=None):
"""Send an instruction to the device and translate its response.
Parameters
----------
instruction : str
Controller command code.
message : str, optional
Arguments appended after the device address.
Returns
-------
tuple or None
Translated response containing code, address, and integer data.
"""
if message is not None:
fullmessage = self.address + " " + message
else:
fullmessage = self.address
cstatus = self.controller.send_instruction(instruction, message = fullmessage)
status = self.translate_response(status=cstatus, debug=self.debug)
return status
def translate_response(self, status, debug=False):
"""Parse a controller response into typed device data.
Parameters
----------
status : tuple
Response tuple containing a code and field list.
debug : bool, default=False
Whether to print parsed fields.
Returns
-------
tuple
``(code, address, data)`` where ``data`` is a list of integers.
Raises
------
ValueError
If the response does not contain a valid integer address.
"""
code = status[0]
fulldata = status[1]
if debug:
print(f'Code: {code}')
print(f'Data (str): {fulldata}')
try:
addr = int(fulldata[0])
except ValueError as exc:
raise ValueError(f"Invalid Address: {status[1]}.") from exc
addr = int(fulldata[0])
data = [int(d) for d in fulldata[1:]]
if debug:
print(f'Parsed Address: {addr}')
print(f'Parsed Data: {data}')
return (code, addr, data)