netmsgs  1.2.2
RoadNarrows Robotics Network Messaging Package
NetMsgsBase.py
Go to the documentation of this file.
1 ###############################################################################
2 #
3 # Package: NetMsgs
4 #
5 # File: NetMsgsBase.py
6 #
7 
8 """
9 NetMsgs Base Data Module
10 """
11 
12 ## \file
13 ## \package NetMsgs.NetMsgsBase
14 ##
15 ## $LastChangedDate: 2012-07-23 14:06:10 -0600 (Mon, 23 Jul 2012) $
16 ## $Rev: 2098 $
17 ##
18 ## \brief NetMsgs Base Data Module
19 ##
20 ## \sa
21 ## \htmlonly
22 ## <a href="../pydoc/NetMsgs.NetMsgsBase.html">PyDoc Generated Documentation</a>
23 ## \endhtmlonly
24 ##
25 ## \author Robin Knight (robin.knight@roadnarrows.com)
26 ##
27 ## \copyright
28 ## \h_copy 2009-2017. RoadNarrows LLC.\n
29 ## http://www.roadnarrows.com\n
30 ## All Rights Reserved
31 ##
32 
33 # Permission is hereby granted, without written agreement and without
34 # license or royalty fees, to use, copy, modify, and distribute this
35 # software and its documentation for any purpose, provided that
36 # (1) The above copyright notice and the following two paragraphs
37 # appear in all copies of the source code and (2) redistributions
38 # including binaries reproduces these notices in the supporting
39 # documentation. Substantial modifications to this software may be
40 # copyrighted by their authors and need not follow the licensing terms
41 # described here, provided that the new terms are clearly indicated in
42 # all files where they apply.
43 #
44 # IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
45 # OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
46 # PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
47 # DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
48 # EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
49 # THE POSSIBILITY OF SUCH DAMAGE.
50 #
51 # THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
52 # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
53 # FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
54 # "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
55 # PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
56 #
57 ###############################################################################
58 
59 import sys
60 
61 from NetMsgsCore import *
62 
63 ## Message Encoding Type Enumeration
64 NMEncoding = ['flat', 'itv'] # future , 'cli']
65 
66 ## Message Byte Ordering Type Enumeration
67 NMEndian = ['big', 'little', 'native']
68 
69 ##
70 ## Built-In message field types, keyed by XML field type name.
71 ## code - message field type byte code
72 ## desc - short description
73 ## flen - packed message field length (bytes)
74 ## comp - complexity. one of: simple compound na
75 ## T - C/C++ type specifier
76 ## pre - member name prefix (quasi-Hungarian)
77 ##
78 NMBuiltInFieldTypes = {
79  'pad': { # not really a field type
80  'code': NMFTypePad,
81  'desc': "pad byte",
82  'flen': 1,
83  'comp': 'na',
84  'T': '',
85  'pre': '',
86  },
87  'char': {
88  'code': NMFTypeChar,
89  'desc': "8-bit character",
90  'flen': NMFVAL_LEN_CHAR,
91  'comp': 'simple',
92  'T': 'char',
93  'pre': 'c',
94  },
95  'u8': {
96  'code': NMFTypeU8,
97  'desc': "unsigned 8-bit integer",
98  'flen': NMFVAL_LEN_U8,
99  'comp': 'simple',
100  'T': 'byte_t',
101  'pre': 'by',
102  },
103  's8': {
104  'code': NMFTypeS8,
105  'desc': "signed 8-bit integer",
106  'flen': NMFVAL_LEN_S8,
107  'comp': 'simple',
108  'T': 'signed char',
109  'pre': 'hhi',
110  },
111  'bool': {
112  'code': NMFTypeBool,
113  'desc': "boolean 0=false, 1(non-zero)=true",
114  'flen': NMFVAL_LEN_BOOL,
115  'comp': 'simple',
116  'T': 'bool_t',
117  'pre': 'b',
118  },
119  'u16': {
120  'code': NMFTypeU16,
121  'desc': "unsigned 16-bit integer",
122  'flen': NMFVAL_LEN_U16,
123  'comp': 'simple',
124  'T': 'ushort_t',
125  'pre': 'hu',
126  },
127  's16': {
128  'code': NMFTypeS16,
129  'desc': "signed 16-bit integer",
130  'flen': NMFVAL_LEN_S16,
131  'comp': 'simple',
132  'T': 'short',
133  'pre': 'hi',
134  },
135  'u32': {
136  'code': NMFTypeU32,
137  'desc': "unsigned 32-bit integer",
138  'flen': NMFVAL_LEN_U32,
139  'comp': 'simple',
140  'T': 'uint_t',
141  'pre': 'u',
142  },
143  's32': {
144  'code': NMFTypeS32,
145  'desc': "signed 32-bit integer",
146  'flen': NMFVAL_LEN_S32,
147  'comp': 'simple',
148  'T': 'int',
149  'pre': 'i',
150  },
151  'u64': {
152  'code': NMFTypeU64,
153  'desc': "unsigned 64-bit integer",
154  'flen': NMFVAL_LEN_U64,
155  'comp': 'simple',
156  'T': 'ulonglong_t',
157  'pre': 'llu',
158  },
159  's64': {
160  'code': NMFTypeS64,
161  'desc': "signed 64-bit integer",
162  'flen': NMFVAL_LEN_S64,
163  'comp': 'simple',
164  'T': 'long long',
165  'pre': 'lli',
166  },
167  'f32': {
168  'code': NMFTypeF32,
169  'desc': "32-bit floating-point number",
170  'flen': NMFVAL_LEN_F32,
171  'comp': 'simple',
172  'T': 'float',
173  'pre': 'hf',
174  },
175  'f64': {
176  'code': NMFTypeF64,
177  'desc': "64-bit floating-point number",
178  'flen': NMFVAL_LEN_F64,
179  'comp': 'simple',
180  'T': 'double',
181  'pre': 'f',
182  },
183  'p32': {
184  'code': NMFTypeP32,
185  'desc': "32-bit pointer",
186  'flen': NMFVAL_LEN_P32,
187  'comp': 'simple',
188  'T': 'void *',
189  'pre': 'p',
190  },
191  'p64': {
192  'code': NMFTypeP64,
193  'desc': "64-bit pointer",
194  'flen': NMFVAL_LEN_P64,
195  'comp': 'simple',
196  'T': 'void *',
197  'pre': 'p',
198  },
199  'string': {
200  'code': NMFTypeString,
201  'desc': "char[] string",
202  'flen': 'variable',
203  'comp': 'compound',
204  'T': 'char',
205  'pre': 's',
206  },
207  'struct': {
208  'code': NMFTypeStruct,
209  'desc': "structure",
210  'flen': 'variable',
211  'comp': 'compound',
212  'T': 'struct',
213  'pre': 'st',
214  },
215  'vector': {
216  'code': NMFTypeVector,
217  'desc': "vector - one dimensional array",
218  'flen': 'variable',
219  'comp': 'compound',
220  'T': '',
221  'pre': 'vec',
222  },
223 }
224 ##
225 
226 #
227 # Aliases
228 #
229 NMBuiltInFieldTypes['byte'] = NMBuiltInFieldTypes['u8']
230 NMBuiltInFieldTypes['schar'] = NMBuiltInFieldTypes['s8']
231 NMBuiltInFieldTypes['ushort'] = NMBuiltInFieldTypes['u16']
232 NMBuiltInFieldTypes['short'] = NMBuiltInFieldTypes['s16']
233 NMBuiltInFieldTypes['uint'] = NMBuiltInFieldTypes['u32']
234 NMBuiltInFieldTypes['int'] = NMBuiltInFieldTypes['s32']
235 NMBuiltInFieldTypes['ulonglong'] = NMBuiltInFieldTypes['u64']
236 NMBuiltInFieldTypes['longlong'] = NMBuiltInFieldTypes['s64']
237 NMBuiltInFieldTypes['pointer'] = NMBuiltInFieldTypes['p32']
238 NMBuiltInFieldTypes['longpointer'] = NMBuiltInFieldTypes['p64']
239 NMBuiltInFieldTypes['float'] = NMBuiltInFieldTypes['f32']
240 NMBuiltInFieldTypes['double'] = NMBuiltInFieldTypes['f64']
241 
242 ## Get NetMsgs field type code given the XML field type.
243 NMFCode = lambda xmlftype: NMBuiltInFieldTypes[xmlftype]['code']
244 
245 ## The full set of XML ftype values
246 NMAliasMap = {
247  'byte': 'u8', 'schar': 's8', 'ushort': 'u16', 'short': 'u16',
248  'uint': 'u32', 'int': 's32', 'ulonglong': 'u64', 'longlong': 's64',
249  'pointer': 'p32', 'longpointer': 'p64', 'float': 'f32', 'double': 'f64',
250 }
251 
252 ## Special DB dictionary order key
253 NMKeyOrder = '>'
254 
255 ## Special DB pad field key
256 NMKeyPad = '#'
257 
258 ## XML ftype attribute vector suffix string
259 NMVectorSuffix = '[]'
260 
261 ## List of simple field types by XML ftype
262 NMFTypeSimple = [
263  'char', 'u8', 's8', 'bool', 'u16', 's16', 'u32', 's32', 'u64',
264  's64', 'f32', 'f64', 'p32', 'p64', ]
265 
266 ## List of simple field types by field type code
267 NMFTypeCodeSimple = [
268  NMFCode('char'), NMFCode('u8'), NMFCode('s8'), NMFCode('bool'),
269  NMFCode('u16'), NMFCode('s16'), NMFCode('u32'), NMFCode('s32'),
270  NMFCode('u64'), NMFCode('s64'), NMFCode('f32'), NMFCode('f64'),
271  NMFCode('p32'), NMFCode('p64') ]
272 
273 ## List of compound field types by XML ftype
274 NMFTypeCompound = [ 'string', 'struct', 'vector' ]
275 
276 ## List of compound field types by field type code
277 NMFTypeCodeCompound = [NMFCode('string'), NMFCode('struct'), NMFCode('vector')]
278 
279 ## List of number field types by XML ftype
280 NMFTypeNumber = [
281  'u8', 's8', 'u16', 's16', 'u32', 's32', 'u64', 's64', 'f32', 'f64' ]
282 
283 ## Field type code to XML file type map
284 NMFTypeCode2Xml = {
285  NMFCode('bool'): 'bool', NMFCode('char'): 'char',
286  NMFCode('u8'): 'u8', NMFCode('s8'): 's8',
287  NMFCode('u16'): 'u16', NMFCode('s16'): 's16',
288  NMFCode('u32'): 'u32', NMFCode('s32'): 's32',
289  NMFCode('u64'): 'u64', NMFCode('s64'): 's64',
290  NMFCode('f32'): 'f32', NMFCode('f64'): 'f64',
291  NMFCode('p32'): 'p32', NMFCode('p64'): 'p64',
292  NMFCode('string'): 'string', NMFCode('pad'): 'pad',
293  NMFCode('struct'): 'struct', NMFCode('vector'): 'vector'
294 }
295 
296 ## Field Header Lengths keyed by message encoding
297 NMFHdrLen = {
298  'flat': {'simple': 0, 'string': 0, 'struct': 0, 'vector': 0},
299  'itv': {
300  'simple': NMITV_FHDR_SIZE_SIMPLE, 'string': NMITV_FHDR_SIZE_STRING,
301  'struct': NMITV_FHDR_SIZE_STRUCT, 'vector': NMITV_FHDR_SIZE_VECTOR},
302 }
303 
304 ## No field id value
305 NMFIdNone = NMFID_NONE
306 
307 ## Default pad count
308 NMPadDftCount = 1
309 
310 ## Pad field value
311 NMPadFVal = NMFTypePadTr
312 
313 ## Maximum and default string maximum length
314 NMStringMaxCount = NMFVAL_LEN_MAX_STRING
315 
316 ## Maximum and default vector maximum item count
317 NMVectorMaxCount = NMFVAL_LEN_MAX_VECTOR
318 
319 ## space quickie
320 space = lambda indent: "%*s" % (indent, '')
321 
322 #--
323 def StrError(ecode):
324  """ Get the error string describing the NetMsgs error code.
325 
326  The absolute value of the error code is taken prior retrieving the
327  string. An unknown or out-of-range error code will be mapped to
328  NM_ECODE_BADEC.
329 
330  Parameters:
331  ecode - NetMsgs error code.
332 
333  Return:
334  The appropriate error code string.
335  """
336  sErr = nmStrError(ecode)
337  if not sErr:
338  sErr = 'Error'
339  return sErr
340 ##
341 
342 
343 #------------------------------------------------------------------------------
344 # CLASS: NetMsgsError
345 #------------------------------------------------------------------------------
346 class NetMsgsError(Exception):
347  """ NetMsgs Exception Class. """
348 
349  def __init__(self, msg='XML Parser Error'):
350  """ Raise exception.
351 
352  Parameters:
353  msg - Exception message string.
354  """
355  Exception.__init__(self, msg)
356 ##
357 
358 
359 #-------------------------------------------------------------------------------
360 # Support Utilities
361 #-------------------------------------------------------------------------------
362 
363 #--
364 def IsIdentifier(token):
365  """ Returns True if token is a valid identifier, else False.
366 
367  Parameters:
368  token - Parsed token.
369  """
370  if not token:
371  return False
372  c = token[0]
373  if not c.isalpha() and c != "_":
374  return False
375  for c in token[1:]:
376  if not c.isalnum() and c != "_":
377  return False
378  return True
379 ##
380 
381 #--
382 def PrettyPrintCols(fp, cursor, *args, **kwargs):
383  """ Pretty print argument strings aligned to column.
384 
385  Parameters:
386  cursor - Current column cursor position.
387  args - List of argument (pos, s) 2-tuples.
388  kwargs - Print control keywords.
389  """
390  while len(args) >= 2:
391  linecont = kwargs.get('linecont', '')
392  force = kwargs.get('force', False)
393  pos = args[0]
394  s = args[1]
395  args = args[2:]
396  if (pos <= cursor) and (cursor > 0):
397  if not force or cursor > 78:
398  fp.write("%s\n" % (linecont))
399  cursor = 0
400  else:
401  fp.write(" ")
402  cursor += 1
403  if pos > cursor:
404  fp.write(space(pos-cursor))
405  cursor = pos
406  fp.write("%s" % (s))
407  cursor += len(s)
408  return cursor
409 ##
410 
411 #--
412 def PrintBuf(buf, count=None, preface='', nlfreq=None, indent=0, col=0,
413  fp=sys.stderr):
414  """ Pretty print binary buffer to opened file stream.
415 
416  Parameters:
417  buf - Buffer to print.
418  count - Number of bytes to print.
419  preface - Optional buffer preface string.
420  nlfreq - Newline frequency (None for no newlines).
421  ident - Indentation column alignment.
422  col - Current column position.
423  fp - Output file pointer.
424  """
425  if preface:
426  s = "%s: " % (preface)
427  col += len(s)
428  fp.write(s)
429  if count is None:
430  count = len(buf)
431  if (count > 0) and (col < indent):
432  fp.write(space(indent-col))
433  i = 0
434  while i < count:
435  c = buf[i]
436  if nlfreq and ((i % nlfreq) == 0) and (i > 0):
437 
438  fp.write("\n%s" % space(indent))
439  col = indent
440  fp.write("0x%02x " % (ord(c)))
441  i += 1
442  fp.write('\n')
443 ##
444 
445 #--
446 def PrintBits(val, msbit, count=None, preface='', fp=sys.stderr):
447  """ Pretty print bits in value to opened file stream.
448 
449  Parameters:
450  val - Bits to print.
451  msbit - Starting most significant bit, zero based.
452  count - Number of bits to print (None = msbit+1).
453  preface - Optional buffer preface string.
454  fp - Output file pointer.
455  """
456  if preface:
457  s = "%s: " % (preface)
458  fp.write(s)
459  if count is None:
460  count = msbit + 1
461  i = 0
462  while i < count:
463  if ((msbit % 8) == 7) and (i > 0):
464  fp.write(' ')
465  if (val >> msbit) & 0x01:
466  fp.write('1')
467  else:
468  fp.write('0')
469  msbit -= 1
470  i += 1
471 ##
472 
473 #--
474 def _atval(val):
475  """ Convert value to string equivaling.
476 
477  String values starting with an '@' are treated as variables, not strings.
478  The '@' is stripped.
479 
480  Parameters:
481  val - ['@']value.
482 
483  Return:
484  Converted value.
485  """
486  if (type(val) == str) and (len(val) > 0) and (val[0] == '@'):
487  return val[1:]
488  else:
489  return repr(val)
490 ##
491 
492 ## return number of spaces given column position and indentation
493 _nspaces = lambda col,indent: col<indent and indent-col or 0
494 
495 #--
496 def PrettyPrintAssignExpr(name, val, col=0, indent=0, fp=sys.stderr):
497  """ Pretty print name = value.
498 
499  Parameters:
500  nam - Variable name
501  val - Variable value.
502  col - Current column position.
503  indent - Indentation.
504  fp - Opened file pointer.
505  """
506  sp = _nspaces(col, indent)
507  lhs = "%s%s = " % (space(sp), name)
508  fp.write(lhs)
509  PrettyPrintVal(val, col=len(lhs), indent=indent, fp=fp)
510  fp.write('\n')
511 ##
512 
513 #--
514 def PrettyPrintVal(val, col=0, indent=0, fp=sys.stderr):
515  """ Pretty print value.
516 
517  Parameters:
518  val - Variable value.
519  col - Current column position.
520  indent - Indentation.
521  fp - Opened file pointer.
522 
523  Return:
524  New column position
525  """
526  if type(val) == dict:
527  return PrettyPrintDict(val, col=col, indent=indent, fp=fp)
528  elif type(val) == list:
529  return PrettyPrintList(val, col=col, indent=indent, fp=fp)
530  else:
531  sp = _nspaces(col, indent)
532  v = _atval(val)
533  fp.write("%s%s" % (space(sp), v))
534  return col + sp + len(v)
535 ##
536 
537 #--
538 def PrettyPrintDict(d, col=0, indent=0, fp=sys.stderr):
539  """ Pretty print dictionary in sorted, indented clarity.
540 
541  Parameters:
542  d - The dictionary.
543  col - Current column position.
544  indent - Indentation.
545  fp - Opened file pointer.
546 
547  Return:
548  New column position
549  """
550  sp = _nspaces(col, indent)
551  s = repr(d)
552  if col + sp + len(s) < 80:
553  fp.write('%s{' % space(sp))
554  col = col + sp + 1
555  keys = d.keys()
556  keys.sort()
557  for k in keys:
558  key = _atval(k)
559  fp.write("%s:" % key)
560  col += len(key) + 1
561  col = PrettyPrintVal(d[k], col=col, indent=indent, fp=fp)
562  fp.write(', ')
563  col += 2
564  fp.write("}")
565  return col + 1
566  else:
567  fp.write('%s{\n' % space(sp))
568  col = 0
569  indent += 2
570  keys = d.keys()
571  keys.sort()
572  for k in keys:
573  key = _atval(k)
574  key = "%s%s: " % (space(indent), key)
575  fp.write(key)
576  PrettyPrintVal(d[k], col=len(key), indent=indent, fp=fp)
577  fp.write(',\n')
578  indent -= 2
579  fp.write("%s}" % (space(indent)))
580  return indent + 1
581 ##
582 
583 #--
584 def PrettyPrintList(l, col=0, indent=0, fp=sys.stderr):
585  """ Pretty print list.
586 
587  Parameters:
588  l - The list.
589  col - Current column position.
590  indent - Indentation.
591  fp - Opened file pointer.
592 
593  Return:
594  New column position
595  """
596  sp = _nspaces(col, indent)
597  issimple = True
598  for v in l:
599  if (type(v) == dict) or (type(v) == list):
600  issimple = False
601  break
602  if issimple:
603  fp.write('%s[ ' % space(sp))
604  col = col + sp + 2
605  for v in l:
606  if col > 60: # heuristiccally 'safe'
607  fp.write('\n%s ' % space(indent))
608  col = col + sp + 2
609  col = PrettyPrintVal(v, col=col, indent=indent, fp=fp)
610  fp.write(', ')
611  col += 2
612  fp.write(' ]')
613  return col + 2
614  else:
615  fp.write('%s[\n' % space(sp))
616  col = 0
617  indent += 2
618  for v in l:
619  PrettyPrintVal(v, col=col, indent=indent, fp=fp)
620  fp.write(',\n')
621  indent -= 2
622  fp.write("%s]" % (space(indent)))
623  return indent + 1
624 ##
string space
space quickie
Definition: NetMsgsBase.py:320
def PrettyPrintAssignExpr(name, val, col=0, indent=0, fp=sys.stderr)
Definition: NetMsgsBase.py:496
def StrError(ecode)
Definition: NetMsgsBase.py:323
def PrintBuf(buf, count=None, preface='', nlfreq=None, indent=0, col=0, fp=sys.stderr)
Definition: NetMsgsBase.py:413
def PrettyPrintVal(val, col=0, indent=0, fp=sys.stderr)
Definition: NetMsgsBase.py:514
def PrettyPrintDict(d, col=0, indent=0, fp=sys.stderr)
Definition: NetMsgsBase.py:538
def IsIdentifier(token)
Definition: NetMsgsBase.py:364
def __init__(self, msg='XML Parser Error')
Definition: NetMsgsBase.py:349
NMFCode
Get NetMsgs field type code given the XML field type.
Definition: NetMsgsBase.py:243
def PrettyPrintCols(fp, cursor, args, kwargs)
Definition: NetMsgsBase.py:382
def PrintBits(val, msbit, count=None, preface='', fp=sys.stderr)
Definition: NetMsgsBase.py:446
def PrettyPrintList(l, col=0, indent=0, fp=sys.stderr)
Definition: NetMsgsBase.py:584