• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ARMmbed / mbed-os-tools / #457

24 Aug 2024 09:15PM UTC coverage: 0.0% (-59.9%) from 59.947%
#457

push

coveralls-python

web-flow
Merge 7c6dbce13 into c467d6f14

0 of 4902 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/mbed_os_tools/detect/lstools_base.py
1
# Copyright (c) 2018, Arm Limited and affiliates.
2
# SPDX-License-Identifier: Apache-2.0
3
#
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15

16
import re
×
17
from abc import ABCMeta, abstractmethod
×
18
from io import open
×
19
from json import load
×
20
from os import listdir
×
21
from os.path import expanduser, isfile, join, exists, isdir
×
22
import logging
×
23
import functools
×
24
import json
×
25

26
from .platform_database import (
×
27
    PlatformDatabase,
28
    LOCAL_PLATFORM_DATABASE,
29
    LOCAL_MOCKS_DATABASE,
30
)
31
from future.utils import with_metaclass
×
32

33
mbedls_root_logger = logging.getLogger("mbedls")
×
34
mbedls_root_logger.setLevel(logging.WARNING)
×
35

36
logger = logging.getLogger("mbedls.lstools_base")
×
37
logger.addHandler(logging.NullHandler())
×
38

39

40
def deprecated(reason):
×
41
    """Deprecate a function/method with a decorator"""
42

43
    def actual_decorator(func):
×
44
        @functools.wraps(func)
×
45
        def new_func(*args, **kwargs):
×
46
            logger.warning("Call to deprecated function %s. %s", func.__name__, reason)
×
47
            return func(*args, **kwargs)
×
48

49
        return new_func
×
50

51
    return actual_decorator
×
52

53

54
class FSInteraction(object):
×
55
    BeforeFilter = 1
×
56
    AfterFilter = 2
×
57
    Never = 3
×
58

59

60
class MbedLsToolsBase(with_metaclass(ABCMeta, object)):
×
61
    """ Base class for mbed-lstools, defines mbed-ls tools interface for
62
    mbed-enabled devices detection for various hosts
63
    """
64

65
    # Which OSs are supported by this module
66
    # Note: more than one OS can be supported by mbed-lstools_* module
67
    os_supported = []
×
68

69
    # Directory where we will store global (OS user specific mocking)
70
    HOME_DIR = expanduser("~")
×
71
    MOCK_FILE_NAME = ".mbedls-mock"
×
72
    RETARGET_FILE_NAME = "mbedls.json"
×
73
    DETAILS_TXT_NAME = "DETAILS.TXT"
×
74
    MBED_HTM_NAME = "mbed.htm"
×
75

76
    VENDOR_ID_DEVICE_TYPE_MAP = {
×
77
        "0483": "stlink",
78
        "0d28": "daplink",
79
        "1366": "jlink",
80
        "03eb": "atmel",
81
    }
82

83
    def __init__(self, list_unmounted=False, **kwargs):
×
84
        """ ctor
85
        """
86
        self.retarget_data = {}  # Used to retarget mbed-enabled platform properties
×
87

88
        platform_dbs = []
×
89
        if isfile(self.MOCK_FILE_NAME) or (
×
90
            "force_mock" in kwargs and kwargs["force_mock"]
91
        ):
92
            platform_dbs.append(self.MOCK_FILE_NAME)
×
93
        elif isfile(LOCAL_MOCKS_DATABASE):
×
94
            platform_dbs.append(LOCAL_MOCKS_DATABASE)
×
95
        platform_dbs.append(LOCAL_PLATFORM_DATABASE)
×
96
        self.plat_db = PlatformDatabase(platform_dbs, primary_database=platform_dbs[0])
×
97
        self.list_unmounted = list_unmounted
×
98

99
        if "skip_retarget" not in kwargs or not kwargs["skip_retarget"]:
×
100
            self.retarget()
×
101

102
    @abstractmethod
×
103
    def find_candidates(self):
×
104
        """Find all candidate devices connected to this computer
105

106
        Note: Should not open any files
107

108
        @return A dict with the keys 'mount_point', 'serial_port' and 'target_id_usb_id'
109
        """
110
        raise NotImplementedError
×
111

112
    def list_mbeds(
×
113
        self,
114
        fs_interaction=FSInteraction.BeforeFilter,
115
        filter_function=None,
116
        unique_names=False,
117
        read_details_txt=False,
118
    ):
119
        """ List details of connected devices
120
        @return Returns list of structures with detailed info about each mbed
121
        @param fs_interaction A member of the FSInteraction class that picks the
122
          trade of between quality of service and speed
123
        @param filter_function Function that is passed each mbed candidate,
124
          should return True if it should be included in the result
125
          Ex. mbeds = list_mbeds(filter_function=lambda m: m['platform_name'] == 'K64F')
126
        @param unique_names A boolean controlling the presence of the
127
          'platform_unique_name' member of the output dict
128
        @param read_details_txt A boolean controlling the presense of the
129
          output dict attributes read from other files present on the 'mount_point'
130
        @details Function returns list of dictionaries with mbed attributes
131
          'mount_point', TargetID name etc.
132
        Function returns mbed list with platform names if possible
133
        """
134
        platform_count = {}
×
135
        candidates = list(self.find_candidates())
×
136
        logger.debug("Candidates for display %r", candidates)
×
137
        result = []
×
138
        for device in candidates:
×
139
            device["device_type"] = self._detect_device_type(device)
×
140
            if (
×
141
                not device["mount_point"]
142
                or not self.mount_point_ready(device["mount_point"])
143
            ) and not self.list_unmounted:
144
                if device["target_id_usb_id"] and device["serial_port"]:
×
145
                    logger.warning(
×
146
                        "MBED with target id '%s' is connected, but not mounted. "
147
                        "Use the '-u' flag to include it in the list.",
148
                        device["target_id_usb_id"],
149
                    )
150
            else:
151
                platform_data = self.plat_db.get(
×
152
                    device["target_id_usb_id"][0:4],
153
                    device_type=device["device_type"] or "daplink",
154
                    verbose_data=True,
155
                )
156
                device.update(platform_data or {"platform_name": None})
×
157
                maybe_device = {
×
158
                    FSInteraction.BeforeFilter: self._fs_before_id_check,
159
                    FSInteraction.AfterFilter: self._fs_after_id_check,
160
                    FSInteraction.Never: self._fs_never,
161
                }[fs_interaction](device, filter_function, read_details_txt)
162
                if maybe_device and (
×
163
                    maybe_device["mount_point"] or self.list_unmounted
164
                ):
165
                    if unique_names:
×
166
                        name = device["platform_name"]
×
167
                        platform_count.setdefault(name, -1)
×
168
                        platform_count[name] += 1
×
169
                        device["platform_name_unique"] = "%s[%d]" % (
×
170
                            name,
171
                            platform_count[name],
172
                        )
173
                    try:
×
174
                        device.update(self.retarget_data[device["target_id"]])
×
175
                        logger.debug(
×
176
                            "retargeting %s with %r",
177
                            device["target_id"],
178
                            self.retarget_data[device["target_id"]],
179
                        )
180
                    except KeyError:
×
181
                        pass
×
182

183
                    # This is done for API compatibility, would prefer for this to
184
                    # just be None
185
                    device["device_type"] = (
×
186
                        device["device_type"] if device["device_type"] else "unknown"
187
                    )
188
                    result.append(maybe_device)
×
189

190
        return result
×
191

192
    def _fs_never(self, device, filter_function, read_details_txt):
×
193
        """Filter device without touching the file system of the device"""
194
        device["target_id"] = device["target_id_usb_id"]
×
195
        device["target_id_mbed_htm"] = None
×
196
        if not filter_function or filter_function(device):
×
197
            return device
×
198
        else:
199
            return None
×
200

201
    def _fs_before_id_check(self, device, filter_function, read_details_txt):
×
202
        """Filter device after touching the file system of the device.
203
        Said another way: Touch the file system before filtering
204
        """
205

206
        device["target_id"] = device["target_id_usb_id"]
×
207
        self._update_device_from_fs(device, read_details_txt)
×
208
        if not filter_function or filter_function(device):
×
209
            return device
×
210
        else:
211
            return None
×
212

213
    def _fs_after_id_check(self, device, filter_function, read_details_txt):
×
214
        """Filter device before touching the file system of the device.
215
        Said another way: Touch the file system after filtering
216
        """
217
        device["target_id"] = device["target_id_usb_id"]
×
218
        device["target_id_mbed_htm"] = None
×
219
        if not filter_function or filter_function(device):
×
220
            self._update_device_from_fs(device, read_details_txt)
×
221
            return device
×
222
        else:
223
            return None
×
224

225
    def _update_device_from_fs(self, device, read_details_txt):
×
226
        """ Updates the device information based on files from its 'mount_point'
227
            @param device Dictionary containing device information
228
            @param read_details_txt A boolean controlling the presense of the
229
              output dict attributes read from other files present on the 'mount_point'
230
        """
231
        if not device.get("mount_point", None):
×
232
            return
×
233

234
        try:
×
235
            directory_entries = listdir(device["mount_point"])
×
236
            device["directory_entries"] = directory_entries
×
237
            device["target_id"] = device["target_id_usb_id"]
×
238

239
            # Always try to update using daplink compatible boards processself.
240
            # This is done for backwards compatibility.
241
            self._update_device_details_daplink_compatible(device, read_details_txt)
×
242

243
            if device.get("device_type") == "jlink":
×
244
                self._update_device_details_jlink(device, read_details_txt)
×
245

246
            if device.get("device_type") == "atmel":
×
247
                self._update_device_details_atmel(device, read_details_txt)
×
248

249
        except (OSError, IOError) as e:
×
250
            logger.warning(
×
251
                'Marking device with mount point "%s" as unmounted due to the '
252
                "following error: %s",
253
                device["mount_point"],
254
                e,
255
            )
256
            device["mount_point"] = None
×
257

258
    def _detect_device_type(self, device):
×
259
        """ Returns a string of the device type
260
            @param device Dictionary containing device information
261
            @return Device type located in VENDOR_ID_DEVICE_TYPE_MAP or None if unknown
262
        """
263

264
        return self.VENDOR_ID_DEVICE_TYPE_MAP.get(device.get("vendor_id"))
×
265

266
    def _update_device_details_daplink_compatible(self, device, read_details_txt):
×
267
        """ Updates the daplink-specific device information based on files from its
268
        'mount_point'
269
            @param device Dictionary containing device information
270
            @param read_details_txt A boolean controlling the presense of the
271
              output dict attributes read from other files present on the 'mount_point'
272
        """
273
        lowercase_directory_entries = [e.lower() for e in device["directory_entries"]]
×
274
        if self.MBED_HTM_NAME.lower() in lowercase_directory_entries:
×
275
            self._update_device_from_htm(device)
×
276
        elif not read_details_txt:
×
277
            logger.debug(
×
278
                "Since mbed.htm is not present, attempting to use "
279
                "details.txt for the target id"
280
            )
281
            read_details_txt = True
×
282

283
        if (
×
284
            read_details_txt
285
            and self.DETAILS_TXT_NAME.lower() in lowercase_directory_entries
286
        ):
287
            details_txt = self._details_txt(device["mount_point"]) or {}
×
288
            device.update(
×
289
                {
290
                    "daplink_%s" % f.lower().replace(" ", "_"): v
291
                    for f, v in details_txt.items()
292
                }
293
            )
294

295
            # If details.txt contains the target id, this is the most trusted source
296
            if device.get("daplink_unique_id", None):
×
297
                device["target_id"] = device["daplink_unique_id"]
×
298

299
        if device["target_id"]:
×
300
            identifier = device["target_id"][0:4]
×
301
            platform_data = self.plat_db.get(
×
302
                identifier, device_type="daplink", verbose_data=True
303
            )
304
            if not platform_data:
×
305
                logger.warning(
×
306
                    'daplink entry: "%s" not found in platform database', identifier
307
                )
308
            else:
309
                device.update(platform_data)
×
310
        else:
311
            device["platform_name"] = None
×
312

313
    def _update_device_details_jlink(self, device, _):
×
314
        """ Updates the jlink-specific device information based on files from its 'mount_point'
315
            @param device Dictionary containing device information
316
        """
317
        lower_case_map = {e.lower(): e for e in device["directory_entries"]}
×
318

319
        if "board.html" in lower_case_map:
×
320
            board_file_key = "board.html"
×
321
        elif "user guide.html" in lower_case_map:
×
322
            board_file_key = "user guide.html"
×
323
        else:
324
            logger.warning("No valid file found to update JLink device details")
×
325
            return
×
326

327
        board_file_path = join(device["mount_point"], lower_case_map[board_file_key])
×
328
        with open(board_file_path, "r") as board_file:
×
329
            board_file_lines = board_file.readlines()
×
330

331
        for line in board_file_lines:
×
332
            m = re.search(r"url=([\w\d\:\-/\\\?\.=-_]+)", line)
×
333
            if m:
×
334
                device["url"] = m.group(1).strip()
×
335
                identifier = device["url"].split("/")[-1]
×
336
                platform_data = self.plat_db.get(
×
337
                    identifier, device_type="jlink", verbose_data=True
338
                )
339
                if not platform_data:
×
340
                    logger.warning(
×
341
                        'jlink entry: "%s", not found in platform database', identifier
342
                    )
343
                else:
344
                    device.update(platform_data)
×
345
                break
×
346

347
    def _update_device_from_htm(self, device):
×
348
        """Set the 'target_id', 'target_id_mbed_htm', 'platform_name' and
349
        'daplink_*' attributes by reading from mbed.htm on the device
350
        """
351
        htm_target_id, daplink_info = self._read_htm_ids(device["mount_point"])
×
352
        if daplink_info:
×
353
            device.update(
×
354
                {
355
                    "daplink_%s" % f.lower().replace(" ", "_"): v
356
                    for f, v in daplink_info.items()
357
                }
358
            )
359
        if htm_target_id:
×
360
            logger.debug(
×
361
                "Found htm target id, %s, for usb target id %s",
362
                htm_target_id,
363
                device["target_id_usb_id"],
364
            )
365
            device["target_id"] = htm_target_id
×
366
        else:
367
            logger.debug(
×
368
                "Could not read htm on from usb id %s. Falling back to usb id",
369
                device["target_id_usb_id"],
370
            )
371
            device["target_id"] = device["target_id_usb_id"]
×
372
        device["target_id_mbed_htm"] = htm_target_id
×
373

374
    def _update_device_details_atmel(self, device, _):
×
375
        """ Updates the Atmel device information based on files from its 'mount_point'
376
            @param device Dictionary containing device information
377
            @param read_details_txt A boolean controlling the presense of the
378
              output dict attributes read from other files present on the 'mount_point'
379
        """
380

381
        # Atmel uses a system similar to DAPLink, but there's no details.txt with a
382
        # target ID to identify device we can use the serial, which is ATMLXXXXYYYYYYY
383
        # where XXXX is the board identifier.
384
        # This can be verified by looking at readme.htm, which also uses the board ID
385
        # to redirect to platform page
386

387
        device["target_id"] = device["target_id_usb_id"][4:8]
×
388
        platform_data = self.plat_db.get(
×
389
            device["target_id"], device_type="atmel", verbose_data=True
390
        )
391

392
        device.update(platform_data or {"platform_name": None})
×
393

394
    def mock_manufacture_id(self, mid, platform_name, oper="+"):
×
395
        """! Replace (or add if manufacture id doesn't exist) entry in self.manufacture_ids
396
        @param oper '+' add new mock / override existing entry
397
                    '-' remove mid from mocking entry
398
        @return Mocked structure (json format)
399
        """
400
        if oper == "+":
×
401
            self.plat_db.add(mid, platform_name, permanent=True)
×
402
        elif oper == "-":
×
403
            self.plat_db.remove(mid, permanent=True)
×
404
        else:
405
            raise ValueError("oper can only be [+-]")
×
406

407
    def retarget_read(self):
×
408
        """! Load retarget data from local file
409
        @return Curent retarget configuration (dictionary)
410
        """
411
        if isfile(self.RETARGET_FILE_NAME):
×
412
            logger.debug("reading retarget file %s", self.RETARGET_FILE_NAME)
×
413
            try:
×
414
                with open(self.RETARGET_FILE_NAME, "r", encoding="utf-8") as f:
×
415
                    return load(f)
×
416
            except IOError as e:
×
417
                logger.exception(e)
×
418
            except ValueError as e:
×
419
                logger.exception(e)
×
420
        return {}
×
421

422
    def retarget(self):
×
423
        """! Enable retargeting
424
        @details Read data from local retarget configuration file
425
        @return Retarget data structure read from configuration file
426
        """
427
        self.retarget_data = self.retarget_read()
×
428
        return self.retarget_data
×
429

430
    def get_dummy_platform(self, platform_name):
×
431
        """! Returns simple dummy platform """
432
        if not hasattr(self, "dummy_counter"):
×
433
            self.dummy_counter = {}  # platform<str>: counter<int>
×
434

435
        if platform_name not in self.dummy_counter:
×
436
            self.dummy_counter[platform_name] = 0
×
437

438
        platform = {
×
439
            "platform_name": platform_name,
440
            "platform_name_unique": "%s[%d]"
441
            % (platform_name, self.dummy_counter[platform_name]),
442
            "mount_point": "DUMMY",
443
            "serial_port": "DUMMY",
444
            "target_id": "DUMMY",
445
            "target_id_mbed_htm": "DUMMY",
446
            "target_id_usb_id": "DUMMY",
447
            "daplink_version": "DUMMY",
448
        }
449
        self.dummy_counter[platform_name] += 1
×
450
        return platform
×
451

452
    def get_supported_platforms(self, device_type=None):
×
453
        """! Return a dictionary of supported target ids and the corresponding platform name
454
        @param device_type Filter which device entries are returned from the platform
455
          database
456
        @return Dictionary of { 'target_id': 'platform_name', ... }
457
        """
458
        kwargs = {}
×
459
        if device_type is not None:
×
460
            kwargs["device_type"] = device_type
×
461

462
        items = self.plat_db.items(**kwargs)
×
463
        return {i[0]: i[1] for i in items}
×
464

465
    # Private functions supporting API
466
    def _read_htm_ids(self, mount_point):
×
467
        """! Function scans mbed.htm to get information about TargetID.
468
        @param mount_point mbed mount point (disk / drive letter)
469
        @return Function returns targetID, in case of failure returns None.
470
        @details Note: This function should be improved to scan variety of boards'
471
          mbed.htm files
472
        """
473
        result = {}
×
474
        target_id = None
×
475
        for line in self._htm_lines(mount_point):
×
476
            target_id = target_id or self._target_id_from_htm(line)
×
477
            ver_bld = self._mbed_htm_comment_section_ver_build(line)
×
478
            if ver_bld:
×
479
                result["version"], result["build"] = ver_bld
×
480

481
            m = re.search(r"url=([\w\d\:/\\\?\.=-_]+)", line)
×
482
            if m:
×
483
                result["url"] = m.group(1).strip()
×
484
        return target_id, result
×
485

486
    def _mbed_htm_comment_section_ver_build(self, line):
×
487
        """! Check for Version and Build date of interface chip firmware im mbed.htm file
488
        @return (version, build) tuple if successful, None if no info found
489
        """
490
        # <!-- Version: 0200 Build: Mar 26 2014 13:22:20 -->
491
        m = re.search(r"^<!-- Version: (\d+) Build: ([\d\w: ]+) -->", line)
×
492
        if m:
×
493
            version_str, build_str = m.groups()
×
494
            return (version_str.strip(), build_str.strip())
×
495

496
        # <!-- Version: 0219 Build: Feb  2 2016 15:20:54 Git Commit SHA:
497
        #   0853ba0cdeae2436c52efcba0ba76a6434c200ff Git local mods:No-->
498
        m = re.search(r"^<!-- Version: (\d+) Build: ([\d\w: ]+) Git Commit SHA", line)
×
499
        if m:
×
500
            version_str, build_str = m.groups()
×
501
            return (version_str.strip(), build_str.strip())
×
502

503
        # <!-- Version: 0.14.3. build 471 -->
504
        m = re.search(r"^<!-- Version: ([\d+\.]+)\. build (\d+) -->", line)
×
505
        if m:
×
506
            version_str, build_str = m.groups()
×
507
            return (version_str.strip(), build_str.strip())
×
508
        return None
×
509

510
    def _htm_lines(self, mount_point):
×
511
        if mount_point:
×
512
            mbed_htm_path = join(mount_point, self.MBED_HTM_NAME)
×
513
            with open(mbed_htm_path, "r") as f:
×
514
                return f.readlines()
×
515

516
    def _details_txt(self, mount_point):
×
517
        """! Load DETAILS.TXT to dictionary:
518
            DETAILS.TXT example:
519
            Version: 0226
520
            Build:   Aug 24 2015 17:06:30
521
            Git Commit SHA: 27a236b9fe39c674a703c5c89655fbd26b8e27e1
522
            Git Local mods: Yes
523

524
            or:
525

526
            # DAPLink Firmware - see https://mbed.com/daplink
527
            Unique ID: 0240000029164e45002f0012706e0006f301000097969900
528
            HIF ID: 97969900
529
            Auto Reset: 0
530
            Automation allowed: 0
531
            Daplink Mode: Interface
532
            Interface Version: 0240
533
            Git SHA: c765cbb590f57598756683254ca38b211693ae5e
534
            Local Mods: 0
535
            USB Interfaces: MSD, CDC, HID
536
            Interface CRC: 0x26764ebf
537
        """
538

539
        if mount_point:
×
540
            path_to_details_txt = join(mount_point, self.DETAILS_TXT_NAME)
×
541
            with open(path_to_details_txt, "r") as f:
×
542
                return self._parse_details(f.readlines())
×
543
        return None
×
544

545
    def _parse_details(self, lines):
×
546
        result = {}
×
547
        for line in lines:
×
548
            if not line.startswith("#"):
×
549
                key, _, value = line.partition(":")
×
550
                if value:
×
551
                    result[key] = value.strip()
×
552
        if "Interface Version" in result:
×
553
            result["Version"] = result["Interface Version"]
×
554
        return result
×
555

556
    def _target_id_from_htm(self, line):
×
557
        """! Extract Target id from htm line.
558
        @return Target id or None
559
        """
560
        # Detecting modern mbed.htm file format
561
        m = re.search("\\?code=([a-fA-F0-9]+)", line)
×
562
        if m:
×
563
            result = m.groups()[0]
×
564
            logger.debug("Found target id %s in htm line %s", result, line)
×
565
            return result
×
566
        # Last resort, we can try to see if old mbed.htm format is there
567
        m = re.search("\\?auth=([a-fA-F0-9]+)", line)
×
568
        if m:
×
569
            result = m.groups()[0]
×
570
            logger.debug("Found target id %s in htm line %s", result, line)
×
571
            return result
×
572

573
        return None
×
574

575
    def mount_point_ready(self, path):
×
576
        """! Check if a mount point is ready for file operations
577
        """
578
        return exists(path) and isdir(path)
×
579

580
    @staticmethod
×
581
    def _run_cli_process(cmd, shell=True):
×
582
        """! Runs command as a process and return stdout, stderr and ret code
583
        @param cmd Command to execute
584
        @return Tuple of (stdout, stderr, returncode)
585
        """
586
        from subprocess import Popen, PIPE
×
587

588
        p = Popen(cmd, shell=shell, stdout=PIPE, stderr=PIPE)
×
589
        _stdout, _stderr = p.communicate()
×
590
        return _stdout, _stderr, p.returncode
×
591

592
    @deprecated(
×
593
        "Functionality has been moved into 'list_mbeds'. "
594
        "Please use list_mbeds with 'unique_names=True' and "
595
        "'read_details_txt=True'"
596
    )
597
    def list_mbeds_ext(self):
×
598
        """! Function adds extra information for each mbed device
599
        @return Returns list of mbed devices plus extended data like
600
        'platform_name_unique'
601
        @details Get information about mbeds with extended parameters/info included
602
        """
603

604
        return self.list_mbeds(unique_names=True, read_details_txt=True)
×
605

606
    @deprecated(
×
607
        "List formatting methods are deprecated for a simpler API. "
608
        "Please use 'list_mbeds' instead."
609
    )
610
    def list_manufacture_ids(self):
×
611
        """! Creates list of all available mappings for target_id -> Platform
612
        @return String with table formatted output
613
        """
614
        from prettytable import PrettyTable, HEADER
×
615

616
        columns = ["target_id_prefix", "platform_name"]
×
617
        pt = PrettyTable(columns, junction_char="|", hrules=HEADER)
×
618
        for col in columns:
×
619
            pt.align[col] = "l"
×
620

621
        for target_id_prefix, platform_name in sorted(self.plat_db.items()):
×
622
            pt.add_row([target_id_prefix, platform_name])
×
623

624
        return pt.get_string()
×
625

626
    @deprecated(
×
627
        "List formatting methods are deprecated to simplify the API. "
628
        "Please use 'list_mbeds' instead."
629
    )
630
    def list_platforms(self):
×
631
        """! Useful if you just want to know which platforms are currently
632
        available on the system
633
        @return List of (unique values) available platforms
634
        """
635
        result = []
×
636
        mbeds = self.list_mbeds()
×
637
        for i, val in enumerate(mbeds):
×
638
            platform_name = str(val["platform_name"])
×
639
            if platform_name not in result:
×
640
                result.append(platform_name)
×
641
        return result
×
642

643
    @deprecated(
×
644
        "List formatting methods are deprecated to simplify the API. "
645
        "Please use 'list_mbeds' instead."
646
    )
647
    def list_platforms_ext(self):
×
648
        """! Useful if you just want to know how many platforms of each type are
649
        currently available on the system
650
        @return Dict of platform: platform_count
651
        """
652
        result = {}
×
653
        mbeds = self.list_mbeds()
×
654
        for i, val in enumerate(mbeds):
×
655
            platform_name = str(val["platform_name"])
×
656
            if platform_name not in result:
×
657
                result[platform_name] = 1
×
658
            else:
659
                result[platform_name] += 1
×
660
        return result
×
661

662
    @deprecated(
×
663
        "List formatting methods are deprecated to simplify the API. "
664
        "Please use 'list_mbeds' instead."
665
    )
666
    def list_mbeds_by_targetid(self):
×
667
        """! Get information about mbeds with extended parameters/info included
668
        @return Returns dictionary where keys are TargetIDs and values are mbed
669
        structures
670
        @details Ordered by target id (key: target_id).
671
        """
672
        result = {}
×
673
        mbed_list = self.list_mbeds_ext()
×
674
        for mbed in mbed_list:
×
675
            target_id = mbed["target_id"]
×
676
            result[target_id] = mbed
×
677
        return result
×
678

679
    @deprecated(
×
680
        "List formatting methods are deprecated to simplify the API. "
681
        "Please use 'list_mbeds' instead."
682
    )
683
    def get_string(
×
684
        self, border=False, header=True, padding_width=1, sortby="platform_name"
685
    ):
686
        """! Printing with some sql table like decorators
687
        @param border Table border visibility
688
        @param header Table header visibility
689
        @param padding_width Table padding
690
        @param sortby Column used to sort results
691
        @return Returns string which can be printed on console
692
        """
693
        from prettytable import PrettyTable, HEADER
×
694

695
        result = ""
×
696
        mbeds = self.list_mbeds(unique_names=True, read_details_txt=True)
×
697
        if mbeds:
×
698
            """ ['platform_name', 'mount_point', 'serial_port', 'target_id'] -
699
                columns generated from USB auto-detection
700
                ['platform_name_unique', ...] -
701
                columns generated outside detection subsystem (OS dependent detection)
702
            """
703
            columns = [
×
704
                "platform_name",
705
                "platform_name_unique",
706
                "mount_point",
707
                "serial_port",
708
                "target_id",
709
                "daplink_version",
710
            ]
711
            pt = PrettyTable(columns, junction_char="|", hrules=HEADER)
×
712
            for col in columns:
×
713
                pt.align[col] = "l"
×
714

715
            for mbed in mbeds:
×
716
                row = []
×
717
                for col in columns:
×
718
                    row.append(mbed[col] if col in mbed and mbed[col] else "unknown")
×
719
                pt.add_row(row)
×
720
            result = pt.get_string(
×
721
                border=border, header=header, padding_width=padding_width, sortby=sortby
722
            )
723
        return result
×
724

725
    # Private functions supporting API
726

727
    @deprecated(
×
728
        "This method will be removed from the public API. "
729
        "Please use 'list_mbeds' instead"
730
    )
731
    def get_json_data_from_file(self, json_spec_filename, verbose=False):
×
732
        """! Loads from file JSON formatted string to data structure
733
        @return None if JSON can be loaded
734
        """
735
        try:
×
736
            with open(json_spec_filename) as data_file:
×
737
                try:
×
738
                    return json.load(data_file)
×
739
                except ValueError as json_error_msg:
×
740
                    logger.error(
×
741
                        "Parsing file(%s): %s", json_spec_filename, json_error_msg
742
                    )
743
                    return None
×
744
        except IOError as fileopen_error_msg:
×
745
            logger.warning(fileopen_error_msg)
×
746
            return None
×
747

748
    @deprecated(
×
749
        "This method will be removed from the public API. "
750
        "Please use 'list_mbeds' instead"
751
    )
752
    def get_htm_target_id(self, mount_point):
×
753
        target_id, _ = self._read_htm_ids(mount_point)
×
754
        return target_id
×
755

756
    @deprecated(
×
757
        "This method will be removed from the public API. "
758
        "Please use 'list_mbeds' instead"
759
    )
760
    def get_mbed_htm(self, mount_point):
×
761
        _, build_info = self._read_htm_ids(mount_point)
×
762
        return build_info
×
763

764
    @deprecated(
×
765
        "This method will be removed from the public API. "
766
        "Please use 'list_mbeds' instead"
767
    )
768
    def get_mbed_htm_comment_section_ver_build(self, line):
×
769
        return self._mbed_htm_comment_section_ver_build(line)
×
770

771
    @deprecated(
×
772
        "This method will be removed from the public API. "
773
        "Please use 'list_mbeds' instead"
774
    )
775
    def get_mbed_htm_lines(self, mount_point):
×
776
        return self._htm_lines(mount_point)
×
777

778
    @deprecated(
×
779
        "This method will be removed from the public API. "
780
        "Please use 'list_mbeds' instead"
781
    )
782
    def get_details_txt(self, mount_point):
×
783
        return self._details_txt(mount_point)
×
784

785
    @deprecated(
×
786
        "This method will be removed from the public API. "
787
        "Please use 'list_mbeds' instead"
788
    )
789
    def parse_details_txt(self, lines):
×
790
        return self._parse_details(lines)
×
791

792
    @deprecated(
×
793
        "This method will be removed from the public API. "
794
        "Please use 'list_mbeds' instead"
795
    )
796
    def scan_html_line_for_target_id(self, line):
×
797
        return self._target_id_from_htm(line)
×
798

799
    @staticmethod
×
800
    @deprecated(
×
801
        "This method will be removed from the public API. "
802
        "Please use 'list_mbeds' instead"
803
    )
804
    def run_cli_process(cmd, shell=True):
×
805
        return MbedLsToolsBase._run_cli_process(cmd, shell)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc