Mbed LS
platform_database.py
Go to the documentation of this file.
1 """
2 mbed SDK
3 Copyright (c) 2017 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 """Functions that manage a platform database"""
19 
20 import datetime
21 import json
22 import re
23 from collections import OrderedDict, defaultdict
24 from copy import copy
25 from io import open
26 from os import makedirs
27 from os.path import join, dirname, getmtime
28 from appdirs import user_data_dir
29 from fasteners import InterProcessLock
30 
31 try:
32  unicode
33 except NameError:
34  unicode = str
35 
36 
37 import logging
38 logger = logging.getLogger("mbedls.platform_database")
39 logger.addHandler(logging.NullHandler())
40 del logging
41 
42 LOCAL_PLATFORM_DATABASE = join(user_data_dir("mbedls"), "platforms.json")
43 LOCAL_MOCKS_DATABASE = join(user_data_dir("mbedls"), "mock.json")
44 
45 DEFAULT_PLATFORM_DB = {
46  u'daplink': {
47  u'0001': u'LPC2368',
48  u'0002': u'LPC2368',
49  u'0003': u'LPC2368',
50  u'0004': u'LPC2368',
51  u'0005': u'LPC2368',
52  u'0006': u'LPC2368',
53  u'0007': u'LPC2368',
54  u'0100': u'LPC2368',
55  u'0183': u'UBLOX_C027',
56  u'0200': u'KL25Z',
57  u'0201': u'KW41Z',
58  u'0210': u'KL05Z',
59  u'0214': u'HEXIWEAR',
60  u'0217': u'K82F',
61  u'0218': u'KL82Z',
62  u'0220': u'KL46Z',
63  u'0227': u'MIMXRT1050_EVK',
64  u'0228': u'RAPIDIOT_K64F',
65  u'0230': u'K20D50M',
66  u'0231': u'K22F',
67  u'0234': u'RAPIDIOT_KW41Z',
68  u'0240': u'K64F',
69  u'0245': u'K64F',
70  u'0250': u'KW24D',
71  u'0261': u'KL27Z',
72  u'0262': u'KL43Z',
73  u'0300': u'MTS_GAMBIT',
74  u'0305': u'MTS_MDOT_F405RG',
75  u'0310': u'MTS_DRAGONFLY_F411RE',
76  u'0311': u'K66F',
77  u'0312': u'MTS_DRAGONFLY_L471QG',
78  u'0315': u'MTS_MDOT_F411RE',
79  u'0350': u'XDOT_L151CC',
80  u'0400': u'MAXWSNENV',
81  u'0405': u'MAX32600MBED',
82  u'0406': u'MAX32620MBED',
83  u'0407': u'MAX32620HSP',
84  u'0408': u'MAX32625NEXPAQ',
85  u'0409': u'MAX32630FTHR',
86  u'0410': u'ETTEPLAN_LORA',
87  u'0415': u'MAX32625MBED',
88  u'0416': u'MAX32625PICO',
89  u'0417': u'MAX32630MBED',
90  u'0418': u'MAX32620FTHR',
91  u'0419': u'MAX35103EVKIT2',
92  u'0420': u'MAX32630HSP3',
93  u'0450': u'MTB_UBLOX_ODIN_W2',
94  u'0451': u'MTB_MXCHIP_EMW3166',
95  u'0452': u'MTB_LAIRD_BL600',
96  u'0453': u'MTB_MTS_XDOT',
97  u'0454': u'MTB_MTS_DRAGONFLY',
98  u'0455': u'MTB_UBLOX_NINA_B1',
99  u'0456': u'MTB_MURATA_ABZ',
100  u'0457': u'MTB_RAK811',
101  u'0458': u'MTB_ADV_WISE_1510',
102  u'0459': u'MTB_ADV_WISE_1530',
103  u'0460': u'MTB_ADV_WISE_1570',
104  u'0461': u'MTB_LAIRD_BL652',
105  u'0462': u'MTB_USI_WM_BN_BM_22',
106  u'0465': u'MTB_LAIRD_BL654',
107  u'0466': u'MTB_MURATA_WSM_BL241',
108  u'0472': u'MTB_ACONNO_ACN52832',
109  u'0500': u'SPANSION_PLACEHOLDER',
110  u'0505': u'SPANSION_PLACEHOLDER',
111  u'0510': u'SPANSION_PLACEHOLDER',
112  u'0602': u'EV_COG_AD3029LZ',
113  u'0603': u'EV_COG_AD4050LZ',
114  u'0700': u'NUCLEO_F103RB',
115  u'0705': u'NUCLEO_F302R8',
116  u'0710': u'NUCLEO_L152RE',
117  u'0715': u'NUCLEO_L053R8',
118  u'0720': u'NUCLEO_F401RE',
119  u'0725': u'NUCLEO_F030R8',
120  u'0730': u'NUCLEO_F072RB',
121  u'0735': u'NUCLEO_F334R8',
122  u'0740': u'NUCLEO_F411RE',
123  u'0742': u'NUCLEO_F413ZH',
124  u'0743': u'DISCO_F413ZH',
125  u'0744': u'NUCLEO_F410RB',
126  u'0745': u'NUCLEO_F303RE',
127  u'0746': u'DISCO_F303VC',
128  u'0747': u'NUCLEO_F303ZE',
129  u'0750': u'NUCLEO_F091RC',
130  u'0755': u'NUCLEO_F070RB',
131  u'0760': u'NUCLEO_L073RZ',
132  u'0764': u'DISCO_L475VG_IOT01A',
133  u'0765': u'NUCLEO_L476RG',
134  u'0766': u'SILICA_SENSOR_NODE',
135  u'0770': u'NUCLEO_L432KC',
136  u'0774': u'DISCO_L4R9I',
137  u'0775': u'NUCLEO_F303K8',
138  u'0776': u'NUCLEO_L4R5ZI',
139  u'0777': u'NUCLEO_F446RE',
140  u'0778': u'NUCLEO_F446ZE',
141  u'0779': u'NUCLEO_L433RC_P',
142  u'0780': u'NUCLEO_L011K4',
143  u'0781': u'NUCLEO_L4R5ZI_P',
144  u'0785': u'NUCLEO_F042K6',
145  u'0788': u'DISCO_F469NI',
146  u'0790': u'NUCLEO_L031K6',
147  u'0791': u'NUCLEO_F031K6',
148  u'0795': u'DISCO_F429ZI',
149  u'0796': u'NUCLEO_F429ZI',
150  u'0797': u'NUCLEO_F439ZI',
151  u'0799': u'ST_PLACEHOLDER',
152  u'0805': u'DISCO_L053C8',
153  u'0810': u'DISCO_F334C8',
154  u'0812': u'NUCLEO_F722ZE',
155  u'0813': u'NUCLEO_H743ZI',
156  u'0815': u'DISCO_F746NG',
157  u'0816': u'NUCLEO_F746ZG',
158  u'0817': u'DISCO_F769NI',
159  u'0818': u'NUCLEO_F767ZI',
160  u'0820': u'DISCO_L476VG',
161  u'0821': u'NUCLEO_L452RE',
162  u'0822': u'DISCO_L496AG',
163  u'0823': u'NUCLEO_L496ZG',
164  u'0824': u'LPC824',
165  u'8012': u'TT_M3HQ',
166  u'0826': u'NUCLEO_F412ZG',
167  u'0827': u'NUCLEO_L486RG',
168  u'0828': u'NUCLEO_L496ZG_P',
169  u'0829': u'NUCLEO_L452RE_P',
170  u'0830': u'DISCO_F407VG',
171  u'0833': u'DISCO_L072CZ_LRWAN1',
172  u'0835': u'NUCLEO_F207ZG',
173  u'0839': u'NUCLEO_WB55RG',
174  u'0840': u'B96B_F446VE',
175  u'0879': u'NUCLEO_F756ZG',
176  u'0900': u'XPRO_SAMR21',
177  u'0905': u'XPRO_SAMW25',
178  u'0910': u'XPRO_SAML21',
179  u'0915': u'XPRO_SAMD21',
180  u'1000': u'LPC2368',
181  u'1001': u'LPC2368',
182  u'1010': u'LPC1768',
183  u'1017': u'HRM1017',
184  u'1018': u'SSCI824',
185  u'1019': u'TY51822R3',
186  u'1022': u'RO359B',
187  u'1034': u'LPC11U34',
188  u'1040': u'LPC11U24',
189  u'1045': u'LPC11U24',
190  u'1050': u'LPC812',
191  u'1054': u'LPC54114',
192  u'1056': u'LPC546XX',
193  u'1060': u'LPC4088',
194  u'1061': u'LPC11U35_401',
195  u'1062': u'LPC4088_DM',
196  u'1070': u'NRF51822',
197  u'1075': u'NRF51822_OTA',
198  u'1080': u'OC_MBUINO',
199  u'1090': u'RBLAB_NRF51822',
200  u'1093': u'RBLAB_BLENANO2',
201  u'1095': u'RBLAB_BLENANO',
202  u'1100': u'NRF51_DK',
203  u'1101': u'NRF52_DK',
204  u'1102': u'NRF52840_DK',
205  u'1105': u'NRF51_DK_OTA',
206  u'1114': u'LPC1114',
207  u'1120': u'NRF51_DONGLE',
208  u'1130': u'NRF51822_SBK',
209  u'1140': u'WALLBOT_BLE',
210  u'1168': u'LPC11U68',
211  u'1200': u'NCS36510',
212  u'1234': u'UBLOX_C027',
213  u'1235': u'UBLOX_C027',
214  u'1236': u'UBLOX_EVK_ODIN_W2',
215  u'1237': u'UBLOX_EVK_NINA_B1',
216  u'1300': u'NUC472-NUTINY',
217  u'1301': u'NUMBED',
218  u'1302': u'NUMAKER_PFM_NUC472',
219  u'1303': u'NUMAKER_PFM_M453',
220  u'1304': u'NUMAKER_PFM_M487',
221  u'1305': u'NUMAKER_PFM_M2351',
222  u'1306': u'NUMAKER_PFM_NANO130',
223  u'1307': u'NUMAKER_PFM_NUC240',
224  u'1308': u'NUMAKER_IOT_M487',
225  u'1549': u'LPC1549',
226  u'1600': u'LPC4330_M4',
227  u'1605': u'LPC4330_M4',
228  u'1701': u'GD32_F307VG',
229  u'1702': u'GD32_F450ZI',
230  u'2000': u'EFM32_G8XX_STK',
231  u'2005': u'EFM32HG_STK3400',
232  u'2010': u'EFM32WG_STK3800',
233  u'2015': u'EFM32GG_STK3700',
234  u'2020': u'EFM32LG_STK3600',
235  u'2025': u'EFM32TG_STK3300',
236  u'2030': u'EFM32ZG_STK3200',
237  u'2035': u'EFM32PG_STK3401',
238  u'2040': u'EFM32PG12_STK3402',
239  u'2041': u'TB_SENSE_12',
240  u'2045': u'TB_SENSE_1',
241  u'2100': u'XBED_LPC1768',
242  u'2201': u'WIZWIKI_W7500',
243  u'2202': u'WIZWIKI_W7500ECO',
244  u'2203': u'WIZWIKI_W7500P',
245  u'2500': u'ADV_WISE_1570',
246  u'3001': u'LPC11U24',
247  u'3101': u'SDT32620B',
248  u'3102': u'SDT32625B',
249  u'3103': u'SDT51822B',
250  u'3104': u'SDT52832B',
251  u'3105': u'SDT64B',
252  u'3106': u'SDT8195B',
253  u'3108': u'SDT32429B',
254  u'3110': u'SDT32439B',
255  u'3300': u'CC3220SF',
256  u'4000': u'LPC11U35_Y5_MBUG',
257  u'4005': u'NRF51822_Y5_MBUG',
258  u'4100': u'MOTE_L152RC',
259  u'4337': u'LPC4337',
260  u'4500': u'DELTA_DFCM_NNN40',
261  u'4501': u'DELTA_DFBM_NQ620',
262  u'4502': u'DELTA_DFCM_NNN50',
263  u'4600': u'REALTEK_RTL8195AM',
264  u'5000': u'ARM_MPS2',
265  u'5001': u'ARM_MPS2_M0',
266  u'5002': u'ARM_BEETLE_SOC',
267  u'5003': u'ARM_MPS2_M0P',
268  u'5005': u'ARM_MPS2_M0DS',
269  u'5006': u'ARM_MUSCA_A1',
270  u'5007': u'ARM_MPS2_M1',
271  u'5009': u'ARM_MPS2_M3',
272  u'5011': u'ARM_MPS2_M4',
273  u'5015': u'ARM_MPS2_M7',
274  u'5020': u'HOME_GATEWAY_6LOWPAN',
275  u'5500': u'RZ_A1H',
276  u'5501': u'GR_LYCHEE',
277  u'6000': u'FUTURE_SEQUANA',
278  u'6660': u'NZ32_SC151',
279  u'7010': u'BLUENINJA_CDP_TZ01B',
280  u'7011': u'TMPM066',
281  u'7013': u'TMPM46B',
282  u'7402': u'MBED_BR_HAT',
283  u'7778': u'TEENSY3_1',
284  u'8001': u'UNO_91H',
285  u'8002': u'UNO_81C',
286  u'8003': u'UNO_81AM',
287  u'8004': u'UNO_81A',
288  u'8080': u'FF1705_L151CC',
289  u'8081': u'FF_LPC546XX',
290  u'9001': u'LPC1347',
291  u'9002': u'LPC11U24',
292  u'9003': u'LPC1347',
293  u'9004': u'ARCH_PRO',
294  u'9006': u'LPC11U24',
295  u'9007': u'LPC11U35_501',
296  u'9008': u'XADOW_M0',
297  u'9009': u'ARCH_BLE',
298  u'9010': u'ARCH_GPRS',
299  u'9011': u'ARCH_MAX',
300  u'9012': u'SEEED_TINY_BLE',
301  u'9014': u'WIO_3G',
302  u'9015': u'WIO_BG96',
303  u'9900': u'NRF51_MICROBIT',
304  u'C002': u'VK_RZ_A1H',
305  u'C005': u'MTM_MTCONNECT04S',
306  u'C006': u'VBLUNO51',
307  u'C008': u'SAKURAIO_EVB_01',
308  u'C030': u'UBLOX_C030_U201',
309  u'C031': u'UBLOX_C030_N211',
310  u'C032': u'UBLOX_C030_R404M',
311  u'C033': u'UBLOX_C030_R410M',
312  u'C034': u'UBLOX_C030_S200',
313  u'C035': u'UBLOX_C030_R3121',
314  u'FFFF': u'K20 BOOTLOADER',
315  u'RIOT': u'RIOT',
316  },
317  u'jlink': {
318  u'X729475D28G': {
319  u'platform_name': u'NRF51_DK',
320  u'jlink_device_name': u'nRF51422_xxAC'
321  },
322  u'X349858SLYN': {
323  u'platform_name': u'NRF52_DK',
324  u'jlink_device_name': u'nRF52832_xxaa'
325  },
326  u'FRDM-KL25Z': {
327  u'platform_name': u'KL25Z',
328  u'jlink_device_name': u'MKL25Z128xxx4'
329  },
330  u'FRDM-KL27Z': {
331  u'platform_name': u'KL27Z',
332  u'jlink_device_name': u'MKL27Z64xxx4'
333  },
334  u'FRDM-KL43Z': {
335  u'platform_name': u'KL43Z',
336  u'jlink_device_name': u'MKL43Z256xxx4'
337  }
338  },
339  u'atmel': {
340  u'2241': 'SAML21J18A'
341  }
342 }
343 
344 
345 def _get_modified_time(path):
346  try:
347  mtime = getmtime(path)
348  except OSError:
349  mtime = 0
350  return datetime.datetime.fromtimestamp(mtime)
351 
352 
353 def _older_than_me(path):
354  return _get_modified_time(path) < _get_modified_time(__file__)
355 
356 
357 def _modify_data_format(data, verbose_data, simple_data_key='platform_name'):
358  if isinstance(data, dict):
359  if verbose_data:
360  return data
361 
362  return data[simple_data_key]
363  else:
364  if verbose_data:
365  return {
366  simple_data_key: data
367  }
368 
369  return data
370 
371 
372 def _overwrite_or_open(db):
373  try:
374  if db is LOCAL_PLATFORM_DATABASE and _older_than_me(db):
375  raise ValueError("Platform Database is out of date")
376  with open(db, encoding="utf-8") as db_in:
377  return json.load(db_in)
378  except (IOError, ValueError) as exc:
379  if db is LOCAL_PLATFORM_DATABASE:
380  logger.warning(
381  "Error loading database %s: %s; Recreating", db, str(exc))
382  try:
383  makedirs(dirname(db))
384  except OSError:
385  pass
386  try:
387  with open(db, "w", encoding="utf-8") as out:
388  out.write(unicode(json.dumps(DEFAULT_PLATFORM_DB)))
389  except IOError:
390  pass
391  return copy(DEFAULT_PLATFORM_DB)
392  else:
393  return {}
394 
395 
397  """Represents a union of multiple platform database files.
398  Handles inter-process synchronization of database files.
399  """
400 
401  target_id_pattern = re.compile(r'^[a-fA-F0-9]{4}$')
402 
403  def __init__(self, database_files, primary_database=None):
404  """Construct a PlatformDatabase object from a series of platform database files"""
405  self._prim_db_prim_db = primary_database
406  if not self._prim_db_prim_db and len(database_files) == 1:
407  self._prim_db_prim_db = database_files[0]
408  self._dbs_dbs = OrderedDict()
409  self._keys_keys = defaultdict(set)
410  for db in database_files:
411  new_db = _overwrite_or_open(db)
412  first_value = None
413  if new_db.values():
414  first_value = next(iter(new_db.values()))
415  if not isinstance(first_value, dict):
416  new_db = {
417  'daplink': new_db
418  }
419 
420  if new_db:
421  for device_type in new_db:
422  duplicates = self._keys_keys[device_type].intersection(set(new_db[device_type].keys()))
423  duplicates = set(["%s.%s" % (device_type, k) for k in duplicates])
424  if duplicates:
425  logger.warning(
426  "Duplicate platform ids found: %s,"
427  " ignoring the definitions from %s",
428  " ".join(duplicates), db)
429  self._dbs_dbs[db] = new_db
430  self._keys_keys[device_type] = self._keys_keys[device_type].union(new_db[device_type].keys())
431  else:
432  self._dbs_dbs[db] = new_db
433 
434 
435  def items(self, device_type='daplink'):
436  for db in self._dbs_dbs.values():
437  for entry in db.get(device_type, {}).items():
438  yield entry
439 
440  def all_ids(self, device_type='daplink'):
441  return iter(self._keys_keys[device_type])
442 
443  def get(self, index, default=None, device_type='daplink', verbose_data=False):
444  """Standard lookup function. Works exactly like a dict. If 'verbose_data'
445  is True, all data for the platform is returned as a dict."""
446  for db in self._dbs_dbs.values():
447  if device_type in db:
448  maybe_answer = db[device_type].get(index, None)
449  if maybe_answer:
450  return _modify_data_format(maybe_answer, verbose_data)
451 
452  return default
453 
454  def _update_db(self):
455  if self._prim_db_prim_db:
456  lock = InterProcessLock("%s.lock" % self._prim_db_prim_db)
457  acquired = lock.acquire(blocking=False)
458  if not acquired:
459  logger.debug("Waiting 60 seconds for file lock")
460  acquired = lock.acquire(blocking=True, timeout=60)
461  if acquired:
462  try:
463  with open(self._prim_db_prim_db, "w", encoding="utf-8") as out:
464  out.write(unicode(
465  json.dumps(self._dbs_dbs[self._prim_db_prim_db])))
466  return True
467  finally:
468  lock.release()
469  else:
470  logger.error("Could not update platform database: "
471  "Lock acquire failed after 60 seconds")
472  return False
473  else:
474  logger.error("Can't update platform database: "
475  "destination database is ambiguous")
476  return False
477 
478  def add(self, id, platform_name, permanent=False, device_type='daplink'):
479  """Add a platform to this database, optionally updating an origin
480  database
481  """
482  if self.target_id_patterntarget_id_pattern.match(id):
483  if self._prim_db_prim_db:
484  if device_type not in self._dbs_dbs[self._prim_db_prim_db]:
485  self._dbs_dbs[self._prim_db_prim_db][device_type] = {}
486  self._dbs_dbs[self._prim_db_prim_db][device_type][id] = platform_name
487  else:
488  cur_db = next(iter(self._dbs_dbs.values()))
489  if device_type not in cur_db:
490  cur_db[device_type] = {}
491  cur_db[device_type][id] = platform_name
492  self._keys_keys[device_type].add(id)
493  if permanent:
494  self._update_db_update_db()
495  else:
496  raise ValueError("Invald target id: %s" % id)
497 
498  def remove(self, id, permanent=False, device_type='daplink', verbose_data=False):
499  """Remove a platform from this database, optionally updating an origin
500  database. If 'verbose_data' is True, all data for the platform is returned
501  as a dict.
502  """
503  logger.debug("Trying remove of %s", id)
504  if id == '*' and device_type in self._dbs_dbs[self._prim_db_prim_db]:
505  self._dbs_dbs[self._prim_db_prim_db][device_type] = {}
506  for db in self._dbs_dbs.values():
507  if device_type in db and id in db[device_type]:
508  logger.debug("Removing id...")
509  removed = db[device_type][id]
510  del db[device_type][id]
511  self._keys_keys[device_type].remove(id)
512  if permanent:
513  self._update_db_update_db()
514 
515  return _modify_data_format(removed, verbose_data)
def remove(self, id, permanent=False, device_type='daplink', verbose_data=False)
def get(self, index, default=None, device_type='daplink', verbose_data=False)
def add(self, id, platform_name, permanent=False, device_type='daplink')
def __init__(self, database_files, primary_database=None)