rs485.py 3.2 KB

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