Fixed node id handling and discovery
[cerebrum.git] / pylibcerebrum / serial_mux.py
blob7925587db70c5a93fd34f3a2ca144abd0e7931b8
2 import serial
3 import threading
4 import struct
5 from pylibcerebrum.ganglion import Ganglion
6 from pylibcerebrum.timeout_exception import TimeoutException
8 class SerialMux(object):
10 def __init__(self, device=None, baudrate=115200, ser=None):
11 s = ser or LockableSerial(port=device, baudrate=baudrate, timeout=1)
12 #Trust me, without the following two lines it *wont* *work*. Fuck serial ports.
13 s.setXonXoff(True)
14 s.setXonXoff(False)
15 s.setDTR(True)
16 s.setDTR(False)
17 self.ser = s
19 def open(self, node_id):
20 """ Open a Ganglion by node ID """
21 return Ganglion(node_id, ser=self.ser)
23 def discover(self, mask=0, address=0, found=[]):
24 """ Discover all node IDs connected to the bus
26 Note: You do not need to set any of the arguments. These are used for the recursive discovery process.
27 """
28 for a in [address, 1<<mask | address]:
29 if self._send_probe(a, 15-mask):
30 if(mask < 15):
31 self.discover(mask+1, a, found)
32 else:
33 found.append(a)
34 return found
36 def _send_probe(self, address, mask):
37 #print('Discovery: address', address, 'mask', mask)
38 with self.ser as s:
39 s.write(b'\\#\xFF\xFF' + struct.pack('>HH', address, mask))
40 timeout_tmp = s.timeout
41 s.timeout = 0.005
42 try:
43 s.read(1)
44 s.timeout = timeout_tmp
45 return True
46 except TimeoutException:
47 s.timeout = timeout_tmp
48 return False
50 def __del__(self):
51 self.ser.close()
53 class LockableSerial(serial.Serial):
54 def __init__(self, *args, **kwargs):
55 super(serial.Serial, self).__init__(*args, **kwargs)
56 self.lock = threading.RLock()
58 def __enter__(self):
59 self.lock.__enter__()
60 return self
62 def __exit__(self, *args):
63 self.lock.__exit__(*args)
65 def read(self, n):
66 """Read n bytes from the serial device and raise a TimeoutException in case of a timeout."""
67 data = serial.Serial.read(self, n)
68 if len(data) != n:
69 raise TimeoutException('Read {} bytes trying to read {}'.format(len(data), n))
70 return data