-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFPGATriggererPythonAPI.py
200 lines (144 loc) · 5.31 KB
/
FPGATriggererPythonAPI.py
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
from enum import Enum, unique
import serial
HEADER_SIZE = 3 # bytes
@unique
class Mode(Enum):
READ = 0b10_000000
WRITE = 0b11_000000
@unique
class Command(Enum):
DELAY_MODULE_DELAY = (8, 3)
DELAY_MODULE_ARM = (9, 1)
DIGITAL_EDGE_DETECTOR_CFG = (16, 1)
DIGITAL_EDGE_DETECTOR_HOLDOFF = (17, 3)
PULSE_EXTENDER_CYCLES = (24, 2)
TARGET_RESETTER_RESET = (32, 1)
def __init__(self, addr, reg_size) -> None:
self.addr = addr
self.reg_size = reg_size
class FPGATriggererAPI:
"""\
Base class to send commands to the FPGATriggerer over UART
"""
def __init__(self, port: str) -> None:
self.serial = serial.Serial(port, baudrate=115200)
def _prepare_header(self, cmd_mode: Mode, cmd: Command):
"""\
Assemble the command mode in the first two bits and the command in the last six bits
"""
header = bytearray(HEADER_SIZE) # we have a 3 byte header
header[0] = cmd_mode.value | cmd.addr # command mode in the first two bits and the address in the last six bits
header[1:3] = cmd.reg_size.to_bytes(2, 'little', signed=False)
return header
def send_command(self, cmd_mode: Mode, cmd: Command, to_write: bytearray = None):
to_send = self._prepare_header(cmd_mode, cmd)
if cmd_mode is Mode.WRITE:
to_send.extend(to_write)
self.serial.write(to_send)
def close(self):
self.serial.close()
class DelayModule():
def __init__(self, triggerer_api: FPGATriggererAPI) -> None:
self.triggerer_api = triggerer_api
self._delay = 0
self._armed = False
@property
def delay(self):
return self._delay
@delay.setter
def delay(self, value):
assert isinstance(value, int), "value must be an int"
self._delay = value
self.triggerer_api.send_command(
Mode.WRITE,
Command.DELAY_MODULE_DELAY,
value.to_bytes(Command.DELAY_MODULE_DELAY.reg_size, byteorder='little', signed=False)
)
@property
def armed(self):
return self._armed
@armed.setter
def armed(self, value):
assert isinstance(value, bool), "value must be a bool"
self._armed = value
self.triggerer_api.send_command(
Mode.WRITE,
Command.DELAY_MODULE_ARM,
value.to_bytes(Command.DELAY_MODULE_ARM.reg_size, byteorder='little', signed=False)
)
class DigitalEdgeDetector():
ARMED = 0b1000_0000
EDGE_SENSITIVITY = 0b0000_0001
def __init__(self, triggerer_api: FPGATriggererAPI) -> None:
self.triggerer_api = triggerer_api
self._config = 0
self._holdoff_cycles = 0
@property
def edge_sensitivity(self):
return self._config & DigitalEdgeDetector.EDGE_SENSITIVITY
@edge_sensitivity.setter
def edge_sensitivity(self, value):
self._change_property(DigitalEdgeDetector.EDGE_SENSITIVITY, value)
self._send_config()
@property
def armed(self):
return self._config & DigitalEdgeDetector.ARMED
@armed.setter
def armed(self, value):
self._change_property(DigitalEdgeDetector.ARMED, value)
self._send_config()
@property
def holdoff_cycles(self):
return self._holdoff_cycles
@holdoff_cycles.setter
def holdoff_cycles(self, value):
self._holdoff_cycles = value
self.triggerer_api.send_command(
Mode.WRITE,
Command.DIGITAL_EDGE_DETECTOR_HOLDOFF,
value.to_bytes(Command.DIGITAL_EDGE_DETECTOR_HOLDOFF.reg_size, byteorder='little', signed=False)
)
def _change_property(self, mask, value: bool):
assert isinstance(value, bool), "value must be a bool"
if value:
self._config |= mask
else:
self._config &= ~(mask)
def _send_config(self):
self.triggerer_api.send_command(
Mode.WRITE,
Command.DIGITAL_EDGE_DETECTOR_CFG,
self._config.to_bytes(Command.DIGITAL_EDGE_DETECTOR_CFG.reg_size, byteorder='little', signed=False)
)
class PulseExtenderModule():
def __init__(self, triggerer_api: FPGATriggererAPI) -> None:
self.triggerer_api = triggerer_api
self._cycles = 0
@property
def cycles(self):
return self._cycles
@cycles.setter
def cycles(self, value):
assert isinstance(value, int), "value must be an int"
self._cycles = value
self.triggerer_api.send_command(
Mode.WRITE,
Command.PULSE_EXTENDER_CYCLES,
value.to_bytes(Command.PULSE_EXTENDER_CYCLES.reg_size, byteorder='little', signed=False)
)
class TargetResetterModule():
def __init__(self, triggerer_api: FPGATriggererAPI) -> None:
self.triggerer_api = triggerer_api
self._reset = False
@property
def reset(self):
return self._reset
@reset.setter
def reset(self, value):
assert isinstance(value, bool), "value must be a bool"
self._reset = value
self.triggerer_api.send_command(
Mode.WRITE,
Command.TARGET_RESETTER_RESET,
value.to_bytes(Command.TARGET_RESETTER_RESET.reg_size, byteorder='little', signed=False)
)