nxt.error.DirProtError: Illegal size specified

15 views
Skip to first unread message

Federico Ferri

unread,
Apr 8, 2014, 9:49:50 AM4/8/14
to nxt-p...@googlegroups.com
I'm writing the driver for HiTechnic IRLink (translating from the leJOS driver which I know it works well).
However I get the above error when sending the command.
I verified that the i2c message is identical at the byte level to the message produced by the lejos driver, so I don't know what's going on...

  File "/Users/user/nxt-python-svn/nxt/sensor/hitechnic.py", line 241, in _complete_send
    self.write_value('tx', pfCommand)
  File "/Users/user/nxt-python-svn/nxt/sensor/digital.py", line 152, in write_value
    self._i2c_command(address, value, fmt)
  File "/Users/user/nxt-python-svn/nxt/sensor/digital.py", line 104, in _i2c_command
    self.brick.ls_write(self.port, msg, 0)
  File "/Users/user/nxt-python-svn/nxt/brick.py", line 31, in poll
    return parse_func(igram)
  File "/Users/user/nxt-python-svn/nxt/direct.py", line 28, in _parse_simple
    tgram.check_status()
  File "/Users/user/nxt-python-svn/nxt/telegram.py", line 114, in check_status
    nxt.error.check_status(self.parse_u8())
  File "/Users/user/nxt-python-svn/nxt/error.py", line 85, in check_status
    raise ex
nxt.error.DirProtError: Illegal size specified


class IRLink(BaseDigitalSensor):
    """Object for HiTechnic IRLink sensor for use with LEGO Power Functions IR
Receivers."""
    I2C_ADDRESS = BaseDigitalSensor.I2C_ADDRESS.copy()
    I2C_ADDRESS.update({
        'tx_buf': (0x45, '10B'),
        'tx_len': (0x4D, 'B'),
        'tx_mode': (0x4E, 'B'),
        'tx_trigger': (0x4F, 'B'),
        'tx': (0x40, '16B'),
    })

    class TXMode(object):
        def __init__(self, code):
            self.code = code

    TXMODE_PF = TXMode(0x02) # used for LEGO PowerFunctions
    TXMODE_UART = TXMode(0x00) # will transmit 8 bytes at time at 2400 baud using a 38kHz carrier frequency (also used for RCX)

    # PF Receiver channel selection
    PF_CHANNEL_1 = 0
    PF_CHANNEL_2 = 1
    PF_CHANNEL_3 = 2
    PF_CHANNEL_4 = 3

    # PF Modes
    ESC_MODE_SELECT = 0
    ESC_PWM = 1
    PF_MODE_EXTENDED = 0
    PF_MODECOMBO_DIRECT = 1

    # PF PWM motor operations for various modes
    PF_PWM_FLOAT = 0
    PF_PWM_FWD_1 = 1
    PF_PWM_FWD_2 = 2
    PF_PWM_FWD_3 = 3
    PF_PWM_FWD_4 = 4
    PF_PWM_FWD_5 = 5
    PF_PWM_FWD_6 = 6
    PF_PWM_FWD_7 = 7
    PF_PWM_BRK_FLT = 8
    PF_PWM_REV_7 = 9
    PF_PWM_REV_6 = 10
    PF_PWM_REV_5 = 11
    PF_PWM_REV_4 = 12
    PF_PWM_REV_3 = 13
    PF_PWM_REV_2 = 14
    PF_PWM_REV_1 = 15

    # PF Combo Direct motor operations
    PF_COMBO_DIRECT_FLOAT = 0
    PF_COMBO_DIRECT_FORWARD = 1
    PF_COMBO_DIRECT_BACKWARD = 2
    PF_COMBO_DIRECT_BRAKE_FLOAT = 3

    # PF Extended mode motor operations
    PF_EXTENDED_BRAKE_FLOAT = 0
    PF_EXTENDED_INC_SPEED_A = 1
    PF_EXTENDED_DEC_SPEED_A = 2
    PF_EXTENDED_TOGGLE_FWD_FLT_B = 4

    # PF Single Mode PWM & CST motor selection
    PF_SINGLE_MODE_RED_PORT = 0
    PF_SINGLE_MODE_BLUE_PORT = 1

    # PF PWM motor operations for various modes
    PF_CST_TOGGLE_FULL_FW = 0
    PF_CST_TOGGLE_DIR = 1
    PF_CST_INC_PWM_NUM = 2
    PF_CST_DEC_PWM_NUM = 3
    PF_CST_INC_PWM = 4
    PF_CST_DEC_PWM = 5
    PF_CST_FULL_FW = 6
    PF_CST_FULL_BW = 7
    PF_CST_TOGGLE_FULL_FW_BW = 8
    PF_CST_CLR_C1 = 9
    PF_CST_SET_C1 = 10
    PF_CST_TOGGLE_C1 = 11
    PF_CST_CLR_C2 = 12
    PF_CST_SET_C2 = 13
    PF_CST_TOGGLE_C2 = 14
    PF_CST_TOGGLE_FL_BW = 15

    def __init__(self, brick, port, check_compatible=True):
        super(IRLink, self).__init__(brick, port, check_compatible)
        self._toggle = 0

    def _uart_send(self, data):
        if len(data) != 8 or any(x < 0 or x > 255 for x in data):
            raise ValueError, 'data must be exactly 8 unsigned bytes'
        self.write_value('tx_buf', data + [len(data), self.TXMODE_UART.code])

    def _complete_send(self, pfData):
        bits = []

        # start bit:
        bits += [True] + [False] * 7

        for i in reversed(range(16)):
            if ((pfData >> i) & 1) == 0:
                # 0 is encoded as 100
                bits += [True, False, False]
            else:
                # 1 is encoded as 10000
                bits += [True, False, False, False, False]

        # stop bit:
        bits += [True]

        self._toggle ^= 1

        byteIndex = 0
        pfCommand = [0] * 16
        while bits:
            for i, bitVal in enumerate(bits[0:8]):
                pfCommand[byteIndex] |= int(bitVal) << (7 - i)
            bits = bits[8:]
            byteIndex += 1
        pfCommand[13] = 13
        pfCommand[14] = self.TXMODE_PF.code
        pfCommand[15] = 1
        print('about to send command %s' % pfCommand)
        self.write_value('tx', pfCommand)

    def send_combo_pwm(self, channel, opA, opB):
        """Send commands to both motors. Uses PF Combo PWM mode.
        Params:    
            channel:  the channel number (0-3)
            opA:      Motor A operation RED
            opB:      Motor B operation BLUE
        """
        nibble1 = ((0 << 3) | (self.ESC_PWM << 2) | channel) & 0xF # 0 is a place holder for a (address) for future use
        nibble2 = opB & 0xF
        nibble3 = opA & 0xF
        lrc = (0xF ^ nibble1 ^ nibble2 ^ nibble3) & 0xF
        pfData = (nibble1 << 12) | (nibble2 << 8) | (nibble3 << 4) | lrc;
        self._complete_send(pfData)

    def send_combo_direct(self, channel, opA, opB):
        """Send commands to both motors. Uses PF Combo DIRECT mode.
        Params:
            channel:  the channel number (0-3)
            opA:      Motor A operation RED
            opB:      Motor B operation BLUE
        """
        nibble1 = ((self._toggle << 3) | (self.ESC_MODE_SELECT << 2) | channel) & 0xF
        nibble2 = ((0 << 3) | self.PF_MODECOMBO_DIRECT) & 0xF # 0 is a place holder for a (address) for future use
        nibble3 = (opB << 2 | opA) & 0xF
        lrc = (0xF ^ nibble1 ^ nibble2 ^ nibble3) & 0xF
        pfData = (nibble1 << 12) | (nibble2 << 8) | (nibble3 << 4) | lrc
        self._complete_send(pfData)

    def send_extended(self, channel, opA):
        """Send commands to both motors. Uses PF Extended mode.
        Params:
            channel:  the channel number (0-3)
            opA:      Refer to action list
        """
        nibble1 = ((self._toggle << 3) | (self.ESC_MODE_SELECT << 2) | channel) & 0xF
        nibble2 = ((0 << 3) | self.PF_MODE_EXTENDED) & 0xF # 0 is a place holder for a (address) for future use
        nibble3 = opA & 0xF
        lrc = (0xF ^ nibble1 ^ nibble2 ^ nibble3) & 0xF
        pfData = (nibble1 << 12) | (nibble2 << 8) | (nibble3 << 4) | lrc;
        self._complete_send(pfData)

    def send_single_mode_pwm(self, channel, opA, opB):
        """Send commands to a single motors. Uses PF Single mode PWM.
        Params:
            channel:  the channel number (0-3)
            opA:      Motor selection Red/Blue port
            opB:      Use PF_PWM operation codes
        """
        # opA = output RED or BlUE, opB command code
        nibble1 = ((self._toggle << 3) | (self.ESC_MODE_SELECT << 2) | channel) & 0xF
        nibble2 = ((0 << 3) | (1 << 2) | (0 << 1) | opA) & 0xF # 0 is a place holder for a (address) for future use
        nibble3 = opB & 0xF
        lrc = (0xF ^ nibble1 ^ nibble2 ^ nibble3) & 0xF
        pfData = (nibble1 << 12) | (nibble2 << 8) | (nibble3 << 4) | lrc
        self._complete_send(pfData)

    def send_single_mode_cst(self, channel, opA, opB):
        """Send commands to a single port. Uses PF Single mode Clear/Set/Toggle
        control PINS.
        Params:
            channel:  the channel number (0-3)
            opA:      Motor selection Red/Blue port
            opB:      Refer to action list
        """
        # opA = output RED or BlUE, opB command code
        nibble1 = ((self._toggle << 3) | (self.ESC_MODE_SELECT << 2) | channel) & 0xF
        nibble2 = ((0 << 3) | (1 << 2) | (1 << 1) | opA) & 0xF # 0 is a place holder for a (address) for future use 
        nibble3 = opB & 0xF
        lrc = (0xF ^ nibble1 ^ nibble2 ^ nibble3) & 0xF
        pfData = (nibble1 << 12) | (nibble2 << 8) | (nibble3 << 4) | lrc
        self._complete_send(pfData)


IRLink.add_compatible_sensor(None, 'HiTechnc', 'IRLink  ')

Reply all
Reply to author
Forward
0 new messages