Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

boards/arduino-mega2560: add TTY_BOARD_FILTER #19012

Merged
merged 3 commits into from
Dec 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions boards/arduino-mega2560/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,34 @@ BAUD ?= 9600

ARDUINO_MEGA2560_BOOTLOADER ?= stk500v2

# If port selection via ttys.py is enabled by `MOST_RECENT_PORT=1`, filter
# USB serials to only select boards that identify as Arduino Mega 2560 or
# ad Arduino Mega ADK (a special official Mega flavor that is compatible)
TTY_BOARD_FILTER := --vendor 'Arduino' --model-db 'Mega 2560|Mega ADK'

# Same, but for clones using a cheap USB <--> UART chip rather than the
# ATmega16U2
TTY_BOARD_FILTER_CLONE := --driver 'cp210x|ch341'

# If set to 1, auto-detection of TTYs will also allow clones. This has a slight
# disadvantage for users of genuine Arduino Mega 2560: If the board is not
# plugged in, it will fall back to a detection that may yield false positives.
# However, most people will plug in their boards correctly prior to typing
# `make term`, so this is only a small loss for users of genuine
# Arduino Mega 2560 but a big win for users of cheap clones. Still, users that
# only will ever use genuine Arduino Mega 2560 boards can disable this via their
# .profile or .bashrc if they want.
ARDUINO_MEGA2560_COMPAT_WITH_CLONES ?= 1

ifeq (1,$(ARDUINO_MEGA2560_COMPAT_WITH_CLONES))
TTY_SELECT_CMD := $(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path \
$(TTY_BOARD_FILTER) || \
$(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path \
$(TTY_BOARD_FILTER_CLONE)
endif

include $(RIOTBOARD)/common/arduino-atmega/Makefile.include
5 changes: 4 additions & 1 deletion dist/tools/usb-serial/ttys.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def generate_filters(args):
Generate filters for use in the filters_match function from the command
line arguments
"""
result = list()
result = []
if args.serial is not None:
result.append(("serial", re.compile(r"^" + re.escape(args.serial)
+ r"$")))
Expand Down Expand Up @@ -225,6 +225,9 @@ def print_ttys(args):
else:
ttys = []

if len(ttys) == 0:
sys.exit(1)

print_results(args, ttys)


Expand Down
66 changes: 65 additions & 1 deletion doc/doxygen/src/flashing.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,68 @@ vendor or model to only considered TTYs that actually may belong to the selected
board. E.g. for Nucleo boards this is `--model 'STM32 STLink'`, as they all use
an integrated STLink as programmer. As long as only one TTY is provided from an
STLink, this will reliably select the correct TTY for an Nucleo regardless of
which TTY was most recently connected.
which TTY was most recently connected. Some boards even provide info that
allows to always reliably identify them correctly (e.g. the firmware on the
ATmega16U2 used as USB to UART converted on Arduino Mega2560 will provide
identification data unique to that board).

Adding Board Filters
--------------------

After connecting as many variants of the board you target (and maybe some others
to test that the filter actually filters out non-matching boards). Then first
run `./dist/tools/usb-serial/ttys.py` without arguments and study the output.
When a genuine Arduino Mega 2560, a genuine Arduino Mega ADK (a variant of the
Mega 2560),a cheap Arduino Mega 2560 clone, a BBC micro:bit v2, and a
Nucleo F767-ZI are connected, the following output is shown:

path | driver | vendor | model | model_db | serial | ctime | iface_num
-------------|---------|--------------------------|--------------------------------------|------------------------------------------------------|--------------------------------------------------|----------|----------
/dev/ttyACM0 | cdc_acm | Arduino (www.arduino.cc) | 0042 | Mega 2560 R3 (CDC ACM) | 857353134333519002C1 | 12:13:55 | 0
/dev/ttyACM1 | cdc_acm | Arduino (www.arduino.cc) | EOS High Power | Mega ADK R3 (CDC ACM) | 75230313733351110120 | 15:59:57 | 0
/dev/ttyACM2 | cdc_acm | STMicroelectronics | STM32 STLink | ST-LINK/V2.1 | 0670FF535155878281123912 | 10:00:39 | 2
/dev/ttyACM3 | cdc_acm | Arm | BBC micro:bit CMSIS-DAP | ARM mbed | 99053602000528334c41b84da1f2f09d000000006e052820 | 12:21:03 | 1
/dev/ttyUSB0 | cp210x | Silicon Labs | CP2102 USB to UART Bridge Controller | CP2102/CP2109 UART Bridge Controller [CP210x family] | 0001 | 16:57:27 | 0

Now we add arguments to the invocation of `ttys.py` to filter the list e.g.
by model, vendor etc. (note: as regex!) ideally until only the target boards
are listed. Some boards do not provide enough information to e.g. tell them
apart from other boards using the same USB to UART bridge or the same debugger.
In that case we have to live with some "bycatch".

In the case of the Arduino Mega 2560 the parameters
`--vendor 'Arduino' --model-db 'Mega 2560|Mega ADK'` will narrow down the
list to only show the genuine Arduino Mega versions. Se we add to the
`Makefile.include` in `boards/arduino-mega2560`:

```Makefile
TTY_BOARD_FILTER := --vendor 'Arduino' --model-db 'Mega 2560|Mega ADK'
```

Note that also matching the `R3` in `Mega 2560 R3` would prevent matching older
or newer revisions than R3, so we don't add that to the regex.

Advances Board Filters
----------------------

In most cases, just adding a simple `TTY_BOARD_FILTER` is sufficient. If we
however have wildly different flavors of the same board (e.g. genuine Arduino
Mega 2560 with an ATmega16U2 and clones with a cheap USB to UART bridge) that we
all want to support, we have to instead provide a `TTY_SELECT_CMD` that prints
the path to the TTY and exists with `0` if a TTY was found, or that exists with
`1` and prints nothing when no TTY was found. We can still use the `ttys.py`
script to detect all Arduino Mega 2560 versions: We first try to detect a
genuine Arduino Mega and fall back to selecting cheap USB UART bridges when that
fails using the `||` shell operator:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TTY_SELECT_CMD := $(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path \
--vendor 'Arduino' \
--model-db 'Mega 2560|Mega ADK' || \
$(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path \
--driver 'cp210x'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 changes: 5 additions & 2 deletions makefiles/tools/serial.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ ifeq (1,$(MOST_RECENT_PORT))
ifneq (,$(filter stdio_cdc_acm,$(USEMODULE)))
TTY_BOARD_FILTER ?= --model $(BOARD) --vendor 'RIOT-os\.org'
endif
TTYS_FLAGS := --most-recent --format path $(TTY_BOARD_FILTER)
PORT_DETECTED := $(shell $(RIOTTOOLS)/usb-serial/ttys.py $(TTYS_FLAGS))
TTY_SELECT_CMD ?= $(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path \
$(TTY_BOARD_FILTER)
PORT_DETECTED := $(shell $(TTY_SELECT_CMD) || echo 'no-tty-detected')
PORT ?= $(PORT_DETECTED)
endif
# Otherwise, use as default the most commonly used ports on Linux and OSX
Expand Down