Skip to content

Commit 52eb112

Browse files
committed
new Parameter --debuglib for only meshtastic debug, more termios fixes for windows tests
(cherry picked from commit 4fc4d41)
1 parent cbf7b9b commit 52eb112

File tree

5 files changed

+51
-58
lines changed

5 files changed

+51
-58
lines changed

meshtastic/__main__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,10 @@ def common():
12741274
format="%(levelname)s file:%(filename)s %(funcName)s line:%(lineno)s %(message)s",
12751275
)
12761276

1277+
# set all meshtastic loggers to DEBUG
1278+
if not (args.debug or args.listen) and args.debuglib:
1279+
logging.getLogger('meshtastic').setLevel(logging.DEBUG)
1280+
12771281
if len(sys.argv) == 1:
12781282
parser.print_help(sys.stderr)
12791283
meshtastic.util.our_exit("", 1)
@@ -2043,6 +2047,10 @@ def initParser():
20432047
"--debug", help="Show API library debug log messages", action="store_true"
20442048
)
20452049

2050+
group.add_argument(
2051+
"--debuglib", help="Show only API library debug log messages", action="store_true"
2052+
)
2053+
20462054
group.add_argument(
20472055
"--test",
20482056
help="Run stress test against all connected Meshtastic devices",

meshtastic/serial_interface.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33
# pylint: disable=R0917
44
import logging
5-
import platform
5+
import sys
66
import time
77

88
from typing import List, Optional
@@ -14,10 +14,6 @@
1414

1515
logger = logging.getLogger(__name__)
1616

17-
if platform.system() != "Windows":
18-
import termios
19-
20-
2117
class SerialInterface(StreamInterface):
2218
"""Interface class for meshtastic devices over a serial link"""
2319

@@ -48,15 +44,7 @@ def __init__(self, devPath: Optional[str]=None, debugOut=None, noProto: bool=Fal
4844

4945
logger.debug(f"Connecting to {self.devPath}")
5046

51-
# first we need to set the HUPCL so the device will not reboot based on RTS and/or DTR
52-
# see https://github.com/pyserial/pyserial/issues/124
53-
if platform.system() != "Windows":
54-
with open(self.devPath, encoding="utf8") as f:
55-
attrs = termios.tcgetattr(f)
56-
attrs[2] = attrs[2] & ~termios.HUPCL
57-
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
58-
f.close()
59-
time.sleep(0.1)
47+
self._set_hupcl_with_termios()
6048

6149
self.stream = serial.Serial(
6250
self.devPath, 115200, exclusive=True, timeout=0.5, write_timeout=0
@@ -68,6 +56,22 @@ def __init__(self, devPath: Optional[str]=None, debugOut=None, noProto: bool=Fal
6856
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes
6957
)
7058

59+
def _set_hupcl_with_termios(self):
60+
"""first we need to set the HUPCL so the device will not reboot based on RTS and/or DTR
61+
see https://github.com/pyserial/pyserial/issues/124
62+
"""
63+
if sys.platform == "win32":
64+
return
65+
66+
with open(self.devPath, encoding="utf8") as f:
67+
import termios # pylint: disable=C0415,E0401
68+
attrs = termios.tcgetattr(f)
69+
attrs[2] = attrs[2] & ~termios.HUPCL
70+
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
71+
f.close()
72+
73+
time.sleep(0.1)
74+
7175
def __repr__(self):
7276
rep = f"SerialInterface(devPath={self.devPath!r}"
7377
if hasattr(self, 'debugOut') and self.debugOut is not None:

meshtastic/slog/slog.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,9 @@ def __init__(
257257

258258
if not dir_name:
259259
app_dir = root_dir()
260-
dir_name = Path(app_dir, datetime.now().strftime('%Y%m%d-%H%M%S'))
261-
dir_name.mkdir(exist_ok=True)
260+
app_time_dir = Path(app_dir, datetime.now().strftime('%Y%m%d-%H%M%S'))
261+
app_time_dir.mkdir(exist_ok=True)
262+
dir_name = str(app_time_dir)
262263

263264
# Also make a 'latest' directory that always points to the most recent logs
264265
latest_dir = Path(app_dir, "latest")

meshtastic/tests/test_main.py

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import platform
77
import re
88
import sys
9-
import types
109
from unittest.mock import mock_open, MagicMock, patch
1110

1211
import pytest
@@ -36,13 +35,6 @@
3635
# from ..remote_hardware import onGPIOreceive
3736
# from ..config_pb2 import Config
3837

39-
# create a fake termios for Wwindows, otherwise errors will occur
40-
if sys.platform == "win32":
41-
fake_termios = types.ModuleType("termios")
42-
fake_termios.tcgetattr = lambda fd: None
43-
fake_termios.tcsetattr = lambda fd, when, settings: None
44-
sys.modules["termios"] = fake_termios
45-
4638
@pytest.mark.unit
4739
@pytest.mark.usefixtures("reset_mt_config")
4840
def test_main_init_parser_no_args(capsys):
@@ -765,12 +757,11 @@ def test_main_sendtext_with_invalid_channel_nine(caplog, capsys):
765757

766758
@pytest.mark.unit
767759
@pytest.mark.usefixtures("reset_mt_config")
768-
@patch("termios.tcsetattr")
769-
@patch("termios.tcgetattr")
760+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
770761
@patch("builtins.open", new_callable=mock_open, read_data="data")
771762
@patch("serial.Serial")
772763
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
773-
def test_main_sendtext_with_dest(mock_findPorts, mock_serial, mocked_open, mock_get, mock_set, capsys, caplog, iface_with_nodes):
764+
def test_main_sendtext_with_dest(mock_findPorts, mock_serial, mocked_open, mock_hupcl, capsys, caplog, iface_with_nodes):
774765
"""Test --sendtext with --dest"""
775766
sys.argv = ["", "--sendtext", "hello", "--dest", "foo"]
776767
mt_config.args = sys.argv
@@ -964,12 +955,11 @@ def test_main_seturl(capsys):
964955

965956
@pytest.mark.unit
966957
@pytest.mark.usefixtures("reset_mt_config")
967-
@patch("termios.tcsetattr")
968-
@patch("termios.tcgetattr")
958+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
969959
@patch("builtins.open", new_callable=mock_open, read_data="data")
970960
@patch("serial.Serial")
971961
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
972-
def test_main_set_valid(mocked_findports, mocked_serial, mocked_open, mocked_get, mocked_set, capsys):
962+
def test_main_set_valid(mocked_findports, mocked_serial, mocked_open, mocked_hupcl, capsys):
973963
"""Test --set with valid field"""
974964
sys.argv = ["", "--set", "network.wifi_ssid", "foo"]
975965
mt_config.args = sys.argv
@@ -989,12 +979,10 @@ def test_main_set_valid(mocked_findports, mocked_serial, mocked_open, mocked_get
989979

990980
@pytest.mark.unit
991981
@pytest.mark.usefixtures("reset_mt_config")
992-
@patch("termios.tcsetattr")
993-
@patch("termios.tcgetattr")
994982
@patch("builtins.open", new_callable=mock_open, read_data="data")
995983
@patch("serial.Serial")
996984
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
997-
def test_main_set_valid_wifi_psk(mocked_findports, mocked_serial, mocked_open, mocked_get, mocked_set, capsys):
985+
def test_main_set_valid_wifi_psk(mocked_findports, mocked_serial, mocked_open, capsys):
998986
"""Test --set with valid field"""
999987
sys.argv = ["", "--set", "network.wifi_psk", "123456789"]
1000988
mt_config.args = sys.argv
@@ -1014,12 +1002,11 @@ def test_main_set_valid_wifi_psk(mocked_findports, mocked_serial, mocked_open, m
10141002

10151003
@pytest.mark.unit
10161004
@pytest.mark.usefixtures("reset_mt_config")
1017-
@patch("termios.tcsetattr")
1018-
@patch("termios.tcgetattr")
1005+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
10191006
@patch("builtins.open", new_callable=mock_open, read_data="data")
10201007
@patch("serial.Serial")
10211008
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
1022-
def test_main_set_invalid_wifi_psk(mocked_findports, mocked_serial, mocked_open, mocked_get, mocked_set, capsys):
1009+
def test_main_set_invalid_wifi_psk(mocked_findports, mocked_serial, mocked_open, mocked_hupcl, capsys):
10231010
"""Test --set with an invalid value (psk must be 8 or more characters)"""
10241011
sys.argv = ["", "--set", "network.wifi_psk", "1234567"]
10251012
mt_config.args = sys.argv
@@ -1042,12 +1029,11 @@ def test_main_set_invalid_wifi_psk(mocked_findports, mocked_serial, mocked_open,
10421029

10431030
@pytest.mark.unit
10441031
@pytest.mark.usefixtures("reset_mt_config")
1045-
@patch("termios.tcsetattr")
1046-
@patch("termios.tcgetattr")
1032+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
10471033
@patch("builtins.open", new_callable=mock_open, read_data="data")
10481034
@patch("serial.Serial")
10491035
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
1050-
def test_main_set_valid_camel_case(mocked_findports, mocked_serial, mocked_open, mocked_get, mocked_set, capsys):
1036+
def test_main_set_valid_camel_case(mocked_findports, mocked_serial, mocked_open, mocked_hupcl, capsys):
10511037
"""Test --set with valid field"""
10521038
sys.argv = ["", "--set", "network.wifi_ssid", "foo"]
10531039
mt_config.args = sys.argv
@@ -1068,12 +1054,11 @@ def test_main_set_valid_camel_case(mocked_findports, mocked_serial, mocked_open,
10681054

10691055
@pytest.mark.unit
10701056
@pytest.mark.usefixtures("reset_mt_config")
1071-
@patch("termios.tcsetattr")
1072-
@patch("termios.tcgetattr")
1057+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
10731058
@patch("builtins.open", new_callable=mock_open, read_data="data")
10741059
@patch("serial.Serial")
10751060
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
1076-
def test_main_set_with_invalid(mocked_findports, mocked_serial, mocked_open, mocked_get, mocked_set, capsys):
1061+
def test_main_set_with_invalid(mocked_findports, mocked_serial, mocked_open, mocked_hupcl, capsys):
10771062
"""Test --set with invalid field"""
10781063
sys.argv = ["", "--set", "foo", "foo"]
10791064
mt_config.args = sys.argv
@@ -1094,12 +1079,11 @@ def test_main_set_with_invalid(mocked_findports, mocked_serial, mocked_open, moc
10941079
# TODO: write some negative --configure tests
10951080
@pytest.mark.unit
10961081
@pytest.mark.usefixtures("reset_mt_config")
1097-
@patch("termios.tcsetattr")
1098-
@patch("termios.tcgetattr")
1082+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
10991083
@patch("builtins.open", new_callable=mock_open, read_data="data")
11001084
@patch("serial.Serial")
11011085
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
1102-
def test_main_configure_with_snake_case(mocked_findports, mocked_serial, mocked_open, mocked_get, mocked_set, capsys):
1086+
def test_main_configure_with_snake_case(mocked_findports, mocked_serial, mocked_open, mocked_hupcl, capsys):
11031087
"""Test --configure with valid file"""
11041088
sys.argv = ["", "--configure", "example_config.yaml"]
11051089
mt_config.args = sys.argv
@@ -1127,12 +1111,11 @@ def test_main_configure_with_snake_case(mocked_findports, mocked_serial, mocked_
11271111

11281112
@pytest.mark.unit
11291113
@pytest.mark.usefixtures("reset_mt_config")
1130-
@patch("termios.tcsetattr")
1131-
@patch("termios.tcgetattr")
1114+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
11321115
@patch("builtins.open", new_callable=mock_open, read_data="data")
11331116
@patch("serial.Serial")
11341117
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
1135-
def test_main_configure_with_camel_case_keys(mocked_findports, mocked_serial, mocked_open, mocked_get, mocked_set, capsys):
1118+
def test_main_configure_with_camel_case_keys(mocked_findports, mocked_serial, mocked_open, mocked_hupcl, capsys):
11361119
"""Test --configure with valid file"""
11371120
sys.argv = ["", "--configure", "exampleConfig.yaml"]
11381121
mt_config.args = sys.argv
@@ -2729,17 +2712,16 @@ def test_tunnel_subnet_arg_with_no_devices(mock_platform_system, caplog, capsys)
27292712
assert err == ""
27302713

27312714

2732-
@pytest.mark.skipif(sys.platform == "win32", reason="Linux is forced in test and no termios")
2715+
@pytest.mark.skipif(sys.platform == "win32", reason="on windows is no fcntl module")
27332716
@pytest.mark.unit
27342717
@pytest.mark.usefixtures("reset_mt_config")
27352718
@patch("platform.system")
2736-
@patch("termios.tcsetattr")
2737-
@patch("termios.tcgetattr")
2719+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
27382720
@patch("builtins.open", new_callable=mock_open, read_data="data")
27392721
@patch("serial.Serial")
27402722
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
27412723
def test_tunnel_tunnel_arg(
2742-
mocked_findPorts, mocked_serial, mocked_open, mock_get, mock_set, mock_platform_system, caplog, iface_with_nodes, capsys
2724+
mocked_findPorts, mocked_serial, mocked_open, mock_hupcl, mock_platform_system, caplog, iface_with_nodes, capsys
27432725
):
27442726
"""Test tunnel with tunnel arg (act like we are on a linux system)"""
27452727

meshtastic/tests/test_serial_interface.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@
1313

1414
@pytest.mark.unit
1515
@patch("time.sleep")
16-
@patch("termios.tcsetattr")
17-
@patch("termios.tcgetattr")
16+
@patch("meshtastic.serial_interface.SerialInterface._set_hupcl_with_termios")
1817
@patch("builtins.open", new_callable=mock_open, read_data="data")
1918
@patch("serial.Serial")
2019
@patch("meshtastic.util.findPorts", return_value=["/dev/ttyUSBfake"])
2120
def test_SerialInterface_single_port(
22-
mocked_findPorts, mocked_serial, mocked_open, mock_get, mock_set, mock_sleep, capsys
21+
mocked_findPorts, mocked_serial, mocked_open, mock_hupcl, mock_sleep, capsys
2322
):
2423
"""Test that we can instantiate a SerialInterface with a single port"""
2524
iface = SerialInterface(noProto=True)
@@ -29,12 +28,11 @@ def test_SerialInterface_single_port(
2928
iface.close()
3029
mocked_findPorts.assert_called()
3130
mocked_serial.assert_called()
31+
mock_hupcl.assert_called()
3232

33-
# doesn't get called in SerialInterface.__init__ on windows
33+
# doesn't get called in SerialInterface._set_hupcl_with_termios on windows
3434
if platform.system() != "Windows":
3535
mocked_open.assert_called()
36-
mock_get.assert_called()
37-
mock_set.assert_called()
3836

3937
mock_sleep.assert_called()
4038
out, err = capsys.readouterr()

0 commit comments

Comments
 (0)