Skip to content

Commit a56090b

Browse files
committed
Merge pull request #26 from dubek/linux_generic
Add Linux generic support
2 parents fb350c9 + 232f42e commit a56090b

File tree

5 files changed

+320
-287
lines changed

5 files changed

+320
-287
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Currently supported operating system:
77

88
* Windows 7.
99
* Ubuntu.
10+
* Linux (generic).
1011
* Mac OS X (Darwin).
1112

1213
The stand-alone mbed-lstools Python package is still under development, but it's already delivered as part of the mbed SDK's test suite and a command line tool (see below).
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
"""
2+
mbed SDK
3+
Copyright (c) 2011-2015 ARM Limited
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
17+
18+
import re
19+
import subprocess
20+
21+
from lstools_base import MbedLsToolsBase
22+
23+
24+
class MbedLsToolsLinuxGeneric(MbedLsToolsBase):
25+
""" MbedLsToolsLinuxGeneric supports mbed-enabled platforms detection across Linux family
26+
"""
27+
def __init__(self):
28+
""" ctor
29+
"""
30+
MbedLsToolsBase.__init__(self)
31+
self.os_supported.append('LinuxGeneric')
32+
self.hex_uuid_pattern = "usb-[0-9a-zA-Z_-]*_([0-9a-zA-Z]*)-.*"
33+
self.name_link_pattern = "(usb-[0-9a-zA-Z_-]*_[0-9a-zA-Z]*-.*$)"
34+
self.mount_media_pattern = "^/[a-zA-Z0-9/]* on (/[a-zA-Z0-9/]*) "
35+
36+
def list_mbeds(self):
37+
"""! Returns detailed list of connected mbeds
38+
39+
@return Returns list of structures with detailed info about each mbed
40+
41+
@details Function returns list of dictionaries with mbed attributes such as mount point, TargetID name etc.
42+
43+
Function returns mbed list with platform names if possible
44+
all_devices =
45+
[
46+
['*not detected', 'sdi', '/media/usb3', '/dev/ttyACM7', 'usb-MBED_microcontroller_066EFF534951775087215736-0:0 -> ../../sdi'],
47+
['*not detected', 'sdg', '/media/usb5', '/dev/ttyACM5', 'usb-MBED_microcontroller_066EFF525257775087141721-0:0 -> ../../sdg'],
48+
['*not detected', 'sdf', '/media/przemek/NUCLEO', '/dev/ttyACM4', 'usb-MBED_microcontroller_0671FF534951775087131543-0:0 -> ../../sdf'],
49+
['*not detected', 'sdd', '/media/usb4', '/dev/ttyACM2', 'usb-MBED_microcontroller_0670FF494951785087152739-0:0 -> ../../sdd'],
50+
['*not detected', 'sdb', '/media/usb0', '/dev/ttyACM0', 'usb-MBED_microcontroller_0674FF484951775087083114-0:0 -> ../../sdb'],
51+
['*not detected', 'sdh', '/media/usb6', '/dev/ttyACM6', 'usb-MBED_microcontroller_066FFF525257775087155144-0:0 -> ../../sdh'],
52+
['*not detected', 'sdc', '/media/usb1', '/dev/ttyACM1', 'usb-MBED_microcontroller_066AFF494956805087155327-0:0 -> ../../sdc'],
53+
['*not detected', 'sde', '/media/usb2', '/dev/ttyACM3', 'usb-MBED_microcontroller_066CFF534951775087112139-0:0 -> ../../sde']
54+
]
55+
56+
MBED format
57+
{
58+
'mount_point' : <>,
59+
'serial_port' : <>,
60+
'target_id' : <>,
61+
'platform_name' : <>,
62+
}
63+
64+
TIDS format
65+
{
66+
"1168": "LPC11U68",
67+
"1549": "LPC1549",
68+
"1070": "NRF51822",
69+
"0200": "KL25Z",
70+
"0220": "KL46Z",
71+
"0230": "K20D50M",
72+
"0240": "K64F"
73+
}
74+
"""
75+
# We harness information about what is mounted and connected to serial ports
76+
disk_ids = self.get_dev_by_id('disk')
77+
serial_ids = self.get_dev_by_id('serial')
78+
mount_ids = self.get_mounts()
79+
80+
# Extra data to identify mbeds by target_id
81+
tids = self.manufacture_ids
82+
83+
# Listing known and undetected / orphan devices
84+
mbeds = self.get_detected(tids, disk_ids, serial_ids, mount_ids)
85+
orphans = self.get_not_detected(tids, disk_ids, serial_ids, mount_ids)
86+
all_devices = mbeds + orphans
87+
88+
self.ERRORLEVEL_FLAG = 0
89+
90+
result = []
91+
tidhex = re.compile(r'_([0-9a-fA-F]+)-\d+:\d+')
92+
for device in all_devices:
93+
tid = None
94+
m = tidhex.search(device[4])
95+
if m and len(m.groups()):
96+
tid = m.group(1)
97+
mbed = {'mount_point' : device[2],
98+
'serial_port' : device[3],
99+
'target_id' : tid,
100+
'platform_name' : device[0]
101+
}
102+
103+
# Deducing mbed-enabled TargetID based on available targetID definition DB.
104+
# If TargetID from USBID is not recognized we will try to check URL in mbed.htm
105+
mbed_htm_target_id = self.get_mbed_htm_target_id(device[2]) # device[2] is a 'mount_point'
106+
if mbed_htm_target_id is not None:
107+
mbed_htm_target_id_prefix = mbed_htm_target_id[0:4]
108+
if mbed_htm_target_id_prefix in tids:
109+
# We need to update platform_name and corresponding TargetID (not USBID, but from mbed.htm)
110+
mbed['platform_name'] = tids[mbed_htm_target_id_prefix]
111+
mbed['target_id'] = mbed_htm_target_id
112+
mbed['target_id_usb_id'] = tid
113+
mbed['target_id_mbed_htm'] = mbed_htm_target_id
114+
result.append(mbed)
115+
116+
if None in mbed:
117+
self.ERRORLEVEL_FLAG = -1
118+
119+
return result
120+
121+
# Private methods
122+
123+
def get_dev_by_id(self, subdir):
124+
"""! Lists disk devices by id
125+
126+
@return List of strings from 'ls' command executed in shell
127+
128+
@details Uses Linux shell command: 'ls -oA /dev/disk/by-id/'
129+
"""
130+
result = []
131+
cmd = 'ls -oA /dev/' + subdir + '/by-id/'
132+
if self.DEBUG_FLAG:
133+
self.debug(self.get_dev_by_id.__name__, cmd)
134+
135+
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
136+
for line in p.stdout.readlines():
137+
line = line.rstrip()
138+
result.append(line)
139+
if self.DEBUG_FLAG:
140+
self.debug(self.get_dev_by_id.__name__, line)
141+
retval = p.wait()
142+
return result
143+
144+
def get_mounts(self):
145+
"""! Lists mounted devices with vfat file system (potential mbeds)
146+
147+
@result Returns list of all mounted vfat devices
148+
149+
@details Uses Linux shell command: 'mount | grep vfat'
150+
"""
151+
result = []
152+
cmd = 'mount | grep vfat'
153+
if self.DEBUG_FLAG:
154+
self.debug(self.get_mounts.__name__, cmd)
155+
156+
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
157+
for line in p.stdout.readlines():
158+
line = line.rstrip()
159+
result.append(line)
160+
if self.DEBUG_FLAG:
161+
self.debug(self.get_mounts.__name__, line)
162+
retval = p.wait()
163+
return result
164+
165+
def get_disk_hex_ids(self, disk_list):
166+
"""! Get only hexadecimal IDs for mbed disks
167+
168+
@param disk_list List of disks in a system with USBID decoration
169+
170+
@return Returns map of disks and corresponding disks' Hex ids
171+
172+
@details Uses regular expressions to get Hex strings (TargeTIDs) from list of disks
173+
"""
174+
nlp = re.compile(self.name_link_pattern)
175+
hup = re.compile(self.hex_uuid_pattern)
176+
disk_hex_ids = {}
177+
for dl in disk_list:
178+
m = nlp.search(dl)
179+
if m and len(m.groups()):
180+
disk_link = m.group(1)
181+
m = hup.search(disk_link)
182+
if m and len(m.groups()):
183+
disk_hex_ids[m.group(1)] = disk_link
184+
return disk_hex_ids
185+
186+
def get_mbed_serial(self, serial_list, dhi):
187+
"""! Get mbed serial by unique hex id (dhi) in disk name
188+
189+
@return Returns None if corresponding serial device is not found, else returns serial device path
190+
191+
@param serial_list List of all serial ports
192+
@param dhi Unique Hex id of possible mbed device
193+
194+
@details Devices are located in Linux '/dev/' directory structure
195+
"""
196+
nlp = re.compile(self.name_link_pattern)
197+
for sl in serial_list:
198+
if dhi in sl:
199+
m = nlp.search(sl)
200+
if m and len(m.groups()):
201+
serial_link = m.group(1)
202+
mbed_dev_serial = "/dev/" + self.get_dev_name(serial_link)
203+
return mbed_dev_serial
204+
return None
205+
206+
def get_detected(self, tids, disk_list, serial_list, mount_list):
207+
"""! Find all known mbed devices and assign name by targetID
208+
209+
@return list of lists [mbed_name, mbed_dev_disk, mbed_mount_point, mbed_dev_serial, disk_hex_id]
210+
211+
@param tids TargetID comprehensive list for detection (manufacturers_ids)
212+
@param disk_list List of disks (mount points in /dev/disk)
213+
@param serial_list List of serial devices (serial ports in /dev/serial)
214+
@param mount_list List of lines from 'mount' command
215+
216+
@details Find for all disk connected all MBED ones we know about from TID list
217+
"""
218+
# Find for all disk connected all MBED ones we know about from TID list
219+
disk_hex_ids = self.get_disk_hex_ids(disk_list)
220+
map_tid_to_mbed = self.get_tid_mbed_name_remap(tids)
221+
222+
result = []
223+
224+
# Search if we have
225+
for dhi in disk_hex_ids.keys():
226+
for mttm in map_tid_to_mbed.keys():
227+
if dhi.startswith(mttm):
228+
mbed_name = map_tid_to_mbed[mttm]
229+
mbed_dev_disk = ""
230+
mbed_dev_serial = ""
231+
232+
disk_link = disk_hex_ids[dhi]
233+
# print "Fount MBED disk: " + disk_link #mbed_name + ": " + mttm + " (" + dhi + ")"
234+
mbed_dev_disk = self.get_dev_name(disk_link) # m.group(1) if m and len(m.groups()) else "unknown"
235+
mbed_dev_serial = self.get_mbed_serial(serial_list, dhi)
236+
# Print detected device
237+
mbed_mount_point = self.get_mount_point(mbed_dev_disk, mount_list)
238+
if mbed_mount_point:
239+
result.append([mbed_name, mbed_dev_disk, mbed_mount_point, mbed_dev_serial, disk_hex_ids[dhi]])
240+
return result
241+
242+
def get_not_detected(self, tids, disk_list, serial_list, mount_list):
243+
"""! Find all unknown mbed-enabled devices (may have 'mbed' string in USBID name)
244+
245+
@return list of lists [mbed_name, mbed_dev_disk, mbed_mount_point, mbed_dev_serial, disk_hex_id]
246+
247+
@param tids TargetID comprehensive list for detection (manufacturers_ids)
248+
@param disk_list List of disks (mount points in /dev/disk)
249+
@param serial_list List of serial devices (serial ports in /dev/serial)
250+
@param mount_list List of lines from 'mount' command
251+
252+
@details Find for all disk connected all MBED ones we know about from TID list
253+
"""
254+
map_tid_to_mbed = self.get_tid_mbed_name_remap(tids)
255+
orphan_mbeds = []
256+
for disk in disk_list:
257+
if "mbed" in disk.lower():
258+
orphan_found = True
259+
for tid in map_tid_to_mbed.keys():
260+
if tid in disk:
261+
orphan_found = False
262+
break
263+
if orphan_found:
264+
orphan_mbeds.append(disk)
265+
266+
# Search for corresponding MBED serial
267+
disk_hex_ids = self.get_disk_hex_ids(orphan_mbeds)
268+
269+
result = []
270+
# FInd orphan serial name
271+
for dhi in disk_hex_ids:
272+
orphan_serial = self.get_mbed_serial(serial_list, dhi)
273+
if orphan_serial:
274+
orphan_dev_disk = self.get_dev_name(disk_hex_ids[dhi])
275+
orphan_dev_serial = '/dev/' + self.get_dev_name(orphan_serial)
276+
orphan_mount_point = self.get_mount_point(orphan_dev_disk, mount_list)
277+
if orphan_mount_point and orphan_dev_serial:
278+
result.append([None, orphan_dev_disk, orphan_mount_point, orphan_dev_serial, disk_hex_ids[dhi]])
279+
return result
280+
281+
def get_tid_mbed_name_remap(self, tids):
282+
""" Remap to get mapping: ID -> mbed name
283+
"""
284+
return tids
285+
286+
def get_dev_name(self, link):
287+
""" Get device name from symbolic link list
288+
"""
289+
device_sufix_pattern = ".*/([a-zA-Z0-9]*)$"
290+
dsp = re.compile(device_sufix_pattern)
291+
m = dsp.search(link)
292+
mbed_dev = m.group(1) if m and len(m.groups()) else "unknown"
293+
return mbed_dev
294+
295+
def get_mount_point(self, dev_name, mount_list):
296+
""" Find mount points for MBED devices using mount command output
297+
298+
@return Returns None if mount point not found. Else returns device mount path
299+
300+
@param dev_name Device name (e.g 'sda')
301+
@param mount_list List of all mounted devices (strings from Linux mount shell command)
302+
303+
@details
304+
"""
305+
mount_media_pattern = "^/[a-zA-Z0-9/]*/" + dev_name + " on (/[a-zA-Z0-9/]*) "
306+
mmp = re.compile(mount_media_pattern)
307+
for mount in mount_list:
308+
m = mmp.search(mount)
309+
if m and len(m.groups()):
310+
return m.group(1)
311+
return None

0 commit comments

Comments
 (0)