Esempio n. 1
0
    def fill(self, byte):
        """
        fill: byte -> None

        Adds the given raw byte to this APIFrame. If this APIFrame is marked
        as escaped and this byte is an escape byte, the next byte in a call
        to fill() will be unescaped.
        """

        if self._unescape_next_byte:
            byte = intToByte(byteToInt(byte) ^ 0x20)
            self._unescape_next_byte = False
        elif self.escaped and byte == APIFrame.ESCAPE_BYTE:
            self._unescape_next_byte = True
            return

        self.raw_data += intToByte(byteToInt(byte))
Esempio n. 2
0
    def escape(data):
        """
        escape: byte string -> byte string

        When a 'special' byte is encountered in the given data string,
        it is preceded by an escape byte and XORed with 0x20.
        """

        escaped_data = b""
        for byte in data:
            if intToByte(byteToInt(byte)) in APIFrame.ESCAPE_BYTES:
                escaped_data += APIFrame.ESCAPE_BYTE
                escaped_data += intToByte(0x20 ^ byteToInt(byte))
            else:
                escaped_data += intToByte(byteToInt(byte))
                    
        return escaped_data
Esempio n. 3
0
    def _parse_samples_header(self, io_bytes):
        """
        _parse_samples_header: binary data in XBee ZB IO data format ->
                        (int, [int ...], [int ...], int, int)
                        
        _parse_samples_header will read the first three bytes of the 
        binary data given and will return the number of samples which
        follow, a list of enabled digital inputs, a list of enabled
        analog inputs, the dio_mask, and the size of the header in bytes

        _parse_samples_header is overloaded here to support the additional
        IO lines offered by the XBee ZB
        """
        header_size = 4

        # number of samples (always 1?) is the first byte
        sample_count = byteToInt(io_bytes[0])

        # bytes 1 and 2 are the DIO mask; bits 9 and 8 aren't used
        dio_mask = (byteToInt(io_bytes[1]) << 8
                    | byteToInt(io_bytes[2])) & 0x0E7F

        # byte 3 is the AIO mask
        aio_mask = byteToInt(io_bytes[3])

        # sorted lists of enabled channels; value is position of bit in mask
        dio_chans = []
        aio_chans = []

        for i in range(0, 13):
            if dio_mask & (1 << i):
                dio_chans.append(i)

        dio_chans.sort()

        for i in range(0, 8):
            if aio_mask & (1 << i):
                aio_chans.append(i)

        aio_chans.sort()

        return (sample_count, dio_chans, aio_chans, dio_mask, header_size)
Esempio n. 4
0
    def _parse_samples_header(self, io_bytes):
        """
        _parse_samples_header: binary data in XBee ZB IO data format ->
                        (int, [int ...], [int ...], int, int)
                        
        _parse_samples_header will read the first three bytes of the 
        binary data given and will return the number of samples which
        follow, a list of enabled digital inputs, a list of enabled
        analog inputs, the dio_mask, and the size of the header in bytes

        _parse_samples_header is overloaded here to support the additional
        IO lines offered by the XBee ZB
        """
        header_size = 4

        # number of samples (always 1?) is the first byte
        sample_count = byteToInt(io_bytes[0])

        # bytes 1 and 2 are the DIO mask; bits 9 and 8 aren't used
        dio_mask = (byteToInt(io_bytes[1]) << 8 | byteToInt(io_bytes[2])) & 0x0E7F

        # byte 3 is the AIO mask
        aio_mask = byteToInt(io_bytes[3])

        # sorted lists of enabled channels; value is position of bit in mask
        dio_chans = []
        aio_chans = []

        for i in range(0, 13):
            if dio_mask & (1 << i):
                dio_chans.append(i)

        dio_chans.sort()

        for i in range(0, 8):
            if aio_mask & (1 << i):
                aio_chans.append(i)

        aio_chans.sort()

        return (sample_count, dio_chans, aio_chans, dio_mask, header_size)
Esempio n. 5
0
    def _parse_samples_header(self, io_bytes):
        """
        _parse_samples_header: binary data in XBee IO data format ->
                        (int, [int ...], [int ...], int, int)
                        
        _parse_samples_header will read the first three bytes of the 
        binary data given and will return the number of samples which
        follow, a list of enabled digital inputs, a list of enabled
        analog inputs, the dio_mask, and the size of the header in bytes
        """
        header_size = 3

        # number of samples (always 1?) is the first byte
        sample_count = byteToInt(io_bytes[0])

        # part of byte 1 and byte 2 are the DIO mask ( 9 bits )
        dio_mask = (byteToInt(io_bytes[1]) << 8
                    | byteToInt(io_bytes[2])) & 0x01FF

        # upper 7 bits of byte 1 is the AIO mask
        aio_mask = (byteToInt(io_bytes[1]) & 0xFE) >> 1

        # sorted lists of enabled channels; value is position of bit in mask
        dio_chans = []
        aio_chans = []

        for i in range(0, 9):
            if dio_mask & (1 << i):
                dio_chans.append(i)

        dio_chans.sort()

        for i in range(0, 7):
            if aio_mask & (1 << i):
                aio_chans.append(i)

        aio_chans.sort()

        return (sample_count, dio_chans, aio_chans, dio_mask, header_size)
Esempio n. 6
0
 def verify(self, chksum):
     """
     verify: 1 byte -> boolean
     
     verify checksums the frame, adds the expected checksum, and 
     determines whether the result is correct. The result should 
     be 0xFF.
     """
     total = 0
     
     # Add together all bytes
     for byte in self.data:
         total += byteToInt(byte)
             
     # Add checksum too
     total += byteToInt(chksum)
     
     # Only keep low bits
     total &= 0xFF
     
     # Check result
     return total == 0xFF
Esempio n. 7
0
 def _parse_samples_header(self, io_bytes):
     """
     _parse_samples_header: binary data in XBee IO data format ->
                     (int, [int ...], [int ...], int, int)
                     
     _parse_samples_header will read the first three bytes of the 
     binary data given and will return the number of samples which
     follow, a list of enabled digital inputs, a list of enabled
     analog inputs, the dio_mask, and the size of the header in bytes
     """
     header_size = 3
     
     # number of samples (always 1?) is the first byte
     sample_count = byteToInt(io_bytes[0])
     
     # part of byte 1 and byte 2 are the DIO mask ( 9 bits )
     dio_mask = (byteToInt(io_bytes[1]) << 8 | byteToInt(io_bytes[2])) & 0x01FF
     
     # upper 7 bits of byte 1 is the AIO mask
     aio_mask = (byteToInt(io_bytes[1]) & 0xFE) >> 1
     
     # sorted lists of enabled channels; value is position of bit in mask
     dio_chans = []
     aio_chans = []
     
     for i in range(0,9):
         if dio_mask & (1 << i):
             dio_chans.append(i)
     
     dio_chans.sort()
     
     for i in range(0,7):
         if aio_mask & (1 << i):
             aio_chans.append(i)
     
     aio_chans.sort()
         
     return (sample_count, dio_chans, aio_chans, dio_mask, header_size)
Esempio n. 8
0
 def checksum(self):
     """
     checksum: None -> single checksum byte
     
     checksum adds all bytes of the binary, unescaped data in the 
     frame, saves the last byte of the result, and subtracts it from 
     0xFF. The final result is the checksum
     """
     total = 0
     
     # Add together all bytes
     for byte in self.data:
         total += byteToInt(byte)
         
     # Only keep the last byte
     total = total & 0xFF
     
     return intToByte(0xFF - total)
Esempio n. 9
0
    def _parse_samples(self, io_bytes):
        """
        _parse_samples: binary data in XBee IO data format ->
                        [ {"dio-0":True,
                           "dio-1":False,
                           "adc-0":100"}, ...]
                           
        _parse_samples reads binary data from an XBee device in the IO
        data format specified by the API. It will then return a 
        dictionary indicating the status of each enabled IO port.
        """

        sample_count, dio_chans, aio_chans, dio_mask, header_size = \
            self._parse_samples_header(io_bytes)

        samples = []

        # split the sample data into a list, so it can be pop()'d
        sample_bytes = [byteToInt(c) for c in io_bytes[header_size:]]

        # repeat for every sample provided
        for sample_ind in range(0, sample_count):
            tmp_samples = {}

            if dio_chans:
                # we have digital data
                digital_data_set = (sample_bytes.pop(0) << 8
                                    | sample_bytes.pop(0))
                digital_values = dio_mask & digital_data_set

                for i in dio_chans:
                    tmp_samples['dio-{0}'.format(
                        i)] = True if (digital_values >> i) & 1 else False

            for i in aio_chans:
                analog_sample = (sample_bytes.pop(0) << 8
                                 | sample_bytes.pop(0))
                tmp_samples['adc-{0}'.format(i)] = analog_sample

            samples.append(tmp_samples)

        return samples
Esempio n. 10
0
    def _parse_samples(self, io_bytes):
        """
        _parse_samples: binary data in XBee IO data format ->
                        [ {"dio-0":True,
                           "dio-1":False,
                           "adc-0":100"}, ...]
                           
        _parse_samples reads binary data from an XBee device in the IO
        data format specified by the API. It will then return a 
        dictionary indicating the status of each enabled IO port.
        """

        sample_count, dio_chans, aio_chans, dio_mask, header_size = \
            self._parse_samples_header(io_bytes)
        
        samples = []
        
        # split the sample data into a list, so it can be pop()'d
        sample_bytes = [byteToInt(c) for c in io_bytes[header_size:]]
        
        # repeat for every sample provided
        for sample_ind in range(0, sample_count):
            tmp_samples = {}
            
            if dio_chans:
                # we have digital data
                digital_data_set = (sample_bytes.pop(0) << 8 | sample_bytes.pop(0))
                digital_values = dio_mask & digital_data_set
                
                for i in dio_chans:
                    tmp_samples['dio-{0}'.format(i)] = True if (digital_values >> i) & 1 else False
                        
            for i in aio_chans:
                analog_sample = (sample_bytes.pop(0) << 8 | sample_bytes.pop(0))
                tmp_samples['adc-{0}'.format(i)] = analog_sample
            
            samples.append(tmp_samples)
        
        return samples