serialio.py 5.52 KB
Newer Older
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#!/usr/bin/python3

import serial
import threading
import struct

class IO:

    def __init__(self):
        self.min = None
        self.max = None
        self.bits = None

    def parseMinMax(self, bits):
        unit = bits & 0x07
        sign = (bits >> 3) & 0x01
        value = (bits >> 4)
        if unit == 0b000 or unit == 0b100:
            result = value
            pass
        elif unit == 0b001:
            result = 1e-3 * value
            pass
        elif unit == 0b010:
            result = 1e-6 * value
            pass
        else:
            result = value
            pass
        if sign == 1:
            result = -result
        return result
    
    def setBits(self, bits):
        self.bits = bits
        
    def setMin(self, min):
        self.min = self.parseMinMax(min)
        
    def setMax(self, max):
        self.max = self.parseMinMax(max)

    def __repr__(self):
        return "bits:%s min:%s max:%s" % (self.bits, self.min, self.max)
        
class DigitalIn(IO):
    pass

class DigitalOut(IO):
    pass

class AnalogIn(IO):
    pass

class AnalogOut(IO):
    pass

class Counter(IO):
    pass

class SerialIOConfig:
    CMD = {
        0: IO.setBits,
        1: IO.setMin,
        2: IO.setMax,
    }

    KIND = {
        0: None,
        1: DigitalIn,
        2: DigitalOut,
        3: AnalogIn,
        4: AnalogOut,
        5: Counter
    }

    def __init__(self, serialio):
        self.serialio = serialio
        self.config = {}
        self.cond = threading.Condition()
        pass

    def digitalIn(self):
        return self.config[DigitalIn]

    def digitalOut(self):
        return self.config[DigitalOut]

    def analogIn(self):
        return self.config[AnalogIn]

    def analogOut(self):
        return self.config[AnalogOut]

    def counter(self):
        return self.config[Counter]

    def __str__(self):
        return "%s" % self.config
    
    def get(self):
        self.serialio.pollchannel(31)
        self.cond.acquire()
        self.cond.wait(2)
        self.cond.release()
        pass
    
    def handle(self, value):
        channel = value & 0x1f
        kind = (value >> 5) & 0x07
        cmd = (value >> 8) & 0x03
        value = value >> 10
        kind = self.KIND[kind]
        if kind == None:
            self.cond.acquire()
            self.cond.notifyAll()
            self.cond.release()
            return True
        else:
            if not kind in self.config:
                self.config[kind] = {}
                pass
            if not channel in self.config[kind]:
                self.config[kind][channel] = kind()
                pass
            cmd = self.CMD[cmd]
            cmd(self.config[kind][channel], value)
            pass
        pass

    pass
    
    
class SerialIO:
    def __init__(self, port):
        self.channel = {}
        self.tty = serial.Serial(port, 115200)
        self.config = SerialIOConfig(self)
        self.cond = threading.Condition()
        t = threading.Thread(target=self.read)
        t.setDaemon(True)
        t.start()
        self.config.get()

    def digitalIn(self):
        return self.config.digitalIn()

    def digitalOut(self):
        return self.config.digitalOut()

    def analogIn(self):
        return self.config.analogIn()

    def analogOut(self):
        return self.config.analogOut()

    def counter(self):
        return self.config.counter()

    def pollchannel(self, index):
        self.cond.acquire()
        self.channel[index] = None
        self.tty.write(struct.pack('B', (0x60 | index)))
        self.cond.release()

    def waitchannel(self, index):
        self.cond.acquire()
        while self.channel[index] == None:
            self.cond.wait()
        result = self.channel[index]
        self.cond.release()
        return result

    def getchannel(self, index):
        self.pollchannel(index)
        return self.waitchannel(index)
    
    def setchannel(self, index, value):
        #value = int(max(0, min(value, bound)))
        self.cond.acquire()
        if value >= (1<<30):
            self.tty.write(struct.pack('B', 0x80 | ((value >> 30) & 0x03)))
        if value >= (1<<23):
            self.tty.write(struct.pack('B', 0x80 | ((value >> 23) & 0x7f)))
        if value >= (1<<16):
            self.tty.write(struct.pack('B', 0x80 | ((value >> 16) & 0x7f)))
        if value >= (1<<9):
            self.tty.write(struct.pack('B', 0x80 | ((value >> 9) & 0x7f)))
        self.tty.write(struct.pack('B', 0x80 | ((value >> 2) & 0x7f)))
        self.tty.write(struct.pack('B', ((value << 5) & 0x60) | (index & 0x1f)))
        self.cond.release()
        pass

    def read(self):
        value = 0
        n = 0
        config = {}
        while True:
            ch = self.tty.read(1)
            
            value = value << 7 | ord(ch) & 0x7f
            n += 1
            if ord(ch) & 0x80 == 0:
                # Last byte, so lets handle it
                if n == 1:
                    # Digital I/O or poll
                    pass
                else:
                    channel = value & 0x1f
                    value = value >> 5
                    if channel != 31:
                        self.cond.acquire()
                        self.channel[channel] = value
                        self.cond.notifyAll()
                        self.cond.release()
                        pass
                    else:
                        self.config.handle(value)
                        pass
                    pass
                value = 0
                n = 0
                pass
            pass
        pass
    
    pass