blob: cc173782fb59a86509ed5a3e1bf9222b264d7037 [file] [log] [blame]
Chris Liechti33f0ec52015-08-06 16:37:21 +02001#!/usr/bin/env python
2
3# RS485 support
4#
5# (C) 2015 Chris Liechti <cliechti@gmx.net>
6
7"""\
8The settings for RS485 are stored in a dedicated object that can be applied to
9serial ports (where supported).
10NOTE: Some implementations may only support a subset of the settings.
11"""
12
13import time
14import serial
15
16class RS485Settings(object):
17 def __init__(self,
18 rts_level_for_tx=True,
19 rts_level_for_rx=False,
20 loopback=False,
21 delay_before_tx=None,
22 delay_before_rx=None):
23 self.rts_level_for_tx = rts_level_for_tx
24 self.rts_level_for_rx = rts_level_for_rx
25 self.loopback = loopback
26 self.delay_before_tx = delay_before_tx
27 self.delay_before_rx = delay_before_rx
28
29
30class RS485(serial.Serial):
31 """\
32 A subclass that replaces the write method with one that toggles RTS
33 according to the RS485 settings.
34
35 NOTE: This may work unreliably on some serial ports (control signals not
36 synchronized or delayed compared to data). Using delays may be
37 unreliable (varying times, larger than expected) as the OS may not
38 support very fine grained delays (no smaller than in the order of
39 tens of milliseconds).
40
41 NOTE: Some implementations support this natively. Better performance
42 can be expected when the native version is used.
43
44 NOTE: The loopback property is ignored by this implementation. The actual
45 behavior depends on the used hardware.
46
47 Usage:
48
49 ser = RS485(...)
50 ser.rs485_mode = RS485Settings(...)
51 ser.write(b'hello')
52 """
53
54 def __init__(self, *args, **kwargs):
55 super(RS485, self).__init__(*args, **kwargs)
56 self._alternate_rs485_settings = None
57
58
59 def write(self, b):
60 """Write to port, controlling RTS before and after transmitting."""
61 if self._alternate_rs485_settings is not None:
62 # apply level for TX and optional delay
63 self.setRTS(self._alternate_rs485_settings.rts_level_for_tx)
64 if self._alternate_rs485_settings.delay_before_tx is not None:
65 time.sleep(self._alternate_rs485_settings.delay_before_tx)
66 # write and wait for data to be written
67 super(RS485, self).write(b)
68 super(RS485, self).flush()
69 # optional delay and apply level for RX
70 if self._alternate_rs485_settings.delay_before_rx is not None:
71 time.sleep(self._alternate_rs485_settings.delay_before_rx)
72 self.setRTS(self._alternate_rs485_settings.rts_level_for_rx)
73 else:
74 super(RS485, self).write(b)
75
76
77 # redirect where the property stores the settings so that underlying Serial
78 # instance does not see them
79 @property
80 def rs485_mode(self):
81 """\
82 Enable RS485 mode and apply new settings, set to None to disable.
83 See serial.rs485.RS485Settings for more info about the value.
84 """
85 return self._alternate_rs485_settings
86
87 @rs485_mode.setter
88 def rs485_mode(self, rs485_settings):
89 self._alternate_rs485_settings = rs485_settings
90
91