def test_calculate_multicast_addr(): universe_1 = '239.255.0.1' universe_63999 = '239.255.249.255' assert calculate_multicast_addr(1) == universe_1 assert calculate_multicast_addr(63999) == universe_63999 packet = DataPacket(cid=tuple(range(0, 16)), sourceName="", universe=1) assert packet.calculate_multicast_addr() == universe_1 packet = DataPacket(cid=tuple(range(0, 16)), sourceName="", universe=63999) assert packet.calculate_multicast_addr() == universe_63999
def test_send_out_all_universes(): handler, socket, cid, source_name, outputs = get_handler() handler.manual_flush = True current_time = 100.0 outputs[1].multicast = False destination = "1.2.3.4" outputs[1].destination = destination assert handler.manual_flush is True assert socket.send_unicast_called is None assert socket.send_multicast_called is None assert outputs[1].multicast is False # check that send packets due to interval are suppressed socket.call_on_periodic_callback(current_time) assert socket.send_unicast_called is None assert socket.send_multicast_called is None # after calling send_out_all_universes, the DataPackets need to send, as well as one SyncPacket sync_universe = 63999 handler.send_out_all_universes(sync_universe, outputs, current_time) assert socket.send_unicast_called[0].__dict__ == DataPacket( cid, source_name, 1, sequence=0, sync_universe=sync_universe).__dict__ assert socket.send_unicast_called[1] == destination assert socket.send_multicast_called[0].__dict__ == SyncPacket( cid, sync_universe, 0).__dict__ assert socket.send_multicast_called[1] == calculate_multicast_addr( sync_universe)
def leave_multicast(self, universe: int) -> None: """ Try to leave the multicast group with the specified universe. This does not throw any exception if the group could not be leaved. :param universe: the universe to leave the multicast group. The network hardware has to support the multicast feature! """ self._handler.socket.leave_multicast(calculate_multicast_addr(universe))
def join_multicast(self, universe: int) -> None: """ Joins the multicast address that is used for the given universe. Note: If you are on Windows you must have given a bind IP-Address for this feature to function properly. On the other hand you are not allowed to set a bind address if you are on any other OS. :param universe: the universe to join the multicast group. The network hardware has to support the multicast feature! """ self._handler.socket.join_multicast(calculate_multicast_addr(universe))
def test_multicast(): handler, socket, cid, source_name, outputs = get_handler() handler.manual_flush = False current_time = 100.0 outputs[1].multicast = True outputs[1].ttl = 123 assert handler.manual_flush is False assert socket.send_multicast_called is None assert outputs[1].multicast is True assert outputs[1].ttl == 123 # first send packet due to interval socket.call_on_periodic_callback(current_time) assert socket.send_multicast_called[0].__dict__ == DataPacket( cid, source_name, 1, sequence=0).__dict__ assert socket.send_multicast_called[1] == calculate_multicast_addr(1) # only send out on dmx change # test same data as before # TODO: currently there is no "are the values different" check. # If it is implemented, enable the following line: # outputs[1].dmx_data = (0, 0) socket.call_on_periodic_callback(current_time) assert socket.send_multicast_called[0].__dict__ == DataPacket( cid, source_name, 1, sequence=0).__dict__ assert socket.send_multicast_called[1] == calculate_multicast_addr(1) # test change in data as before outputs[1].dmx_data = (1, 2) socket.call_on_periodic_callback(current_time) assert socket.send_multicast_called[0].__dict__ == DataPacket( cid, source_name, 1, sequence=1, dmxData=(1, 2)).__dict__ assert socket.send_multicast_called[1] == calculate_multicast_addr(1) # assert that no unicast was send assert socket.send_unicast_called is None
def send_out_all_universes(self): """ Sends out all universes in one go. This is not done by this thread! This is done by the caller's thread. This uses the E1.31 sync mechanism to try to sync all universes. Note that not all receivers support this feature. """ sync_universe = 63999 # currently hardcoded # go through the list of outputs and send everything out # Note: dict may changes size during iteration (multithreading) for output in list(self._outputs.values()): output._packet.syncAddr = sync_universe # temporarily set the sync universe self.send_out(output) output._packet.syncAddr = 0 sync_packet = SyncPacket(cid=self.__CID, syncAddr=sync_universe) self.send_packet(sync_packet, calculate_multicast_addr(sync_universe))
def send_out_all_universes(self, sync_universe: int, universes: dict): """ Sends out all universes in one go. This is not done by this thread! This is done by the caller's thread. This uses the E1.31 sync mechanism to try to sync all universes. Note that not all receivers support this feature. """ # go through the list of outputs and send everything out # Note: dict may changes size during iteration (multithreading) for output in list(universes.values()): output._packet.syncAddr = sync_universe # temporarily set the sync universe self.send_out(output) output._packet.syncAddr = 0 sync_packet = SyncPacket(cid=self.__CID, syncAddr=sync_universe, sequence=self._sync_sequence) # Increment sequence number for next time. self._sync_sequence += 1 if self._sync_sequence > 255: self._sync_sequence = 0 self.send_packet(sync_packet, calculate_multicast_addr(sync_universe))