utils.py
Go to the documentation of this file.
00001 #! /usr/bin/env python -m
00002 # -*- coding: utf-8 -*-
00003 #     _____
00004 #    /  _  \
00005 #   / _/ \  \
00006 #  / / \_/   \
00007 # /  \_/  _   \  ___  _    ___   ___   ____   ____   ___   _____  _   _
00008 # \  / \_/ \  / /  _\| |  | __| / _ \ | ┌┐ \ | ┌┐ \ / _ \ |_   _|| | | |
00009 #  \ \_/ \_/ /  | |  | |  | └─┐| |_| || └┘ / | └┘_/| |_| |  | |  | └─┘ |
00010 #   \  \_/  /   | |_ | |_ | ┌─┘|  _  || |\ \ | |   |  _  |  | |  | ┌─┐ |
00011 #    \_____/    \___/|___||___||_| |_||_| \_\|_|   |_| |_|  |_|  |_| |_|
00012 #            ROBOTICS™
00013 #
00014 #  File: utils.py
00015 #  Desc: Clearpath Robotics Inc. Utilities Python Module
00016 #  Auth: Ryan Gariepy
00017 #  
00018 #  Copyright © 2010 Clearpath Robotics, Inc. 
00019 #  All Rights Reserved
00020 # 
00021 #  Redistribution and use in source and binary forms, with or without
00022 #  modification, are permitted provided that the following conditions are met:
00023 #      * Redistributions of source code must retain the above copyright
00024 #        notice, this list of conditions and the following disclaimer.
00025 #      * Redistributions in binary form must reproduce the above copyright
00026 #        notice, this list of conditions and the following disclaimer in the
00027 #        documentation and/or other materials provided with the distribution.
00028 #      * Neither the name of Clearpath Robotics, Inc. nor the
00029 #        names of its contributors may be used to endorse or promote products
00030 #        derived from this software without specific prior written permission.
00031 # 
00032 #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
00033 #  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
00034 #  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
00035 #  ARE DISCLAIMED. IN NO EVENT SHALL CLEARPATH ROBOTICS, INC. BE LIABLE FOR ANY
00036 #  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00037 #  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00038 #  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00039 #  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00040 #  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00041 #  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00042 #
00043 #  Please send comments, questions, or patches to code@clearpathrobotics.com
00044 #
00045   
00046 
00047 
00048 
00049 ################################################################################
00050 # Script
00051 
00052 
00053 
00054 # Check if run as a script
00055 if __name__ == "__main__":
00056     import sys
00057     
00058     # Warn of Module ONLY status
00059     if (sys.version_info[0] > 2 and sys.version_info[1] > 0) or \
00060             (sys.version_info[0] == 2 and sys.version_info[1] > 6):
00061         print ("ERROR: clearpath.utils is a module and can NOT be run as a "\
00062                "script!\nFor a listing of installed Clearpath Robotics Inc. "\
00063                "modules, run:\n  python -m clearpath")
00064     else:
00065         print ("ERROR: clearpath.utils is a module and can NOT be run as a "\
00066                "script!\nFor a listing of installed Clearpath Robotics Inc. "\
00067                "modules, run:\n  python -m clearpath.__main__")
00068 
00069     # Exit Error
00070     sys.exit(1)
00071 
00072 
00073 
00074 
00075 ################################################################################
00076 # Module
00077 
00078 
00079 
00080 ## @package clearpath.utils 
00081 #  Clearpath Robotics Inc. Utilities Python Module
00082 # 
00083 #  Utilities for use with Horizon and other Clearpath Modules                 \n
00084 #                                                                             \n
00085 #  Contains:
00086 #  - Byte List Conversions
00087 #  - Checksum Utilities: 16-bit CRC - CCITT polynomial x16+x12+x5+1 (0x1021)
00088 #  - Common Exceptions
00089 #  - Logging Utilities
00090 #  - Transport Utilities
00091 #
00092 #  @author     Ryan Gariepy
00093 #  @author     Malcolm Robert
00094 #  @date       18/01/10
00095 #  @req        pySerial [http://pyserial.sourceforge.net/]                    \n
00096 #              -- for list_serial_ports()
00097 #  @version    1.0
00098 #
00099 #  @section USE
00100 #
00101 #  The intended purpose of this module is to contain common classes and methods
00102 #  that are (or could be) used in multiple Clearpath Python packages and/or
00103 #  modules and do not provide functionality specific to one package 
00104 #  (hence utilities).
00105 #
00106 #  Due to backward support for Python 2.6 and the lack of support for bytes
00107 #  in Python 2.6, it is useful to store an array of bytes as an array of 
00108 #  numbers. Without strict types, this presents requirements for extracting
00109 #  and appending numbers of various types to the byte list. The methods that
00110 #  begin with 'from_' take the number of the appropriate type (or ascii string 
00111 #  for from_ascii) and converts it to an array of numbers all within [0,255]
00112 #  that can be appended or inserted into other arrays. Likewise, the methods
00113 #  that begin with 'to_' takes an array of numbers (must be of proper size)
00114 #  and converts it to the desired type. Since most streams in 2.6 use strings
00115 #  and streams in 3.x use bytes, the method to_bytes can be used to convert
00116 #  the array of numbers into the appropriate format. Further, the method hex
00117 #  is provided to display a number [0,255] in hex form (in a format preferable
00118 #  to python's default hex method).
00119 #
00120 #  The method ccitt_checksum provides a 16-bit CRC table based checksum on the 
00121 #  given array of numbers (each [0,255]) using the CCITT Polynomial (0x1021).
00122 #  Checksums are very useful for verifying data is transmitted without error.
00123 #
00124 #  The Python standard built-ins do not provide many exception classes. To
00125 #  help differentiate the types of errors encountered, the exceptions
00126 #  ChecksumError, FormatError, SubscriptionError, TransportError, TimeoutError,
00127 #  and UnsupportedCodeError are provided without any additional functionality
00128 #  added beyond their parent classes.
00129 #
00130 #  The majority of Clearpath's Python code is in library form, intended to be
00131 #  used by other scripts/programs/libraries. While logging debug messages is
00132 #  useful, developers do not expect libraries to be logging messages by default
00133 #  so the class NullLoggingHandler is provided to disable the default logging
00134 #  action. For library loggers, set the logging level to NOTSET, set propagate
00135 #  to False and add an instance of NullLoggingHandler as the only logging 
00136 #  handler and all messages will be rendered disabled.
00137 #
00138 #  While actual communication over RS-232 (serial) is typically package
00139 #  specific and not common, programs/scripts that invoke communication packages
00140 #  find it useful to be able to find out what serial ports exist and are 
00141 #  accessible on the computer. For that purpose, the method list_serial_ports
00142 #  is provided. Note that this method requires the non-standard Python
00143 #  library pySerial to be installed into the Python search path. 
00144 #
00145 #  Various logging messages (debug, warning,...) are logged with the standard
00146 #  Python logger to the log named 'clearpath.utils'.                          \n
00147 #  Messages are ignored by default; remove the only handler from it and turn
00148 #  on propagation to get messages to propagate.
00149 #
00150 #  @section HISTORY
00151 #  Version 0.1 - 0.3 {Ryan Gariepy}
00152 #  - Initial Creation in protocol.py
00153 #  
00154 #  Version 0.5 {Malcolm Robert}
00155 #  - Move to clearpath_utils.py
00156 #  - Added Serial Port Listing
00157 #  - Added TransportError
00158 #  - Added Logging Utils
00159 #  - Added Doxygen documentation
00160 #  - Added independent version scheme
00161 #
00162 #  Version 1.0
00163 #  - Added Exceptions
00164 #  - Python 2.6+ & 3.x compatible
00165 #
00166 #  @section License
00167 #  @copydoc public_license
00168 #
00169 """Utilities for use with Horizon and other Clearpath Modules 
00170 
00171    Copyright © 2010 Clearpath Robotics, Inc.
00172    All rights reserved
00173    
00174    Created: 18/01/10
00175    Authors: Malcolm Robert
00176    Version: 1.0
00177    """
00178 
00179 
00180 # Required Modules
00181 import logging                  # Logging Utilities
00182 import os                       # Operating System Capabilities
00183 import re                       # Regular Expressions
00184 import sys                      # Python Interpreter Functionality
00185 
00186 # Non-Standard Modules
00187 try:
00188     import serial               # Serial Port Control
00189 except ImportError:
00190     pass
00191 
00192 
00193 # Module Support
00194 ## Module Version
00195 __version__  = "1.0" 
00196 """Module Version"""
00197 ## SVN Code Revision
00198 __revision__ = "$Revision: 674 $"
00199 """ SVN Code Revision"""
00200 
00201 
00202 ## Message Log
00203 logger = logging.getLogger('clearpath.utils')
00204 """Clearpath Utilities Module Log"""
00205 logger.setLevel(logging.NOTSET)
00206 logger.propagate = False
00207 logger.debug("Loading clearpath.utils ...")     
00208 
00209 
00210 
00211 
00212 ################################################################################
00213 # Byte List
00214 # @todo Consider making methods static methods within a bytes_list class
00215 
00216 
00217 
00218 ## Byte to Hex String
00219 #
00220 #  Display a byte in a string as HEX.
00221 #
00222 #  @param  byte The byte to display
00223 #  @return string
00224 #
00225 #  @pydoc
00226 def hex(byte):
00227     """Byte to Hex String"""
00228     
00229     return '%02X' % byte
00230 
00231 
00232 
00233 # ----------------------------------- Signed -----------------------------------
00234 # Signed negative numbers use two's compliment
00235 
00236 
00237 
00238 ## From Char to Byte List
00239 #
00240 #  Convert a signed byte to a byte list.
00241 #  Do not pass an actual character to this function; if you need to convert
00242 #  an actual character use from_byte(ord(character)).
00243 #
00244 #  @param  input The number to convert to a byte list [-128,127]
00245 #  @return byte list
00246 #
00247 #  @pydoc
00248 def from_char(input, scale = 1):
00249     """Char -> Byte List"""
00250     input = int(input * scale)
00251     assert input > -129 and input < 128
00252     
00253     # Convert to byte
00254     output = 0x00
00255     if input > -1: 
00256         
00257         # truncate 
00258         output = 0xFF & input
00259     else:
00260         
00261         # twos compliment
00262         output = 0xFF & (-input)
00263         output = 0xFF & (~output)
00264         output += 0x01
00265     
00266     return [output]
00267 
00268 
00269 
00270 ## From Byte List to Char
00271 #
00272 #  Convert a byte list to a signed byte.
00273 #
00274 #  @param  input The byte list to convert to a signed byte [byte]
00275 #  @return signed byte
00276 #
00277 #  @pydoc
00278 def to_char(input, scale = 1):
00279     """Byte List -> Char"""
00280     
00281     # Ensure number is correct
00282     assert len(input) == 1 and input[0] > -1 and input[0] < 256
00283     
00284     # convert to char
00285     output = 0
00286     if input[0] < 128: output = input[0]
00287     else:
00288         
00289         # invert twos compliment
00290         output = input[0] - 0x01
00291         output = 0xFF & (~output)
00292         output *= -1
00293 
00294     return output / float(scale)
00295 
00296 
00297 ## From Short to Byte List
00298 #
00299 #  Convert a signed short to a byte list.
00300 #
00301 #  @param  input The number to convert to a byte list [-32768, 32767]
00302 #  @return byte list
00303 #
00304 #  @pydoc
00305 def from_short(input, scale = 1):
00306     """Short -> Byte List"""
00307     input = int(input * scale)
00308 
00309     # Ensure number is correct
00310     assert input > -32769 and input < 32768
00311     
00312     # Convert to unsigned short
00313     output = 0x0000
00314     if input > -1: 
00315         
00316         # truncate 
00317         output = 0xFFFF & input
00318     else:
00319         
00320         # twos compliment
00321         output = 0xFFFF & (-input)
00322         output = 0xFFFF & (~output)
00323         output += 0x01
00324     
00325     return [output & 0xFF, (output >> 8) & 0xFF]
00326 
00327 
00328 
00329 ## From Byte List to Short
00330 #
00331 #  Convert a byte list to a signed short.
00332 #
00333 #  @param  input The byte list to convert to a signed short [byte,byte]
00334 #  @return signed short
00335 #
00336 #  @pydoc
00337 def to_short(input, scale = 1):
00338     """Byte List -> Short"""
00339 
00340     # Ensure number is correct
00341     assert len(input) == 2 and input[0] > -1 and input[0] < 256 and \
00342         input[1] > -1 and input[1] < 256
00343     
00344     # convert to short
00345     output = 0xFFFF & ((input[1] << 8) | input[0])
00346     if output > 32767:
00347         
00348         # invert twos compliment
00349         output -= 0x0001
00350         output = 0xFFFF & (~output)
00351         output *= -1
00352     
00353     return output / float(scale)
00354 
00355 
00356 
00357 ## From Int to Byte List
00358 #
00359 #  Convert a signed integer to a byte list.
00360 #
00361 #  @param  input The number to convert to a byte list [-2147483648, 2147483647]
00362 #  @return byte list
00363 #
00364 #  @pydoc
00365 def from_int(input, scale = 1):
00366     """Int -> Byte List"""
00367     input = int(input * scale)
00368 
00369     # Ensure number is correct
00370     if type(input) == float: input = int(input)
00371     assert input > -2147483649 and input < 2147483648
00372     
00373     # Convert to unsigned short
00374     output = 0x00000000
00375     if input > -1: 
00376         
00377         # truncate 
00378         output = 0xFFFFFFFF & input
00379     else:
00380         
00381         # twos compliment
00382         output = 0xFFFFFFFF & (-input)
00383         output = 0xFFFFFFFF & (~output)
00384         output += 0x01
00385     
00386     return [output & 0xFF, (output >> 8) & 0xFF, (output >> 16) & 0xFF, 
00387             (output >> 24) & 0xFF]
00388 
00389 
00390 
00391 ## From Byte List to Int
00392 #
00393 #  Convert a byte list to a signed integer.
00394 #
00395 #  @param  input The byte list to convert to a signed integer 
00396 #                [byte,byte,byte,byte]
00397 #  @return signed integer
00398 #
00399 #  @pydoc
00400 def to_int(input, scale = 1):
00401     """Byte List -> Int"""
00402     
00403     # Ensure number is correct
00404     assert len(input) == 4 and input[0] > -1 and input[0] < 256 and \
00405         input[1] > -1 and input[1] < 256 and input[2] > -1 and input[2] < 256\
00406         and input[3] > -1 and input[3] < 256
00407     
00408     # convert to integer
00409     output = 0xFFFFFFFF & ((input[3] << 24) | (input[2] << 16) | 
00410                            (input[1] << 8) | input[0])
00411     if output > 2147483647:
00412         
00413         # invert twos compliment
00414         output -= 0x00000001
00415         output = 0xFFFFFFFF & (~output)
00416         output *= -1
00417     
00418     return output / float(scale)
00419 
00420 
00421 
00422 # ---------------------------------- Unsigned ----------------------------------
00423 
00424 
00425 
00426 ## From Byte to Byte List
00427 #
00428 #  Convert an unsigned byte to a byte list.
00429 #
00430 #  @param  input The number to convert to a byte list [0,255]
00431 #  @return byte list
00432 #
00433 #  @pydoc
00434 def from_byte(input, scale = 1):
00435     """Byte -> Byte List"""
00436     input = int(input * scale)
00437     
00438     # Ensure number is correct
00439     if type(input) == float: input = int(input)
00440     assert input > -1 and input < 256
00441     
00442     # truncate 
00443     output = 0xFF & input
00444     
00445     return [output]
00446 
00447 
00448 
00449 ## From Byte List to Byte
00450 #
00451 #  Convert a byte list to an unsigned byte.
00452 #
00453 #  @param  input The byte list to convert to an unsigned byte [byte]
00454 #  @return unsigned byte
00455 #
00456 #  @pydoc
00457 def to_byte(input):
00458     """Byte List -> Byte"""
00459     
00460     # Ensure number is correct
00461     assert len(input) == 1 and input[0] > -1 and input[0] < 256
00462     
00463     return input[0]
00464 
00465 
00466 
00467 ## From Unsigned Short to Byte List
00468 #
00469 #  Convert an unsigned short to a byte list.
00470 #
00471 #  @param  input The number to convert to a byte list [0, 65535]
00472 #  @return byte list
00473 #
00474 #  @pydoc
00475 def from_unsigned_short(input, scale = 1):
00476     """Unsigned Short -> Byte List"""
00477     input = int(input * scale)
00478     
00479     # Ensure number is correct
00480     if type(input) == float: input = int(input)
00481     assert input > -1 and input < 65536
00482     
00483     # truncate 
00484     output = 0xFFFF & input
00485     
00486     return [output & 0xFF, (output >> 8) & 0xFF]
00487 
00488 
00489 
00490 ## From Byte List to Unsigned Short
00491 #
00492 #  Convert a byte list to an unsigned short.
00493 #
00494 #  @param  input The byte list to convert to an unsigned short [byte,byte]
00495 #  @return unsigned short
00496 #
00497 #  @pydoc
00498 def to_unsigned_short(input):
00499     """Byte List -> Unsigned Short"""
00500     
00501     # Ensure number is correct
00502     assert len(input) == 2 and input[0] > -1 and input[0] < 256 and \
00503         input[1] > -1 and input[1] < 256
00504     
00505     # convert to short
00506     output = 0xFFFF & ((input[1] << 8) | input[0])
00507     
00508     return output
00509 
00510 
00511 
00512 ## From Unsigned Int to Byte List
00513 #
00514 #  Convert an unsigned integer to a byte list.
00515 #
00516 #  @param  input The number to convert to a byte list [0, 4294967295]
00517 #  @return byte list
00518 #
00519 #  @pydoc
00520 def from_unsigned_int(input, scale = 1):
00521     """Unsigned Int -> Byte List"""
00522     input = int(input * scale)
00523     
00524     # Ensure number is correct
00525     if type(input) == float: input = int(input)
00526     assert input > -1 and input < 4294967296
00527     
00528     # truncate 
00529     output = 0xFFFFFFFF & input
00530     
00531     return [output & 0xFF, (output >> 8) & 0xFF, (output >> 16) & 0xFF, 
00532             (output >> 24) & 0xFF]
00533 
00534 
00535 
00536 ## From Byte List to Unsigned Int
00537 #
00538 #  Convert a byte list to an unsigned integer.
00539 #
00540 #  @param  input The byte list to convert to an unsigned integer 
00541 #                [byte,byte,byte,byte]
00542 #  @return unsigned integer
00543 #
00544 #  @pydoc
00545 def to_unsigned_int(input):
00546     """Byte List -> Unsigned Int"""
00547     
00548     # Ensure number is correct
00549     assert len(input) == 4 and input[0] > -1 and input[0] < 256 and \
00550         input[1] > -1 and input[1] < 256 and input[2] > -1 and input[2] < 256\
00551         and input[3] > -1 and input[3] < 256
00552     
00553     # convert to integer
00554     output = 0xFFFFFFFF & ((input[3] << 24) | (input[2] << 16) | 
00555                            (input[1] << 8) | input[0])
00556     
00557     return output
00558 
00559 
00560 
00561 ## From ASCII to Byte List
00562 #
00563 #  Convert a string of ASCII to a byte list.
00564 #
00565 #  @param  input The string to convert to a byte list
00566 #  @return byte list
00567 #
00568 #  @pydoc
00569 def from_ascii(input):
00570     """ASCII -> Byte List"""
00571     
00572     # Ensure string is correct
00573     assert all(ord(c) < 256 for c in input)
00574     
00575     # Wrapper method for map
00576     def tmp(char):
00577         return to_byte([ord(char)])
00578     
00579     # Convert to bytes
00580     return list(map(tmp,input))
00581 
00582 
00583 
00584 ## From Byte List to ASCII
00585 #
00586 #  Convert a byte list to an ASCII string.
00587 #
00588 #  @param  input The byte list to convert to an ASCII string
00589 #  @return ASCII string
00590 #
00591 #  @pydoc
00592 def to_ascii(input):
00593     """Byte List -> ASCII"""
00594     
00595     return ''.join(map(chr,input))
00596 
00597 
00598 
00599 ## From Byte List to bytes
00600 #
00601 #  Convert a byte list to a bytes type.
00602 #
00603 #  @param  input The byte list to convert to bytes
00604 #  @return bytes string
00605 #
00606 #  @pydoc
00607 def to_bytes(input):
00608     """Byte List -> bytes"""
00609     
00610     if sys.version_info[0] > 2:
00611         return bytes(input)
00612     else:
00613         return b''.join(map(chr,input))
00614 
00615   
00616   
00617   
00618 ################################################################################
00619 # Checksum
00620 ## @defgroup crc CRC Generation
00621 #  @ingroup doc
00622 #  
00623 #  A 16-bit CRC using one of the CCITT polynomials is used to confirm message 
00624 #  integrity.                                                               \n\n
00625 #
00626 #  <i>Polynomial:</i> x16+x12+x5+1 (0x1021)                                   \n
00627 #
00628 #  <i>Initial value:</i> 0xFFFF                                               \n
00629 #
00630 #  <i>Check constant:</i> 0x1D0F                                            \n\n
00631 #
00632 #  The calculated CRC of the string '123456789' should be 0x29B1              \n
00633 #
00634 #  To confirm CRC implementation, the following process can be used:
00635 #  -# Calculate the CRC of any message
00636 #  -# XOR it with 0xFFFF (bitwise inversion)
00637 #  -# Append it to the original message
00638 #  -# Perform the CRC calculation on the extended message
00639 #  -# Confirm that the new CRC is equal to the check constant (0x1D0F)
00640 #
00641 #  \b Sample \b C \b Code \b for \b table-driven \b CRC \b computation:     \n\n
00642 #  @code
00643 #  /*
00644 #   * crc.h
00645 #   */
00646 #
00647 #  #ifndef __CRC16_H
00648 #  #define __CRC16_H
00649 #
00650 #  /***----------Table-driven crc function----------***/
00651 #  /* Inputs: -size of the character array,           */ 
00652 #  /*              the CRC of which is being computed */
00653 #  /*         - the initial value of the register to  */
00654 #  /*              be used in the calculation         */
00655 #  /*         - a pointer to the first element of     */
00656 #  /*              said character array               */
00657 #  /* Outputs: the crc as an unsigned short int       */
00658 #  unsigned short int crc16(int size, int init_val, char *data);
00659 #
00660 #  #endif
00661 #
00662 #  /*
00663 #   * crc.c
00664 #   */
00665 #
00666 #  #include "crc.h"
00667 #
00668 #  //CRC lookup table for polynomial 0x1021
00669 #  const unsigned short int table[256] =
00670 #  {0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 
00671 #  45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 
00672 #  17044, 29431, 25302, 37689, 33560, 45947, 41818, 54205, 50076, 62463, 
00673 #  58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 
00674 #  46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907, 9842, 5649, 
00675 #  1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 
00676 #  59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 
00677 #  14371, 51660, 55789, 59790, 63919, 35144, 39273, 43274, 47403, 23285, 
00678 #  19156, 31415, 27286, 6769, 2640, 14899, 10770, 56317, 52188, 64447, 
00679 #  60318, 39801, 35672, 47931, 43802, 27814, 31879, 19684, 23749, 11298, 
00680 #  15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395, 36200, 
00681 #  40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 
00682 #  61374, 57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 
00683 #  41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 
00684 #  16421, 28742, 24679, 33721, 37784, 41979, 46042, 49981, 54044, 58239, 
00685 #  62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 
00686 #  42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 
00687 #  1153, 29798, 25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 
00688 #  63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 
00689 #  22068, 55628, 51565, 63758, 59695, 39368, 35305, 47498, 43435, 22596, 
00690 #  18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 
00691 #  64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801, 
00692 #  6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 
00693 #  36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 
00694 #  65342, 53085, 57212, 44955, 49082, 36825, 40952, 28183, 32310, 20053, 
00695 #  24180, 11923, 16050, 3793, 7920};
00696 #
00697 #  /***----------Table-driven crc function----------***/
00698 #  /* Inputs: - size of the character array, the CRC  */
00699 #  /*               of which is being computed        */
00700 #  /*         - the initial value of the register to  */
00701 #  /*               be used in the calculation        */
00702 #  /*         - a pointer to the first element of     */
00703 #  /*               said character array              */
00704 #  /* Outputs: the crc as an unsigned short int       */
00705 #  unsigned short int crc16(int size, int init_val, char *data)
00706 #  {
00707 #        unsigned short int crc = (unsigned short int) init_val;
00708 #        while(size--) {
00709 #              crc = (crc << 8) ^ table[((crc >> 8) ^ *data++) & 0xFFFF];
00710 #        }
00711 #        return crc;
00712 #  }
00713 #  @endcode
00714 
00715   
00716 ## Precomputed checksum table. Polynomial 0x1021. 
00717 #
00718 #  Used for performing a 16-bit CRC with polynomial 0x1021
00719 CCIT_CRC_TABLE = (
00720     0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 
00721     0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
00722     0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 
00723     0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
00724     0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 
00725     0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
00726     0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
00727     0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
00728     0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823, 
00729     0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 
00730     0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12, 
00731     0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
00732     0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41, 
00733     0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 
00734     0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70, 
00735     0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
00736     0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
00737     0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 
00738     0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 
00739     0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 
00740     0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 
00741     0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405, 
00742     0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 
00743     0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 
00744     0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 
00745     0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3, 
00746     0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 
00747     0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92, 
00748     0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 
00749     0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1, 
00750     0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 
00751     0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0
00752     )
00753 
00754 
00755 
00756 ## Perform a 16-bit CRC with CCITT Polynomial 0x1021
00757 #
00758 #  @param  data     A Byte List to checksum
00759 #  @param  init_val The initial value to calculate the checksum with. 
00760 #                   The default value of 0xffff performs a proper checksum.
00761 #  @return          Resultant Checksum (16-bits)
00762 #
00763 #  @pydoc
00764 def ccitt_checksum(data, init_val=0xFFFF):
00765     """Perform a 16-bit CRC with CCITT Polynomial 0x1021"""
00766     
00767     crc = init_val
00768     for byte in data:
00769         crc = ((crc << 8) & 0xff00) ^ CCIT_CRC_TABLE[((crc >> 8) ^ byte) & 0xFF]
00770     return crc
00771 
00772 
00773 
00774 
00775 ################################################################################
00776 # Exceptions
00777 
00778 
00779 ## Checksum Exception
00780 #
00781 #  Used to indicate a bad checksum.
00782 class ChecksumError(ValueError):
00783     """Used to indicate a bad checksum."""
00784 
00785 
00786 ## Format Exception
00787 #
00788 #  Used to indicate a bad data format.
00789 class FormatError(ValueError):
00790     """Used to indicate a bad data format."""
00791 
00792 
00793 ## Subscription Exception
00794 #
00795 #  Used to indicate a bad subscription request.
00796 class SubscriptionError(ValueError):
00797     """Used to indicate a bad subscription request."""
00798 
00799 
00800 ## Transport Exception
00801 #
00802 #  Used to indicate a transport problem.
00803 class TransportError(IOError):
00804     """Used to indicate a transport problem."""
00805 
00806 
00807 ## Timeout Exception
00808 #
00809 #  Used to indicate a timeout occurred.
00810 class TimeoutError(TransportError):
00811     """Used to indicate a timeout occurred."""
00812 
00813 
00814 ## Unsupported Code Exception
00815 #
00816 #  Used to indicate an unsupported code.
00817 class UnsupportedCodeError(NotImplementedError):
00818     """Used to indicate an unsupported code."""
00819 
00820 
00821 
00822 
00823 ################################################################################
00824 # Logging
00825 
00826 
00827 ## Null Logging Handler
00828 #
00829 #  Implements a logging handler that does nothing with the event.             \n
00830 #  Useful for suppressing log messages when logging in a library.
00831 #
00832 #  @pydoc
00833 class NullLoggingHandler(logging.Handler):
00834     """Null Logging Handler"""
00835     
00836     
00837     ## Logging Event
00838     #
00839     #  Does Nothing.
00840     #
00841     #  @param record The received logging record.
00842     #
00843     #  @pydoc
00844     def emit(self, record):
00845         """Logging Event"""
00846     
00847         pass # Do Nothing
00848    
00849    
00850 
00851 # Update module logger
00852 logger.addHandler(NullLoggingHandler())
00853 
00854 
00855 
00856 
00857 ################################################################################
00858 # Transport
00859 
00860 
00861 
00862 ## List machine serial ports.
00863 #
00864 #  Utility to get a listing of OS known serial ports.
00865 #  - Posix:   Lists devices in /dev that matches ttyS# or ttyUSB#             \n
00866 #             Degrades to listing devices accessible by the serial module 
00867 #  - Windows: Lists COM devices accessible by the serial module
00868 #
00869 #  @req       pySerial [http://pyserial.sourceforge.net/]
00870 #
00871 #  @pre       OS must be Posix compliant or Windows NT
00872 #  @pre       Posix: Read access on /dev or full access of Serial ports
00873 #  @pre       Windows: Full access of COM ports
00874 #  @throws    OSError If Unsupported OS (not Posix or Windows)
00875 #  @throws    IOError If can't read '/dev' on Posix
00876 #  @return    List of serial port names ('/dev/ttyS0', '/dev/ttyUSB0', 'COM0'),
00877 #             Empty List if none found
00878 #
00879 #  @pydoc
00880 def list_serial_ports():
00881     """List machine serial ports."""
00882     
00883     # ensure pySerial exists
00884     try:
00885         serial
00886     except NameError:
00887         logger.error("Cannot search for serial ports without pySerial!")
00888         raise ImportError ("pySerial not found!")
00889 
00890     ports = []
00891 
00892     # POSIX Environment
00893     
00894     if os.name == "posix":
00895         logger.debug("Linux environment searching /dev...")
00896         
00897         # Test for /dev readability
00898         if os.access("/dev", os.R_OK):
00899             regex = re.compile("^tty(USB|S)[0-9]+$")
00900             all_ports = [s for s in os.listdir('/dev') if regex.match(s)]
00901             logger.debug("Found %d serial ports in /dev." % len(all_ports))
00902 
00903             for port in all_ports:
00904                 port = '/dev/' + port
00905                 if os.access(port, os.R_OK | os.W_OK):
00906                     ports.append(port)
00907                     
00908             logger.info("Found %d available serial ports." % len(ports))
00909 
00910         # Cannot read /dev
00911         else:
00912             logger.warning("Insufficient access privileges on /dev.")
00913             pass
00914     
00915     # Non-POSIX system; check for windows-style COMX serial ports.
00916     if os.name == "nt" or len(ports) == 0:
00917         for i in range(100):
00918 
00919             # Attempt to create the COM device
00920             try:
00921                 tmp = serial.Serial(port=i)
00922                 logger.info("Found serial port at COM %d." % i)
00923                 # portstr is deprecated. Use "name" as of pyserial 2.5.
00924                 ports.append(tmp.portstr)
00925                 
00926             # Catch Non-Existent Device Exception
00927             except serial.SerialException:
00928                 pass    # Port creation failed; move on.
00929 
00930     # Return the list
00931     return ports
00932 
00933 
00934 logger.debug("... clearpath.utils loaded.")


clearpath_base
Author(s): Mike Purvis
autogenerated on Sat Dec 28 2013 16:50:48