aboutsummaryrefslogtreecommitdiff
path: root/serial/tools/hexlify_codec.py
diff options
context:
space:
mode:
Diffstat (limited to 'serial/tools/hexlify_codec.py')
-rw-r--r--serial/tools/hexlify_codec.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/serial/tools/hexlify_codec.py b/serial/tools/hexlify_codec.py
new file mode 100644
index 0000000..bd8f6b0
--- /dev/null
+++ b/serial/tools/hexlify_codec.py
@@ -0,0 +1,126 @@
+#! python
+#
+# This is a codec to create and decode hexdumps with spaces between characters. used by miniterm.
+#
+# This file is part of pySerial. https://github.com/pyserial/pyserial
+# (C) 2015-2016 Chris Liechti <cliechti@gmx.net>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""\
+Python 'hex' Codec - 2-digit hex with spaces content transfer encoding.
+
+Encode and decode may be a bit missleading at first sight...
+
+The textual representation is a hex dump: e.g. "40 41"
+The "encoded" data of this is the binary form, e.g. b"@A"
+
+Therefore decoding is binary to text and thus converting binary data to hex dump.
+
+"""
+
+from __future__ import absolute_import
+
+import codecs
+import serial
+
+
+try:
+ unicode
+except (NameError, AttributeError):
+ unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name
+
+
+HEXDIGITS = '0123456789ABCDEF'
+
+
+# Codec APIs
+
+def hex_encode(data, errors='strict'):
+ """'40 41 42' -> b'@ab'"""
+ return (serial.to_bytes([int(h, 16) for h in data.split()]), len(data))
+
+
+def hex_decode(data, errors='strict'):
+ """b'@ab' -> '40 41 42'"""
+ return (unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))), len(data))
+
+
+class Codec(codecs.Codec):
+ def encode(self, data, errors='strict'):
+ """'40 41 42' -> b'@ab'"""
+ return serial.to_bytes([int(h, 16) for h in data.split()])
+
+ def decode(self, data, errors='strict'):
+ """b'@ab' -> '40 41 42'"""
+ return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data)))
+
+
+class IncrementalEncoder(codecs.IncrementalEncoder):
+ """Incremental hex encoder"""
+
+ def __init__(self, errors='strict'):
+ self.errors = errors
+ self.state = 0
+
+ def reset(self):
+ self.state = 0
+
+ def getstate(self):
+ return self.state
+
+ def setstate(self, state):
+ self.state = state
+
+ def encode(self, data, final=False):
+ """\
+ Incremental encode, keep track of digits and emit a byte when a pair
+ of hex digits is found. The space is optional unless the error
+ handling is defined to be 'strict'.
+ """
+ state = self.state
+ encoded = []
+ for c in data.upper():
+ if c in HEXDIGITS:
+ z = HEXDIGITS.index(c)
+ if state:
+ encoded.append(z + (state & 0xf0))
+ state = 0
+ else:
+ state = 0x100 + (z << 4)
+ elif c == ' ': # allow spaces to separate values
+ if state and self.errors == 'strict':
+ raise UnicodeError('odd number of hex digits')
+ state = 0
+ else:
+ if self.errors == 'strict':
+ raise UnicodeError('non-hex digit found: {!r}'.format(c))
+ self.state = state
+ return serial.to_bytes(encoded)
+
+
+class IncrementalDecoder(codecs.IncrementalDecoder):
+ """Incremental decoder"""
+ def decode(self, data, final=False):
+ return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data)))
+
+
+class StreamWriter(Codec, codecs.StreamWriter):
+ """Combination of hexlify codec and StreamWriter"""
+
+
+class StreamReader(Codec, codecs.StreamReader):
+ """Combination of hexlify codec and StreamReader"""
+
+
+def getregentry():
+ """encodings module API"""
+ return codecs.CodecInfo(
+ name='hexlify',
+ encode=hex_encode,
+ decode=hex_decode,
+ incrementalencoder=IncrementalEncoder,
+ incrementaldecoder=IncrementalDecoder,
+ streamwriter=StreamWriter,
+ streamreader=StreamReader,
+ #~ _is_text_encoding=True,
+ )