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