-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreader.py
More file actions
187 lines (163 loc) · 7.47 KB
/
reader.py
File metadata and controls
187 lines (163 loc) · 7.47 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
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
#!/usr/bin/python
import os
import sys
import threading
import stat
import time
import serial
def print_thread_err(text):
"""
Prefix text with Thread name and send to stderr
"""
thread_name = str(threading.current_thread().getName())
print('\r[%s] %s'%(thread_name,text),file=sys.stderr)
class Source:
def __init__(self,path,model="vc820"):
if type(path) is not str:
raise TypeError("Expecting str")
if os.name == 'nt': #running on windows
if os.path.exists(path):
self.type = "file"
else: #no file with this name, assuming serial port
self.type = "serial"
elif os.name == "posix": #Linux or Unix (including macOS)
if stat.S_ISCHR(os.stat(path).st_mode): #Character device, assuming serial port
self.type = "serial"
elif stat.S_ISREG(os.stat(path).st_mode): #Regular file
self.type = "file"
elif stat.S_ISFIFO(os.stat(path).st_mode): #Pipe
self.type = "pipe"
else:
raise TypeError("Unsupported input")
self.MultimeterMessage = __import__(model).MultimeterMessage
self.model = model
self.path = path
def __str__(self):
return self.model+"["+self.path+"]"
def __repr__(self):
return "Source(path="+self.path+",model="+self.model+")"
class Reader():
def __init__(self,source,message_handler=None,raw_handler=None,filewait=0.5,quiet=False):
self.quiet = quiet
self.source = source
self.message_handler = message_handler
self.raw_handler = raw_handler
self.filewait = filewait
if source.type == "serial":
self.serial_port = serial.Serial(source.path, baudrate=2400, parity='N', bytesize=8, timeout=1, rtscts=1, dsrdtr=1)
#dtr and rts required for supplying adapter with power
self.serial_port.dtr = True
self.serial_port.rts = False
elif source.type == "file" or source.type == "pipe":
self.serial_port = open(source.path, "rb")
else:
#should never happen, prevented by Source.__init__()
raise TypeError("Unsupported input")
def print(self, *args,**kwargs):
if not self.quiet:
print(*args,**kwargs)
def read_one(self):
while True:
test = self.serial_port.read(1)
if len(test) != 1:
if self.source.type == "file":
return #EOF
raise Exception("recieved incomplete data")
if self.source.MultimeterMessage.check_first_byte(test[0]):
data = test + self.serial_port.read(self.source.MultimeterMessage.MESSAGE_LENGTH-1)
else:
self.print("received incorrect data (%s), skipping..."%test.hex(), file=sys.stderr)
continue
if len(data) != self.source.MultimeterMessage.MESSAGE_LENGTH:
self.print("received incomplete message (%s), skipping..."%data.hex(), file=sys.stderr)
continue
return self.source.MultimeterMessage(data)
def start(self):
while True:
test = self.serial_port.read(1)
if len(test) != 1:
if self.source.type == "file":
return #EOF
self.print("recieved incomplete data, skipping...", file=sys.stderr)
continue
if self.source.MultimeterMessage.check_first_byte(test[0]):
data = test + self.serial_port.read(self.source.MultimeterMessage.MESSAGE_LENGTH-1)
if self.raw_handler is not None:
self.raw_handler(data,self.source)
else:
if self.raw_handler is not None:
self.raw_handler(test,self.source)
self.print("received incorrect data (%s), skipping..."%test.hex(), file=sys.stderr)
continue
if len(data) != self.source.MultimeterMessage.MESSAGE_LENGTH:
self.print("received incomplete message (%s), skipping..."%data.hex(), file=sys.stderr)
continue
try:
message = self.source.MultimeterMessage(data)
except ValueError as e:
self.print("Error decoding: %s on message %s"%(str(e),data.hex()))
continue
if self.message_handler(message,self.source) == "exit":
break
if self.source.type == "file":
time.sleep(filewait)
class ThreadedReader(threading.Thread):
def __init__(self,source,value_callback=None,error_callback=None,filewait=0.5):
threading.Thread.__init__(self)
self.source = source
self.setName(str(self.source))
self.stop_flag = False
self.value_callback = value_callback
self.error_callback = error_callback
self.filewait = filewait
if source.type == "serial":
self.serial_port = serial.Serial(source.path, baudrate=2400, parity='N', bytesize=8, timeout=1, rtscts=1, dsrdtr=1)
#dtr and rts required for supplying adapter with power
self.serial_port.dtr = True
self.serial_port.rts = False
elif source.type == "file" or source.type == "pipe":
self.serial_port = open(source.path, "rb")
else:
#should never happen, prevented by Source.__init__()
raise TypeError("Unsupported input")
def stop(self):
self.stop_flag = True
def run(self):
while True:
if self.stop_flag:
return
if self.source.type == "file":
time.sleep(self.filewait)
test = self.serial_port.read(1) #read one byte, used for determining if message is valid
#blocking if using fifo, times out if using serial port
if len(test) != 1:
if self.source.type == "file":
if self.error_callback is not None:
self.error_callback(source)
print_thread_err("EOF reached")
exit(0) #EOF
print_thread_err("recieved incomplete data, skipping...")
if self.error_callback is not None:
self.error_callback(self.source)
continue
if self.source.MultimeterMessage.check_first_byte(test[0]):
data = test + self.serial_port.read(self.source.MultimeterMessage.MESSAGE_LENGTH-1) #looks good, read the remaining message
else:
print_thread_err("received incorrect data (%s), skipping..."%test.hex())
if self.error_callback is not None:
self.error_callback(self.source)
continue
if len(data) != self.source.MultimeterMessage.MESSAGE_LENGTH:
print_thread_err("received incomplete message (%s), skipping..."%data.hex())
if self.error_callback is not None:
self.error_callback(source)
continue
try:
message = self.source.MultimeterMessage(data)
except ValueError as e:
print_thread_err("Error decoding: %s on message %s"%(str(e),data.hex()))
if self.error_callback is not None:
self.error_callback(self.source)
continue
if self.value_callback is not None:
self.value_callback(message,self.source)