Skip to content

Commit c66814f

Browse files
committed
boards: Get boards with J-Link slug
When using J-Link, the only available board data may be the product page URL. The URL's slug may indicate the board, but not match the Mbed database slug, so this is searched against Mbed slug, board_type and board_name in the database to try to find a match.
1 parent 5a87d37 commit c66814f

File tree

6 files changed

+84
-4
lines changed

6 files changed

+84
-4
lines changed

news/20210330104425.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add detection of devices connected with J-Link.

src/mbed_tools/devices/_internal/resolve_board.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313

1414
from typing import Optional
1515

16-
from mbed_tools.targets import Board, get_board_by_product_code, get_board_by_online_id
16+
from mbed_tools.targets import (
17+
Board,
18+
get_board_by_product_code,
19+
get_board_by_online_id,
20+
get_board_by_jlink_slug,
21+
)
1722
from mbed_tools.targets.exceptions import UnknownBoard, MbedTargetsError
1823

1924
from mbed_tools.devices._internal.exceptions import NoBoardForCandidate, ResolveBoardError
@@ -36,7 +41,7 @@ def resolve_board(
3641
The rules are as follows:
3742
3843
1. Use the product code from the mbed.htm file or details.txt if available
39-
2. Use online ID from the htm file if available
44+
2. Use online ID from the htm file or Board.html if available
4045
3. Try to use the first 4 chars of the USB serial number as the product code
4146
"""
4247
if product_code:
@@ -54,7 +59,10 @@ def resolve_board(
5459
slug = online_id.slug
5560
target_type = online_id.target_type
5661
try:
57-
return get_board_by_online_id(slug=slug, target_type=target_type)
62+
if target_type == "jlink":
63+
return get_board_by_jlink_slug(slug=slug)
64+
else:
65+
return get_board_by_online_id(slug=slug, target_type=target_type)
5866
except UnknownBoard:
5967
logger.error(f"Could not identify a board with the slug: '{slug}' and target type: '{target_type}'.")
6068
except MbedTargetsError as e:

src/mbed_tools/targets/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
from mbed_tools.targets.get_board import (
2929
get_board_by_product_code,
3030
get_board_by_online_id,
31+
get_board_by_jlink_slug,
3132
)
3233
from mbed_tools.targets.board import Board

src/mbed_tools/targets/get_board.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,25 @@ def get_board_by_online_id(slug: str, target_type: str) -> Board:
4545
return get_board(lambda board: board.slug.casefold() == matched_slug and board.target_type == target_type)
4646

4747

48+
def get_board_by_jlink_slug(slug: str) -> Board:
49+
"""Returns first `mbed-tools.targets.board.Board` matching given slug.
50+
51+
With J-Link, the slug is extracted from a board manufacturer URL, and may not match
52+
the Mbed slug. The J-Link slug is compared against the slug, board_name and
53+
board_type of entries in the board database until a match is found.
54+
55+
Args:
56+
slug: the J-Link slug to look up in the database.
57+
58+
Raises:
59+
UnknownBoard: a board matching the slug was not found.
60+
"""
61+
matched_slug = slug.casefold()
62+
return get_board(
63+
lambda board: any(matched_slug == c.casefold() for c in [board.slug, board.board_name, board.board_type])
64+
)
65+
66+
4867
def get_board(matching: Callable) -> Board:
4968
"""Returns first `mbed_tools.targets.board.Board` for which `matching` is True.
5069

tests/devices/_internal/test_resolve_board.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ def get_board_by_product_code_mock():
1818
yield gbp
1919

2020

21+
@pytest.fixture
22+
def get_board_by_jlink_slug_mock():
23+
with mock.patch("mbed_tools.devices._internal.resolve_board.get_board_by_jlink_slug", autospec=True) as gbp:
24+
yield gbp
25+
26+
2127
@pytest.fixture
2228
def get_board_by_online_id_mock():
2329
with mock.patch("mbed_tools.devices._internal.resolve_board.get_board_by_online_id", autospec=True) as gbp:
@@ -76,6 +82,33 @@ def test_raises_when_database_lookup_fails(self, get_board_by_online_id_mock, ca
7682
assert caplog.records[-1].levelname == "ERROR"
7783

7884

85+
class TestResolveBoardUsingSlugFromJlink:
86+
def test_returns_resolved_board(self, get_board_by_jlink_slug_mock):
87+
online_id = OnlineId("jlink", "test-board")
88+
89+
subject = resolve_board(online_id=online_id)
90+
91+
assert subject == get_board_by_jlink_slug_mock.return_value
92+
get_board_by_jlink_slug_mock.assert_called_once_with(online_id.slug)
93+
94+
def test_raises_when_board_not_found(self, get_board_by_jlink_slug_mock):
95+
get_board_by_jlink_slug_mock.side_effect = UnknownBoard
96+
online_id = OnlineId("jlink", "test-board")
97+
98+
with pytest.raises(NoBoardForCandidate):
99+
resolve_board(online_id=online_id)
100+
101+
def test_raises_when_database_lookup_fails(self, get_board_by_jlink_slug_mock, caplog):
102+
get_board_by_jlink_slug_mock.side_effect = MbedTargetsError
103+
online_id = OnlineId("jlink", "test-board")
104+
105+
with pytest.raises(ResolveBoardError):
106+
resolve_board(online_id=online_id)
107+
108+
assert repr(online_id) in caplog.text
109+
assert caplog.records[-1].levelname == "ERROR"
110+
111+
79112
class TestResolveBoardUsingProductCodeFromSerial:
80113
def test_resolves_board_using_product_code_when_available(self, get_board_by_product_code_mock):
81114
serial_number = "0A9KJFKD0993WJKUFS0KLJ329090"

tests/targets/test_get_board.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from mbed_tools.targets._internal.exceptions import BoardAPIError
1111

1212
# Import from top level as this is the expected interface for users
13-
from mbed_tools.targets import get_board_by_online_id, get_board_by_product_code
13+
from mbed_tools.targets import get_board_by_online_id, get_board_by_product_code, get_board_by_jlink_slug
1414
from mbed_tools.targets.get_board import (
1515
_DatabaseMode,
1616
_get_database_mode,
@@ -125,6 +125,24 @@ def test_matches_boards_by_online_id(self, mock_get_board):
125125
assert not fn(not_matching_board)
126126

127127

128+
class TestGetBoardByJlinkSlug:
129+
def test_matches_boards_by_online_id(self, mock_get_board):
130+
assert get_board_by_jlink_slug(slug="slug") == mock_get_board.return_value
131+
132+
# Test callable matches correct boards
133+
fn = mock_get_board.call_args[0][0]
134+
135+
matching_board_1 = make_board(slug="slug")
136+
matching_board_2 = make_board(board_type="slug")
137+
matching_board_3 = make_board(board_name="slug")
138+
not_matching_board = make_board()
139+
140+
assert fn(matching_board_1)
141+
assert fn(matching_board_2)
142+
assert fn(matching_board_3)
143+
assert not fn(not_matching_board)
144+
145+
128146
class TestGetDatabaseMode:
129147
def test_returns_configured_database_mode(self, mock_env):
130148
mock_env.MBED_DATABASE_MODE = "OFFLINE"

0 commit comments

Comments
 (0)