def run(self): self.logger.info(f'Started new sACN receiver thread') self.socket.settimeout(0.1) # timeout as 100ms self.enabled_flag = True while self.enabled_flag: # before receiving: check for timeouts self.check_for_timeouts() # receive the data try: raw_data, ip_sender = list(self.socket.recvfrom( 1144)) # 1144 because the longest possible packet # in the sACN standard is the universe discovery packet with a max length of 1144 except socket.timeout: continue # if a timeout happens just go through while from the beginning try: tmp_packet = DataPacket.make_data_packet(raw_data) except: # try to make a DataPacket. If it fails just go over it continue self.logger.debug(f'Received sACN packet:\n{tmp_packet}') self.check_for_stream_terminated_and_refresh_timestamp(tmp_packet) self.refresh_priorities(tmp_packet) if not self.is_legal_priority(tmp_packet): continue if not self.is_legal_sequence( tmp_packet): # check for bad sequence number continue self.fire_callbacks_universe(tmp_packet) self.logger.info('Stopped sACN receiver thread')
def test_property_adjustment_and_deconstruction(): # Converting DataPacket -> bytes -> DataPacket should produce the same result, # but with changed properties that are not the default built_packet = DataPacket(cid=(16, 1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8), sourceName='Test Name', universe=30) built_packet.cid = tuple(range(16)) built_packet.sourceName = '2nd Test Name' built_packet.universe = 31425 built_packet.dmxData = ((200, ) + tuple(range(255, 0, -1)) + tuple(range(255)) + (0, )) built_packet.priority = 12 built_packet.sequence = 45 built_packet.option_StreamTerminated = True built_packet.option_PreviewData = True built_packet.option_ForceSync = True built_packet.syncAddr = 34003 built_packet.dmxStartCode = 8 read_packet = DataPacket.make_data_packet(built_packet.getBytes()) assert read_packet.cid == tuple(range(16)) assert read_packet.sourceName == '2nd Test Name' assert read_packet.universe == 31425 assert read_packet.dmxData == ((200, ) + tuple(range(255, 0, -1)) + tuple(range(255)) + (0, )) assert read_packet.priority == 12 assert read_packet.sequence == 45 assert read_packet.option_StreamTerminated is True assert read_packet.option_PreviewData is True assert read_packet.option_ForceSync is True assert read_packet.syncAddr == 34003 assert read_packet.dmxStartCode == 8
def on_data(self, data: bytes, current_time: float) -> None: try: tmp_packet = DataPacket.make_data_packet(data) except TypeError: # try to make a DataPacket. If it fails just ignore it return self.check_for_stream_terminated_and_refresh_timestamp( tmp_packet, current_time) self.refresh_priorities(tmp_packet, current_time) if not self.is_legal_priority(tmp_packet): return if not self.is_legal_sequence( tmp_packet): # check for bad sequence number return self.fire_callbacks_universe(tmp_packet)
def test_byte_construction_and_deconstruction(): built_packet = DataPacket(cid=(16, 1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8), sourceName='Test Name', universe=62000, dmxData=tuple(x % 256 for x in range(0, 512)), priority=195, sequence=34, streamTerminated=True, previewData=True, forceSync=True, sync_universe=12000, dmxStartCode=12) read_packet = DataPacket.make_data_packet(built_packet.getBytes()) assert built_packet.dmxData == read_packet.dmxData assert built_packet == read_packet
def test_parse_data_packet(): # Use the example present in the E1.31 spec in appendix B raw_data = [ # preamble size 0x00, 0x10, # postamble size 0x00, 0x00, # ACN packet identifier 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00, # flags and length 0x72, 0x7d, # Root vector 0x00, 0x00, 0x00, 0x04, # CID 0xef, 0x07, 0xc8, 0xdd, 0x00, 0x64, 0x44, 0x01, 0xa3, 0xa2, 0x45, 0x9e, 0xf8, 0xe6, 0x14, 0x3e, # Framing flags and length 0x72, 0x57, # Framing vector 0x00, 0x00, 0x00, 0x02, # Source name 'Source_A' 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # priority 0x64, # sync address 0x1f, 0x1a, # sequence number 0x9a, # options 0x00, # universe 0x00, 0x01, # DMP flags and length 0x72, 0x0d, # DMP vector 0x02, # address type & data type 0xa1, # first property address 0x00, 0x00, # address increment 0x00, 0x01, # property value count 0x02, 0x01, # DMX start code 0x00, ] # DMX data (starting with 0 and incrementing with wrap around at 255) dmx_data = [x % 256 for x in range(0, 512)] raw_data.extend(dmx_data) # parse raw data packet = DataPacket.make_data_packet(raw_data) assert packet.length == 638 assert packet._vector == (0x00, 0x00, 0x00, 0x04) assert packet.cid == (0xef, 0x07, 0xc8, 0xdd, 0x00, 0x64, 0x44, 0x01, 0xa3, 0xa2, 0x45, 0x9e, 0xf8, 0xe6, 0x14, 0x3e) assert packet.sourceName == 'Source_A' assert packet.priority == 100 assert packet.syncAddr == 7962 assert packet.sequence == 154 assert packet.option_ForceSync is False assert packet.option_PreviewData is False assert packet.option_StreamTerminated is False assert packet.universe == 1 assert packet.dmxStartCode == 0 assert packet.dmxData == tuple(dmx_data) # test for invalid data # test for too short data arrays for i in range(1, 126): with pytest.raises(TypeError): DataPacket.make_data_packet([x % 256 for x in range(0, i)]) # test for invalid vectors with pytest.raises(TypeError): DataPacket.make_data_packet([x % 256 for x in range(0, 126)])