EMANE  1.2.1
build/lib/emane/shell/emaneshell.py
Go to the documentation of this file.
1 #!/us/bin/env python
2 #
3 # Copyright (c) 2013-2014,2016-2017 - Adjacent Link LLC, Bridgewater,
4 # New Jersey
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 # * Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # * Redistributions in binary form must reproduce the above copyright
14 # notice, this list of conditions and the following disclaimer in
15 # the documentation and/or other materials provided with the
16 # distribution.
17 # * Neither the name of Adjacent Link LLC nor the names of its
18 # contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 #
34 
35 from __future__ import absolute_import, division, print_function
36 import cmd
37 import os
38 import sys
39 import re
40 import glob
41 import textwrap
42 from . import ControlPortClient
43 from . import ControlPortException
44 from . import Manifest
45 from . import ManifestException
46 
47 class EMANEShell(cmd.Cmd):
48  def __init__(self,host,port):
49  cmd.Cmd.__init__(self)
50  self.prompt="[emanesh (%s:%d)] ## " % (host,port)
51  self._client = ControlPortClient(host,port)
52  self._manifest = {'emulator' : [(0,'all','nemmanager')]}
53  self._mapping = {'emulator': {}}
54  self._shims = set()
55  self._pluginInfo = {}
56 
57  for (nem,components) in list(self._client.getManifest().items()):
58  self._manifest[nem] = []
59  self._mapping[nem] = {}
60  shimcount = 0
61  for component in components:
62  name = component[1].lower()
63  if name == 'shim':
64  name += str(shimcount)
65  shimcount+=1
66  self._shims.add(name)
67 
68  self._mapping[nem][name] = component[0]
69  self._manifest[nem].append((component[0],name,component[2]))
70 
71  manifestpath = os.getenv('EMANEMANIFESTPATH','/usr/share/emane/manifest')
72 
73  for directory in manifestpath.split(':'):
74  for manifestXML in glob.glob("%s/*.xml" % directory):
75  try:
76  manifest = Manifest(manifestXML)
77  self._pluginInfo[manifest.getName()] = manifest
78  except ManifestException:
79  pass
80 
81  if not len(self._pluginInfo):
82  print("warning: no plugin manifest XML loaded. Check EMANEMANIFESTPATH.")
83 
84  def emptyline(self):
85  pass
86 
87  def can_exit(self):
88  return True
89 
90  def default(self,line):
91  print("error: unknown command:",line.split()[0])
92 
93  def help_help(self):
94  print("""
95  The help command is used to get usage information for each
96  command.
97 
98  usage: help <command>
99  <command> ::= 'get' | 'clear' | 'show' | 'info' |
100  'exit' | 'help'
101  """)
102 
103  def do_EOF(self,args):
104  """
105  The ^D (Ctrl+d) command is used to exit the shell.
106 
107  usage: ^D
108 
109  example:
110  ## ^D
111  """
112  print()
113  return self.do_exit(args)
114 
115 
116  def do_exit(self,message):
117  """
118  The exit command is used to exit the shell.
119 
120  usage: exit
121 
122  example:
123  ## exit
124  """
125  if message:
126  print(message)
127  self._client.stop()
128  return True
129 
130  def do_show(self,args):
131  """
132  The show command is used to display manifest information provided
133  by the connected control port server.
134 
135  The displayed information will include the NEM ids, component layer
136  types present and the name of the component layer plugin.
137 
138  usage: show
139 
140  example:
141  ## show
142  """
143  args = args.split()
144 
145  if not len(args):
146  for (nem,components) in list(self._manifest.items()):
147  if nem != 'emulator':
148  print("nem %-3d" % nem, end=' ')
149  for component in components:
150  print("%s(%s)" % (component[1],component[2]), end=' ')
151  print()
152  else:
153  print('error: too many arguements')
154 
155  def do_info(self,args):
156  """
157  The info command is used to display information loaded from plugin
158  manifest files. There are four types of info commands: manifest,
159  config, stat and table. The manifest info command is used to display
160  the names of discovered plugins. The config, stat and table info
161  commands are used to display plugin specific item descriptions.
162 
163 
164  The config, stat and table info commands use a single optional
165  plugin-specific name parameter:
166  * config name specifies a configuration parameter name
167  * stat name specifies a statistic element name
168  * table name specifies a table name
169 
170  When no name is specified all known names are listed.
171 
172  usage: info <type> <plugin> [<plugin-specific>]
173  <type> ::= 'config' | 'stat' | 'table'
174  <plugin> ::= plugin-name
175  <plugin-specific> ::= <names>
176  <names> ::= <name> | <name> <names>
177  <name> ::= [A-Za-z0-9]+
178 
179  info 'manifest'
180 
181  example:
182  ## info manifest
183  ## info config rfpipemaclayer
184  ## info config rfpipemaclayer neighbormetricdeletetime
185  ## info stat emanephy processedEvents
186  """
187  args = args.split()
188 
189  if not len(args):
190  print('error: missing info type')
191  return
192  else:
193  command = args[0].lower()
194 
195  if command != 'config' and \
196  command != 'stat' and \
197  command != 'table' and \
198  command != 'manifest':
199  print("error: invalid info command type:",args[0])
200  return
201 
202  if command == "manifest":
203  if len(args) == 1:
204  print()
205  print(' Loaded plugin manifests')
206  print()
207  names = list(self._pluginInfo.keys())
208  names.sort()
209  for name in names:
210  print(' ',name)
211  print()
212  return
213 
214  else:
215  print('error: too many arguements')
216  return
217 
218  if len(args) >= 2:
219  plugin = args[1]
220 
221  if plugin not in self._pluginInfo:
222  print("error: invalid plugin name or missing manifest:",plugin)
223  return
224 
225  if len(args) == 3:
226  if command == 'config':
227  parameter = args[2]
228 
229  try:
230  info = self._pluginInfo[plugin].getConfigurationInfo(parameter)
231  print()
232  for line in textwrap.wrap("Configuration parameter"
233  " information for %s %s" % (plugin,
234  parameter),
235  initial_indent=' ',
236  subsequent_indent=' ',
237  width=75):
238  print(line)
239  print()
240  for line in textwrap.wrap(info['description'],
241  initial_indent=' ',
242  subsequent_indent=' ',
243  width=75):
244  print(line)
245  print()
246  print(' default :',info['default'])
247  print(' required :',info['required'])
248  print(' modifiable:',info['modifiable'])
249 
250  if 'numeric' in info:
251  print(" type :",info['numeric']['type'])
252  print(" range : [%s,%s]" % (info['numeric']['minValue'],
253  info['numeric']['maxValue']))
254  else:
255  print(" type :",info['nonnumeric']['type'])
256 
257  print(" regex : %s" % info['regex'])
258  print(" occurs : [%d,%d]" % (info['minOccurs'],info['maxOccurs']))
259  print(' default :', end=' ')
260  for value in info['values']:
261  print(value,' ', end=' ')
262  print()
263  print()
264 
265  except:
266  print("error: invalid configuration parameter name:",parameter)
267  return
268 
269  elif command == 'stat':
270  element = args[2]
271  try:
272  info = self._pluginInfo[plugin].getStatisticInfo(element)
273  print()
274  for line in textwrap.wrap("Statistic element information for"
275  " %s %s" % (plugin,
276  element),
277  initial_indent=' ',
278  subsequent_indent=' ',
279  width=75):
280  print(line)
281  print()
282  for line in textwrap.wrap(info['description'],
283  initial_indent=' ',
284  subsequent_indent=' ',
285  width=75):
286  print(line)
287  print()
288  print(' clearable :',info['clearable'])
289  print(' type :',info['type'])
290  print()
291 
292  except:
293  print("error: invalid statistic element name:",element)
294  return
295 
296 
297  elif command == 'table':
298  table = args[2]
299  try:
300  info = self._pluginInfo[plugin].getTableInfo(table)
301  print()
302  for line in textwrap.wrap("Table information for %s %s" % (plugin,
303  table),
304  initial_indent=' ',
305  subsequent_indent=' ',
306  width=75):
307  print(line)
308  print()
309  for line in textwrap.wrap(info['description'],
310  initial_indent=' ',
311  subsequent_indent=' ',
312  width=75):
313  print(line)
314  print()
315  print(' clearable :',info['clearable'])
316  print()
317 
318  except:
319  print("error: invalid statistic table name:",table)
320  return
321 
322 
323  elif len(args) > 3:
324  print('error: too many arguements')
325  return
326 
327  else:
328  if command == 'config':
329  print()
330  print(' Available configuration parameters for',plugin)
331  print()
332  names = self._pluginInfo[plugin].getAllConfiguration()
333  names.sort()
334  for name in names:
335  print(' ',name)
336  print()
337 
338  elif command == 'stat':
339  print()
340  print(' Available statistic elements for',plugin)
341  print()
342  names = self._pluginInfo[plugin].getAllStatistics()
343  names.sort()
344  for name in names:
345  print(' ',name)
346  print()
347 
348  elif command == 'table':
349  print()
350  print(' Available statistic tables for',plugin)
351  print()
352  names = self._pluginInfo[plugin].getAllTables()
353  names.sort()
354  for name in names:
355  print(' ',name)
356  print()
357 
358 
359  else:
360  print("error: missing plugin name")
361  return
362 
363 
364  def complete_info(self, text, line, begidx, endidx):
365  args = line.split()
366  completions = {'info' : ['config','stat','table','manifest'],
367  'config' : list(self._pluginInfo.keys()),
368  'stat' : list(self._pluginInfo.keys()),
369  'table' : list(self._pluginInfo.keys())}
370 
371  if len(args) >= 3:
372  if args[2] in self._pluginInfo:
373  if args[1] == 'config':
374  completions[args[2]] = self._pluginInfo[args[2]].getAllConfiguration()
375  elif args[1] == 'stat':
376  completions[args[2]] = self._pluginInfo[args[2]].getAllStatistics()
377  elif args[1] == 'table':
378  completions[args[2]] = self._pluginInfo[args[2]].getAllTables()
379 
380  if text:
381  return [
382  item for item in completions[args[-2]]
383  if item.startswith(args[-1])
384  ]
385  else:
386  return completions[args[-1]]
387 
388  def do_get(self,args):
389  """
390  The get command is used to get configuration, statistic and
391  statistic table values.
392 
393  All get types use optional target-specific name parameters:
394  * 'config' names specify configuration parameter names
395  * 'stat' names specify statistic element names
396  * 'table' names specify table names
397 
398  When no names are specified all items are retrieved.
399 
400  usage: get <type> <targets> <layer> [<target-specific>]
401  <type> ::= 'config' | 'stat' | 'table'
402  <targets> ::= <nem> | <nem> <target> | 'emulator' |
403  'nems'| '*'
404  <layer> ::= 'all' | 'mac' | 'phy' | <shim>
405  <nem> ::= [1-9] | [1-9][0-9]+
406  <shim> ::= 'shim'[0-9]+
407  <target-specific> ::= <names> | ''
408  <names> ::= <name> | <name> <names>
409  <name> ::= [A-Za-z0-9]+
410 
411  example:
412 
413  Get all configuration info from all NEM layers and the emulator
414  ## get config * all
415 
416  Get all statistic tables from all NEM mac layers
417  ## get table nems mac
418 
419  Get two statistic items from the mac layers of NEM 1 and 2
420  ## get stat 1 2 mac processedEvents processedDownstreamControl
421  """
422  return self._process('get',args)
423 
424  def complete_get(self, text, line, begidx, endidx):
425  return self._completeMany('get',
426  text, line, begidx, endidx,"",
427  config='getAllConfiguration',
428  stat='getAllStatistics',
429  table='getAllTables')
430 
431  def do_clear(self,args):
432  """
433  The clear command is used to clear statistic elements that have
434  been designated as clearable.
435 
436  Optional target-specific statistic element names can be specified.
437  When no names are specified all clearable statistic elements will
438  be cleared.
439 
440  usage: clear stat <targets> <layer> [<target-specific>]
441  <type> ::= 'stat' | 'table'
442  <targets> ::= <nem> | <nem> <target> | 'emulator' |
443  'nems'| '*'
444  <layer> ::= 'all' | 'mac' | 'phy' | <shim>
445  <nem> ::= [1-9] | [1-9][0-9]+
446  <shim> ::= 'shim'[0-9]+
447  <target-specific> ::= <names> | ''
448  <names> ::= <name> | <name> <names>
449  <name> ::= [A-Za-z0-9]+
450 
451  example:
452  Clear all statistics from all NEM layers and the emulator
453  ## clear stat * all
454 
455  Clear all statistics from all NEM mac layers
456  ## clear stat nems mac
457 
458  Clear two statistic items from the phy layers of NEM 1 and 2
459  ## clear stat 1 2 phy processedEvents processedDownstreamControl
460  """
461  return self._process('clear',args)
462 
463 
464  def complete_clear(self, text, line, begidx, endidx):
465  return self._completeMany('clear',
466  text, line, begidx, endidx,"",
467  stat='getClearableStatistics',
468  table='getClearableTables')
469 
470  def _process(self,action,args):
471  args = args.split()
472 
473  if(action == 'get'):
474  if len(args):
475  command = args[0].lower()
476  if command == 'config':
477  command = 'configuration'
478  elif command == 'stat':
479  command = 'statistic'
480  elif command == 'table':
481  command = 'table'
482  else:
483  print("error: invalid get command type:",args[0])
484  return
485  else:
486  print("error: missing get command type")
487  return
488 
489  elif(action == 'clear'):
490  if len(args):
491  command = args[0].lower()
492  if command == 'stat':
493  command = 'statistic'
494  elif command == 'table':
495  command = 'table'
496  else:
497  print("error: invalid clear command type:",args[0])
498  return
499  else:
500  print("error: missing clear command type")
501  return
502 
503  index = 1
504  targets = []
505 
506  if len(args) > index:
507  for arg in args[index:]:
508  try:
509  nem = int(arg)
510  if nem not in self._manifest:
511  print("error: invalid target:",nem)
512  return
513  else:
514  targets.append(nem)
515  except:
516  if arg.lower() == 'nems':
517  targets.extend([x for x in list(self._manifest.keys()) if x != 'emulator'])
518 
519  elif arg.lower() == '*':
520  targets.extend(list(self._manifest.keys()))
521 
522  elif arg.lower() == 'emu' or arg.lower() == 'emulator':
523  targets.append('emulator')
524  else:
525  break
526 
527  index+=1
528 
529  if not len(targets):
530  print("error: missing target(s)")
531  return
532 
533  targets = list(set(targets))
534 
535  component = ""
536 
537  if len(args) > index:
538  component = args[index].lower()
539  if component != 'phy' and \
540  component != 'mac' and \
541  component != 'transport' and \
542  component != 'all' and \
543  not (re.match('^shim\d+$', component) and component in self._shims):
544  print("error: invalid component layer:",args[index])
545  return
546 
547  index+=1
548  else:
549  print("error: missing component layer")
550  return
551 
552 
553  if component != "all":
554  for target in set(targets):
555  if component not in self._mapping[target]:
556  if target != 'emulator':
557  print("error: component not present in target %d: %s" % (target,component))
558  else:
559  print("error: component not present in emulator: %s" % (component))
560  return
561 
562  names = []
563 
564  if len(args) > index:
565  names = args[index:]
566 
567  for target in targets:
568  for componentInfo in self._manifest[target]:
569  if component == "all" or component == componentInfo[1]:
570  if action == "get":
571  if command == "configuration":
572  try:
573  entries = self._client.getConfiguration(componentInfo[0],names)
574 
575  for name in sorted(entries.keys()):
576  values = entries[name]
577  if target != 'emulator':
578  print("nem %-3d %s "%(target,componentInfo[1]),name,"=",",".join([str(x[0]) for x in values]))
579  else:
580  print("emulator",name,"=",",".join([str(x[0]) for x in values]))
581 
582  except ControlPortException as exp:
583  if exp.fatal():
584  return self.do_exit(exp)
585  else:
586  if target != 'emulator':
587  print("nem %-3d %s "%(target,componentInfo[1]),exp)
588  else:
589  print("emulator",exp)
590 
591 
592  elif command == "statistic":
593  try:
594  statistics = self._client.getStatistic(componentInfo[0],names)
595 
596  for name in sorted(statistics.keys()):
597  value = statistics[name]
598  if target != 'emulator':
599  print("nem %-3d %s "%(target,componentInfo[1]),name,"=",value[0])
600  else:
601  print("emulator",name,"=",value[0])
602 
603  except ControlPortException as exp:
604  if exp.fatal():
605  return self.do_exit(exp)
606  else:
607  if target != 'emulator':
608  print("nem %-3d %s "%(target,componentInfo[1]),exp)
609  else:
610  print("emulator",exp)
611 
612 
613  elif command == "table":
614  try:
615  statisticTables = self._client.getStatisticTable(componentInfo[0],names)
616 
617  for name in sorted(statisticTables.keys()):
618  widths = []
619  (labels,rows) = statisticTables[name]
620 
621  for label in labels:
622  widths.append(len(label))
623 
624  for row in rows:
625  i = 0
626  for item in row:
627  widths[i] = max(len(str(item[0])),widths[i])
628  i += 1
629 
630  if target != 'emulator':
631  print("nem %-3d %s %s"%(target,componentInfo[1],name))
632  else:
633  print("emulator", name)
634 
635  i = 0
636  for label in labels:
637  print('|',str(label).ljust(widths[i]), end=' ')
638  i += 1
639  print("|")
640  if not len(rows):
641  print()
642  else:
643  for row in rows:
644  i = 0
645  for item in row:
646  print('|',str(item[0]).ljust(widths[i]), end=' ')
647  i += 1
648  print("|")
649  print()
650  except ControlPortException as exp:
651  if exp.fatal():
652  return self.do_exit(exp)
653  else:
654  if target != 'emulator':
655  print("nem %-3d %s "%(target,componentInfo[1]),exp)
656  else:
657  print("emulator",exp)
658 
659  elif action =="clear":
660  if command == "statistic":
661  try:
662  self._client.clearStatistic(componentInfo[0],names)
663 
664  if target != 'emulator':
665  print("nem %-3d %s "%(target,componentInfo[1]),"statistics cleared")
666  else:
667  print("emulator statistics cleared")
668 
669  except ControlPortException as exp:
670  if exp.fatal():
671  return self.do_exit(exp)
672  else:
673  if target != 'emulator':
674  print("nem %-3d %s "%(target,componentInfo[1]),exp)
675  else:
676  print("emulator",exp)
677 
678  elif command == "table":
679  try:
680  self._client.clearTable(componentInfo[0],names)
681 
682  if target != 'emulator':
683  print("nem %-3d %s "%(target,componentInfo[1]),"tables cleared")
684  else:
685  print("emulator tables cleared")
686 
687  except ControlPortException as exp:
688  if exp.fatal():
689  return self.do_exit(exp)
690  else:
691  if target != 'emulator':
692  print("nem %-3d %s "%(target,componentInfo[1]),exp)
693  else:
694  print("emulator",exp)
695 
696 
697  def complete_set(self, text, line, begidx, endidx):
698  return self._completeMany('set',
699  text, line, begidx, endidx,"=",
700  config='getModifiableConfiguration')
701 
702 
703  def do_set(self,args):
704  """
705  The set command is used to set configuration elements that have
706  been designated as modifiable.
707 
708  One or more configuration parameter value expressions can be
709  specified.
710 
711  usage: set config <targets> <layer> <expressions>
712  <targets> ::= <nem> | <nem> <target> | 'nems' |
713  '*'
714  <layer> ::= 'all' | 'mac' | 'phy' | <shim>
715  <nem> ::= [1-9] | [1-9][0-9]+
716  <shim> ::= 'shim'[0-9]+
717  <nem> ::= [1-9] | [1-9][0-9]+
718  <expressions> ::= <expression> | <expression> <expressions>
719  <expression> ::= <name>'='<values>
720  <name> ::= [.A-Za-z0-9]+
721  <values> ::= <value> | <value>','<values>
722  <value> ::= value-string
723 
724  example:
725  Set the txpower parameter for all NEM phy layers
726  ## set config nems phy txpower=20
727 
728  Set the cwmin0 and cwmax0 parameters for NEM 1, 2 and 3 mac layers
729  ## set config 1 2 3 mac cwmin0=100 cwmax0=200
730  """
731  args = args.split()
732 
733  if len(args):
734  command = args[0].lower()
735  if command == 'config':
736  command = 'configuration'
737  else:
738  print("error: invalid get command type:",args[0])
739  return
740  else:
741  print("error: missing set command type")
742  return
743 
744  index = 1
745 
746  targets = []
747 
748  for arg in args[index:]:
749  try:
750  nem = int(args[index])
751 
752  if nem not in self._mapping:
753  print("error: invalid target:",target)
754  return
755  else:
756  targets.append(nem)
757 
758  except:
759  if args[index] == 'nems':
760  targets = [x for x in list(self._mapping.keys()) if x != 'emulator']
761  else:
762  break
763 
764  index+=1
765  else:
766  print("error: missing target")
767  return
768 
769  component = None
770 
771  if len(args) > index:
772  component = args[index].lower()
773  if component != 'phy' and \
774  component != 'mac' and \
775  component != 'transport' and \
776  component != 'all' and \
777  not (re.match('^shim\d+$', component) and component in self._shims):
778  print("error: invalid component layer:",args[index])
779  return
780 
781  index+=1
782  else:
783  print("error: missing component layer")
784  return
785 
786  for target in targets:
787  if component != 'all' and component not in self._mapping[target]:
788  print("error: component not present in target %d: %s" % (target,component))
789  return
790 
791  names = []
792 
793  for target in targets:
794  updates = []
795  if len(args) > index:
796  for expression in args[index:]:
797  m = re.match('^([.0-9A-Za-z]+)=(.+)', expression)
798 
799  def toBool(val):
800  val = val.lower()
801 
802  if val in ('yes','on','enable','true','1'):
803  return True
804  elif val in ('no','off','disable','false','0'):
805  return False
806  else:
807  raise ValueError()
808 
809  convert = {'uint64' : (ControlPortClient.TYPE_UINT64,int),
810  'uint32' : (ControlPortClient.TYPE_UINT32,int),
811  'uint16' : (ControlPortClient.TYPE_UINT16,int),
812  'uint8' : (ControlPortClient.TYPE_UINT8,int),
813  'int64' : (ControlPortClient.TYPE_INT64,int),
814  'int32' : (ControlPortClient.TYPE_INT32,int),
815  'int16' : (ControlPortClient.TYPE_INT16,int),
816  'int8' : (ControlPortClient.TYPE_INT8,int),
817  'bool' : (ControlPortClient.TYPE_BOOLEAN,toBool),
818  'string': (ControlPortClient.TYPE_STRING,str),
819  'inetaddr' : (ControlPortClient.TYPE_INETADDR,str),
820  'float' : (ControlPortClient.TYPE_FLOAT,float),
821  'double' : (ControlPortClient.TYPE_DOUBLE,float)}
822 
823  if m:
824  name = m.group(1)
825  items = m.group(2).split(',')
826  dataType = None
827  for (_,layer,plugin) in self._manifest[target]:
828  if component == 'all' or layer == component:
829  try:
830  info = self._pluginInfo[plugin].getConfigurationInfo(name)
831 
832  if 'numeric' in info:
833  dataType = info['numeric']['type']
834  break
835  else:
836  dataType = info['nonnumeric']['type']
837  break
838  except:
839  print("error: nem %hu %s unknown configuration paramater: %s" % (target,
840  layer,
841  name))
842  return
843 
844  values = []
845 
846  try:
847  for item in items:
848  values.append(convert[dataType][1](item))
849 
850  except:
851  print("error: invalid conversion %s type %s : %s" % (name,dataType,item))
852  return
853 
854  updates.append((name,convert[dataType][0],tuple(values)))
855 
856  else:
857  print("error: invalid configuration parameter format:", expression)
858  return
859  else:
860  print("error: missing configration items")
861  return
862 
863 
864 
865  buildId = self._mapping[target][component]
866 
867  try:
868  self._client.updateConfiguration(buildId,updates)
869  print("nem %-3d %s "%(target,component),"configuration updated")
870 
871  except ControlPortException as exp:
872  if exp.fatal():
873  return self.do_exit(exp)
874  else:
875  print("nem %-3d %s "%(target,component),exp)
876 
877 
878  def _completeMany(self,action,text, line, begidx, endidx,trailer,**subactions):
879  try:
880  layer = None
881  args = line.split()
882 
883  completions = {}
884 
885  if len(args) == 1:
886  completions = {action : list(subactions.keys())}
887 
888  elif len(args) == 2:
889  if text:
890  completions = {action : list(subactions.keys())}
891  else:
892  if args[1] in subactions:
893  subaction = args[1]
894  completions[subaction] = [str(x) for x in list(self._mapping.keys())]
895  completions[subaction].extend(['*','nems'])
896 
897  elif len(args) > 2 and args[1] in subactions:
898  nems = set()
899  layers = set()
900  skip = False
901 
902  for arg in args[2:]:
903  try:
904  nems.add(int(arg))
905  except:
906  if arg == 'nems':
907  nems |= set([x for x in list(self._mapping.keys()) if x != 'emulator'])
908 
909  elif arg == '*':
910  nems |= set(self._mapping.keys())
911 
912  elif arg == 'emulator':
913  nems.add('emulator')
914 
915  elif arg == 'phy' or \
916  arg == 'mac' or \
917  arg == 'transport' or \
918  arg == 'all' or \
919  (re.match('^shim\d+$', arg) and arg in self._shims):
920  layer = arg
921  skip = True
922  break
923 
924  for nem in nems:
925  if not len(layers):
926  layers = set(self._mapping[nem].keys())
927  else:
928  layers = layers & set(self._mapping[nem].keys())
929 
930  layers.add('all')
931 
932  if not layer:
933  completions['nems'] = list(layers)
934  completions['*'] = ['all']
935 
936  if not skip:
937  remaining = []
938 
939  possibilities = [x for x in list(self._mapping.keys()) if x != 'emulator']
940 
941  if '*' not in args:
942  if not ('nems' in args and 'emulator' in args):
943  possibilities.extend(['*'])
944 
945  if 'nems' not in args:
946  if '*' not in args:
947  possibilities.extend(['nems'])
948 
949  if 'emulator' not in args:
950  if '*' not in args:
951  possibilities.extend(['emulator'])
952 
953  remaining = list(set(possibilities) - nems)
954 
955  if text:
956  index = -2
957  else:
958  index = -1
959 
960  if args[index] not in layers and args[index] != '*':
961  completions[args[index]] = [str(x) for x in remaining]
962  completions[args[index]].extend(list(layers))
963 
964  params = set()
965 
966  for nem in nems:
967  for (_,l,plugin) in self._manifest[nem]:
968  if layer == 'all' or l == layer:
969  method = getattr(self._pluginInfo[plugin],subactions[args[1]])
970  items = ["".join([x,trailer]) for x in method()]
971  if not len(params):
972  params=set(items)
973  else:
974  params = params & set(items)
975 
976  if layer in layers:
977  completions[layer] = list(params)
978  else:
979  layer = None
980 
981 
982  if text or line[-1] != ' ':
983  if layer:
984  return [
985  item for item in params
986  if item.startswith(args[-1])
987  ]
988  else:
989  return [
990  item for item in completions[args[-2]]
991  if item.startswith(args[-1])
992  ]
993  else:
994  if layer:
995  return list(params)
996  else:
997  return completions[args[-1]]
998 
999  except Exception as err:
1000  pass
1001 
1002  def complete_loglevel(self, text, line, begidx, endidx):
1003  args = line.split()
1004  completions = {'loglevel' : ['0','1','2','3','4']}
1005 
1006  if text:
1007  return [
1008  item for item in completions[args[-2]]
1009  if item.startswith(args[-1])
1010  ]
1011  else:
1012  return completions[args[-1]]
1013 
1014  def do_loglevel(self,args):
1015  """
1016  The loglevel command is used to set the emulator loglevel.
1017 
1018  0 - No log messages
1019  1 - Abort log messages
1020  2 - Error log messages
1021  3 - Info log messages
1022  4 - Debug log messages
1023 
1024  usage: loglevel [0,4]
1025 
1026  example:
1027  ## loglevel 4
1028  """
1029  args = args.split()
1030 
1031  if(len(args) != 1):
1032  print('error: invalid number of arguments')
1033  return
1034 
1035  try:
1036  self._client.setLogLevel(int(args[0]))
1037  print("log level updated")
1038 
1039  except ControlPortException as exp:
1040  if exp.fatal():
1041  return self.do_exit(exp)
1042  else:
1043  print("error: ",exp)
1044  except:
1045  print("error: invalid log level")
def complete_loglevel(self, text, line, begidx, endidx)
def _completeMany(self, action, text, line, begidx, endidx, trailer, subactions)
def complete_set(self, text, line, begidx, endidx)
def complete_clear(self, text, line, begidx, endidx)
def complete_info(self, text, line, begidx, endidx)
def complete_get(self, text, line, begidx, endidx)