mirror of
https://github.com/meshtastic/python.git
synced 2025-12-26 17:37:51 -05:00
78 lines
3.8 KiB
Python
78 lines
3.8 KiB
Python
""" Serial interface class
|
|
"""
|
|
import logging
|
|
import platform
|
|
import os
|
|
import stat
|
|
import serial
|
|
|
|
import meshtastic.util
|
|
from .stream_interface import StreamInterface
|
|
|
|
class SerialInterface(StreamInterface):
|
|
"""Interface class for meshtastic devices over a serial link"""
|
|
|
|
def __init__(self, devPath=None, debugOut=None, noProto=False, connectNow=True):
|
|
"""Constructor, opens a connection to a specified serial port, or if unspecified try to
|
|
find one Meshtastic device by probing
|
|
|
|
Keyword Arguments:
|
|
devPath {string} -- A filepath to a device, i.e. /dev/ttyUSB0 (default: {None})
|
|
debugOut {stream} -- If a stream is provided, any debug serial output from the device will be emitted to that stream. (default: {None})
|
|
"""
|
|
|
|
if devPath is None:
|
|
ports = meshtastic.util.findPorts()
|
|
logging.debug(f"ports:{ports}")
|
|
if len(ports) == 0:
|
|
meshtastic.util.our_exit("Warning: No Meshtastic devices detected.")
|
|
elif len(ports) > 1:
|
|
message = "Warning: Multiple serial ports were detected so one serial port must be specified with the '--port'.\n"
|
|
message += f" Ports detected:{ports}"
|
|
meshtastic.util.our_exit(message)
|
|
else:
|
|
devPath = ports[0]
|
|
|
|
logging.debug(f"Connecting to {devPath}")
|
|
|
|
# Note: we provide None for port here, because we will be opening it later
|
|
self.stream = serial.Serial(
|
|
None, 921600, exclusive=True, timeout=0.5, write_timeout=0)
|
|
|
|
# rts=False Needed to prevent TBEAMs resetting on OSX, because rts is connected to reset
|
|
self.stream.port = devPath
|
|
|
|
# HACK: If the platform driving the serial port is unable to leave the RTS pin in high-impedance
|
|
# mode, set RTS to false so that the device platform won't be reset spuriously.
|
|
# Linux does this properly, so don't apply this hack on Linux (because it makes the reset button not work).
|
|
if self._hostPlatformAlwaysDrivesUartRts():
|
|
self.stream.rts = False
|
|
self.stream.open()
|
|
|
|
StreamInterface.__init__(
|
|
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
|
|
|
|
"""true if platform driving the serial port is Windows Subsystem for Linux 1."""
|
|
def _isWsl1(self):
|
|
# WSL1 identifies itself as Linux, but has a special char device at /dev/lxss for use with session control,
|
|
# e.g. /init. We should treat WSL1 as Windows for the RTS-driving hack because the underlying platfrom
|
|
# serial driver for the CP21xx still exhibits the buggy behavior.
|
|
# WSL2 is not covered here, as it does not (as of 2021-May-25) support the appropriate functionality to
|
|
# share or pass-through serial ports.
|
|
try:
|
|
# Claims to be Linux, but has /dev/lxss; must be WSL 1
|
|
return platform.system() == 'Linux' and stat.S_ISCHR(os.stat('/dev/lxss').st_mode)
|
|
except:
|
|
# Couldn't stat /dev/lxss special device; not WSL1
|
|
return False
|
|
|
|
def _hostPlatformAlwaysDrivesUartRts(self):
|
|
# OS-X/Windows seems to have a bug in its CP21xx serial drivers. It ignores that we asked for no RTSCTS
|
|
# control and will always drive RTS either high or low (rather than letting the CP102 leave
|
|
# it as an open-collector floating pin).
|
|
# TODO: When WSL2 supports USB passthrough, this will get messier. If/when WSL2 gets virtual serial
|
|
# ports that "share" the Windows serial port (and thus the Windows drivers), this code will need to be
|
|
# updated to reflect that as well -- or if T-Beams get made with an alternate USB to UART bridge that has
|
|
# a less buggy driver.
|
|
return platform.system() != 'Linux' or self._isWsl1()
|