diff --git a/pycrc/COPYING b/pycrc/COPYING new file mode 100644 index 0000000..c7eb2e8 --- /dev/null +++ b/pycrc/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2006-2012, Thomas Pircher + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/pycrc/ChangeLog b/pycrc/ChangeLog new file mode 100644 index 0000000..7ca2502 --- /dev/null +++ b/pycrc/ChangeLog @@ -0,0 +1,432 @@ +# +# Version 0.7.10, 2012-02-13 +# + +2012-02-08 Thomas Pircher + + * crc_symtable.py: + Bad-looking C code generated; make sure the bit-by-bit(fast) code does not + contain two instructions on one line. Thanks to "intgr" for the fix. + + * crc_symtable.py: + Some small code clean-up: use set() when appropriate. + +2011-12-19 Thomas Pircher + + * crc_models.py: + * doc/pycrc.xml: + Added the models crc-12-3gpp, crc-16-genibus, crc-32-bzip2 and crc-64-xz. + Taken from Greg Cook's Catalogue of parametrised CRC algorithms: + http://regregex.bbcmicro.net/crc-catalogue.htm + +2011-12-14 Thomas Pircher + + * doc/pycrc.xml: + Fixed a mistake in the man page that still used the old model name + crc-32mpeg instead of crc-32-mpeg. Thanks to Marek Erban. + +# +# Version 0.7.9, 2011-12-08 +# + +2011-12-08 Thomas Pircher + + * crc_symtable.py: + Fixed a bug in the generated C89 code that included stdint.h. + Thanks to Frank (ftheile). + Closes issue 3454356. + +2011-11-08 Thomas Pircher + + * crc_symtable.py: + Fixed a bug in the generated C89 code when using a 64 bit CRC. + + * pycrc.py: + Using the --verbose option made pycrc quit without error message. + +# +# Version 0.7.8, 2011-07-10 +# + +2011-07-10 Thomas Pircher + + * crc_symtable.py: + When generating C code for the C89 or ANSI standard, don't include . + This closes issue 3338930 + + * crc_symtable.py: + If no output file name is given while generating a C file, then pycrc will + #include a hypothetical pycrc.h file instead of a stdout.h file. + Also, added a comment on that line to make debugging easier. + Closes issue 3325109. + + * crc_symtable.py: + Removed unused variable "this_option_optind" in the generated option parser. + +# +# Version 0.7.7, 2011-02-11 +# + +2011-02-11 Thomas Pircher + + * all files: + Updated the copyright year. + Fixed some coding style issues found by pylint and pychecker. + +2010-12-13 Thomas Pircher + + * crc_opt.py: + Substituted the deprecated function atoi() with int(). Closes issue 3136566. + Thanks to Tony Smith. + + * doc/pycrc.xml: + Updated the documentation using Windows-style calls to the Python interpreter. + +# +# Version 0.7.6, 2010-10-21 +# + +2010-10-21 Thomas Pircher + + * crc_symtable.py: + Fixed a minor bug in the command line parsing of the generated main function. + +2010-08-07 Thomas Pircher + + * crc_symtable.py, crc_parser.py, crc_lexer.py: + Rewritten macro parser from scratch. Simplified the macro language. + +2010-08-03 Thomas Pircher + + * crc_symtable.py: changed a simple division (/) to a integer division (//) + for Python3 compatibility. + +# +# Version 0.7.5, 2010-03-28 +# + +2010-03-27 Thomas Pircher + + * crc_symtable.py: + C/C++ code can now be generated for the table-driven algorithm with widths + that are not byte-ligned or less than 8. + + W A R N I N G: introduced new variable crc_shift, member of the crc_cfg_t + structure, that must be initialised manually when the width + was undefined during C/C++ code generation. + +2010-03-27 Thomas Pircher + + * crc_opt.py, crc_algorithms.py: + Python implementation of the table-driven algorithm can handle widths less + than 8. + * crc_symtable.py: + Suppressed warnings of unused cfg structure on partially defined models. + +2010-03-26 Thomas Pircher + + * pycrc.py, crc_opt.py, crc_algorithms.py, crc_symtable.py: + Removed half-baken and confusing --direct option. + +2010-02-10 Thomas Pircher + + * pycrc.py, crc_opt.py: minor code cleanup. + +# +# Version 0.7.4, 2010-01-24 +# + +2010-01-24 Thomas Pircher + + * crc_models.py: changed the xor-in value of the crc-64-jones model. + * crc_models.py: Set xmodem parameters equal to the zmodem params. + +2009-12-29 Thomas Pircher + + * pycrc.py, crc_opt.py, crc_parser: uniform error messages. + * crc_opt.py: added a warning for even polynoms. + +2009-11-12 Thomas Pircher + + * crc_models.py: added crc-16-modbus. Closes issue 2896611. + +2009-11-07 Thomas Pircher + + * crc_opt.py: Fix for unused variable argv. + Closes issue 2893224. Thanks to Marko von Oppen. + +# +# Version 0.7.3, 2009-10-25 +# + +2009-10-25 Thomas Pircher + + * crc_models.py: renamed crc-32mpeg to crc-32-mpeg. + +2009-10-19 Thomas Pircher + + * crc_models.py: added crc-64-jones CRC model. Thanks to Waterspirit. + +# +# Version 0.7.2, 2009-09-30 +# + +2009-09-30 Thomas Pircher + + * pycrc.py: fixed a bug that caused the result of the Python table-driven + code not being evaluated at all. + Closes issue 2870630. Thanks to Ildar Muslukhov. + +# +# Version 0.7.1, 2009-04-05 +# + +2009-03-26 Thomas Pircher + + * crc_models.py: added crc-32mpeg. Thanks to Thomas Edwards. + +# +# Version 0.7, 2009-02-27 +# + +2009-02-15 Thomas Pircher + + * crc_algorithms.py: code tidy-up. + * crc_algorithms.py, crc_opt.py: added --direct option. + * crc_symtable.py: added --direct option for the generated code. + +2009-02-03 Thomas Pircher + + * crc_opt.py: added --check-hexstring option. Closes issue 2545183. + Thanks to Arnim Littek. + +2009-01-31 Thomas Pircher + + * crc_opt.py: added a check for extra arguments on the command line. + Closes issue 2545185. Thanks to Arnim Littek. + +2008-12-24 Thomas Pircher + + * doc/pycrc.xml: Added one more example. + +# +# Version 0.6.7, 2008-12-11 +# + +2008-12-11 Thomas Pircher + + * all files: run Python's 2to3 script on the files. + * all files: check the code on a x64 platform. + * crc_opt.py: fixed a bug that raised an exception when an unknown model + was selected. + +# +# Version 0.6.6, 2008-06-05 +# + +2008-06-05 Thomas Pircher + + * crc_symtable.py: fixed a bug in the print_params function. Closes issue + 1985197. Thanks to Artur Lipowski. + +2008-03-03 Thomas Pircher + + * pycrc.xml: new license: Creative Commons Attribution-Share Alike 3.0 + Unported License. + +# +# Version 0.6.5, 2008-03-03 +# + +2008-03-02 Thomas Pircher + + * crc_models.py: added dallas-1-wire 8 bit CRC. + +2008-02-07 Thomas Pircher + + * crc_symtable.py: fixed a problem with the generated code for + bit-by-bit-fast algorithms. Thanks to Hans Bacher. + +2007-12-19 Thomas Pircher + + * crc_models.py: added r-crc-16 model (DECT (cordless digital standard) + packets A-field according to ETSI EN 300 175-3 v2.1.1). + Thanks to "raimondo". + +2007-12-10 Thomas Pircher + + * crc_symtable.py: added extern "C" declaration to the generated C header + file. Thanks to Nathan Royer. + +2007-12-10 Thomas Pircher + + * crc_algorithms.py: changed the API to take the CRC model direct as + parameter. Deleted the need for an obscure "opt" object. + +2007-12-09 Thomas Pircher + + * crc_opt.py: added --crc-type and --include-file options. + * crc_models.py: added new file to handle CRC models + +# +# Version 0.6.4, 2007-12-05 +# + +2007-12-05 Thomas Pircher + + * crc_symtable.py: fixed a bug in the code generator for the table-driven + algorithm. Thanks to Tom McDermott. Closes issue 1843774 + +# +# Version 0.6.3, 2007-10-13 +# + +2007-10-13 Thomas Pircher + + * crc_symtable.py: fixed some portability problems in the generated code. + Thanks to Helmut Bauer. Closes issue 1812894 + +2007-09-10 Thomas Pircher + + * crc_opt.py: added new models: crc-5, crc-15, crc-16-usb, crc-24, crc-64. + The new models are taken from Ray Burr's CrcMoose. + * pycrc.py: --check-file works now with --width < 8. Closes issue 1794343 + * pycrc.py: Removed unnecessary restriction on the width when using the + bit-by-bit-fast algorithm. Closes issue 1794344 + +# +# Version 0.6.2, 2007-08-25 +# + +2007-08-25 Thomas Pircher + + * crc_opt.py: the parameter to --check-string was ignored. Closes issue + 1781637 + * pycrc.py: the parameter to --check-string was ignored. Closes issue + 1781637 + +2007-08-18 Thomas Pircher + + * crc_symtable.py: simplified the table-driven code. Closes issue 1727128 + +2007-08-18 Thomas Pircher + + * crc_parser.py: changed the macro language syntax to a better format + * crc_lexer.py: changed the macro language syntax to a better format + * crc_symtable.py: changed the macro language syntax to a better format + * crc_parser.py: Renamed crc_code_gen.py to crc_parser.py + * all files: Documented thge usage of the crc_* modules + +# +# Version 0.6.1, 2007-08-12 +# + +2007-08-12 Thomas Pircher + + * test/test.sh: Added test for C89 compilation + * test/main.c: Added a test case to loop over the input bytes one by one + * crc_symtable.py: Bugfix in the source code generator for C89: + Compilation error due to mismatch of parameters in the crc_finalize + funtion + * crc_symtable.py: Changes related to 919107: Code generator includes + reflect() function even if not needed + +2007-07-22 Thomas Pircher + + * crc_symtable.py: Fixed a typo in the C89 source code generator. + Thanks to Helmut Bauer + +2007-06-10 Thomas Pircher + + * all files: Tidied up the documentation + * all files: Code cleanup + +2007-05-15 Thomas Pircher + + * crc_opt.py: Deleted obsolete options + +# +# Version 0.6, 2007-05-21 +# + +2007-05-15 Thomas Pircher + + * crc_opt.py: Added the --std option to generate C89 (ANSI) compliant code + * crc_symtable.py: Reduced the size of the symbol table by re-arranging + items + +2007-05-13 Thomas Pircher + + * test/test.sh: Added a new check to the test script which validate all + possible combination of undefined parameters + * crc_code_gen.py: Made the generated main function cope with command line + arguments + +2007-05-12 Thomas Pircher + + * pycrc.py: Added the --generate table option + * pycrc.py: Added a template engine for the code generation. Split up + pycrc.py into smaller modules + +2007-04-11 Thomas Pircher + + * pycrc.py: Added obsolete options again tor legacy reasons. + Added a better handling of the --model parameter. + +2007-04-07 Thomas Pircher + + * pycrc.py: Changed licence to the MIT licence. This makes the additional + clause for generated source code obsolete. + Changed all command line options with underscores to hyphen (e.g. + table_driven becomes table-driven). + Added the option --generate which obsoletes the old options --generate_c + --generate_h etc. + +# +# Version 0.5, 2007-03-25 +# + +2007-03-25 Thomas Pircher + + * pycrc.py: Fixed bug 1686404: unhandled exception when called with + both options --table_idx_width and --check_file + * pycrc.py: Eliminated useless declaration of crc_reflect, when not used + * pycrc.py: Corrected typos in the documentation + +# +# Version 0.4, 2007-01-26 +# + +2007-01-27 Thomas Pircher + + * pycrc.py: Eliminated needless documentation of not generated functions + +2007-01-23 Thomas Pircher + + * pycrc.py: Added more parameter sets (now supported: crc-8, crc-16, citt, + kermit, x-25, xmodem, zmodem, crc-32, crc-32c, posix, jam, xfer) from + http://homepages.tesco.net/~rainstorm/crc-catalogue.htm + * doc/pycrc.xml: Many corrections to the manual (thanks Francesca) + Documented the new parameter sets + * test/test.sh: added some new tests, disabled the random loop + +2007-01-21 Thomas Pircher + + * pycrc.py: Added Doxygen documentation strings to the functions. + Added the --symbol_prefix option + Added the --check_file option + + * doc/pycrc.xml: Corrected many typos and bad phrasing (still a lot to do) + Documented the --symbol_prefix option + +2007-01-17 Thomas Pircher + + * test/test.sh: Added a non-regression test on the generated C source + +# +# Version 0.3, 2007-01-14 +# + +2007-01-14 Thomas Pircher + + * pycrc.py: first public release pycrc v0.3 diff --git a/pycrc/README b/pycrc/README new file mode 100644 index 0000000..d5bdfd2 --- /dev/null +++ b/pycrc/README @@ -0,0 +1,66 @@ + + + _ __ _ _ ___ _ __ ___ + | '_ \| | | |/ __| '__/ __| + | |_) | |_| | (__| | | (__ + | .__/ \__, |\___|_| \___| + |_| |___/ + + + http://www.tty1.net/pycrc/ + + +pycrc is a free, easy to use Cyclic Redundancy Check (CRC) calculator and +source code generator. + + + +Installation +============ + +pycrc requires Python 2.4 or later. Python 3.x is supported. + +This program doesn't need any particular installation. The script can be +called from any directory. +Simply call the python interpreter with the script as parameter: + +python pycrc.py [options] + +On UNIX-like systems, you might want to make the script executable: + +chmod +x pycrc.py + +Then the script can be called like an application. +./pycrc.py [options] + + +Getting help +============ + +If you are new to pycrc and want to generate C code, start with the tutorial +http://www.tty1.net/pycrc/tutorial_en.html + +The manual page (http://www.tty1.net/pycrc/pycrc.html) explains the command +line options and gives some examples how to use pycrc. + +If you have questions about using pycrc which is not answered in a satisfactory +way by the documentation, please send a mail to the pycrc user mailing list +. The list info page is available at +https://lists.sourceforge.net/lists/listinfo/pycrc-users +Due to excessive spamming a subscription is required to post on the list. + +If you have found a bug in pycrc, please take the time and file it to the issue +tracker at https://sourceforge.net/tracker/?group_id=186891 +Thanks for your collaboration. + +Also see http://www.tty1.net/pycrc/faq.html for frequently asked questions. + + +Copyright of the generated source code +====================================== + +Prior to v0.6, pycrc was released under the GPL and an additional addition to +the licence was required to permit to use the generated source code in products +with a OSI unapproved licence. As of version 0.6, pycrc is released under the +terms of the MIT licence and such an additional clause to the licence is no +more required. diff --git a/pycrc/crc_algorithms.py b/pycrc/crc_algorithms.py new file mode 100644 index 0000000..90af6cd --- /dev/null +++ b/pycrc/crc_algorithms.py @@ -0,0 +1,231 @@ +# -*- coding: Latin-1 -*- + +# pycrc -- parametrisable CRC calculation utility and C source code generator +# +# Copyright (c) 2006-2012 Thomas Pircher +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + + +""" +CRC algorithms implemented in Python. +If you want to study the Python implementation of the CRC routines, then this +is a good place to start from. + +The algorithms Bit by Bit, Bit by Bit Fast and Table-Driven are implemented. + +This module can also be used as a library from within Python. + +Examples +======== + +This is an example use of the different algorithms: + +>>> from crc_algorithms import Crc +>>> +>>> crc = Crc(width = 16, poly = 0x8005, +... reflect_in = True, xor_in = 0x0000, +... reflect_out = True, xor_out = 0x0000) +>>> print("0x%x" % crc.bit_by_bit("123456789")) +>>> print("0x%x" % crc.bit_by_bit_fast("123456789")) +>>> print("0x%x" % crc.table_driven("123456789")) +""" + +# Class Crc +############################################################################### +class Crc(object): + """ + A base class for CRC routines. + """ + + # Class constructor + ############################################################################### + def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_idx_width = None): + """The Crc constructor. + + The parameters are as follows: + width + poly + reflect_in + xor_in + reflect_out + xor_out + """ + self.Width = width + self.Poly = poly + self.ReflectIn = reflect_in + self.XorIn = xor_in + self.ReflectOut = reflect_out + self.XorOut = xor_out + self.TableIdxWidth = table_idx_width + + self.MSB_Mask = 0x1 << (self.Width - 1) + self.Mask = ((self.MSB_Mask - 1) << 1) | 1 + if self.TableIdxWidth != None: + self.TableWidth = 1 << self.TableIdxWidth + else: + self.TableIdxWidth = 8 + self.TableWidth = 1 << self.TableIdxWidth + + self.DirectInit = self.XorIn + self.NonDirectInit = self.__get_nondirect_init(self.XorIn) + if self.Width < 8: + self.CrcShift = 8 - self.Width + else: + self.CrcShift = 0 + + + # function __get_nondirect_init + ############################################################################### + def __get_nondirect_init(self, init): + """ + return the non-direct init if the direct algorithm has been selected. + """ + crc = init + for i in range(self.Width): + bit = crc & 0x01 + if bit: + crc^= self.Poly + crc >>= 1 + if bit: + crc |= self.MSB_Mask + return crc & self.Mask + + + # function reflect + ############################################################################### + def reflect(self, data, width): + """ + reflect a data word, i.e. reverts the bit order. + """ + x = data & 0x01 + for i in range(width - 1): + data >>= 1 + x = (x << 1) | (data & 0x01) + return x + + + # function bit_by_bit + ############################################################################### + def bit_by_bit(self, in_str): + """ + Classic simple and slow CRC implementation. This function iterates bit + by bit over the augmented input message and returns the calculated CRC + value at the end. + """ + register = self.NonDirectInit + for c in in_str: + octet = ord(c) + if self.ReflectIn: + octet = self.reflect(octet, 8) + for i in range(8): + topbit = register & self.MSB_Mask + register = ((register << 1) & self.Mask) | ((octet >> (7 - i)) & 0x01) + if topbit: + register ^= self.Poly + + for i in range(self.Width): + topbit = register & self.MSB_Mask + register = ((register << 1) & self.Mask) + if topbit: + register ^= self.Poly + + if self.ReflectOut: + register = self.reflect(register, self.Width) + return register ^ self.XorOut + + + # function bit_by_bit_fast + ############################################################################### + def bit_by_bit_fast(self, in_str): + """ + This is a slightly modified version of the bit-by-bit algorithm: it + does not need to loop over the augmented bits, i.e. the Width 0-bits + wich are appended to the input message in the bit-by-bit algorithm. + """ + register = self.DirectInit + for c in in_str: + octet = ord(c) + if self.ReflectIn: + octet = self.reflect(octet, 8) + for i in range(8): + topbit = register & self.MSB_Mask + if octet & (0x80 >> i): + topbit ^= self.MSB_Mask + register <<= 1 + if topbit: + register ^= self.Poly + register &= self.Mask + if self.ReflectOut: + register = self.reflect(register, self.Width) + return register ^ self.XorOut + + + # function gen_table + ############################################################################### + def gen_table(self): + """ + This function generates the CRC table used for the table_driven CRC + algorithm. The Python version cannot handle tables of an index width + other than 8. See the generated C code for tables with different sizes + instead. + """ + table_length = 1 << self.TableIdxWidth + tbl = [0] * table_length + for i in range(table_length): + register = i + if self.ReflectIn: + register = self.reflect(register, self.TableIdxWidth) + register = register << (self.Width - self.TableIdxWidth + self.CrcShift) + for j in range(self.TableIdxWidth): + if register & (self.MSB_Mask << self.CrcShift) != 0: + register = (register << 1) ^ (self.Poly << self.CrcShift) + else: + register = (register << 1) + if self.ReflectIn: + register = self.reflect(register >> self.CrcShift, self.Width) << self.CrcShift + tbl[i] = register & (self.Mask << self.CrcShift) + return tbl + + + # function table_driven + ############################################################################### + def table_driven(self, in_str): + """ + The Standard table_driven CRC algorithm. + """ + tbl = self.gen_table() + + register = self.DirectInit << self.CrcShift + if not self.ReflectIn: + for c in in_str: + tblidx = ((register >> (self.Width - self.TableIdxWidth + self.CrcShift)) ^ ord(c)) & 0xff + register = ((register << (self.TableIdxWidth - self.CrcShift)) ^ tbl[tblidx]) & (self.Mask << self.CrcShift) + register = register >> self.CrcShift + else: + register = self.reflect(register, self.Width + self.CrcShift) << self.CrcShift + for c in in_str: + tblidx = ((register >> self.CrcShift) ^ ord(c)) & 0xff + register = ((register >> self.TableIdxWidth) ^ tbl[tblidx]) & (self.Mask << self.CrcShift) + register = self.reflect(register, self.Width + self.CrcShift) & self.Mask + + if self.ReflectOut: + register = self.reflect(register, self.Width) + return register ^ self.XorOut + diff --git a/pycrc/crc_algorithms.pyc b/pycrc/crc_algorithms.pyc new file mode 100644 index 0000000..124b92f Binary files /dev/null and b/pycrc/crc_algorithms.pyc differ diff --git a/pycrc/crc_lexer.py b/pycrc/crc_lexer.py new file mode 100644 index 0000000..ea2051b --- /dev/null +++ b/pycrc/crc_lexer.py @@ -0,0 +1,301 @@ +# -*- coding: Latin-1 -*- + +# pycrc -- parametrisable CRC calculation utility and C source code generator +# +# Copyright (c) 2006-2012 Thomas Pircher +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + + +""" +Lexical analyzer for pycrc. This module is used internally by pycrc for the +macro processing and code generation. + +A basic example of how the lexer is used: + + from crc_lexer import Lexer + + input_str = "the input string to parse" + lex = Lexer() + lex.set_str(input_str) + while True: + tok = lex.peek() + if tok == lex.tok_EOF: + break + else: + print("%4d: %s\n" % (tok, lex.text)) + lex.advance() +""" + +import re + + +# Class Lexer +############################################################################### +class Lexer(object): + """ + A lexical analyser base class. + """ + + tok_unknown = 0 + tok_EOF = 1 + tok_gibberish = 10 + tok_identifier = 11 + tok_block_open = 12 + tok_block_close = 13 + tok_num = 20 + tok_str = 21 + tok_par_open = 22 + tok_par_close = 23 + tok_op = 24 + tok_and = 25 + tok_or = 26 + + state_gibberish = 0 + state_expr = 1 + + + # Class constructor + ############################################################################### + def __init__(self, input_str = ""): + """ + The class constructor. + """ + self.re_id = re.compile("^\\$[a-zA-Z][a-zA-Z0-9_-]*") + self.re_num = re.compile("^(0[xX][0-9a-fA-F]+|[0-9]+)") + self.re_op = re.compile("<=|<|==|!=|>=|>") + self.re_str = re.compile("\"?([a-zA-Z0-9_-]+)\"?") + self.set_str(input_str) + self.state = self.state_gibberish + + + # function set_str + ############################################################################### + def set_str(self, input_str): + """ + Set the parse input string. + """ + self.input_str = input_str + self.text = "" + self.next_token = None + + + # function peek + ############################################################################### + def peek(self): + """ + Return the next token, without taking it away from the input_str. + """ + if self.next_token == None: + self.next_token = self._parse_next() + return self.next_token + + + # function advance + ############################################################################### + def advance(self, skip_nl = False): + """ + Discard the current symbol from the input stream and advance to the + following characters. If skip_nl is True, then skip also a following + newline character. + """ + self.next_token = None + if skip_nl and len(self.input_str) > 1 and self.input_str[0] == "\n": + self.input_str = self.input_str[1:] + + + # function delete_spaces + ############################################################################### + def delete_spaces(self, skip_unconditional = True): + """ + Delete spaces in the input string. + If skip_unconditional is False, then skip the spaces only if followed + by $if() $else() or $elif(). + """ + new_input = self.input_str.lstrip(" \t") + + # check for an identifier + m = self.re_id.match(new_input) + if m != None: + text = m.group(0)[1:] + # if the identifier is a reserved keyword, skip the spaces. + if (text == "if" or text == "elif" or text == "else"): + skip_unconditional = True + if skip_unconditional: + self.next_token = None + self.input_str = new_input + + + # function prepend + ############################################################################### + def prepend(self, in_str): + """ + Prepend the parameter to to the input string. + """ + self.input_str = in_str + self.input_str + + + # function set_state + ############################################################################### + def set_state(self, new_state): + """ + Set the new state for the lexer. + This changes the behaviour of the lexical scanner from normal operation + to expression scanning (within $if () expressions) and back. + """ + self.state = new_state + self.next_token = None + + + # function _parse_next + ############################################################################### + def _parse_next(self): + """ + Parse the next token, update the state variables and take the consumed + text from the imput stream. + """ + if len(self.input_str) == 0: + return self.tok_EOF + + if self.state == self.state_gibberish: + return self._parse_gibberish() + if self.state == self.state_expr: + return self._parse_expr() + return self.tok_unknown + + + # function _parse_gibberish + ############################################################################### + def _parse_gibberish(self): + """ + Parse the next token, update the state variables and take the consumed + text from the imput stream. + """ + # check for an identifier + m = self.re_id.match(self.input_str) + if m != None: + self.text = m.group(0)[1:] + self.input_str = self.input_str[m.end():] + return self.tok_identifier + + if len(self.input_str) > 1: + # check for "{:" + if self.input_str[0:2] == "{:": + self.text = self.input_str[0:2] + self.input_str = self.input_str[2:] + return self.tok_block_open + # check for ":}" + if self.input_str[0:2] == ":}": + self.text = self.input_str[0:2] + self.input_str = self.input_str[2:] + return self.tok_block_close + # check for "$$" + if self.input_str[0:2] == "$$": + self.text = self.input_str[0:1] + self.input_str = self.input_str[2:] + return self.tok_gibberish + # check for malformed "$" + if self.input_str[0] == "$": + self.text = self.input_str[0:1] + # self.input_str = self.input_str[1:] + return self.tok_unknown + + # the character is gibberish. + # find the position of the next special character. + pos = self.input_str.find("$") + tmp = self.input_str.find("{:") + if pos < 0 or (tmp >= 0 and tmp < pos): + pos = tmp + tmp = self.input_str.find(":}") + if pos < 0 or (tmp >= 0 and tmp < pos): + pos = tmp + + if pos < 0 or len(self.input_str) == 1: + # neither id nor block start nor block end found: + # the whole text is just gibberish. + self.text = self.input_str + self.input_str = "" + else: + self.text = self.input_str[:pos] + self.input_str = self.input_str[pos:] + return self.tok_gibberish + + + # function _parse_expr + ############################################################################### + def _parse_expr(self): + """ + Parse the next token, update the state variables and take the consumed + text from the imput stream. + """ + # skip whitespaces + pos = 0 + while pos < len(self.input_str) and self.input_str[pos] == ' ': + pos = pos + 1 + if pos > 0: + self.input_str = self.input_str[pos:] + + if len(self.input_str) == 0: + return self.tok_EOF + + m = self.re_id.match(self.input_str) + if m != None: + self.text = m.group(0)[1:] + self.input_str = self.input_str[m.end():] + return self.tok_identifier + + m = self.re_num.match(self.input_str) + if m != None: + self.text = m.group(0) + self.input_str = self.input_str[m.end():] + return self.tok_num + + m = self.re_op.match(self.input_str) + if m != None: + self.text = m.string[:m.end()] + self.input_str = self.input_str[m.end():] + return self.tok_op + + if self.input_str[:4] == "and ": + self.text = "and" + self.input_str = self.input_str[len(self.text) + 1:] + return self.tok_and + + if self.input_str[:3] == "or ": + self.text = "or" + self.input_str = self.input_str[len(self.text) + 1:] + return self.tok_or + + m = self.re_str.match(self.input_str) + if m != None: + self.text = m.group(1) + self.input_str = self.input_str[m.end():] + return self.tok_str + + if self.input_str[0] == "(": + self.text = self.input_str[0] + self.input_str = self.input_str[len(self.text):] + return self.tok_par_open + + if self.input_str[0] == ")": + self.text = self.input_str[0] + self.input_str = self.input_str[len(self.text):] + return self.tok_par_close + + return self.tok_unknown diff --git a/pycrc/crc_lexer.pyc b/pycrc/crc_lexer.pyc new file mode 100644 index 0000000..88e73b9 Binary files /dev/null and b/pycrc/crc_lexer.pyc differ diff --git a/pycrc/crc_models.py b/pycrc/crc_models.py new file mode 100644 index 0000000..00f2805 --- /dev/null +++ b/pycrc/crc_models.py @@ -0,0 +1,370 @@ +# -*- coding: Latin-1 -*- + +# pycrc -- parametrisable CRC calculation utility and C source code generator +# +# Copyright (c) 2006-2012 Thomas Pircher +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + + +""" +Collection of CRC models. This module contains the CRC models known to pycrc. + +To print the parameters of a particular model: + + from crc_models import CrcModels + + models = CrcModels() + print(models.getList()) + m = models.getParams("crc-32") + if m != None: + print("Width: %(width)s" % m) + print("Poly: %(poly)s" % m) + print("ReflectIn: %(reflect_in)s" % m) + print("XorIn: %(xor_in)s" % m) + print("ReflectOut: %(reflect_out)s" % m) + print("XorOut: %(xor_out)s" % m) + print("Check: %(check)s" % m) + else: + print("model not found.") +""" + + + +# Class CrcModels +############################################################################### +class CrcModels(object): + """ + CRC Models. + All models are generated in the constructor. + """ + + models = [] + + models.append({ + 'name': 'crc-5', + 'width': 5, + 'poly': 0x05, + 'reflect_in': True, + 'xor_in': 0x1f, + 'reflect_out': True, + 'xor_out': 0x1f, + 'direct': True, + 'check': 0x19, + }) + models.append({ + 'name': 'crc-8', + 'width': 8, + 'poly': 0x07, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': True, + 'check': 0xf4, + }) + models.append({ + 'name': 'dallas-1-wire', + 'width': 8, + 'poly': 0x31, + 'reflect_in': True, + 'xor_in': 0x0, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0xa1, + }) + models.append({ + 'name': 'crc-12-3gpp', + 'width': 12, + 'poly': 0x80f, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0xdaf, + }) + models.append({ + 'name': 'crc-15', + 'width': 15, + 'poly': 0x4599, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x59e, + }) + models.append({ + 'name': 'crc-16', + 'width': 16, + 'poly': 0x8005, + 'reflect_in': True, + 'xor_in': 0x0, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0xbb3d, + }) + models.append({ + 'name': 'crc-16-usb', + 'width': 16, + 'poly': 0x8005, + 'reflect_in': True, + 'xor_in': 0xffff, + 'reflect_out': True, + 'xor_out': 0xffff, + 'direct': True, + 'check': 0xb4c8, + }) + models.append({ + 'name': 'crc-16-modbus', + 'width': 16, + 'poly': 0x8005, + 'reflect_in': True, + 'xor_in': 0xffff, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x4b37, + }) + models.append({ + 'name': 'crc-16-genibus', + 'width': 16, + 'poly': 0x1021, + 'reflect_in': False, + 'xor_in': 0xffff, + 'reflect_out': False, + 'xor_out': 0xffff, + 'direct': True, + 'check': 0xd64e, + }) + models.append({ + 'name': 'ccitt', + 'width': 16, + 'poly': 0x1021, + 'reflect_in': False, + 'xor_in': 0xffff, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x29b1, + }) + models.append({ + 'name': 'r-crc-16', + 'width': 16, + 'poly': 0x0589, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': False, + 'xor_out': 0x0001, + 'direct': True, + 'check': 0x007e, + }) + models.append({ + 'name': 'kermit', + 'width': 16, + 'poly': 0x1021, + 'reflect_in': True, + 'xor_in': 0x0, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x2189, + }) + models.append({ + 'name': 'x-25', + 'width': 16, + 'poly': 0x1021, + 'reflect_in': True, + 'xor_in': 0xffff, + 'reflect_out': True, + 'xor_out': 0xffff, + 'direct': True, + 'check': 0x906e, + }) + models.append({ + 'name': 'xmodem', + 'width': 16, + 'poly': 0x1021, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x31c3, + }) + models.append({ + 'name': 'zmodem', + 'width': 16, + 'poly': 0x1021, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x31c3, + }) + models.append({ + 'name': 'crc-24', + 'width': 24, + 'poly': 0x864cfb, + 'reflect_in': False, + 'xor_in': 0xb704ce, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x21cf02, + }) + models.append({ + 'name': 'crc-32', + 'width': 32, + 'poly': 0x4c11db7, + 'reflect_in': True, + 'xor_in': 0xffffffff, + 'reflect_out': True, + 'xor_out': 0xffffffff, + 'direct': True, + 'check': 0xcbf43926, + }) + models.append({ + 'name': 'crc-32c', + 'width': 32, + 'poly': 0x1edc6f41, + 'reflect_in': True, + 'xor_in': 0xffffffff, + 'reflect_out': True, + 'xor_out': 0xffffffff, + 'direct': True, + 'check': 0xe3069283, + }) + models.append({ + 'name': 'crc-32-mpeg', + 'width': 32, + 'poly': 0x4c11db7, + 'reflect_in': False, + 'xor_in': 0xffffffff, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': False, + 'check': 0x0376e6e7, + }) + models.append({ + 'name': 'crc-32-bzip2', + 'width': 32, + 'poly': 0x04c11db7, + 'reflect_in': False, + 'xor_in': 0xffffffff, + 'reflect_out': False, + 'xor_out': 0xffffffff, + 'direct': True, + 'check': 0xfc891918, + }) + models.append({ + 'name': 'posix', + 'width': 32, + 'poly': 0x4c11db7, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': False, + 'xor_out': 0xffffffff, + 'direct': True, + 'check': 0x765e7680, + }) + models.append({ + 'name': 'jam', + 'width': 32, + 'poly': 0x4c11db7, + 'reflect_in': True, + 'xor_in': 0xffffffff, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x340bc6d9, + }) + models.append({ + 'name': 'xfer', + 'width': 32, + 'poly': 0x000000af, + 'reflect_in': False, + 'xor_in': 0x0, + 'reflect_out': False, + 'xor_out': 0x0, + 'direct': True, + 'check': 0xbd0be338, + }) + models.append({ + 'name': 'crc-64', + 'width': 64, + 'poly': 0x000000000000001b, + 'reflect_in': True, + 'xor_in': 0x0, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0x46a5a9388a5beffe, + }) + models.append({ + 'name': 'crc-64-jones', + 'width': 64, + 'poly': 0xad93d23594c935a9, + 'reflect_in': True, + 'xor_in': 0xffffffffffffffff, + 'reflect_out': True, + 'xor_out': 0x0, + 'direct': True, + 'check': 0xe9c6d914c4b8d9ca, + }) + models.append({ + 'name': 'crc-64-xz', + 'width': 64, + 'poly': 0x42f0e1eba9ea3693, + 'reflect_in': True, + 'xor_in': 0xffffffffffffffff, + 'reflect_out': True, + 'xor_out': 0xffffffffffffffff, + 'direct': True, + 'check': 0x995dc9bbdf1939fa, + }) + + + # function getList + ############################################################################### + def getList(self): + """ + This function returns the list of supported CRC models. + """ + l = [] + for i in self.models: + l.append(i['name']) + return l + + + # function getParams + ############################################################################### + def getParams(self, model): + """ + This function returns the paremeters of a given model. + """ + model = model.lower(); + for i in self.models: + if i['name'] == model: + return i + return None diff --git a/pycrc/crc_models.pyc b/pycrc/crc_models.pyc new file mode 100644 index 0000000..c7495a8 Binary files /dev/null and b/pycrc/crc_models.pyc differ diff --git a/pycrc/crc_opt.py b/pycrc/crc_opt.py new file mode 100644 index 0000000..419bca7 --- /dev/null +++ b/pycrc/crc_opt.py @@ -0,0 +1,398 @@ +# -*- coding: Latin-1 -*- + +# pycrc -- parametrisable CRC calculation utility and C source code generator +# +# Copyright (c) 2006-2012 Thomas Pircher +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + + +""" +Option parsing library for pycrc. +use as follows: + + from crc_opt import Options + + opt = Options() + opt.parse(sys.argv[1:]) +""" + +from optparse import OptionParser, Option, OptionValueError +from copy import copy +import sys +from crc_models import CrcModels + + +# Class Options +############################################################################### +class Options(object): + """ + The options parsing and validationg class + """ + + # Program details + ProgramName = "pycrc" + Version = "0.7.10" + VersionStr = "%s v%s" % (ProgramName, Version) + WebAddress = "http://www.tty1.net/pycrc/" + + # Bitmap of the algorithms + Algo_None = 0x00 + Algo_Bit_by_Bit = 0x01 + Algo_Bit_by_Bit_Fast = 0x02 + Algo_Table_Driven = 0x04 + + Action_Check_String = 0x01 + Action_Check_Hex_String = 0x02 + Action_Check_File = 0x03 + Action_Generate_H = 0x04 + Action_Generate_C = 0x05 + Action_Generate_C_Main = 0x06 + Action_Generate_Table = 0x07 + + + # Class constructor + ############################################################################### + def __init__(self): + self.Width = None + self.Poly = None + self.ReflectIn = None + self.XorIn = None + self.ReflectOut = None + self.XorOut = None + self.TableIdxWidth = 8 + self.TableWidth = 1 << self.TableIdxWidth + self.Verbose = False + self.CheckString = "123456789" + self.MSB_Mask = None + self.Mask = None + + self.Algorithm = self.Algo_None + self.SymbolPrefix = "crc_" + self.CrcType = None + self.IncludeFile = None + self.OutputFile = None + self.Action = self.Action_Check_String + self.CheckFile = None + self.CStd = None + self.UndefinedCrcParameters = False + + + # function parse + ############################################################################### + def parse(self, argv = None): + """ + Parses and validates the options given as arguments + """ + usage = """\ +%prog [OPTIONS] + +To generate the checksum of a string or hexadecimal data: + %prog [model] --check-string "123456789" + %prog [model] --check-hexstring "313233343536373839" + +To generate the checksum of a file: + %prog [model] --check-file filename + +To generate the c-source and write it to filename: + %prog [model] --generate c -o filename + +The model can be defined by the --model switch or by specifying each of the +following parameters: + --width --poly --reflect-in --xor-in --reflect-out --xor-out""" + + models = CrcModels() + model_list = ", ".join(models.getList()) + parser = OptionParser(option_class=MyOption, usage=usage, version=self.VersionStr) + parser.add_option("-v", "--verbose", + action="store_true", dest="verbose", default=False, + help="print information about the model") + parser.add_option("--check-string", + action="store", type="string", dest="check_string", + help="calculate the checksum of the given string (default: '123456789')", metavar="STRING") + parser.add_option("--check-hexstring", + action="store", type="string", dest="check_hexstring", + help="calculate the checksum of the given hexadecimal number string", metavar="STRING") + parser.add_option("--check-file", + action="store", type="string", dest="check_file", + help="calculate the checksum of the given file", metavar="FILE") + parser.add_option("--generate", + action="store", type="string", dest="generate", default=None, + help="choose which type of code to generate from {c, h, c-main, table}", metavar="CODE") + parser.add_option("--std", + action="store", type="string", dest="c_std", default="C99", + help="C standard style of the generated code from {C89, ANSI, C99}", metavar="STD") + parser.add_option("--algorithm", + action="store", type="string", dest="algorithm", default="all", + help="choose an algorithm from {bit-by-bit, bit-by-bit-fast, table-driven, all}", metavar="ALGO") + parser.add_option("--model", + action="callback", callback=self.model_cb, type="string", dest="model", default=None, + help="choose a parameter set from {%s}" % model_list, metavar="MODEL") + parser.add_option("--width", + action="store", type="hex", dest="width", + help="use NUM bits in the polynomial", metavar="NUM") + parser.add_option("--poly", + action="store", type="hex", dest="poly", + help="use HEX as Polynom", metavar="HEX") + parser.add_option("--reflect-in", + action="store", type="bool", dest="reflect_in", + help="reflect input bytes", metavar="BOOL") + parser.add_option("--xor-in", + action="store", type="hex", dest="xor_in", + help="use HEX as initial value", metavar="HEX") + parser.add_option("--reflect-out", + action="store", type="bool", dest="reflect_out", + help="reflect output bytes", metavar="BOOL") + parser.add_option("--xor-out", + action="store", type="hex", dest="xor_out", + help="xor the final crc value with HEX", metavar="HEX") + parser.add_option("--table-idx-width", + action="store", type="int", dest="table_idx_width", + help="use NUM bits to index the crc table; NUM must be one of the values {1, 2, 4, 8}", metavar="NUM") + parser.add_option("--symbol-prefix", + action="store", type="string", dest="symbol_prefix", + help="when generating source code, use STRING as prefix to the generated symbols", metavar="STRING") + parser.add_option("--crc-type", + action="store", type="string", dest="crc_type", + help="when generating source code, use STRING as crc_t type", metavar="STRING") + parser.add_option("--include-file", + action="store", type="string", dest="include_file", + help="when generating source code, use FILE as additional include file", metavar="FILE") + parser.add_option("-o", "--output", + action="store", type="string", dest="output_file", + help="write the generated code to file instead to stdout", metavar="FILE") + + (options, args) = parser.parse_args(argv) + + undefined_params = [] + if options.width != None: + self.Width = options.width + else: + undefined_params.append("--width") + if options.poly != None: + self.Poly = options.poly + else: + undefined_params.append("--poly") + if options.reflect_in != None: + self.ReflectIn = options.reflect_in + else: + undefined_params.append("--reflect-in") + if options.xor_in != None: + self.XorIn = options.xor_in + else: + undefined_params.append("--xor-in") + if options.reflect_out != None: + self.ReflectOut = options.reflect_out + else: + undefined_params.append("--reflect-out") + if options.xor_out != None: + self.XorOut = options.xor_out + else: + undefined_params.append("--xor-out") + if options.table_idx_width != None: + if options.table_idx_width == 1 or \ + options.table_idx_width == 2 or \ + options.table_idx_width == 4 or \ + options.table_idx_width == 8: + self.TableIdxWidth = options.table_idx_width + self.TableWidth = 1 << options.table_idx_width + else: + sys.stderr.write("%s: error: unsupported table-idx-width %d\n" % (sys.argv[0], options.table_idx_width)) + sys.exit(1) + + if self.Poly != None and self.Poly % 2 == 0: + sys.stderr.write("%s: warning: the polynomial 0x%x is even. A valid CRC polynomial must be odd.\n" % (sys.argv[0], self.Poly)) + + if self.Width != None: + if self.Width <= 0: + sys.stderr.write("%s: error: Width must be strictly positive\n" % sys.argv[0]) + sys.exit(1) + self.MSB_Mask = 0x1 << (self.Width - 1) + self.Mask = ((self.MSB_Mask - 1) << 1) | 1 + if self.Poly != None: + self.Poly = self.Poly & self.Mask + if self.XorIn != None: + self.XorIn = self.XorIn & self.Mask + if self.XorOut != None: + self.XorOut = self.XorOut & self.Mask + else: + self.MSB_Mask = None + self.Mask = None + + if self.Width == None or \ + self.Poly == None or \ + self.ReflectIn == None or \ + self.XorIn == None or \ + self.ReflectOut == None or \ + self.XorOut == None: + self.UndefinedCrcParameters = True + else: + self.UndefinedCrcParameters = False + + if options.algorithm != None: + alg = options.algorithm.lower() + if alg == "bit-by-bit" or alg == "all": + self.Algorithm |= self.Algo_Bit_by_Bit + if alg == "bit-by-bit-fast" or alg == "all": + self.Algorithm |= self.Algo_Bit_by_Bit_Fast + if alg == "table-driven" or alg == "all": + self.Algorithm |= self.Algo_Table_Driven + if self.Algorithm == 0: + sys.stderr.write("%s: error: unknown algorithm %s\n" % (sys.argv[0], options.algorithm)) + sys.exit(1) + + if options.c_std != None: + std = options.c_std.upper() + if std == "ANSI" or std == "C89": + self.CStd = "C89" + elif std == "C99": + self.CStd = std + else: + sys.stderr.write("%s: error: unknown C standard %s\n" % (sys.argv[0], options.c_std)) + sys.exit(1) + if options.symbol_prefix != None: + self.SymbolPrefix = options.symbol_prefix + if options.include_file != None: + self.IncludeFile = options.include_file + if options.crc_type != None: + self.CrcType = options.crc_type + if options.output_file != None: + self.OutputFile = options.output_file + op_count = 0 + if options.check_string != None: + self.Action = self.Action_Check_String + self.CheckString = options.check_string + op_count += 1 + if options.check_hexstring != None: + self.Action = self.Action_Check_Hex_String + self.CheckString = options.check_hexstring + op_count += 1 + if options.check_file != None: + self.Action = self.Action_Check_File + self.CheckFile = options.check_file + op_count += 1 + if options.generate != None: + arg = options.generate.lower() + if arg == 'h': + self.Action = self.Action_Generate_H + elif arg == 'c': + self.Action = self.Action_Generate_C + elif arg == 'c-main': + self.Action = self.Action_Generate_C_Main + elif arg == 'table': + self.Action = self.Action_Generate_Table + else: + sys.stderr.write("%s: error: don't know how to generate %s\n" % (sys.argv[0], options.generate)) + sys.exit(1) + op_count += 1 + + if self.Action == self.Action_Generate_Table: + if self.Algorithm & self.Algo_Table_Driven == 0: + sys.stderr.write("%s: error: the --generate table option is incompatible with the --algorithm option\n" % sys.argv[0]) + sys.exit(1) + self.Algorithm = self.Algo_Table_Driven + elif self.Algorithm != self.Algo_Bit_by_Bit and self.Algorithm != self.Algo_Bit_by_Bit_Fast and self.Algorithm != self.Algo_Table_Driven: + sys.stderr.write("%s: error: select an algorithm to be used in the generated file\n" % sys.argv[0]) + sys.exit(1) + else: + if self.TableIdxWidth != 8: + sys.stderr.write("%s: warning: reverting to Table Index Width = 8 for internal CRC calculation\n" % sys.argv[0]) + self.TableIdxWidth = 8 + self.TableWidth = 1 << options.table_idx_width + if op_count == 0: + self.Action = self.Action_Check_String + if op_count > 1: + sys.stderr.write("%s: error: too many actions scecified\n" % sys.argv[0]) + sys.exit(1) + + if len(args) != 0: + sys.stderr.write("%s: error: unrecognized argument(s): %s\n" % (sys.argv[0], " ".join(args))) + sys.exit(1) + + if self.UndefinedCrcParameters and self.Action in set((self.Action_Check_String, self.Action_Check_Hex_String, self.Action_Check_File, self.Action_Generate_Table)): + sys.stderr.write("%s: error: undefined parameters: Add %s or use --model\n" % (sys.argv[0], ", ".join(undefined_params))) + sys.exit(1) + self.Verbose = options.verbose + + + # function model_cb + ############################################################################## + def model_cb(self, option, opt_str, value, parser): + """ + This function sets up the single parameters if the 'model' option has been selected + by the user. + """ + model_name = value.lower() + models = CrcModels() + model = models.getParams(model_name) + if model != None: + setattr(parser.values, 'width', model['width']) + setattr(parser.values, 'poly', model['poly']) + setattr(parser.values, 'reflect_in', model['reflect_in']) + setattr(parser.values, 'xor_in', model['xor_in']) + setattr(parser.values, 'reflect_out', model['reflect_out']) + setattr(parser.values, 'xor_out', model['xor_out']) + else: + raise OptionValueError("Error: unsupported model %s" % (value)) + + +# function check_hex +############################################################################### +def check_hex(option, opt, value): + """ + Checks if a value is given in a decimal integer of hexadecimal reppresentation. + Returns the converted value or rises an exception on error. + """ + try: + if value.lower().startswith("0x"): + return int(value, 16) + else: + return int(value) + except ValueError: + raise OptionValueError("option %s: invalid integer or hexadecimal value: %r" % (opt, value)) + + +# function check_bool +############################################################################### +def check_bool(option, opt, value): + """ + Checks if a value is given as a boolean value (either 0 or 1 or "true" or "false") + Returns the converted value or rises an exception on error. + """ + if value.isdigit(): + return int(value, 10) != 0 + elif value.lower() == "false": + return False + elif value.lower() == "true": + return True + else: + raise OptionValueError("option %s: invalid boolean value: %r" % (opt, value)) + + +# Class MyOption +############################################################################### +class MyOption(Option): + """ + New option parsing class extends the Option class + """ + TYPES = Option.TYPES + ("hex", "bool") + TYPE_CHECKER = copy(Option.TYPE_CHECKER) + TYPE_CHECKER["hex"] = check_hex + TYPE_CHECKER["bool"] = check_bool + diff --git a/pycrc/crc_opt.pyc b/pycrc/crc_opt.pyc new file mode 100644 index 0000000..0b4ca6d Binary files /dev/null and b/pycrc/crc_opt.pyc differ diff --git a/pycrc/crc_parser.py b/pycrc/crc_parser.py new file mode 100644 index 0000000..78d22de --- /dev/null +++ b/pycrc/crc_parser.py @@ -0,0 +1,418 @@ +# -*- coding: Latin-1 -*- + +# pycrc -- parametrisable CRC calculation utility and C source code generator +# +# Copyright (c) 2006-2012 Thomas Pircher +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + + +""" +Macro Language parser for pycrc. +use as follows: + + import sys + from crc_opt import Options + from crc_parser import MacroParser + + opt = Options() + opt.parse(sys.argv[1:]) + mp = MacroParser(opt) + if mp.parse("Test 1 2 3"): + print(mp.out_str) +""" + +from crc_symtable import SymbolTable +from crc_lexer import Lexer +import re +import sys + + +# Class ParseError +############################################################################### +class ParseError(Exception): + """ + The exception class for the parser. + """ + + # Class constructor + ############################################################################### + def __init__(self, reason): + self.reason = reason + + # function __str__ + ############################################################################### + def __str__(self): + return self.reason + + +# Class MacroParser +############################################################################### +class MacroParser(object): + """ + The macro language parser and code generator class. + """ + re_is_int = re.compile("^[-+]?[0-9]+$") + #re_is_hex = re.compile("^(0[xX])?[0-9a-fA-F]+$") + re_is_hex = re.compile("^0[xX][0-9a-fA-F]+$") + + opt = None + sym = None + lex = Lexer() + + + # Class constructor + ############################################################################### + def __init__(self, opt): + self.opt = opt + self.sym = SymbolTable(opt) + self.out_str = None + + # function parse + # + # The used grammar is: + # term: LITERAL + # | IDENTIFIER + # | '(' or_exp ')' + # ; + # + # comp_exp: term OP_COMPARISON term + # ; + # + # and_exp: term + # | and_exp OP_AND comp_exp + # ; + # + # or_exp: and_exp + # | or_exp OP_OR and_exp + # ; + # + # else_block: /* empty */ + # | ELSE '{:' data ':}' + # ; + # + # elif_blocks: /* empty */ + # | elif_blocks ELIF '(' or_exp ')' '{:' data ':}' + # ; + # + # if_block: IF '(' or_exp ')' '{:' data ':}' elif_blocks else_block + # ; + # + # data: /* empty */ + # | data GIBBERISH + # | data IDENTIFIER + # | data '{:' data ':}' + # | data if_block + # ; + ############################################################################### + def parse(self, in_str): + """ + Parse a macro string. + """ + self.lex.set_str(in_str) + self.out_str = "" + self._parse_data(do_print = True) + + tok = self.lex.peek() + if tok != self.lex.tok_EOF: + raise ParseError("%s: error: misaligned closing block '%s'" % (sys.argv[0], self.lex.text)) + + + # function _parse_data + ############################################################################### + def _parse_data(self, do_print): + """ + Private top-level parsing function. + """ + tok = self.lex.peek() + while tok != self.lex.tok_EOF: + if tok == self.lex.tok_gibberish: + self._parse_gibberish(do_print) + elif tok == self.lex.tok_block_open: + self._parse_data_block(do_print) + elif tok == self.lex.tok_identifier and self.lex.text == "if": + self._parse_if_block(do_print) + elif tok == self.lex.tok_identifier: + self._parse_identifier(do_print) + elif tok == self.lex.tok_block_close: + return + else: + raise ParseError("%s: error: wrong token '%s'" % (sys.argv[0], self.lex.text)) + tok = self.lex.peek() + + + # function _parse_gibberish + ############################################################################### + def _parse_gibberish(self, do_print): + """ + Parse gibberish. + Actually, just print the characters in 'text' if do_print is True. + """ + if do_print: + self.out_str = self.out_str + self.lex.text + self.lex.advance() + + + # function _parse_identifier + ############################################################################### + def _parse_identifier(self, do_print): + """ + Parse an identifier. + """ + try: + sym_value = self.sym.getTerminal(self.lex.text) + except LookupError: + raise ParseError("%s: error: unknown terminal '%s'" % (sys.argv[0], self.lex.text)) + self.lex.advance() + if do_print: + self.lex.prepend(sym_value) + + + # function _parse_if_block + ############################################################################### + def _parse_if_block(self, do_print): + """ + Parse an if block. + """ + # parse the expression following the 'if' and the associated block. + exp_res = self._parse_conditional_block(do_print) + do_print = do_print and not exp_res + + # try $elif + tok = self.lex.peek() + while tok == self.lex.tok_identifier and self.lex.text == "elif": + exp_res = self._parse_conditional_block(do_print) + do_print = do_print and not exp_res + tok = self.lex.peek() + + # try $else + if tok == self.lex.tok_identifier and self.lex.text == "else": + # get rid of the tok_identifier, 'else' and following spaces + self.lex.advance() + self.lex.delete_spaces() + + # expect a data block + self._parse_data_block(do_print) + + + + # function _parse_conditional_block + ############################################################################### + def _parse_conditional_block(self, do_print): + """ + Parse a conditional block (such as $if or $elif). + Return the truth value of the expression. + """ + # get rid of the tok_identifier, 'if' or 'elif' + self.lex.advance() + self.lex.set_state(self.lex.state_expr) + + # expect an open parenthesis + tok = self.lex.peek() + if tok != self.lex.tok_par_open: + raise ParseError("%s: error: open parenthesis expected: '%s'" % (sys.argv[0], self.lex.text)) + self.lex.advance() + + # parse the boolean expression + exp_res = self._parse_exp_or() + + # expect a closed parenthesis + tok = self.lex.peek() + if tok != self.lex.tok_par_close: + raise ParseError("%s: error: closed parenthesis expected: '%s'" % (sys.argv[0], self.lex.text)) + self.lex.advance() + + # get rid of eventual spaces, and switch back to gibberish. + self.lex.delete_spaces() + self.lex.set_state(self.lex.state_gibberish) + + # expect a data block + self._parse_data_block(do_print and exp_res) + + # get rid of eventual spaces + # but only if followed by $if, $else or $elif + self.lex.delete_spaces(skip_unconditional = False) + + return exp_res + + + # function _parse_data_block + ############################################################################### + def _parse_data_block(self, do_print): + """ + Parse a data block. + """ + # expect an open block + tok = self.lex.peek() + if tok != self.lex.tok_block_open: + raise ParseError("%s: error: open block expected: '%s'" % (sys.argv[0], self.lex.text)) + self.lex.advance(skip_nl = True) + + # more data follows... + self._parse_data(do_print) + + # expect a closed block + tok = self.lex.peek() + if tok != self.lex.tok_block_close: + raise ParseError("%s: error: closed block expected: '%s'" % (sys.argv[0], self.lex.text)) + self.lex.advance(skip_nl = True) + + + # function _parse_exp_or + ############################################################################### + def _parse_exp_or(self): + """ + Parse a boolean 'or' expression. + """ + ret = False + while True: + ret = self._parse_exp_and() or ret + + # is the expression terminated? + tok = self.lex.peek() + if tok == self.lex.tok_par_close: + return ret + # expect an 'or' token. + elif tok == self.lex.tok_or: + self.lex.advance() + # everything else is the end of the expression. + # Let the caling function worry about error reporting. + else: + return ret + return False + + + # function _parse_exp_and + ############################################################################### + def _parse_exp_and(self): + """ + Parse a boolean 'and' expression. + """ + ret = True + while True: + ret = self._parse_exp_comparison() and ret + + # is the expression terminated? + tok = self.lex.peek() + if tok == self.lex.tok_par_close: + return ret + # expect an 'and' token. + elif tok == self.lex.tok_and: + self.lex.advance() + # everything else is a parse error. + else: + return ret + return False + + + # function _parse_exp_comparison + ############################################################################### + def _parse_exp_comparison(self): + """ + Parse a boolean comparison. + """ + # left hand side of the comparison + lhs = self._parse_exp_term() + + # expect a comparison + tok = self.lex.peek() + if tok != self.lex.tok_op: + raise ParseError("%s: error: operator expected: '%s'" % (sys.argv[0], self.lex.text)) + operator = self.lex.text + self.lex.advance() + + # right hand side of the comparison + rhs = self._parse_exp_term() + + # if both operands ar numbers, convert them + num_l = self._get_num(lhs) + num_r = self._get_num(rhs) + if num_l != None and num_r != None: + lhs = num_l + rhs = num_r + + # now calculate the result of the comparison, whatever that means + if operator == "<=": + ret = lhs <= rhs + elif operator == "<": + ret = lhs < rhs + elif operator == "==": + ret = lhs == rhs + elif operator == "!=": + ret = lhs != rhs + elif operator == ">=": + ret = lhs >= rhs + elif operator == ">": + ret = lhs > rhs + else: + raise ParseError("%s: error: unknow operator: '%s'" % (sys.argv[0], self.lex.text)) + return ret + + + # function _parse_exp_term + ############################################################################### + def _parse_exp_term(self): + """ + Parse a terminal. + """ + tok = self.lex.peek() + + # identifier + if tok == self.lex.tok_identifier: + try: + ret = self.sym.getTerminal(self.lex.text) + except LookupError: + raise ParseError("%s: error: unknown terminal '%s'" % (sys.argv[0], self.lex.text)) + if ret == None: + ret = "Undefined" + # string + elif tok == self.lex.tok_str: + ret = self.lex.text + # number + elif tok == self.lex.tok_num: + ret = self.lex.text + # parenthesised expression + elif tok == self.lex.tok_par_open: + self.lex.advance() + ret = self._parse_exp_or() + tok = self.lex.peek() + if tok != self.lex.tok_par_close: + raise ParseError("%s: error: closed parenthesis expected: '%s'" % (sys.argv[0], self.lex.text)) + self.lex.advance() + return ret + + + # function _get_num + ############################################################################### + def _get_num(self, in_str): + """ + Check if in_str is a number and return the numeric value. + """ + ret = None + + if in_str != None: + m = self.re_is_int.match(in_str) + if m != None: + ret = int(in_str) + + m = self.re_is_hex.match(in_str) + if m != None: + ret = int(in_str, 16) + + return ret diff --git a/pycrc/crc_parser.pyc b/pycrc/crc_parser.pyc new file mode 100644 index 0000000..164a26e Binary files /dev/null and b/pycrc/crc_parser.pyc differ diff --git a/pycrc/crc_symtable.py b/pycrc/crc_symtable.py new file mode 100644 index 0000000..651250d --- /dev/null +++ b/pycrc/crc_symtable.py @@ -0,0 +1,1354 @@ +# -*- coding: Latin-1 -*- + +# pycrc -- parametrisable CRC calculation utility and C source code generator +# +# Copyright (c) 2006-2012 Thomas Pircher +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + + +""" +Symbol table for the macro processor used by pycrc. +use as follows: + + from crc_opt import Options + from crc_symtable import SymbolTable + + opt = Options("0.6") + sym = SymbolTable(opt) + + str = " .... " + terminal = sym.getTerminal(str) +""" + +from crc_algorithms import Crc +import time +import os + + +# Class SymbolTable +############################################################################### +class SymbolTable: + """ + The symbol table class. + """ + opt = None + table = {} + + + # Class constructor + ############################################################################### + def __init__(self, opt): + """ + The class constructor. + """ + self.opt = opt + self.table["nop"] = "" + self.table["datetime"] = time.asctime() + self.table["program_version"] = self.opt.VersionStr + self.table["program_url"] = self.opt.WebAddress + if self.opt.OutputFile == None: + self.table["filename"] = "pycrc_stdout" + else: + self.table["filename"] = self.opt.OutputFile + + if self.opt.OutputFile == None: + self.table["header_filename"] = "pycrc_stdout.h" + elif self.opt.OutputFile[-2:] == ".c": + self.table["header_filename"] = self.opt.OutputFile[0:-1] + "h" + else: + self.table["header_filename"] = self.opt.OutputFile + ".h" + + self.table["crc_width"] = self.__pretty_str(self.opt.Width) + self.table["crc_poly"] = self.__pretty_hex(self.opt.Poly, self.opt.Width) + self.table["crc_reflect_in"] = self.__pretty_bool(self.opt.ReflectIn) + self.table["crc_xor_in"] = self.__pretty_hex(self.opt.XorIn, self.opt.Width) + self.table["crc_reflect_out"] = self.__pretty_bool(self.opt.ReflectOut) + self.table["crc_xor_out"] = self.__pretty_hex(self.opt.XorOut, self.opt.Width) + self.table["crc_table_idx_width"] = str(self.opt.TableIdxWidth) + self.table["crc_table_width"] = str(1 << self.opt.TableIdxWidth) + self.table["crc_table_mask"] = self.__pretty_hex(self.opt.TableWidth - 1, 8) + self.table["crc_mask"] = self.__pretty_hex(self.opt.Mask, self.opt.Width) + self.table["crc_msb_mask"] = self.__pretty_hex(self.opt.MSB_Mask, self.opt.Width) + if self.opt.Algorithm == self.opt.Algo_Table_Driven and (self.opt.Width == None or self.opt.Width < 8): + self.table["crc_do_shift"] = self.__pretty_bool(True) + if self.opt.Width == None: + self.table["crc_shift"] = self.__pretty_str(None) + else: + self.table["crc_shift"] = self.__pretty_str(8 - self.opt.Width) + else: + self.table["crc_do_shift"] = self.__pretty_bool(False) + self.table["crc_shift"] = self.__pretty_str(0) + + self.table["cfg_width"] = "$if ($crc_width != Undefined) {:$crc_width:} $else {:cfg->width:}" + self.table["cfg_poly"] = "$if ($crc_poly != Undefined) {:$crc_poly:} $else {:cfg->poly:}" + self.table["cfg_poly_shifted"] = "$if ($crc_do_shift == True) {:($cfg_poly << $cfg_shift):} $else {:$cfg_poly:}" + self.table["cfg_reflect_in"] = "$if ($crc_reflect_in != Undefined) {:$crc_reflect_in:} $else {:cfg->reflect_in:}" + self.table["cfg_xor_in"] = "$if ($crc_xor_in != Undefined) {:$crc_xor_in:} $else {:cfg->xor_in:}" + self.table["cfg_reflect_out"] = "$if ($crc_reflect_out != Undefined) {:$crc_reflect_out:} $else {:cfg->reflect_out:}" + self.table["cfg_xor_out"] = "$if ($crc_xor_out != Undefined) {:$crc_xor_out:} $else {:cfg->xor_out:}" + self.table["cfg_table_idx_width"] = "$if ($crc_table_idx_width != Undefined) {:$crc_table_idx_width:} $else {:cfg->table_idx_width:}" + self.table["cfg_table_width"] = "$if ($crc_table_width != Undefined) {:$crc_table_width:} $else {:cfg->table_width:}" + self.table["cfg_mask"] = "$if ($crc_mask != Undefined) {:$crc_mask:} $else {:cfg->crc_mask:}" + self.table["cfg_mask_shifted"] = "$if ($crc_do_shift == True) {:($cfg_mask << $cfg_shift):} $else {:$cfg_mask:}" + self.table["cfg_msb_mask"] = "$if ($crc_msb_mask != Undefined) {:$crc_msb_mask:} $else {:cfg->msb_mask:}" + self.table["cfg_msb_mask_shifted"] = "$if ($crc_do_shift == True) {:($cfg_msb_mask << $cfg_shift):} $else {:$cfg_msb_mask:}" + self.table["cfg_shift"] = "$if ($crc_shift != Undefined) {:$crc_shift:} $else {:cfg->crc_shift:}" + + self.table["undefined_parameters"] = self.__pretty_bool(self.opt.UndefinedCrcParameters) + self.table["use_cfg_t"] = self.__pretty_bool(self.opt.UndefinedCrcParameters) + self.table["c_std"] = self.opt.CStd + self.table["c_bool"] = "$if ($c_std == C89) {:int:} $else {:bool:}" + self.table["c_true"] = "$if ($c_std == C89) {:1:} $else {:true:}" + self.table["c_false"] = "$if ($c_std == C89) {:0:} $else {:false:}" + + self.table["underlying_crc_t"] = self.__get_underlying_crc_t() + self.table["include_file"] = self.__get_include_file() + + self.table["crc_prefix"] = self.opt.SymbolPrefix + self.table["crc_t"] = self.opt.SymbolPrefix + "t" + self.table["cfg_t"] = self.opt.SymbolPrefix + "cfg_t" + self.table["crc_reflect_function"] = self.opt.SymbolPrefix + "reflect" + self.table["crc_table_gen_function"] = self.opt.SymbolPrefix + "table_gen" + self.table["crc_init_function"] = self.opt.SymbolPrefix + "init" + self.table["crc_update_function"] = self.opt.SymbolPrefix + "update" + self.table["crc_finalize_function"] = self.opt.SymbolPrefix + "finalize" + + + # function getTerminal + ############################################################################### + def getTerminal(self, id): + """ + Return the expanded terminal, if it exists or None otherwise. + """ + + if id != None: + if id == "": + return "" + if id in self.table: + return self.table[id] + key = self.__getTerminal(id) + if key != None: + self.table[id] = key + return key + raise LookupError + + + # function __getTerminal + ############################################################################### + def __getTerminal(self, id): + """ + Return the expanded terminal, if it exists or None otherwise. + """ + if id == "constant_crc_init": + if self.__get_init_value() == None: + return self.__pretty_bool(False) + else: + return self.__pretty_bool(True) + + if id == "constant_crc_table": + if self.opt.Width != None and self.opt.Poly != None and self.opt.ReflectIn != None: + return self.__pretty_bool(True) + else: + return self.__pretty_bool(False) + + elif id == "simple_crc_update_def": + if self.opt.Algorithm in set([self.opt.Algo_Bit_by_Bit, self.opt.Algo_Bit_by_Bit_Fast]): + if self.opt.Width != None and self.opt.Poly != None and self.opt.ReflectIn != None: + return self.__pretty_bool(True) + elif self.opt.Algorithm == self.opt.Algo_Table_Driven: + if self.opt.Width != None and self.opt.ReflectIn != None: + return self.__pretty_bool(True) + return self.__pretty_bool(False) + + elif id == "inline_crc_finalize": + if self.opt.Algorithm in set([self.opt.Algo_Bit_by_Bit_Fast, self.opt.Algo_Table_Driven]) and \ + (self.opt.Width != None and self.opt.ReflectIn != None and self.opt.ReflectOut != None and self.opt.XorOut != None): + return self.__pretty_bool(True) + else: + return self.__pretty_bool(False) + + elif id == "simple_crc_finalize_def": + if self.opt.Algorithm == self.opt.Algo_Bit_by_Bit: + if self.opt.Width != None and self.opt.Poly != None and self.opt.ReflectOut != None and self.opt.XorOut != None: + return self.__pretty_bool(True) + elif self.opt.Algorithm == self.opt.Algo_Bit_by_Bit_Fast: + if self.opt.Width != None and self.opt.ReflectOut != None and self.opt.XorOut != None: + return self.__pretty_bool(True) + elif self.opt.Algorithm == self.opt.Algo_Table_Driven: + if self.opt.Width != None and self.opt.ReflectIn != None and self.opt.ReflectOut != None and self.opt.XorOut != None: + return self.__pretty_bool(True) + return self.__pretty_bool(False) + + elif id == "use_reflect_func": + if self.opt.ReflectOut == False and self.opt.ReflectIn == False: + return self.__pretty_bool(False) + else: + return self.__pretty_bool(True) + + elif id == "static_reflect_func": + if self.opt.Algorithm == self.opt.Algo_Table_Driven: + return self.__pretty_bool(False) + elif self.opt.ReflectOut != None and self.opt.Algorithm == self.opt.Algo_Bit_by_Bit_Fast: + return self.__pretty_bool(False) + else: + return self.__pretty_bool(True) + + elif id == "crc_algorithm": + if self.opt.Algorithm == self.opt.Algo_Bit_by_Bit: + return "bit-by-bit" + elif self.opt.Algorithm == self.opt.Algo_Bit_by_Bit_Fast: + return "bit-by-bit-fast" + elif self.opt.Algorithm == self.opt.Algo_Table_Driven: + return "table-driven" + else: + return "UNDEFINED" + + elif id == "crc_table_init": + return self.__get_table_init() + elif id == "crc_table_core_algorithm_ni": + return self.__get_table_core_algorithm_ni() + elif id == "crc_table_core_algorithm_ri": + return self.__get_table_core_algorithm_ri() + + elif id == "header_protection": + return self.__pretty_hdrprotection() + + elif id == "crc_init_value": + ret = self.__get_init_value() + if ret == None: + return "" + else: + return ret + + elif id == "crc_final_value": + return """\ +$if ($crc_algorithm == "table-driven") {: +$if ($crc_reflect_in == $crc_reflect_out) {: +$if ($crc_do_shift == True) {:(crc >> $cfg_shift):} $else {:crc:} ^ $crc_xor_out\ +:} $else {: +$crc_reflect_function($if ($crc_do_shift == True) {:(crc >> $cfg_shift):} $else {:crc:}, $crc_width) ^ $crc_xor_out\ +:}:} $elif ($crc_reflect_out == True) {: +$crc_reflect_function(crc, $crc_width) ^ $crc_xor_out\ +:} $else {: +crc ^ $crc_xor_out\ +:}\ +""" + elif id == "h_template": + return """\ +$source_header +#ifndef $header_protection +#define $header_protection + +$if ($include_file != Undefined) {: +#include $include_file +:} +#include +$if ($c_std != C89) {: +#include +:} +$if ($undefined_parameters == True and $c_std != C89) {: +#include +:} + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * The definition of the used algorithm. + *****************************************************************************/ +$if ($crc_algorithm == "bit-by-bit") {: +#define CRC_ALGO_BIT_BY_BIT 1 +:} $elif ($crc_algorithm == "bit-by-bit-fast") {: +#define CRC_ALGO_BIT_BY_BIT_FAST 1 +:} $elif ($crc_algorithm == "table-driven") {: +#define CRC_ALGO_TABLE_DRIVEN 1 +:} + + +/** + * The type of the CRC values. + * + * This type must be big enough to contain at least $cfg_width bits. + *****************************************************************************/ +typedef $underlying_crc_t $crc_t; + + +$if ($undefined_parameters == True) {: +/** + * The configuration type of the CRC algorithm. + *****************************************************************************/ +typedef struct { +$if ($crc_width == Undefined) {: + unsigned int width; /*!< The width of the polynomial */ +:} +$if ($crc_poly == Undefined) {: + $crc_t poly; /*!< The CRC polynomial */ +:} +$if ($crc_reflect_in == Undefined) {: + $c_bool reflect_in; /*!< Whether the input shall be reflected or not */ +:} +$if ($crc_xor_in == Undefined) {: + $crc_t xor_in; /*!< The initial value of the algorithm */ +:} +$if ($crc_reflect_out == Undefined) {: + $c_bool reflect_out; /*!< Wether the output shall be reflected or not */ +:} +$if ($crc_xor_out == Undefined) {: + $crc_t xor_out; /*!< The value which shall be XOR-ed to the final CRC value */ +:} +$if ($crc_width == Undefined) {: + + /* internal parameters */ + $crc_t msb_mask; /*!< a bitmask with the Most Significant Bit set to 1 + initialise as 1UL << (width - 1) */ + $crc_t crc_mask; /*!< a bitmask with all width bits set to 1 + initialise as (cfg->msb_mask - 1) | cfg->msb_mask */ + unsigned int crc_shift; /*!< a shift count that is used when width < 8 + initialise as cfg->width < 8 ? 8 - cfg->width : 0 */ +:} +} $cfg_t; + + +:} +$if ($use_reflect_func == True and $static_reflect_func != True) {: +$crc_reflect_doc +$crc_reflect_function_def; + + +:} +$if ($crc_algorithm == "table-driven" and $constant_crc_table != True) {: +$crc_table_gen_doc +$crc_table_gen_function_def; + + +:} +$crc_init_doc +$if ($constant_crc_init == False) {: +$crc_init_function_def; +:} $elif ($c_std == C89) {: +#define $crc_init_function() ($crc_init_value$if ($crc_do_shift == True) {: << $cfg_shift:}) +:} $else {: +static inline $crc_init_function_def$nop +{ + return $crc_init_value$if ($crc_do_shift == True) {: << $cfg_shift:}; +} +:} + + +$crc_update_doc +$crc_update_function_def; + + +$crc_finalize_doc +$if ($inline_crc_finalize == True) {: +$if ($c_std == C89) {: +#define $crc_finalize_function(crc) ($crc_final_value) +:} $else {: +static inline $crc_finalize_function_def$nop +{ + return $crc_final_value; +} +:} +:} $else {: +$crc_finalize_function_def; +:} + + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* $header_protection */ +""" + + elif id == "source_header": + return """\ +/** + * \\file $filename + * Functions and types for CRC checks. + * + * Generated on $datetime, + * by $program_version, $program_url + * using the configuration: + * Width = $crc_width + * Poly = $crc_poly + * XorIn = $crc_xor_in + * ReflectIn = $crc_reflect_in + * XorOut = $crc_xor_out + * ReflectOut = $crc_reflect_out + * Algorithm = $crc_algorithm + *****************************************************************************/\ +""" + + elif id == "crc_reflect_doc": + return """\ +/** + * Reflect all bits of a \\a data word of \\a data_len bytes. + * + * \\param data The data word to be reflected. + * \\param data_len The width of \\a data expressed in number of bits. + * \\return The reflected data. + *****************************************************************************/\ +""" + + elif id == "crc_reflect_function_def": + return """\ +$crc_t $crc_reflect_function($crc_t data, size_t data_len)\ +""" + + elif id == "crc_reflect_function_body": + return """\ +$if ($crc_reflect_in == Undefined or $crc_reflect_in == True or $crc_reflect_out == Undefined or $crc_reflect_out == True) {: +$crc_reflect_doc +$crc_reflect_function_def$nop +{ + unsigned int i; + $crc_t ret; + + ret = data & 0x01; + for (i = 1; i < data_len; i++) { + data >>= 1; + ret = (ret << 1) | (data & 0x01); + } + return ret; +} +:}\ +""" + + elif id == "crc_table_gen_doc": + return """\ +/** + * Populate the private static crc table. + * + * \\param cfg A pointer to a initialised $cfg_t structure. + * \\return void + *****************************************************************************/\ +""" + + elif id == "crc_table_gen_function_def": + return """\ +void $crc_table_gen_function(const $cfg_t *cfg)\ +""" + + elif id == "crc_init_doc": + return """\ +/** + * Calculate the initial crc value. + * +$if ($use_cfg_t == True) {: + * \\param cfg A pointer to a initialised $cfg_t structure. +:} + * \\return The initial crc value. + *****************************************************************************/\ +""" + + elif id == "crc_init_function_def": + return """\ +$if ($constant_crc_init == False) {: +$crc_t $crc_init_function(const $cfg_t *cfg)\ +:} $else {: +$crc_t $crc_init_function(void)\ +:}\ +""" + + elif id == "crc_update_doc": + return """\ +/** + * Update the crc value with new data. + * + * \\param crc The current crc value. +$if ($simple_crc_update_def != True) {: + * \\param cfg A pointer to a initialised $cfg_t structure. +:} + * \\param data Pointer to a buffer of \\a data_len bytes. + * \\param data_len Number of bytes in the \\a data buffer. + * \\return The updated crc value. + *****************************************************************************/\ +""" + + elif id == "crc_update_function_def": + return """\ +$if ($simple_crc_update_def != True) {: +$crc_t $crc_update_function(const $cfg_t *cfg, $crc_t crc, const unsigned char *data, size_t data_len)\ +:} $else {: +$crc_t $crc_update_function($crc_t crc, const unsigned char *data, size_t data_len)\ +:}\ +""" + + elif id == "crc_finalize_doc": + return """\ +/** + * Calculate the final crc value. + * +$if ($simple_crc_finalize_def != True) {: + * \\param cfg A pointer to a initialised $cfg_t structure. +:} + * \\param crc The current crc value. + * \\return The final crc value. + *****************************************************************************/\ +""" + + elif id == "crc_finalize_function_def": + return """\ +$if ($simple_crc_finalize_def != True) {: +$crc_t $crc_finalize_function(const $cfg_t *cfg, $crc_t crc)\ +:} $else {: +$crc_t $crc_finalize_function($crc_t crc)\ +:}\ +""" + + elif id == "c_template": + return """\ +$source_header +$if ($include_file != Undefined) {: +#include $include_file +:} +#include "$header_filename" /* include the header file generated with pycrc */ +#include +$if ($c_std != C89) {: +#include +$if ($undefined_parameters == True or $crc_algorithm == "bit-by-bit" or $crc_algorithm == "bit-by-bit-fast") {: +#include +:} +:} + +$if ($use_reflect_func == True and $static_reflect_func == True) {: +static $crc_reflect_function_def; + +:} +$if ($crc_algorithm == "bit-by-bit") {: +$c_bit_by_bit +:} $elif ($crc_algorithm == "bit-by-bit-fast") {: +$c_bit_by_bit_fast +:} $elif ($crc_algorithm == "table-driven") {: +$c_table_driven +:} +""" + + elif id == "c_table": + return """\ +/** + * Static table used for the table_driven implementation. +$if ($undefined_parameters == True) {: + * Must be initialised with the $crc_init_function function. +:} + *****************************************************************************/ +$if ($constant_crc_table != True) {: +static $crc_t crc_table[$crc_table_width]; +:} $else {: +static const $crc_t crc_table[$crc_table_width] = { +$crc_table_init +}; +:} +""" + + elif id == "c_bit_by_bit": + return """\ +$if ($use_reflect_func == True) {: +$crc_reflect_function_body + +:} +$if ($constant_crc_init == False) {: +$crc_init_doc +$crc_init_function_def$nop +{ + unsigned int i; + $c_bool bit; + $crc_t crc = $cfg_xor_in; + for (i = 0; i < $cfg_width; i++) { + bit = crc & 0x01; + if (bit) { + crc = ((crc ^ $cfg_poly) >> 1) | $cfg_msb_mask; + } else { + crc >>= 1; + } + } + return crc & $cfg_mask; +} +:} + +$crc_update_doc +$crc_update_function_def$nop +{ + unsigned int i; + $c_bool bit; + unsigned char c; + + while (data_len--) { +$if ($crc_reflect_in == Undefined) {: + if ($cfg_reflect_in) { + c = $crc_reflect_function(*data++, 8); + } else { + c = *data++; + } +:} $elif ($crc_reflect_in == True) {: + c = $crc_reflect_function(*data++, 8); +:} $else {: + c = *data++; +:} + for (i = 0; i < 8; i++) { + bit = $if ($c_std == C89) {:!!(crc & $cfg_msb_mask):} $else {:crc & $cfg_msb_mask:}; + crc = (crc << 1) | ((c >> (7 - i)) & 0x01); + if (bit) { + crc ^= $cfg_poly; + } + } + crc &= $cfg_mask; + } + return crc & $cfg_mask; +} + + +$crc_finalize_doc +$crc_finalize_function_def$nop +{ + unsigned int i; + $c_bool bit; + + for (i = 0; i < $cfg_width; i++) { + bit = $if ($c_std == C89) {:!!(crc & $cfg_msb_mask):} $else {:crc & $cfg_msb_mask:}; + crc = (crc << 1) | 0x00; + if (bit) { + crc ^= $cfg_poly; + } + } +$if ($crc_reflect_out == Undefined) {: + if ($cfg_reflect_out) { + crc = $crc_reflect_function(crc, $cfg_width); + } +:} $elif ($crc_reflect_out == True) {: + crc = $crc_reflect_function(crc, $cfg_width); +:} + return (crc ^ $cfg_xor_out) & $cfg_mask; +} +""" + + elif id == "c_bit_by_bit_fast": + return """\ +$if ($use_reflect_func == True) {: +$crc_reflect_function_body + +:} +$if ($constant_crc_init == False) {: +$crc_init_doc +$crc_init_function_def$nop +{ + return $cfg_xor_in & $cfg_mask; +} +:} + +$crc_update_doc +$crc_update_function_def$nop +{ + unsigned int i; + $c_bool bit; + unsigned char c; + + while (data_len--) { +$if ($crc_reflect_in == Undefined) {: + if ($cfg_reflect_in) { + c = $crc_reflect_function(*data++, 8); + } else { + c = *data++; + } +:} $else {: + c = *data++; +:} +$if ($crc_reflect_in == True) {: + for (i = 0x01; i & 0xff; i <<= 1) { +:} $else {: + for (i = 0x80; i > 0; i >>= 1) { +:} + bit = $if ($c_std == C89) {:!!(crc & $cfg_msb_mask):} $else {:crc & $cfg_msb_mask:}; + if (c & i) { + bit = !bit; + } + crc <<= 1; + if (bit) { + crc ^= $cfg_poly; + } + } + crc &= $cfg_mask; + } + return crc & $cfg_mask; +} + +$if ($inline_crc_finalize != True) {: +$crc_finalize_doc +$crc_finalize_function_def$nop +{ +$if ($crc_reflect_out == Undefined) {: + if (cfg->reflect_out) { + crc = $crc_reflect_function(crc, $cfg_width); + } +:} $elif ($crc_reflect_out == True) {: + crc = $crc_reflect_function(crc, $cfg_width); +:} + return (crc ^ $cfg_xor_out) & $cfg_mask; +} + +:} +""" + + elif id == "c_table_driven": + return """\ +$c_table +$if ($use_reflect_func == True) {: +$crc_reflect_function_body +:} + +$if ($constant_crc_init == False) {: +$crc_init_doc +$crc_init_function_def$nop +{ +$if ($crc_reflect_in == Undefined) {: + if ($cfg_reflect_in) { + return $crc_reflect_function($cfg_xor_in & $cfg_mask, $cfg_width)$if ($crc_do_shift == True) {: << $cfg_shift:}; + } else { + return $cfg_xor_in & $cfg_mask$if ($crc_do_shift == True) {: << $cfg_shift:}; + } +:} $elif ($crc_reflect_in == True) {: + return $crc_reflect_function($cfg_xor_in & $cfg_mask, $cfg_width)$if ($crc_do_shift == True) {: << $cfg_shift:}; +:} $else {: + return $cfg_xor_in & $cfg_mask$if ($crc_do_shift == True) {: << $cfg_shift:}; +:} +} +:} + +$if ($constant_crc_table != True) {: +$crc_table_gen_doc +$crc_table_gen_function_def +{ + $crc_t crc; + unsigned int i, j; + + for (i = 0; i < $cfg_table_width; i++) { +$if ($crc_reflect_in == Undefined) {: + if (cfg->reflect_in) { + crc = $crc_reflect_function(i, $cfg_table_idx_width); + } else { + crc = i; + } +:} $elif ($crc_reflect_in == True) {: + crc = $crc_reflect_function(i, $cfg_table_idx_width); +:} $else {: + crc = i; +:} +$if ($crc_do_shift == True) {: + crc <<= ($cfg_width - $cfg_table_idx_width + $cfg_shift); +:} $else {: + crc <<= ($cfg_width - $cfg_table_idx_width); +:} + for (j = 0; j < $cfg_table_idx_width; j++) { + if (crc & $cfg_msb_mask_shifted) { + crc = (crc << 1) ^ $cfg_poly_shifted; + } else { + crc = crc << 1; + } + } +$if ($crc_reflect_in == Undefined) {: + if (cfg->reflect_in) { +$if ($crc_do_shift == True) {: + crc = $crc_reflect_function(crc >> $cfg_shift, $cfg_width) << $cfg_shift; +:} $else {: + crc = $crc_reflect_function(crc, $cfg_width); +:} + } +:} $elif ($crc_reflect_in == True) {: +$if ($crc_do_shift == True) {: + crc = $crc_reflect_function(crc >> $cfg_shift, $cfg_width) << $cfg_shift; +:} $else {: + crc = $crc_reflect_function(crc, $cfg_width); +:} +:} + crc_table[i] = crc & $cfg_mask_shifted; + } +} + +:} +$crc_update_doc +$crc_update_function_def$nop +{ + unsigned int tbl_idx; + +$if ($crc_reflect_in == Undefined) {: + if (cfg->reflect_in) { + while (data_len--) { +$crc_table_core_algorithm_ri + data++; + } + } else { + while (data_len--) { +$crc_table_core_algorithm_ni + data++; + } + } +:} $else {: + while (data_len--) { +$if ($crc_reflect_in == True) {: +$crc_table_core_algorithm_ri +:} $elif ($crc_reflect_in == False) {: +$crc_table_core_algorithm_ni +:} + data++; + } +:} + return crc & $cfg_mask_shifted; +} + +$if ($inline_crc_finalize == False) {: +$crc_finalize_doc +$crc_finalize_function_def$nop +{ +$if ($crc_do_shift == True) {: + crc >>= $cfg_shift; +:} +$if ($crc_reflect_in == Undefined or $crc_reflect_out == Undefined) {: +$if ($crc_reflect_in == Undefined and $crc_reflect_out == Undefined) {: + if (cfg->reflect_in == !cfg->reflect_out):} + $elif ($crc_reflect_out == Undefined) {: + if ($if ($crc_reflect_in == True) {:!:}cfg->reflect_out):} + $elif ($crc_reflect_in == Undefined) {: + if ($if ($crc_reflect_out == True) {:!:}cfg->reflect_in):} { + crc = $crc_reflect_function(crc, $cfg_width); + } +:} $elif ($crc_reflect_in != $crc_reflect_out) {: + crc = $crc_reflect_function(crc, $cfg_width); +:} + return (crc ^ $cfg_xor_out) & $cfg_mask; +} +:} +""" + + elif id == "main_template": + return """\ +$if ($include_file != Undefined) {: +#include $include_file +:} +#include +#include +$if ($undefined_parameters == True) {: +#include +#include +#include +:} +$if ($c_std != C89) {: +#include +:} +#include + +static char str[256] = "123456789"; +static $c_bool verbose = $c_false; + +void print_params($if ($undefined_parameters == True) {:const $cfg_t *cfg:} $else {:void:}); +$getopt_template + +void print_params($if ($undefined_parameters == True) {:const $cfg_t *cfg:} $else {:void:}) +{ + char format[20]; + + snprintf(format, sizeof(format), "%%-16s = 0x%%0%dx\\n", (unsigned int)($cfg_width + 3) / 4); + printf("%-16s = %d\\n", "width", (unsigned int)$cfg_width); + printf(format, "poly", (unsigned int)$cfg_poly); + printf("%-16s = %s\\n", "reflect_in", $if ($crc_reflect_in == Undefined) {:$cfg_reflect_in ? "true": "false":} $else {:$if ($crc_reflect_in == True) {:"true":} $else {:"false":}:}); + printf(format, "xor_in", $cfg_xor_in); + printf("%-16s = %s\\n", "reflect_out", $if ($crc_reflect_out == Undefined) {:$cfg_reflect_out ? "true": "false":} $else {:$if ($crc_reflect_out == True) {:"true":} $else {:"false":}:}); + printf(format, "xor_out", (unsigned int)$cfg_xor_out); + printf(format, "crc_mask", (unsigned int)$cfg_mask); + printf(format, "msb_mask", (unsigned int)$cfg_msb_mask); +} + +/** + * C main function. + * + * \\return 0 on success, != 0 on error. + *****************************************************************************/ +int main(int argc, char *argv[]) +{ +$if ($undefined_parameters == True) {: + $cfg_t cfg = { +$if ($crc_width == Undefined) {: + 0, /* width */ +:} +$if ($crc_poly == Undefined) {: + 0, /* poly */ +:} +$if ($crc_xor_in == Undefined) {: + 0, /* xor_in */ +:} +$if ($crc_reflect_in == Undefined) {: + 0, /* reflect_in */ +:} +$if ($crc_xor_out == Undefined) {: + 0, /* xor_out */ +:} +$if ($crc_reflect_out == Undefined) {: + 0, /* reflect_out */ +:} +$if ($crc_width == Undefined) {: + + 0, /* crc_mask */ + 0, /* msb_mask */ + 0, /* crc_shift */ +:} + }; +:} + $crc_t crc; + +$if ($undefined_parameters == True) {: + get_config(argc, argv, &cfg); +:} $else {: + get_config(argc, argv); +:} +$if ($crc_algorithm == "table-driven" and $constant_crc_table != True) {: + $crc_table_gen_function(&cfg); +:} + crc = $crc_init_function($if ($constant_crc_init != True) {:&cfg:}); + crc = $crc_update_function($if ($simple_crc_update_def != True) {:&cfg, :}crc, (unsigned char *)str, strlen(str)); + crc = $crc_finalize_function($if ($simple_crc_finalize_def != True) {:&cfg, :}crc); + + if (verbose) { + print_params($if ($undefined_parameters == True) {:&cfg:}); + } + printf("0x%lx\\n", (unsigned long)crc); + return 0; +} +""" + + elif id == "getopt_template": + return """\ +$if ($crc_reflect_in == Undefined or $crc_reflect_out == Undefined) {: +static $c_bool atob(const char *str); +:} +$if ($crc_poly == Undefined or $crc_xor_in == Undefined or $crc_xor_out == Undefined) {: +static crc_t xtoi(const char *str); +:} +static int get_config(int argc, char *argv[]$if ($undefined_parameters == True) {:, $cfg_t *cfg:}); + + +$if ($crc_reflect_in == Undefined or $crc_reflect_out == Undefined) {: +$c_bool atob(const char *str) +{ + if (!str) { + return 0; + } + if (isdigit(str[0])) { + return ($c_bool)atoi(str); + } + if (tolower(str[0]) == 't') { + return $c_true; + } + return $c_false; +} + +:} +$if ($crc_poly == Undefined or $crc_xor_in == Undefined or $crc_xor_out == Undefined) {: +crc_t xtoi(const char *str) +{ + crc_t ret = 0; + + if (!str) { + return 0; + } + if (str[0] == '0' && tolower(str[1]) == 'x') { + str += 2; + while (*str) { + if (isdigit(*str)) + ret = 16 * ret + *str - '0'; + else if (isxdigit(*str)) + ret = 16 * ret + tolower(*str) - 'a' + 10; + else + return ret; + str++; + } + } else if (isdigit(*str)) { + while (*str) { + if (isdigit(*str)) + ret = 10 * ret + *str - '0'; + else + return ret; + str++; + } + } + return ret; +} + + +:} +static int get_config(int argc, char *argv[]$if ($undefined_parameters == True) {:, $cfg_t *cfg:}) +{ + int c; + int option_index; + static struct option long_options[] = { +$if ($crc_width == Undefined) {: + {"width", 1, 0, 'w'}, +:} +$if ($crc_poly == Undefined) {: + {"poly", 1, 0, 'p'}, +:} +$if ($crc_reflect_in == Undefined) {: + {"reflect-in", 1, 0, 'n'}, +:} +$if ($crc_xor_in == Undefined) {: + {"xor-in", 1, 0, 'i'}, +:} +$if ($crc_reflect_out == Undefined) {: + {"reflect-out", 1, 0, 'u'}, +:} +$if ($crc_xor_out == Undefined) {: + {"xor-out", 1, 0, 'o'}, +:} + {"verbose", 0, 0, 'v'}, + {"check-string", 1, 0, 's'}, +$if ($crc_width == Undefined) {: + {"table-idx-with", 1, 0, 't'}, +:} + {0, 0, 0, 0} + }; + + while (1) { + option_index = 0; + + c = getopt_long (argc, argv, "w:p:n:i:u:o:s:vt", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\\n"); +$if ($crc_width == Undefined) {: + case 'w': + cfg->width = atoi(optarg); + break; +:} +$if ($crc_poly == Undefined) {: + case 'p': + cfg->poly = xtoi(optarg); + break; +:} +$if ($crc_reflect_in == Undefined) {: + case 'n': + cfg->reflect_in = atob(optarg); + break; +:} +$if ($crc_xor_in == Undefined) {: + case 'i': + cfg->xor_in = xtoi(optarg); + break; +:} +$if ($crc_reflect_out == Undefined) {: + case 'u': + cfg->reflect_out = atob(optarg); + break; +:} +$if ($crc_xor_out == Undefined) {: + case 'o': + cfg->xor_out = xtoi(optarg); + break; +:} + case 's': + memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str)); + str[sizeof(str) - 1] = '\\0'; + break; + case 'v': + verbose = $c_true; + break; +$if ($crc_width == Undefined) {: + case 't': + /* ignore --table_idx_width option */ + break; +:} + case '?': + return -1; + case ':': + fprintf(stderr, "missing argument to option %c\\n", c); + return -1; + default: + fprintf(stderr, "unhandled option %c\\n", c); + return -1; + } + } +$if ($crc_width == Undefined) {: + cfg->msb_mask = 1UL << (cfg->width - 1); + cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask; + cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0; +:} + +$if ($crc_poly == Undefined) {: + cfg->poly &= $cfg_mask; +:} +$if ($crc_xor_in == Undefined) {: + cfg->xor_in &= $cfg_mask; +:} +$if ($crc_xor_out == Undefined) {: + cfg->xor_out &= $cfg_mask; +:} + return 0; +}\ +""" + + + # function __pretty_str + ############################################################################### + def __pretty_str(self, value): + """ + Return a value of width bits as a pretty string. + """ + if value == None: + return "Undefined" + return str(value) + + + # function __pretty_hex + ############################################################################### + def __pretty_hex(self, value, width = None): + """ + Return a value of width bits as a pretty hexadecimal formatted string. + """ + if value == None: + return "Undefined" + if width == None: + return "0x%x" % value + width = (width + 3) // 4 + hex_str = "0x%%0%dx" % width + return hex_str % value + + + # function __pretty_bool + ############################################################################### + def __pretty_bool(self, value): + """ + Return a boolen value of width bits as a pretty formatted string. + """ + if value == None: + return "Undefined" + if value: + return "True" + else: + return "False" + + + # function __pretty_hdrprotection + ############################################################################### + def __pretty_hdrprotection(self): + """ + Return the name of a C header protection (e.g. __CRC_IMPLEMENTATION_H__). + """ + tr_str = "" + for i in range(256): + if chr(i).isalpha(): + tr_str += chr(i).upper() + else: + tr_str += '_' + if self.opt.OutputFile == None: + out_str = "pycrc_stdout" + else: + out_str = self.opt.OutputFile + out_str = os.path.basename(out_str) + out_str = out_str.upper() + out_str = out_str.translate(tr_str) + return "__" + out_str + "__" + + + # function __get_underlying_crc_t + ############################################################################### + def __get_underlying_crc_t(self): + """ + Return the C type of the crc_t typedef. + """ + if self.opt.CrcType != None: + return self.opt.CrcType + if self.opt.Width == None: + return "unsigned long" + if self.opt.CStd == "C89": + if self.opt.Width <= 8: + return "unsigned char" + elif self.opt.Width <= 16: + return "unsigned int" + else: + return "unsigned long" + else: # C99 + if self.opt.Width <= 8: + return "uint8_t" + elif self.opt.Width <= 16: + return "uint16_t" + elif self.opt.Width <= 32: + return "uint32_t" + else: + return "unsigned long" + return "unsigned long" + + + # function __get_include_file + ############################################################################### + def __get_include_file(self): + """ + Return an addittional include instruction if specified. + """ + if self.opt.IncludeFile == None: + return None + if self.opt.IncludeFile[0] == '"' or self.opt.IncludeFile[0] == '<': + return self.opt.IncludeFile + return '"%s"' % self.opt.IncludeFile + + + # function __get_init_value + ############################################################################### + def __get_init_value(self): + """ + Return the init value of a C implementation, according to the selected algorithm and + to the given options. + If no default option is given for a given parameter, value in the cfg_t structure must be used. + """ + if self.opt.Algorithm == self.opt.Algo_Bit_by_Bit: + if self.opt.XorIn == None or self.opt.Width == None or self.opt.Poly == None: + return None + crc = Crc(width = self.opt.Width, poly = self.opt.Poly, + reflect_in = self.opt.ReflectIn, xor_in = self.opt.XorIn, + reflect_out = self.opt.ReflectOut, xor_out = self.opt.XorOut, + table_idx_width = self.opt.TableIdxWidth) + init = crc.NonDirectInit + elif self.opt.Algorithm == self.opt.Algo_Bit_by_Bit_Fast: + if self.opt.XorIn == None: + return None + init = self.opt.XorIn + elif self.opt.Algorithm == self.opt.Algo_Table_Driven: + if self.opt.ReflectIn == None or self.opt.XorIn == None or self.opt.Width == None: + return None + if self.opt.Poly == None: + poly = 0 + else: + poly = self.opt.Poly + crc = Crc(width = self.opt.Width, poly = poly, + reflect_in = self.opt.ReflectIn, xor_in = self.opt.XorIn, + reflect_out = self.opt.ReflectOut, xor_out = self.opt.XorOut, + table_idx_width = self.opt.TableIdxWidth) + if self.opt.ReflectIn: + init = crc.reflect(crc.DirectInit, self.opt.Width) + else: + init = crc.DirectInit + else: + init = 0 + return self.__pretty_hex(init, self.opt.Width) + + + # function __get_table_init + ############################################################################### + def __get_table_init(self): + """ + Return the precalculated CRC table for the table_driven implementation. + """ + if self.opt.Algorithm != self.opt.Algo_Table_Driven: + return "0" + if self.opt.Width == None or self.opt.Poly == None or self.opt.ReflectIn == None: + return "0" + crc = Crc(width = self.opt.Width, poly = self.opt.Poly, + reflect_in = self.opt.ReflectIn, + xor_in = 0, reflect_out = False, xor_out = 0, # set unimportant variables to known values + table_idx_width = self.opt.TableIdxWidth) + tbl = crc.gen_table() + if self.opt.Width >= 32: + values_per_line = 4 + elif self.opt.Width >= 16: + values_per_line = 8 + else: + values_per_line = 16 + format_width = max(self.opt.Width, 8) + out = "" + for i in range(self.opt.TableWidth): + if i % values_per_line == 0: + out += " " + if i == (self.opt.TableWidth - 1): + out += "%s" % self.__pretty_hex(tbl[i], format_width) + elif i % values_per_line == (values_per_line - 1): + out += "%s,\n" % self.__pretty_hex(tbl[i], format_width) + else: + out += "%s, " % self.__pretty_hex(tbl[i], format_width) + return out + + + # function __get_table_core_algorithm_ni + ############################################################################### + def __get_table_core_algorithm_ni(self): + """ + Return the core loop of the table-driven algorithm. + """ + if self.opt.Algorithm != self.opt.Algo_Table_Driven: + return "" + + loop_core_ni = "" + loop_indent = "" + if self.opt.UndefinedCrcParameters: + loop_indent = " " + else: + loop_indent = " " + + if self.opt.Width == None: + shr = "($cfg_width - $cfg_table_idx_width + $cfg_shift)" + elif self.opt.Width < 8: + shr = "%d" % (self.opt.Width - self.opt.TableIdxWidth + 8 - self.opt.Width) + else: + shr = "%d" % (self.opt.Width - self.opt.TableIdxWidth) + + reg_shift = "$if ($crc_do_shift == True) {:($cfg_table_idx_width - $cfg_shift):} $else {:$cfg_table_idx_width:}" + + if self.opt.TableIdxWidth == 8: + loop_core_ni += loop_indent + "tbl_idx = ((crc >> " + shr + ") ^ *data) & $crc_table_mask;" + '\n' + \ + loop_indent + "crc = (crc_table[tbl_idx] ^ (crc << " + reg_shift + ")) & $cfg_mask_shifted;" + '\n' + else: + for i in range (8 / self.opt.TableIdxWidth): + str_idx = "%s" % (8 - (i + 1) * self.opt.TableIdxWidth) + loop_core_ni += loop_indent + "tbl_idx = (crc >> " + shr + ") ^ (*data >> " + str_idx + ");" + '\n' + \ + loop_indent + "crc = crc_table[tbl_idx & $crc_table_mask] ^ (crc << " + reg_shift + ");" + '\n' + return loop_core_ni + + + # function __get_table_core_algorithm_ri + ############################################################################### + def __get_table_core_algorithm_ri(self): + """ + Return the core loop of the table-driven algorithm. + """ + if self.opt.Algorithm != self.opt.Algo_Table_Driven: + return "" + + loop_core_ri = "" + loop_indent = "" + if self.opt.UndefinedCrcParameters: + loop_indent = " " + else: + loop_indent = " " + crc_shifted = "$if ($crc_do_shift == True) {:(crc >> $cfg_shift):} $else {:crc:}" + + if self.opt.TableIdxWidth == 8: + loop_core_ri += loop_indent + "tbl_idx = (" + crc_shifted + " ^ *data) & $crc_table_mask;" + '\n' + \ + loop_indent + "crc = (crc_table[tbl_idx] ^ (crc >> $cfg_table_idx_width)) & $cfg_mask_shifted;" + '\n' + else: + for i in range (8 / self.opt.TableIdxWidth): + str_idx = "%d" % i + loop_core_ri += loop_indent + "tbl_idx = " + crc_shifted + " ^ (*data >> (" + str_idx + " * $cfg_table_idx_width));" + '\n' + \ + loop_indent + "crc = crc_table[tbl_idx & $crc_table_mask] ^ (crc >> $cfg_table_idx_width);" + '\n' + + return loop_core_ri diff --git a/pycrc/crc_symtable.pyc b/pycrc/crc_symtable.pyc new file mode 100644 index 0000000..361108b Binary files /dev/null and b/pycrc/crc_symtable.pyc differ diff --git a/pycrc/doc/Makefile b/pycrc/doc/Makefile new file mode 100644 index 0000000..b4f843d --- /dev/null +++ b/pycrc/doc/Makefile @@ -0,0 +1,26 @@ +XSLTPROC = xsltproc +XSLTPARAM = --nonet --novalid +HTML_STYLESHEET = /usr/share/xml/docbook/stylesheet/nwalsh/xhtml/docbook.xsl +MAN_STYLESHEET = /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl + +source = pycrc.xml +targets = $(source:.xml=.html) $(source:.xml=.1) + +all: $(targets) + +.PHONY: clean +clean: + $(RM) $(targets) + +.PHONY: check +check: + xmllint --valid --noout $(source) + +%.html: %.xml + $(XSLTPROC) $(XSLTPARAM) -o $@ $(HTML_STYLESHEET) $< + +%.1: %.xml + $(XSLTPROC) $(XSLTPARAM) -o $@ $(MAN_STYLESHEET) $< + +%.txt: %.html + links -dump -no-numbering -no-references $< > $@ diff --git a/pycrc/doc/pycrc.1 b/pycrc/doc/pycrc.1 new file mode 100644 index 0000000..99fcfec --- /dev/null +++ b/pycrc/doc/pycrc.1 @@ -0,0 +1,531 @@ +'\" t +.\" Title: pycrc +.\" Author: Thomas Pircher +.\" Generator: DocBook XSL Stylesheets v1.76.1 +.\" Date: 2011-11-19 +.\" Manual: pycrc +.\" Source: pycrc 0.7.9 +.\" Language: English +.\" +.TH "PYCRC" "1" "2011\-11\-19" "pycrc 0.7.9" "pycrc" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +pycrc \- a free, easy to use Cyclic Redundancy Check (CRC) calculator and source code generator\&. +.SH "SYNOPSIS" +.HP \w'\fBpycrc\fR\ 'u +\fBpycrc\fR [OPTIONS] +.SH "DESCRIPTION" +.PP + +\m[blue]\fBpycrc\fR\m[]\&\s-2\u[1]\d\s+2 +provides a parametrised CRC reference implementation written in Python and a source code generator for C\&. The generated C source code can be optimised for simplicity, speed or tight memory constraints for embedded platforms\&. The following operations are implemented: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +generate the checksum of a string (ASCII or hex) +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +generate the checksum of a file +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +generate the C header and source files for a client implementation\&. +.RE +.PP +The following variants of the CRC algorithm are supported: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} + +\fIbit\-by\-bit\fR: the basic algorithm which operates individually on every bit of the augmented message (i\&.e\&. the input data with +\fIWidth\fR +0\-bits attached to the end)\&. This algorithm is the easiest to understand because it is a straightforward implementation of the basic polynomial division, but it is also the slowest among all possible variants\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} + +\fIbit\-by\-bit\-fast\fR: a variation of the simple +\fIbit\-by\-bit\fR +algorithm, with the difference that it does not need to augment the data, i\&.e\&. it does not add +\fIWidth\fR +zero bits at the end of the message\&. This algorithm might be a good choice for embedded platforms, where code space is a major concern\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} + +\fItable\-driven\fR: the standard table driven algorithm\&. This is the fastest variant because it operates on one byte at a time, as opposed to bits, and uses a look\-up table of 256 elements, which might not be feasible for small embedded systems, though\&. Anyway, the number of elements in the look\-up table can be reduced by means of the +\fB\-\-table\-idx\-width\fR +command line switch\&. By using 4 bits (16 elements in the look\-up table) a significant speed\-up can be measured with respect to the bit\-by\-bit algorithms\&. +.RE +.sp +.SH "OPTIONS" +.PP +\fB\-\-version\fR +.RS 4 +show program\*(Aqs version number and exit +.RE +.PP +\fB\-h\fR, \fB\-\-help\fR +.RS 4 +show this help message and exit +.RE +.PP +\fB\-\-verbose\fR +.RS 4 +be more verbose; in particular, print the value of the parameters and the chosen model +.RE +.PP +\fB\-\-check\-string=\fR\fISTRING\fR +.RS 4 +calculate the checksum of the given string (\*(Aq\fI123456789\fR\*(Aq default) +.RE +.PP +\fB\-\-check\-hexstring=\fR\fISTRING\fR +.RS 4 +calculate the checksum of the given hexadecimal string +.RE +.PP +\fB\-\-check\-file=\fR\fIFILE\fR +.RS 4 +calculate the checksum of the given file +.RE +.PP +\fB\-\-generate=\fR\fICODE\fR +.RS 4 +generate the source code type as a choice from {c, h, c\-main, table} +.RE +.PP +\fB\-\-std=\fR\fISTD\fR +.RS 4 +C standard style of the generated code from {C89, ANSI, C99} +.RE +.PP +\fB\-\-algorithm=\fR\fIALGO\fR +.RS 4 +choose an algorithm from {\fIbit\-by\-bit\fR, +\fIbit\-by\-bit\-fast\fR, +\fItable\-driven\fR, +\fIall\fR} +.RE +.PP +\fB\-\-model=\fR\fIMODEL\fR +.RS 4 +choose a parameter set from {\fIcrc\-5\fR, +\fIcrc\-8\fR, +\fIdallas\-1\-wire\fR, +\fIcrc\-12\-3gpp\fR, +\fIcrc\-15\fR, +\fIcrc\-16\fR, +\fIcrc\-16\-usb\fR, +\fIcrc\-16\-modbus\fR, +\fIcrc\-16\-genibus\fR, +\fIccitt\fR, +\fIr\-crc\-16\fR, +\fIkermit\fR, +\fIx\-25\fR, +\fIxmodem\fR, +\fIzmodem\fR, +\fIcrc\-24\fR, +\fIcrc\-32\fR, +\fIcrc\-32c\fR, +\fIcrc\-32\-mpeg\fR, +\fIcrc\-32\-bzip2\fR, +\fIposix\fR, +\fIjam\fR, +\fIxfer\fR, +\fIcrc\-64\fR, +\fIcrc\-64\-jones\fR, +\fIcrc\-64\-xz\fR} +.RE +.PP +\fB\-\-width=\fR\fINUM\fR +.RS 4 +use +\fINUM\fR +bits in the +\fIPolynomial\fR +.RE +.PP +\fB\-\-poly=\fR\fIHEX\fR +.RS 4 +use +\fIHEX\fR +as +\fIPolynomial\fR +.RE +.PP +\fB\-\-reflect\-in=\fR\fIBOOL\fR +.RS 4 +reflect input bytes +.RE +.PP +\fB\-\-xor\-in=\fR\fIHEX\fR +.RS 4 +use +\fIHEX\fR +as initial value +.RE +.PP +\fB\-\-reflect\-out=\fR\fIBOOL\fR +.RS 4 +reflect output bytes +.RE +.PP +\fB\-\-xor\-out=\fR\fIHEX\fR +.RS 4 +xor the final CRC value with +\fIHEX\fR +.RE +.PP +\fB\-\-table\-idx\-width=\fR\fINUM\fR +.RS 4 +use +\fINUM\fR +bits to index the CRC table; +\fINUM\fR +must be one of the values {\fI1\fR, +\fI2\fR, +\fI4\fR, +\fI8\fR} +.RE +.PP +\fB\-\-symbol\-prefix=\fR\fISTRING\fR +.RS 4 +when generating source code, use +\fISTRING\fR +as prefix to the generated symbols +.RE +.PP +\fB\-\-crc\-type=\fR\fISTRING\fR +.RS 4 +when generating source code, use +\fISTRING\fR +as crc_t type +.RE +.PP +\fB\-\-include\-file=\fR\fIFILE\fR +.RS 4 +when generating source code, include also +\fIFILE\fR +as header file +.RE +.PP +\fB\-o\fR\fIFILE\fR, \fB\-\-output=\fR\fIFILE\fR +.RS 4 +write the generated code to +\fIFILE\fR +instead to stdout +.RE +.SH "THE CRC PARAMETRIC MODEL" +.PP +The parametric model follows Ross N\&. Williams\*(Aq convention described in +\m[blue]\fBA Painless Guide to CRC Error Detection Algorithms\fR\m[]\&\s-2\u[2]\d\s+2, commonly called the Rocksoft Model\&. Since most people are familiar with this kind of parameters, pycrc follows this convention, described as follows: +.PP +\fIWidth\fR +.RS 4 +The width of the CRC +\fIPolynomial\fR, in number of bits\&. This is also the width of the final CRC result\&. Previous versions of pycrc only multiples of 8 could be be used as +\fIWidth\fR +for the +\fItable\-driven\fR +algorithm\&. As of version 0\&.7\&.5, any +\fIWidth\fR +is accepted on all algorithms\&. +.RE +.PP +\fIPolynomial\fR +.RS 4 +The unreflected polynomial of the CRC algorithm\&. +.sp +The +\fIPolynomial\fR +may be specified in its standard form, i\&.e\&. with bit +\fIWidth\fR+1 set to 1, but the most significant bit may also be omitted\&. For example, for a +\fIWidth\fR +of 16, both forms 0x18005 and 0x8005 are accepted\&. +.RE +.PP +\fIReflectIn\fR +.RS 4 +Reflect the bytes of the message before processing them\&. A word is reflected by inverting the position of its bits with respect to the middle axis of the word\&. The reversed value of 0xa3 (10100010b) is 0x45 (01000101b), for example\&. Some CRC algorithms can be implemented more efficiently in a bit reversed version\&. +.sp +Reflected algorithms are more efficient than straight\-forward implementations, thus many of the standard algorithmic variants use reflected input bytes\&. +.RE +.PP +\fIXorIn\fR +.RS 4 +The initial value (usually all 0 or all 1) in the algorithms which operate on the non\-augmented message\&. This value can be seen as a value which will be XOR\-ed into the CRC register after +\fIWidth\fR +iterations of the +\fIbit\-by\-bit\fR +algorithm\&. This means the simple +\fIbit\-by\-bit\fR +algorithm must calculate the initial value using some sort of reverse CRC algorithm on the +\fIXorIn\fR +value\&. +.RE +.PP +\fIReflectOut\fR +.RS 4 +Reflect the final CRC result\&. This operation takes place before XOR\-ing the final CRC value with the +\fIXorOut\fR +parameter\&. +.RE +.PP +\fIXorOut\fR +.RS 4 +A value (usually all bits 0 or all 1) which will be XOR\-ed to the final CRC value\&. +.RE +.PP +\fICheck\fR +.RS 4 +This value is not exactly a parameter of a model but it is sometimes given together with the Rocksoft Model parameters\&. It is the CRC value of the parametrised model over the string "\fI123456789\fR" and may be used to validate an implementation\&. +.RE +.SH "CODE GENERATION" +.PP +In the default configuration, the generated code is strict ISO C99 code\&. A minimal set of three functions are defined for each algorithm: +\fBcrc_init()\fR, +\fBcrc_update()\fR +and +\fBcrc_finalize()\fR\&. According to the number of parameters given to pycrc, a different interface definition is generated\&. Fully parametrised models have a simpler API, while the generated code for runtime\-specified implementations adds a pointer to a configuration structure as first parameter to all functions\&. +.PP +The generated source code uses the type +\fBcrc_t\fR, which is used throughout the code\&. It may be redefined in the generated header file\&. +.SS "Fully parametrised models" +.PP +The prototypes of these functions are normally generated by pycrc using the +\fI\-\-generate h\fR +option\&. The prototypes of the +.sp +.ft B +.nf +#include +/* pycrc will define the appropriate type + * when generating the header file\&. */ +typedef XXXX crc_t; + +.fi +.ft +.HP \w'crc_t\ crc_init('u +.BI "crc_t crc_init(void);" +.HP \w'crc_t\ crc_update('u +.BI "crc_t crc_update(crc_t\ " "crc" ", const\ unsigned\ char\ *" "data" ", size_t\ " "data_len" ");" +.HP \w'crc_t\ crc_finalize('u +.BI "crc_t crc_finalize(crc_t\ " "crc" ");" +.PP +The following code snippet shows how to use the generated functions\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +#include "pycrc_generated_crc\&.h" +#include + +int main(void) +{ + static const unsigned char str1[] = "1234"; + static const unsigned char str2[] = "56789"; + crc_t crc; + + crc = crc_init(); + crc = crc_update(crc, str1, sizeof(str1) \- 1); + crc = crc_update(crc, str2, sizeof(str2) \- 1); + // more calls to crc_update\&.\&.\&. + crc = crc_finalize(crc); + + printf("0x%lx\en", (long)crc); + return 0; +} + +.fi +.if n \{\ +.RE +.\} +.sp +.SS "Models with runtime\-configurable parameters" +.PP +When the model is not fully defined then the missing parameters are contained in a structure of type +\fBcrc_cfg_t\fR\&. The first argument of the CRC functions is a pointer to that structure, and its fields must be initialised properly by the user before the first call to the CRC functions\&. This structure contains three additional parameters, +\fImsb_mask\fR, +\fIcrc_mask\fR +and +\fIcrc_shift\fR, if the +\fIWidth\fR +was undefined when the code was generated\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +typedef struct { + unsigned int width; + crc_t poly; + bool reflect_in; + crc_t xor_in; + bool reflect_out; + crc_t xor_out; + + // internal parameters + crc_t msb_mask; // initialise as 1UL << (cfg\->width \- 1) + crc_t crc_mask; // initialise as (cfg\->msb_mask \- 1) | cfg\->msb_mask + unsigned int crc_shift; // initialise as cfg\->width < 8 ? 8 \- cfg\->width : 0 +} crc_cfg_t; + +.fi +.if n \{\ +.RE +.\} +.PP + +\fImsb_mask\fR +is a bitmask with the most significant bit of a +\fIWidth\fR +bits wide data type set to 1\&. +\fIcrc_mask\fR +is a bitmask with all bits of a +\fIWidth\fR +bits wide data type set to 1\&. +\fIcrc_shift\fR +is a shift counter that is used when +\fIWidth\fR +is less than 8\&. It is the number of bits to shift the CRC register to align its top bit at a byte boundary\&. +.PP +The file +test/main\&.c +in the source package of pycrc contains a fully featured example of how to use the generated source code\&. A shorter, more compact +main() +function can be generated with the +\fI\-\-generate c\-main\fR +option\&. This second variant is the better option when some of the CRC parameters are known and some are unknown during code generation\&. +.SH "EXAMPLES" +.PP +.PP +Calculate the CRC\-32 checksum of the string 123456789: +.RS 4 + +\fBpython pycrc\&.py \-\-model crc\-32 \-\-check\-string 123456789\fR +.RE +.PP +Generate the source code of the table\-driven algorithm for an embedded application\&. +.RS 4 + +\fBpython pycrc\&.py \-\-model crc\-16 \-\-algorithm table\-driven \-\-table\-idx\-width 4 \-\-generate h \-o crc\&.h\fR +.sp + +\fBpython pycrc\&.py \-\-model crc\-16 \-\-algorithm table\-driven \-\-table\-idx\-width 4 \-\-generate c \-o crc\&.c\fR +.sp +The table index width of 4 bits ensures a moderate memory consumption\&. In fact, the size of the resulting table is +16 * sizeof(crc_t) +bytes\&. A variant of the last generated output is the +\fIc\-main\fR +target: a simple +\fImain()\fR +function is generated in addition to the CRC routines: +.sp + +\fBpython pycrc\&.py \-\-model crc\-16 \-\-algorithm table\-driven \-\-table\-idx\-width 4 \-\-generate c\-main \-o crc\&.c\fR +.RE +.PP +Generate the CRC table only: +.RS 4 + +\fBpython pycrc\&.py \-\-model kermit \-\-generate table \-o crc\-table\&.txt\fR +.RE +.SH "SEE ALSO" +.PP +The homepage of pycrc is +\m[blue]\fBhttp://www\&.tty1\&.net/pycrc/\fR\m[]\&. +.PP +For a long list of known CRC models, see Greg Cook\*(Aqs +\m[blue]\fBCatalogue of Parameterised CRC Algorithms\fR\m[]\&\s-2\u[3]\d\s+2\&. +.SH "COPYRIGHT" +.PP +This work is licensed under a +\m[blue]\fBCreative Commons Attribution\-Share Alike 3\&.0 Unported License\fR\m[]\&\s-2\u[4]\d\s+2\&. +.SH "AUTHOR" +.PP +\fBThomas Pircher\fR <\&tehpeh@gmx\&.net\&> +.RS 4 +Author of pycrc and this manual page\&. +.RE +.SH "NOTES" +.IP " 1." 4 +pycrc +.RS 4 +\%http://www.tty1.net/pycrc/ +.RE +.IP " 2." 4 +A Painless Guide to CRC Error Detection Algorithms +.RS 4 +\%http://www.ross.net/crc/crcpaper.html +.RE +.IP " 3." 4 +Catalogue of Parameterised CRC Algorithms +.RS 4 +\%http://regregex.bbcmicro.net/crc-catalogue.htm +.RE +.IP " 4." 4 +Creative Commons Attribution-Share Alike 3.0 Unported License +.RS 4 +\%http://creativecommons.org/licenses/by-sa/3.0/ +.RE diff --git a/pycrc/doc/pycrc.html b/pycrc/doc/pycrc.html new file mode 100644 index 0000000..17d4df7 --- /dev/null +++ b/pycrc/doc/pycrc.html @@ -0,0 +1,247 @@ + + +pycrc

Name

pycrc — a free, easy to use Cyclic Redundancy Check (CRC) calculator and source code generator.

Synopsis

pycrc [OPTIONS]

Description

+ pycrc + provides a parametrised CRC reference implementation written in Python and a source code generator for C. + The generated C source code can be optimised for simplicity, speed or tight memory constraints for embedded platforms. + + The following operations are implemented: +

  • + generate the checksum of a string (ASCII or hex) +

  • + generate the checksum of a file +

  • + generate the C header and source files for a client implementation. +

+

+ The following variants of the CRC algorithm are supported: +

  • + bit-by-bit: the basic algorithm which operates individually on every bit of the augmented message + (i.e. the input data with Width 0-bits attached to the end). + This algorithm is the easiest to understand because it is a straightforward implementation of the basic polynomial division, + but it is also the slowest among all possible variants. +

  • + bit-by-bit-fast: a variation of the simple bit-by-bit algorithm, + with the difference that it does not need to augment the data, i.e. it does not add Width zero + bits at the end of the message. + This algorithm might be a good choice for embedded platforms, where code space is a major concern. +

  • + table-driven: the standard table driven algorithm. + This is the fastest variant because it operates on one byte at a time, as opposed to bits, and uses a look-up table of 256 elements, + which might not be feasible for small embedded systems, though. Anyway, the number of elements in the look-up table can be reduced by + means of the --table-idx-width command line switch. By using 4 bits (16 elements in the look-up table) a significant + speed-up can be measured with respect to the bit-by-bit algorithms. +

+

Options

+ --version +

show program's version number and exit

+ -h + , + --help +

show this help message and exit

+ --verbose +

be more verbose; in particular, print the value of the parameters and the chosen model

+ --check-string=STRING +

calculate the checksum of the given string ('123456789' default)

+ --check-hexstring=STRING +

calculate the checksum of the given hexadecimal string

+ --check-file=FILE +

calculate the checksum of the given file

+ --generate=CODE +

generate the source code type as a choice from {c, h, c-main, table}

+ --std=STD +

C standard style of the generated code from {C89, ANSI, C99}

+ --algorithm=ALGO +

choose an algorithm from {bit-by-bit, bit-by-bit-fast, + table-driven, all}

+ --model=MODEL +

choose a parameter set from + {crc-5, + crc-8, + dallas-1-wire, + crc-12-3gpp, + crc-15, + crc-16, + crc-16-usb, + crc-16-modbus, + crc-16-genibus, + ccitt, + r-crc-16, + kermit, + x-25, + xmodem, + zmodem, + crc-24, + crc-32, + crc-32c, + crc-32-mpeg, + crc-32-bzip2, + posix, + jam, + xfer, + crc-64, + crc-64-jones, + crc-64-xz}

+ --width=NUM +

use NUM bits in the Polynomial

+ --poly=HEX +

use HEX as Polynomial

+ --reflect-in=BOOL +

reflect input bytes

+ --xor-in=HEX +

use HEX as initial value

+ --reflect-out=BOOL +

reflect output bytes

+ --xor-out=HEX +

xor the final CRC value with HEX

+ --table-idx-width=NUM +

use NUM bits to index the CRC table; NUM must be one of the values + {1, 2, 4, 8}

+ --symbol-prefix=STRING +

when generating source code, use STRING as prefix to the generated symbols

+ --crc-type=STRING +

when generating source code, use STRING as crc_t type

+ --include-file=FILE +

when generating source code, include also FILE as header file

+ -oFILE + , + --output=FILE +

write the generated code to FILE instead to stdout

The CRC Parametric Model

+ The parametric model follows Ross N. Williams' convention described in + A Painless Guide to CRC Error Detection Algorithms, + commonly called the Rocksoft Model. + Since most people are familiar with this kind of parameters, pycrc follows this convention, described as follows: +

Width

+ The width of the CRC Polynomial, in number of bits. This is also the width of the final CRC result. + Previous versions of pycrc only multiples of 8 could be be used as Width for the + table-driven algorithm. As of version 0.7.5, any Width is accepted + on all algorithms. +

Polynomial

+ The unreflected polynomial of the CRC algorithm. +

+ The Polynomial may be specified in its standard form, i.e. with bit Width+1 + set to 1, but the most significant bit may also be omitted. For example, for a Width of 16, + both forms 0x18005 and 0x8005 are accepted. +

ReflectIn

+ Reflect the bytes of the message before processing them. A word is reflected by inverting the position of its bits with + respect to the middle axis of the word. + The reversed value of 0xa3 (10100010b) is 0x45 (01000101b), for example. + Some CRC algorithms can be implemented more efficiently in a bit reversed version. +

+ Reflected algorithms are more efficient than straight-forward implementations, thus many of the standard algorithmic + variants use reflected input bytes. +

XorIn

+ The initial value (usually all 0 or all 1) in the algorithms which operate on the non-augmented message. + This value can be seen as a value which will be XOR-ed into the CRC register after Width + iterations of the bit-by-bit algorithm. + This means the simple bit-by-bit algorithm must calculate the initial value using some sort of + reverse CRC algorithm on the XorIn value. +

ReflectOut

+ Reflect the final CRC result. This operation takes place before XOR-ing the final CRC + value with the XorOut parameter. +

XorOut

+ A value (usually all bits 0 or all 1) which will be XOR-ed to the final CRC value. +

Check

+ This value is not exactly a parameter of a model but it is sometimes given together with the Rocksoft Model parameters. + It is the CRC value of the parametrised model over the string "123456789" and + may be used to validate an implementation. +

+

Code generation

+ In the default configuration, the generated code is strict ISO C99 code. + A minimal set of three functions are defined for each algorithm: + crc_init(), crc_update() and crc_finalize(). + According to the number of parameters given to pycrc, a different interface definition is generated. + Fully parametrised models have a simpler API, while the generated code for runtime-specified implementations adds a + pointer to a configuration structure as first parameter to all functions. +

+ The generated source code uses the type crc_t, which is used throughout the code. It may be redefined in the generated header file. +

Fully parametrised models

+ The prototypes of these functions are normally generated by pycrc using the --generate h option. + The prototypes of the +

+#include <stdlib.h>
+/* pycrc will define the appropriate type
+ * when generating the header file. */
+typedef XXXX crc_t;
+                
crc_t fsfunccrc_init(void); 
 
crc_t fsfunccrc_update(crc_t crc,
 const unsigned char *data,
 size_t data_len);
 
crc_t fsfunccrc_finalize(crc_t crc);
 

+ The following code snippet shows how to use the generated functions. +

+#include "pycrc_generated_crc.h"
+#include <stdio.h>
+
+int main(void)
+{
+    static const unsigned char str1[] = "1234";
+    static const unsigned char str2[] = "56789";
+    crc_t crc;
+
+    crc = crc_init();
+    crc = crc_update(crc, str1, sizeof(str1) - 1);
+    crc = crc_update(crc, str2, sizeof(str2) - 1);
+    // more calls to crc_update...
+    crc = crc_finalize(crc);
+
+    printf("0x%lx\n", (long)crc);
+    return 0;
+}
+            

+

Models with runtime-configurable parameters

+ When the model is not fully defined then the missing parameters are contained in a structure of + type crc_cfg_t. + The first argument of the CRC functions is a pointer to that structure, and its fields must be initialised + properly by the user before the first call to the CRC functions. + This structure contains three additional parameters, msb_mask, crc_mask + and crc_shift, if the Width was undefined when the code was generated. +

+typedef struct {
+    unsigned int width;
+    crc_t poly;
+    bool reflect_in;
+    crc_t xor_in;
+    bool reflect_out;
+    crc_t xor_out;
+
+    // internal parameters
+    crc_t msb_mask;             // initialise as 1UL << (cfg->width - 1)
+    crc_t crc_mask;             // initialise as (cfg->msb_mask - 1) | cfg->msb_mask
+    unsigned int crc_shift;     // initialise as cfg->width < 8 ? 8 - cfg->width : 0
+} crc_cfg_t;
+            

+

+ msb_mask is a bitmask with the most significant bit of a Width bits + wide data type set to 1. + crc_mask is a bitmask with all bits of a Width bits + wide data type set to 1. + crc_shift is a shift counter that is used when Width is less than 8. + It is the number of bits to shift the CRC register to align its top bit at a byte boundary. +

+ The file test/main.c in the source package of pycrc contains a fully featured example + of how to use the generated source code. + A shorter, more compact main() function can be generated with the --generate c-main + option. + This second variant is the better option when some of the CRC parameters are known and some are unknown during code generation. +

Examples

+

Calculate the CRC-32 checksum of the string 123456789:

+ python pycrc.py --model crc-32 --check-string 123456789 +

Generate the source code of the table-driven algorithm for an embedded application.

+ python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate h -o crc.h +

+ python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c -o crc.c +

+ The table index width of 4 bits ensures a moderate memory consumption. + In fact, the size of the resulting table is 16 * sizeof(crc_t) bytes. + A variant of the last generated output is the c-main target: + a simple main() function is generated in addition to the CRC routines: +

+ python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c-main -o crc.c +

Generate the CRC table only:

+ python pycrc.py --model kermit --generate table -o crc-table.txt +

+

See Also

+ The homepage of pycrc is http://www.tty1.net/pycrc/. +

+ For a long list of known CRC models, see Greg Cook's Catalogue of Parameterised CRC Algorithms. +

Copyright

+ This work is licensed under a + Creative Commons Attribution-Share Alike 3.0 Unported License. +

diff --git a/pycrc/doc/pycrc.xml b/pycrc/doc/pycrc.xml new file mode 100644 index 0000000..eeffea2 --- /dev/null +++ b/pycrc/doc/pycrc.xml @@ -0,0 +1,582 @@ + + + + + + + + + + + + + + + + + + +]> + + + + + &program_name; + &program_name; + &program_version; + + &author_firstname; + &author_surname; + Author of &program_name; and this manual page. + &author_email; + + &date; + + + + &program_name; + 1 + + + + &program_name; + a free, easy to use Cyclic Redundancy Check (CRC) calculator and source code generator. + + + + + &program_name; + OPTIONS + + + + Description + + &program_name; + provides a parametrised CRC reference implementation written in Python and a source code generator for C. + The generated C source code can be optimised for simplicity, speed or tight memory constraints for embedded platforms. + + The following operations are implemented: + + + + generate the checksum of a string (ASCII or hex) + + + + + generate the checksum of a file + + + + + generate the C header and source files for a client implementation. + + + + + + The following variants of the CRC algorithm are supported: + + + + &bit-by-bit;: the basic algorithm which operates individually on every bit of the augmented message + (i.e. the input data with &width; 0-bits attached to the end). + This algorithm is the easiest to understand because it is a straightforward implementation of the basic polynomial division, + but it is also the slowest among all possible variants. + + + + + &bit-by-bit-fast;: a variation of the simple &bit-by-bit; algorithm, + with the difference that it does not need to augment the data, i.e. it does not add &width; zero + bits at the end of the message. + This algorithm might be a good choice for embedded platforms, where code space is a major concern. + + + + + &table-driven;: the standard table driven algorithm. + This is the fastest variant because it operates on one byte at a time, as opposed to bits, and uses a look-up table of 256 elements, + which might not be feasible for small embedded systems, though. Anyway, the number of elements in the look-up table can be reduced by + means of the command line switch. By using 4 bits (16 elements in the look-up table) a significant + speed-up can be measured with respect to the bit-by-bit algorithms. + + + + + + + Options + + + + + + + show program's version number and exit + + + + + + + + + + + show this help message and exit + + + + + + + + be more verbose; in particular, print the value of the parameters and the chosen model + + + + + STRING + + + calculate the checksum of the given string ('123456789' default) + + + + + STRING + + + calculate the checksum of the given hexadecimal string + + + + + FILE + + + calculate the checksum of the given file + + + + + CODE + + + generate the source code type as a choice from {c, h, c-main, table} + + + + + STD + + + C standard style of the generated code from {C89, ANSI, C99} + + + + + ALGO + + + choose an algorithm from {bit-by-bit, bit-by-bit-fast, + table-driven, all} + + + + + MODEL + + + choose a parameter set from + {crc-5, + crc-8, + dallas-1-wire, + crc-12-3gpp, + crc-15, + crc-16, + crc-16-usb, + crc-16-modbus, + crc-16-genibus, + ccitt, + r-crc-16, + kermit, + x-25, + xmodem, + zmodem, + crc-24, + crc-32, + crc-32c, + crc-32-mpeg, + crc-32-bzip2, + posix, + jam, + xfer, + crc-64, + crc-64-jones, + crc-64-xz} + + + + + NUM + + + use NUM bits in the &poly; + + + + + HEX + + + use HEX as &poly; + + + + + BOOL + + + reflect input bytes + + + + + HEX + + + use HEX as initial value + + + + + BOOL + + + reflect output bytes + + + + + HEX + + + xor the final CRC value with HEX + + + + + NUM + + + use NUM bits to index the CRC table; NUM must be one of the values + {1, 2, 4, 8} + + + + + STRING + + + when generating source code, use STRING as prefix to the generated symbols + + + + + STRING + + + when generating source code, use STRING as crc_t type + + + + + FILE + + + when generating source code, include also FILE as header file + + + + + FILE + + + FILE + + + write the generated code to FILE instead to stdout + + + + + + The CRC Parametric Model + + The parametric model follows Ross N. Williams' convention described in + A Painless Guide to CRC Error Detection Algorithms, + commonly called the Rocksoft Model. + Since most people are familiar with this kind of parameters, &program_name; follows this convention, described as follows: + + + &width; + + + The width of the CRC &poly;, in number of bits. This is also the width of the final CRC result. + Previous versions of &program_name; only multiples of 8 could be be used as &width; for the + &table-driven; algorithm. As of version 0.7.5, any &width; is accepted + on all algorithms. + + + + + &poly; + + + The unreflected polynomial of the CRC algorithm. + + + The &poly; may be specified in its standard form, i.e. with bit &width;+1 + set to 1, but the most significant bit may also be omitted. For example, for a &width; of 16, + both forms 0x18005 and 0x8005 are accepted. + + + + + &reflect_in; + + + Reflect the bytes of the message before processing them. A word is reflected by inverting the position of its bits with + respect to the middle axis of the word. + The reversed value of 0xa3 (10100010b) is 0x45 (01000101b), for example. + Some CRC algorithms can be implemented more efficiently in a bit reversed version. + + + Reflected algorithms are more efficient than straight-forward implementations, thus many of the standard algorithmic + variants use reflected input bytes. + + + + + &xor_in; + + + The initial value (usually all 0 or all 1) in the algorithms which operate on the non-augmented message. + This value can be seen as a value which will be XOR-ed into the CRC register after &width; + iterations of the &bit-by-bit; algorithm. + This means the simple &bit-by-bit; algorithm must calculate the initial value using some sort of + reverse CRC algorithm on the &xor_in; value. + + + + + &reflect_out; + + + Reflect the final CRC result. This operation takes place before XOR-ing the final CRC + value with the &xor_out; parameter. + + + + + &xor_out; + + + A value (usually all bits 0 or all 1) which will be XOR-ed to the final CRC value. + + + + + + + + This value is not exactly a parameter of a model but it is sometimes given together with the Rocksoft Model parameters. + It is the CRC value of the parametrised model over the string "123456789" and + may be used to validate an implementation. + + + + + + + + Code generation + + In the default configuration, the generated code is strict ISO C99 code. + A minimal set of three functions are defined for each algorithm: + crc_init(), crc_update() and crc_finalize(). + According to the number of parameters given to &program_name;, a different interface definition is generated. + Fully parametrised models have a simpler API, while the generated code for runtime-specified implementations adds a + pointer to a configuration structure as first parameter to all functions. + + + The generated source code uses the type crc_t, which is used throughout the code. It may be redefined in the generated header file. + + + Fully parametrised models + + The prototypes of these functions are normally generated by &program_name; using the --generate h option. + The prototypes of the + + + +#include <stdlib.h> +/* &program_name; will define the appropriate type + * when generating the header file. */ +typedef XXXX crc_t; + + + + crc_t crc_init + + + + + + crc_t crc_update + crc_t crc + const unsigned char *data + size_t data_len + + + + + crc_t crc_finalize + crc_t crc + + + + + The following code snippet shows how to use the generated functions. + +#include "&program_name;_generated_crc.h" +#include <stdio.h> + +int main(void) +{ + static const unsigned char str1[] = "1234"; + static const unsigned char str2[] = "56789"; + crc_t crc; + + crc = crc_init(); + crc = crc_update(crc, str1, sizeof(str1) - 1); + crc = crc_update(crc, str2, sizeof(str2) - 1); + // more calls to crc_update... + crc = crc_finalize(crc); + + printf("0x%lx\n", (long)crc); + return 0; +} + + + + + Models with runtime-configurable parameters + + When the model is not fully defined then the missing parameters are contained in a structure of + type crc_cfg_t. + The first argument of the CRC functions is a pointer to that structure, and its fields must be initialised + properly by the user before the first call to the CRC functions. + This structure contains three additional parameters, msb_mask, crc_mask + and crc_shift, if the &width; was undefined when the code was generated. + +typedef struct { + unsigned int width; + crc_t poly; + bool reflect_in; + crc_t xor_in; + bool reflect_out; + crc_t xor_out; + + // internal parameters + crc_t msb_mask; // initialise as 1UL << (cfg->width - 1) + crc_t crc_mask; // initialise as (cfg->msb_mask - 1) | cfg->msb_mask + unsigned int crc_shift; // initialise as cfg->width < 8 ? 8 - cfg->width : 0 +} crc_cfg_t; + + + + msb_mask is a bitmask with the most significant bit of a &width; bits + wide data type set to 1. + crc_mask is a bitmask with all bits of a &width; bits + wide data type set to 1. + crc_shift is a shift counter that is used when &width; is less than 8. + It is the number of bits to shift the CRC register to align its top bit at a byte boundary. + + + + The file test/main.c in the source package of &program_name; contains a fully featured example + of how to use the generated source code. + A shorter, more compact main() function can be generated with the --generate c-main + option. + This second variant is the better option when some of the CRC parameters are known and some are unknown during code generation. + + + + + Examples + + + + Calculate the CRC-32 checksum of the string 123456789: + + + python pycrc.py --model crc-32 --check-string 123456789 + + + + + Generate the source code of the table-driven algorithm for an embedded application. + + + python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate h -o crc.h + + + python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c -o crc.c + + + The table index width of 4 bits ensures a moderate memory consumption. + In fact, the size of the resulting table is 16 * sizeof(crc_t) bytes. + A variant of the last generated output is the c-main target: + a simple main() function is generated in addition to the CRC routines: + + + python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c-main -o crc.c + + + + + Generate the CRC table only: + + + python pycrc.py --model kermit --generate table -o crc-table.txt + + + + + + + + See Also + + The homepage of &program_name; is http://www.tty1.net/pycrc/. + + + For a long list of known CRC models, see Greg Cook's Catalogue of Parameterised CRC Algorithms. + + + + Copyright + + This work is licensed under a + Creative Commons Attribution-Share Alike 3.0 Unported License. + + + + + diff --git a/pycrc/pycrc.py b/pycrc/pycrc.py new file mode 100644 index 0000000..b5354da --- /dev/null +++ b/pycrc/pycrc.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python +# -*- coding: Latin-1 -*- + +# pycrc -- parametrisable CRC calculation utility and C source code generator +# +# Copyright (c) 2006-2012 Thomas Pircher +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + + +""" +pycrc is a fully parametrisable Cyclic Redundancy Check (CRC) calculation +utility and C source code generator written in Python. + +It can: + - generate the checksum of a string + - generate the checksum of a file + - generate the C header file and source of any of the algorithms below + +It supports the following CRC algorithms: + - bit-by-bit the basic algorithm which operates bit by bit on the + augmented message + - bit-by-bit-fast a variation of the simple bit-by-bit algorithm + - table-driven the standard table driven algorithm +""" + +from crc_opt import Options +from crc_algorithms import Crc +from crc_parser import MacroParser +import binascii +import sys + + +# function print_parameters +############################################################################### +def print_parameters(opt): + """ + Generate a string with the options pretty-printed (used in the --verbose mode). + """ + in_str = "" + in_str += "Width = $crc_width\n" + in_str += "Poly = $crc_poly\n" + in_str += "ReflectIn = $crc_reflect_in\n" + in_str += "XorIn = $crc_xor_in\n" + in_str += "ReflectOut = $crc_reflect_out\n" + in_str += "XorOut = $crc_xor_out\n" + in_str += "Algorithm = $crc_algorithm\n" + + mp = MacroParser(opt) + mp.parse(in_str) + return mp.out_str + + +# function check_string +############################################################################### +def check_string(opt): + """ + Return the calculated CRC sum of a string. + """ + error = False + if opt.UndefinedCrcParameters: + sys.stderr.write("%s: error: undefined parameters\n" % sys.argv[0]) + sys.exit(1) + if opt.Algorithm == 0: + opt.Algorithm = opt.Algo_Bit_by_Bit | opt.Algo_Bit_by_Bit_Fast | opt.Algo_Table_Driven + + alg = Crc(width = opt.Width, poly = opt.Poly, + reflect_in = opt.ReflectIn, xor_in = opt.XorIn, + reflect_out = opt.ReflectOut, xor_out = opt.XorOut, + table_idx_width = opt.TableIdxWidth) + crc = None + if opt.Algorithm & opt.Algo_Bit_by_Bit: + bbb_crc = alg.bit_by_bit(opt.CheckString) + if crc != None and bbb_crc != crc: + error = True + crc = bbb_crc + if opt.Algorithm & opt.Algo_Bit_by_Bit_Fast: + bbf_crc = alg.bit_by_bit_fast(opt.CheckString) + if crc != None and bbf_crc != crc: + error = True + crc = bbf_crc + if opt.Algorithm & opt.Algo_Table_Driven: + opt.TableIdxWidth = 8 # no point making the python implementation slower by using less than 8 bits as index. + tbl_crc = alg.table_driven(opt.CheckString) + if crc != None and tbl_crc != crc: + error = True + crc = tbl_crc + + if error: + sys.stderr.write("%s: error: different checksums!\n" % sys.argv[0]) + if opt.Algorithm & opt.Algo_Bit_by_Bit: + sys.stderr.write(" bit-by-bit: 0x%x\n" % bbb_crc) + if opt.Algorithm & opt.Algo_Bit_by_Bit_Fast: + sys.stderr.write(" bit-by-bit-fast: 0x%x\n" % bbf_crc) + if opt.Algorithm & opt.Algo_Table_Driven: + sys.stderr.write(" table_driven: 0x%x\n" % tbl_crc) + sys.exit(1) + return crc + + +# function check_hexstring +############################################################################### +def check_hexstring(opt): + """ + Return the calculated CRC sum of a hex string. + """ + if opt.UndefinedCrcParameters: + sys.stderr.write("%s: error: undefined parameters\n" % sys.argv[0]) + sys.exit(1) + if len(opt.CheckString) % 2 != 0: + opt.CheckString = "0" + opt.CheckString + try: + check_str = binascii.unhexlify(opt.CheckString) + except TypeError: + sys.stderr.write("%s: error: invalid hex string %s\n" % (sys.argv[0], opt.CheckString)) + sys.exit(1) + + opt.CheckString = check_str + return check_string(opt) + + +# function crc_file_update +############################################################################### +def crc_file_update(alg, register, check_str): + """ + Update the CRC using the bit-by-bit-fast CRC algorithm. + """ + for i in range(len(check_str)): + octet = ord(check_str[i]) + if alg.ReflectIn: + octet = alg.reflect(octet, 8) + for j in range(8): + bit = register & alg.MSB_Mask + register <<= 1 + if octet & (0x80 >> j): + bit ^= alg.MSB_Mask + if bit: + register ^= alg.Poly + register &= alg.Mask + return register + + +# function check_file +############################################################################### +def check_file(opt): + """ + Calculate the CRC of a file. + This algorithm uses the table_driven CRC algorithm. + """ + if opt.UndefinedCrcParameters: + sys.stderr.write("%s: error: undefined parameters\n" % sys.argv[0]) + sys.exit(1) + alg = Crc(width = opt.Width, poly = opt.Poly, + reflect_in = opt.ReflectIn, xor_in = opt.XorIn, + reflect_out = opt.ReflectOut, xor_out = opt.XorOut, + table_idx_width = opt.TableIdxWidth) + + try: + in_file = open(opt.CheckFile, 'rb') + except IOError: + sys.stderr.write("%s: error: can't open file %s\n" % (sys.argv[0], opt.CheckFile)) + sys.exit(1) + + if not opt.ReflectIn: + register = opt.XorIn + else: + register = alg.reflect(opt.XorIn, opt.Width) + try: + check_str = in_file.read() + except IOError: + sys.stderr.write("%s: error: can't open read %s\n" % (sys.argv[0], opt.CheckFile)) + sys.exit(1) + while len(check_str): + register = crc_file_update(alg, register, check_str) + try: + check_str = in_file.read() + except IOError: + sys.stderr.write("%s: error: can't open read %s\n" % (sys.argv[0], opt.CheckFile)) + sys.exit(1) + in_file.close() + + if opt.ReflectOut: + register = alg.reflect(register, opt.Width) + register = register ^ opt.XorOut + return register + + +# main function +############################################################################### +def main(): + """ + Main function. + """ + opt = Options() + opt.parse(sys.argv[1:]) + if opt.Verbose: + print(print_parameters(opt)) + if opt.Action == opt.Action_Check_String: + crc = check_string(opt) + print("0x%x" % crc) + if opt.Action == opt.Action_Check_Hex_String: + crc = check_hexstring(opt) + print("0x%x" % crc) + if opt.Action == opt.Action_Check_File: + crc = check_file(opt) + print("0x%x" % crc) + if opt.Action == opt.Action_Generate_H or opt.Action == opt.Action_Generate_C or opt.Action == opt.Action_Generate_C_Main or opt.Action == opt.Action_Generate_Table: + mp = MacroParser(opt) + if opt.Action == opt.Action_Generate_H: + in_str = "$h_template" + elif opt.Action == opt.Action_Generate_C: + in_str = "$c_template" + elif opt.Action == opt.Action_Generate_C_Main: + in_str = "$c_template\n\n$main_template" + elif opt.Action == opt.Action_Generate_Table: + in_str = "$crc_table_init" + else: + sys.stderr.write("%s: error: unknown action. Please file a bug report!\n" % sys.argv[0]) + sys.exit(1) + mp.parse(in_str) + if opt.OutputFile == None: + print(mp.out_str) + else: + try: + out_file = open(opt.OutputFile, "w") + out_file.write(mp.out_str) + out_file.close() + except IOError: + sys.stderr.write("%s: error: cannot write to file %s\n" % (sys.argv[0], opt.OutputFile)) + sys.exit(1) + return 0 + + +# program entry point +############################################################################### +if __name__ == "__main__": + sys.exit(main()) diff --git a/pycrc/pycrc.pyc b/pycrc/pycrc.pyc new file mode 100644 index 0000000..744f9d9 Binary files /dev/null and b/pycrc/pycrc.pyc differ diff --git a/pycrc/test/main.c b/pycrc/test/main.c new file mode 100644 index 0000000..a752dba --- /dev/null +++ b/pycrc/test/main.c @@ -0,0 +1,283 @@ +// Copyright (c) 2006-2010 Thomas Pircher +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "crc.h" +#include +#include +#include +#include +#include +#include + +static bool atob(const char *str); +static crc_t xtoi(const char *str); +static int get_config(int argc, char *argv[], crc_cfg_t *cfg); +#if CRC_ALGO_BIT_BY_BIT +static crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc); +static crc_t crc_reflect(crc_t data, size_t data_len); +#endif + + + +static bool verbose = false; +static unsigned char str[256] = "123456789"; + +bool atob(const char *str) +{ + if (!str) { + return 0; + } + if (isdigit(str[0])) { + return (bool)atoi(str); + } + if (tolower(str[0]) == 't') { + return true; + } + return false; +} + +crc_t xtoi(const char *str) +{ + crc_t ret = 0; + + if (!str) { + return 0; + } + if (str[0] == '0' && tolower(str[1]) == 'x') { + str += 2; + while (*str) { + if (isdigit(*str)) + ret = 16 * ret + *str - '0'; + else if (isxdigit(*str)) + ret = 16 * ret + tolower(*str) - 'a' + 10; + else + return ret; + str++; + } + } else if (isdigit(*str)) { + while (*str) { + if (isdigit(*str)) + ret = 10 * ret + *str - '0'; + else + return ret; + str++; + } + } + return ret; +} + + +int get_config(int argc, char *argv[], crc_cfg_t *cfg) +{ + int c; + int option_index; + static struct option long_options[] = { + {"width", 1, 0, 'w'}, + {"poly", 1, 0, 'p'}, + {"reflect-in", 1, 0, 'n'}, + {"xor-in", 1, 0, 'i'}, + {"reflect-out", 1, 0, 'u'}, + {"xor-out", 1, 0, 'o'}, + {"verbose", 0, 0, 'v'}, + {"check-string", 1, 0, 's'}, + {"table-idx-with", 1, 0, 't'}, + {0, 0, 0, 0} + }; + + while (1) { + option_index = 0; + + c = getopt_long (argc, argv, "w:p:ni:uo:v", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + case 'w': + cfg->width = atoi(optarg); + break; + case 'p': + cfg->poly = xtoi(optarg); + break; + case 'n': + cfg->reflect_in = atob(optarg); + break; + case 'i': + cfg->xor_in = xtoi(optarg); + break; + case 'u': + cfg->reflect_out = atob(optarg); + break; + case 'o': + cfg->xor_out = xtoi(optarg); + break; + case 's': + memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str)); + str[sizeof(str) - 1] = '\0'; + break; + case 'v': + verbose = true; + break; + case 't': + // ignore --table_idx_width option + break; + case '?': + return -1; + case ':': + fprintf(stderr, "missing argument to option %c\n", c); + return -1; + default: + fprintf(stderr, "unhandled option %c\n", c); + return -1; + } + } + cfg->msb_mask = 1UL << (cfg->width - 1); + cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask; + cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0; + + cfg->poly &= cfg->crc_mask; + cfg->xor_in &= cfg->crc_mask; + cfg->xor_out &= cfg->crc_mask; + return 0; +} + + +#if CRC_ALGO_BIT_BY_BIT +crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc) +{ + crc_t result; + unsigned char data; + unsigned int i; + + // don't verify if the width is not a multiple of 8 + if (cfg->width % 8) { + return 0; + } + if (cfg->xor_out) { + crc ^= cfg->xor_out; + } + if (cfg->reflect_out) { + crc = crc_reflect(crc, cfg->width); + } + result = crc_pre_final; + for (i = 0; i < cfg->width / 8; i++) { + data = (crc >> (cfg->width - 8 * i - 8)) & 0xff; + if (cfg->reflect_in) { + data = crc_reflect(data, 8); + } + result = crc_update(cfg, result, &data, 1); + } + // no crc_finalize, because if the CRC calculation is correct, result == 0. + // A crc_finalize would XOR-in again some ones into the solution. + // In theory the finalize function of the bit-by-bit algorithm + // would also loop over cfg->width zero bits, but since + // a) result == 0, and + // b) input data == 0 + // the output would always be zero + return result; +} + +crc_t crc_reflect(crc_t data, size_t data_len) +{ + unsigned int i; + crc_t ret; + + ret = 0; + for (i = 0; i < data_len; i++) + { + if (data & 0x01) { + ret = (ret << 1) | 1; + } else { + ret = ret << 1; + } + data >>= 1; + } + return ret; +} +#endif // CRC_ALGO_BIT_BY_BIT + + +int main(int argc, char *argv[]) +{ + crc_cfg_t cfg = { + 0, // width + 0, // poly + 0, // xor_in + 0, // reflect_in + 0, // xor_out + 0, // reflect_out + + 0, // crc_mask + 0, // msb_mask + 0, // crc_shift + }; + crc_t crc; + crc_t crc_test, crc_pre_final; + char format[20]; + int ret, i; + + ret = get_config(argc, argv, &cfg); + if (ret == 0) { +# if CRC_ALGO_TABLE_DRIVEN + crc_table_gen(&cfg); +# endif // CRC_ALGO_TABLE_DRIVEN + crc = crc_init(&cfg); + crc = crc_pre_final = crc_update(&cfg, crc, str, strlen((char *)str)); + crc = crc_finalize(&cfg, crc); + +# if CRC_ALGO_BIT_BY_BIT + if (crc_verify(&cfg, crc_pre_final, crc) != 0) { + fprintf(stderr, "error: crc verification failed\n"); + return 1; + } +# endif + + // calculate the checksum again, but this time loop over the input + // bytes one-by-one. + crc_test = crc_init(&cfg); + for (i = 0; str[i]; i++) + { + crc_test = crc_update(&cfg, crc_test, str + i, 1); + } + crc_test = crc_finalize(&cfg, crc_test); + if (crc_test != crc) { + fprintf(stderr, "error: crc loop verification failed\n"); + return 1; + } + + if (verbose) { + snprintf(format, sizeof(format), "%%-16s = 0x%%0%dx\n", (unsigned int)(cfg.width + 3) / 4); + printf("%-16s = %d\n", "width", (unsigned int)cfg.width); + printf(format, "poly", (unsigned int)cfg.poly); + printf("%-16s = %s\n", "reflect_in", cfg.reflect_in ? "true": "false"); + printf(format, "xor_in", cfg.xor_in); + printf("%-16s = %s\n", "reflect_out", cfg.reflect_out ? "true": "false"); + printf(format, "xor_out", (unsigned int)cfg.xor_out); + printf(format, "crc_mask", (unsigned int)cfg.crc_mask); + printf(format, "msb_mask", (unsigned int)cfg.msb_mask); + } + printf("0x%lx\n", (unsigned long)crc); + } + return !ret; +} diff --git a/pycrc/test/performance.sh b/pycrc/test/performance.sh new file mode 100644 index 0000000..25c70a4 --- /dev/null +++ b/pycrc/test/performance.sh @@ -0,0 +1,152 @@ +#!/bin/bash +set -e + +PYCRC=`dirname $0`/../pycrc.py + +function cleanup { + rm -f a.out performance.c crc_bbb.[ch] crc_bbf.[ch] crc_tbl.[ch] crc_tb4.[ch] +} + +trap cleanup 0 1 2 3 15 + + +prefix=bbb +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit +prefix=bbf +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit-fast +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit-fast +prefix=tbl +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven +prefix=tb4 +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --table-idx-width 4 +$PYCRC --model crc-32 --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --table-idx-width 4 + + +function print_main { +cat < +#include +#include +#include +#include +#include + +#define NUM_RUNS (256*256) + +unsigned char buf[1024]; + +void test_bbb(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); +void test_bbf(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); +void test_tbl(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); +void test_tb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); + +/** + * Print results. + * + * \param dsc Description of the test + * \param crc Resulting CRC + * \param buflen Length of one buffer + * \param num_runs Number of runs over that buffer + * \param t_user user time + * \param t_sys system time + * \return void + *****************************************************************************/ +void show_times(const char *dsc, unsigned int crc, size_t buflen, size_t num_runs, double t_user, double t_sys) +{ + printf("%s of %ld bytes (%ld * %ld): 0x%08x\n", dsc, (long)buflen*num_runs, (long)buflen, (long)num_runs, crc); + printf("%13s: %7.3f s\n", "user time", t_user); + printf("%13s: %7.3f s\n", "system time", t_sys); + printf("\n"); +} + + +/** + * C main function. + * + * \retval 0 on success + * \retval 1 on failure + *****************************************************************************/ +int main(void) +{ + unsigned int i; + long int clock_per_sec; + + for (i = 0; i < sizeof(buf); i++) { + buf[i] = (unsigned char)rand(); + } + clock_per_sec = sysconf(_SC_CLK_TCK); + + // bit-by-bit + test_bbb(buf, sizeof(buf), NUM_RUNS, clock_per_sec); + + // bit-by-bit-fast + test_bbf(buf, sizeof(buf), NUM_RUNS, clock_per_sec); + + // table-driven + test_tbl(buf, sizeof(buf), NUM_RUNS, clock_per_sec); + + // table-driven idx4 + test_tb4(buf, sizeof(buf), NUM_RUNS, clock_per_sec); + + return 0; +} +EOF +} + +function print_routine { + algo=$1 + prefix=$2 + cat < performance.c +print_routine "bit-by-bit" bbb >> performance.c +print_routine "bit-by-bit-fast" bbf >> performance.c +print_routine "table-driven" tbl >> performance.c +print_routine "table-driven idx4" tb4 >> performance.c + +gcc -W -Wall -O3 crc_bbb.c crc_bbf.c crc_tbl.c crc_tb4.c performance.c +./a.out diff --git a/pycrc/test/test.sh b/pycrc/test/test.sh new file mode 100644 index 0000000..def5442 --- /dev/null +++ b/pycrc/test/test.sh @@ -0,0 +1,473 @@ +#!/bin/bash +set -e + +PYCRC=`dirname $0`/../pycrc.py + +usage() { + echo >&2 "usage: $0 [OPTIONS]" + echo >&2 "" + echo >&2 "with OPTIONS in" + echo >&2 " -c test compiled version" + echo >&2 " -n test compiled version with fixed parameters" + echo >&2 " -f test file" + echo >&2 " -r test random parameters" + echo >&2 " -p test compiled C program with random arguments" + echo >&2 " -w test variable width from 1 to 64" + echo >&2 " -a do all tests" +} + + +crc_std_test=on +crc_compiled_test=off +crc_compile_noparam_test=off +crc_file_test=off +crc_random_loop_test=off +crc_args_compile_test=off +crc_variable_width_test=off +crc_all_tests=off + +while getopts cnfrpwah opt; do + case "$opt" in + c) crc_compiled_test=on;; + n) crc_compile_noparam_test=on;; + f) crc_file_test=on;; + r) crc_random_loop_test=on;; + p) crc_args_compile_test=on;; + w) crc_variable_width_test=on;; + a) crc_all_tests=on;; + h) usage + exit 0 + ;; + \?) usage # unknown flag + exit 1 + ;; + esac +done +shift `expr $OPTIND - 1` + + +cleanup() { + rm -f crc.c crc.h a.out crc-bb crc-bf crc-td2 crc-td4 crc-td8 file.txt +} + +trap cleanup 0 1 2 3 15 + + +testres() { + testres_lcmd="$1" + testres_lres="$2" + testres_lres=`echo $testres_lres | sed -e 's/.*0x0*\([0-9a-fA-F][0-9a-fA-F]*\).*/\1/'` + testres_lclc=`$testres_lcmd | sed -e '$!d; s/.*0x0*\([0-9a-fA-F][0-9a-fA-F]*\).*/\1/'` + if [ "$testres_lclc" != "$testres_lres" ]; then + echo >&2 test failed: $testres_lcmd + echo >&2 got $testres_lclc instead of expected $testres_lres + return 1 + fi +} + + +teststr() { + teststr_lopt="$1 --check-string 123456789" + teststr_lres="$2" + testres "$teststr_lopt" "$teststr_lres" +} + + +compile() { + compile_lalg="$1" + compile_lopt="$2" + compile_lout="$3" + + $PYCRC --algorithm "$compile_lalg" $compile_lopt --generate h -o crc.h + ldef=`echo "$compile_lopt" | egrep -c 'width|poly|reflect|xor'` || true + if [ "$ldef" -eq 0 ]; then + $PYCRC --algorithm "$compile_lalg" $compile_lopt --generate c -o crc.c + gcc -W -Wall -pedantic -std=c99 main.c crc.c -o "$compile_lout" + else + $PYCRC --algorithm "$compile_lalg" $compile_lopt --generate c-main -o crc.c + gcc -W -Wall -pedantic -std=c99 crc.c -o "$compile_lout" + fi +} + + +testcmp() { + testcmp_lalg="$1" + testcmp_lopt="$2" + testcmp_larg="$3" + testcmp_lres="$4" + + compile "$testcmp_lalg" "$testcmp_lopt --std C89" "a.out" + testres "./a.out $testcmp_larg" "$testcmp_lres" + + compile "$testcmp_lalg" "$testcmp_lopt --std C99" "a.out" + testres "./a.out $testcmp_larg" "$testcmp_lres" +} + + +testbin() { + testbin_lopt="$1" + testbin_lres="$2" + + if [ "$crc_compiled_test" == on -o "$crc_all_tests" == on ]; then + testres "./crc-bb $testbin_lopt" "$testbin_lres" + testres "./crc-bf $testbin_lopt" "$testbin_lres" + testres "./crc-td2 $testbin_lopt" "$testbin_lres" + testres "./crc-td4 $testbin_lopt" "$testbin_lres" + testres "./crc-td8 $testbin_lopt" "$testbin_lres" + + if [ "$crc_compile_noparam_test" == on -o "$crc_all_tests" == on ]; then + testcmp bit-by-bit "$testbin_lopt" "" "$testbin_lres" + testcmp bit-by-bit-fast "$testbin_lopt" "" "$testbin_lres" + testcmp table-driven "$testbin_lopt --table-idx-width 2" "" "$testbin_lres" + testcmp table-driven "$testbin_lopt --table-idx-width 4" "" "$testbin_lres" + testcmp table-driven "$testbin_lopt --table-idx-width 8" "" "$testbin_lres" + fi + fi +} + + +testfil() { + testfil_lopt="$1 --check-file file.txt" + testfil_lres="$2" + + if [ "$crc_file_test" == on -o "$crc_all_tests" == on ]; then + testres "$testfil_lopt" "$testfil_lres" + fi +} + + +if [ "$crc_compiled_test" == on -o "$crc_all_tests" == on ]; then + compile "bit-by-bit" "" "crc-bb" + compile "bit-by-bit-fast" "" "crc-bf" + compile "table-driven" "--table-idx-width 2" "crc-td2" + compile "table-driven" "--table-idx-width 4" "crc-td4" + compile "table-driven" "--table-idx-width 8" "crc-td8" +fi +if [ ! -f file.txt ]; then + echo -n "123456789" > file.txt +fi + + +if [ "$crc_std_test" == on -o "$crc_all_tests" == on ]; then +#CRC-5 +res="0x19" +cmd="$PYCRC --model crc-5" +opt="--width 5 --poly 0x05 --reflect-in 1 --xor-in 0x1f --reflect-out 1 --xor-out 0x1f" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-8 +res="0xf4" +cmd="$PYCRC --model crc-8" +opt="--width 8 --poly 0x07 --reflect-in 0 --xor-in 0x0 --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#DALLAS-1-WIRE +res="0xa1" +cmd="$PYCRC --model dallas-1-wire" +opt="--width 8 --poly 0x31 --reflect-in 1 --xor-in 0 --reflect-out 1 --xor-out 0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#3gpp +res="0xdaf" +cmd="$PYCRC --model crc-12-3gpp" +opt="--width 12 --poly 0x80f --reflect-in 0 --xor-in 0x0 --reflect-out 1 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-15 +res="0x59e" +cmd="$PYCRC --model crc-15" +opt="--width 15 --poly 0x4599 --reflect-in 0 --xor-in 0x0 --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-16/ARC +res="0xbb3d" +cmd="$PYCRC --model crc-16" +opt="--width 16 --poly 0x8005 --reflect-in 1 --xor-in 0x0 --reflect-out 1 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-16-USB +res="0xb4c8" +cmd="$PYCRC --model crc-16-usb" +opt="--width 16 --poly 0x8005 --reflect-in 1 --xor-in 0xffff --reflect-out 1 --xor-out 0xffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-16-MODBUS +res="0x4b37" +cmd="$PYCRC --model crc-16-modbus" +opt="--width 16 --poly 0x8005 --reflect-in 1 --xor-in 0xffff --reflect-out 1 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-16-GENIBUS +res="0xd64e" +cmd="$PYCRC --model crc-16-genibus" +opt="--width 16 --poly 0x1021 --reflect-in 0 --xor-in 0xffff --reflect-out 0 --xor-out 0xffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-16/CITT +res="0x29b1" +cmd="$PYCRC --model ccitt" +opt="--width 16 --poly 0x1021 --reflect-in 0 --xor-in 0xffff --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#R-CRC-16/DECT packets A-field according to ETSI EN 300 175-3 v2.1.1 +res="0x007e" +cmd="$PYCRC --model r-crc-16" +opt="--width 16 --poly 0x0589 --reflect-in 0 --xor-in 0x0 --reflect-out 0 --xor-out 0x0001" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#kermit +res="0x2189" +cmd="$PYCRC --model kermit" +opt="--width 16 --poly 0x1021 --reflect-in 1 --xor-in 0x0 --reflect-out 1 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#X-25 +res="0x906e" +cmd="$PYCRC --model x-25" +opt="--width 16 --poly 0x1021 --reflect-in 1 --xor-in 0xffff --reflect-out 1 --xor-out 0xffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#xmodem +res="0x31c3" +cmd="$PYCRC --model xmodem" +opt="--width 16 --poly 0x1021 --reflect-in 0 --xor-in 0x0 --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#zmodem +res="0x31c3" +cmd="$PYCRC --model zmodem" +opt="--width 16 --poly 0x1021 --reflect-in 0 --xor-in 0x0 --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#crc-24 +res="0x21cf02" +cmd="$PYCRC --model crc-24" +opt="--width 24 --poly 0x1864cfb --reflect-in 0 --xor-in 0xb704ce --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-32 +res="0xcbf43926" +cmd="$PYCRC --model crc-32" +opt="--width 32 --poly 0x4c11db7 --reflect-in 1 --xor-in 0xffffffff --reflect-out 1 --xor-out 0xffffffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-32C +res="0xe3069283" +cmd="$PYCRC --model crc-32c" +opt="--width 32 --poly 0x1edc6f41 --reflect-in 1 --xor-in 0xffffffff --reflect-out 1 --xor-out 0xffffffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-32/POSIX +res="0x765e7680" +cmd="$PYCRC --model posix" +opt="--width 32 --poly 0x4c11db7 --reflect-in 0 --xor-in 0x0 --reflect-out 0 --xor-out 0xffffffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#JAMCRC +res="0x340bc6d9" +cmd="$PYCRC --model jam" +opt="--width 32 --poly 0x4c11db7 --reflect-in 1 --xor-in 0xffffffff --reflect-out 1 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-32MPEG +res="0x376e6e7" +cmd="$PYCRC --model crc-32-mpeg" +opt="--width 32 --poly 0x4c11db7 --reflect-in 0 --xor-in 0xffffffff --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-32-BZIP2 +res="0xfc891918" +cmd="$PYCRC --model crc-32-bzip2" +opt="--width 32 --poly 0x04c11db7 --reflect-in 0 --xor-in 0xffffffff --reflect-out 0 --xor-out 0xffffffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#XFER +res="0xbd0be338" +cmd="$PYCRC --model xfer" +opt="--width 32 --poly 0x000000af --reflect-in 0 --xor-in 0x0 --reflect-out 0 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-64 +res="0x46a5a9388a5beffe" +cmd="$PYCRC --model crc-64" +opt="--width 64 --poly 0x000000000000001b --reflect-in 1 --xor-in 0x0 --reflect-out 1 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-64-jones +res="0xcaa717168609f281" +cmd="$PYCRC --model crc-64-jones" +opt="--width 64 --poly 0xad93d23594c935a9 --reflect-in 1 --xor-in 0xffffffffffffffff --reflect-out 1 --xor-out 0x0" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" + +#CRC-64-zx +res="0x995dc9bbdf1939fa" +cmd="$PYCRC --model crc-64-xz" +opt="--width 64 --poly 0x42f0e1eba9ea3693 --reflect-in 1 --xor-in 0xffffffffffffffff --reflect-out 1 --xor-out 0xffffffffffffffff" +teststr "$cmd" "$res" +teststr "$PYCRC $opt" "$res" +testfil "$cmd" "$res" +testbin "$opt" "$res" +fi + + +if [ "$crc_random_loop_test" == on -o "$crc_all_tests" == on ]; then + for width in 8 16 32; do + for poly in 0x8005 0x4c11db7 0xa5a5a5a5; do + for refxx in "--reflect-in 0 --reflect-out 0" "--reflect-in 0 --reflect-out 1" "--reflect-in 1 --reflect-out 0" "--reflect-in 1 --reflect-out 1"; do + for init in 0x0 0x1 0xa5a5a5a5; do + opt="--width $width --poly $poly $refxx --xor-in $init --xor-out 0x0" + cmd="$PYCRC $opt" + res=`$cmd` || $cmd + testbin "$opt" "$res" + done + done + done + done +fi + + +if [ "$crc_args_compile_test" == on -o "$crc_all_tests" == on ]; then + #zmodem + res="0x31c3" + opt_width="--width 16" + opt_poly="--poly 0x1021" + opt_refin="--reflect-in 0" + opt_xorin="--xor-in 0x0" + opt_refout="--reflect-out 0" + opt_xorout="--xor-out 0x0" + for b_width in 0 1; do + if [ "$b_width" -eq 1 ]; then cmp_width="$opt_width"; arg_width=""; else cmp_width=""; arg_width="$opt_width"; fi + for b_poly in 0 1; do + if [ "$b_poly" -eq 1 ]; then cmp_poly="$opt_poly"; arg_poly=""; else cmp_poly=""; arg_poly="$opt_poly"; fi + for b_ref_in in 0 1; do + if [ "$b_ref_in" -eq 1 ]; then cmp_refin="$opt_refin"; arg_refin=""; else cmp_refin=""; arg_refin="$opt_refin"; fi + for b_ref_out in 0 1; do + if [ "$b_ref_out" -eq 1 ]; then cmp_refout="$opt_refout"; arg_refout=""; else cmp_refout=""; arg_refout="$opt_refout"; fi + for b_xor_in in 0 1; do + if [ "$b_xor_in" -eq 1 ]; then cmp_xorin="$opt_xorin"; arg_xorin=""; else cmp_xorin=""; arg_xorin="$opt_xorin"; fi + for b_xor_out in 0 1; do + if [ "$b_xor_out" -eq 1 ]; then cmp_xorout="$opt_xorout"; arg_xorout=""; else cmp_xorout=""; arg_xorout="$opt_xorout"; fi + + cmp_opt="$cmp_width $cmp_poly $cmp_refin $cmp_refout $cmp_xorin $cmp_xorout" + arg_opt="$arg_width $arg_poly $arg_refin $arg_refout $arg_xorin $arg_xorout" + testcmp bit-by-bit "$cmp_opt" "$arg_opt" "$res" + testcmp bit-by-bit-fast "$cmp_opt" "$arg_opt" "$res" + testcmp table-driven "$cmp_opt" "$arg_opt" "$res" + done + done + done + done + done + done +fi + + +if [ "$crc_variable_width_test" == on -o "$crc_all_tests" == on ]; then + opt_poly="--poly 0xad93d23594c935a9" + opt_refin="--reflect-in 1" + opt_xorin="--xor-in 0xffffffffffffffff" + opt_refout="--reflect-out 1" + opt_xorout="--xor-out 0x0000000000000000" + for width in 1 2 3 4 5 6 7 8 9 11 12 15 16 17 24 31 32 33 63 64; do + for b_width in 0 1; do + if [ "$b_width" -eq 1 ]; then cmp_width="--width $width"; arg_width=""; else cmp_width=""; arg_width="--width $width"; fi + for b_poly in 0 1; do + if [ "$b_poly" -eq 1 ]; then cmp_poly="$opt_poly"; arg_poly=""; else cmp_poly=""; arg_poly="$opt_poly"; fi + for b_ref_in in 0 1; do + if [ "$b_ref_in" -eq 1 ]; then cmp_refin="$opt_refin"; arg_refin=""; else cmp_refin=""; arg_refin="$opt_refin"; fi + for b_ref_out in 0 1; do + if [ "$b_ref_out" -eq 1 ]; then cmp_refout="$opt_refout"; arg_refout=""; else cmp_refout=""; arg_refout="$opt_refout"; fi + for b_xor_in in 0 1; do + if [ "$b_xor_in" -eq 1 ]; then cmp_xorin="$opt_xorin"; arg_xorin=""; else cmp_xorin=""; arg_xorin="$opt_xorin"; fi + for b_xor_out in 0 1; do + if [ "$b_xor_out" -eq 1 ]; then cmp_xorout="$opt_xorout"; arg_xorout=""; else cmp_xorout=""; arg_xorout="$opt_xorout"; fi + + cmp_opt="$cmp_width $cmp_poly $cmp_refin $cmp_refout $cmp_xorin $cmp_xorout" + arg_opt="$arg_width $arg_poly $arg_refin $arg_refout $arg_xorin $arg_xorout" + res=`$PYCRC --algorithm bit-by-bit $cmp_opt $arg_opt` + testcmp table-driven "$cmp_opt" "$arg_opt" "$res" + done + done + done + done + done + done + done +fi + +echo Test OK