Source code for chess_link_protocol


"""
Helper functions for the Chess Link protocol for character-based odd-parity and 
message-block-parity.

The chess link protocol sends ASCII messages. Each ASCII character gets an additional
odd-parity-bit. Each block of ASCII+odd-parity bytes gets an additional block parity.

Details of the Chess Link protocol are documented in `magic-board.md <https://github.com/domschl/python-mchess/blob/master/mchess/magic-board.md>`_.
"""

import logging

protocol_replies = {'v': 7, 's': 67, 'l': 3, 'x': 3, 'w': 7, 'r': 7}


[docs]def add_odd_par(b): """ The chess link protocol is 7-Bit ASCII. This adds an odd-parity-bit to an ASCII char :param b: an ASCII character (0..127) :returns: a byte (0..255) with odd parity in most significant bit. """ byte = ord(b) & 127 par = 1 for _ in range(7): bit = byte & 1 byte = byte >> 1 par = par ^ bit if par == 1: byte = ord(b) | 128 else: byte = ord(b) & 127 return byte
[docs]def hexd(digit): """ Returns a hex digit '0'..'F' for an integer 0..15 :param digit: integer 0..15 :returns: an ASCII hex character '0'..'F' """ if digit < 10: return chr(ord('0')+digit) else: return chr(ord('A')-10+digit)
[docs]def hex2(num): """ Convert integer to 2-digit hex string. Most numeric parameters and the block CRC are encoded as such 2-digit hex-string. :param num: uint_8 integer 0..255 :returns: Returns a 2-digit hex code '00'..'FF' """ d1 = num//16 d2 = num % 16 s = hexd(d1)+hexd(d2) return s
[docs]def check_block_crc(msg): """ Chess link messages consist of 7-bit-ASCII characters with odd parity. At the end of each message, an additional block-parity is added. Valid chess link messages must have correct odd parity for each character and a valid block parity at the end. :param msg: a byte array with the message. :returns: True, if the last two bytes of msg contain a correct CRC, False otherwise. """ if len(msg) > 2: gpar = 0 for b in msg[:-2]: gpar = gpar ^ ord(b) if msg[-2]+msg[-1] != hex2(gpar): logging.warning("CRC error rep={} CRCs: {}!={}".format(msg, ord(msg[-2]), hex2(gpar))) return False else: return True else: logging.warning("Message {} too short for CRC check".format(msg)) return False
[docs]def add_block_crc(msg): """Add block parity at the end of the message :param msg: a message byte array (each byte must have already been encoded with odd parity). This function adds two bytes of block CRC at the end of the message. :param msg: byte array with a message (incl. odd-parity bits set already) :return: two byte longer message that includes 2 CRC bytes. """ gpar = 0 for b in msg: gpar = gpar ^ ord(b) msg = msg+hex2(gpar) return msg