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.")