def get_round_request(self): if (not all([stream.is_ack for stream in self.notification_streams]) or not all([stream.is_ack for stream in self.datastreams])): return SimMessage(self.node.local_timestamp, self.node, lwb_slot.LWB_CONTENTION_HEADER_LENGTH, 0, self.node.lwb.base, SimMessageType.ROUND_REQUEST) else: return None
def receive_message_on_tx_done_before_rx_timeout( self, rx_node: 'sim_node.SimNode', modulation, band, message: SimMessage, rx_start: float, tx_start: float, transmission ) -> Tuple[Optional[SimMessage], Optional['sim_node.SimNode']]: if not self.is_reachable(modulation, rx_node, message.source, lwb_slot.RADIO_POWERS[message.power_level]): return None, None config = RadioConfiguration( modulation, preamble=gloria.GloriaTimings(modulation).preamble_len) math = RadioMath(config) valid_rx_start = rx_start + math.get_symbol_time() * 0.1 if valid_rx_start > message.tx_start: return None, None interfering_set = ( self.mm.mq.loc[(self.mm.mq.modulation == modulation) & (self.mm.mq.band == band) & (self.mm.mq.tx_end >= message.tx_start) & (self.mm.mq.tx_start <= message.tx_end)]).copy() def calc_power_message(item): return -self.calculate_path_loss(rx_node, item.source) + item.power interfering_set['rx_power'] = interfering_set.apply(calc_power_message, axis=1) rx_power = -self.calculate_path_loss( rx_node, message.source) + lwb_slot.RADIO_POWERS[message.power_level] interfering_power = 0 for interferer_index, interferer in interfering_set.iterrows(): if interferer['message_hash'] != message.hash or not ( (tx_start - 100E6) < interferer['tx_start'] < (tx_start + 100E6)): interfering_power += np.power(10, interferer['rx_power'] / 10) if np.power(10, rx_power / 10) > (interfering_power * np.power(10, RADIO_SNR[modulation])): rx_node.mm.unregister_rx(rx_node) self.network.tracer.log_activity( RxActivity( rx_start, self.network.global_timestamp, rx_node, RadioConfiguration.rx_energy( self.network.global_timestamp - rx_start), modulation, True)) return message.copy(), transmission['source'] else: return None, None
def get_stream_request( self, round: 'lwb_round.LWBRound', modulation: int, power_level: int ) -> Tuple[Optional[Union[DataStream, NotificationStream]], Optional[SimMessage]]: for stream in self.notification_streams: if not stream.is_ack and stream.check_request(round, power_level): stream = copy(stream) stream.advertised_ack_power_level = self.node.lwb.link_manager.get_link( round.master)['power_level'] message = SimMessage(self.node.local_timestamp, self.node, lwb_slot.LWB_CONTENTION_HEADER_LENGTH, 0, self.node.lwb.base, SimMessageType.STREAM_REQUEST, content={ 'type': 'notification', 'stream': stream }) return stream, message for stream in self.datastreams: if not stream.is_ack and stream.check_request(round, modulation): stream = copy(stream) stream.advertised_ack_power_level = self.node.lwb.link_manager.get_link( round.master)['power_level'] message = SimMessage(self.node.local_timestamp, self.node, lwb_slot.LWB_CONTENTION_HEADER_LENGTH, 0, self.node.lwb.base, SimMessageType.STREAM_REQUEST, content={ 'type': 'data', 'stream': stream }) return stream, message return None, None
def tx_ack_stream_request(self, stream: Union[DataStream, NotificationStream]): return SimMessage( self.node.local_timestamp, self.node, lwb_slot.GLORIA_HEADER_LENGTH, 0, stream.master, SimMessageType.ACK, content={ 'type': ('data' if type(stream) is DataStream else 'notification'), 'stream': copy(stream) })
def tx_ack(self, stream: Union[DataStream, NotificationStream]): for local_stream in self.datastreams: if stream.id == local_stream.id: local_stream.success() for local_stream in self.notification_streams: if stream.id == local_stream.id: local_stream.success() return SimMessage(self.node.local_timestamp, self.node, lwb_slot.GLORIA_HEADER_LENGTH, 0, stream.master, SimMessageType.ACK, content={'stream': copy(stream)})
def get_notification( self, low_power=False ) -> Tuple[Optional[NotificationStream], Optional[SimMessage]]: stream = self.select_notification(low_power=low_power) content = {'notification': stream.get(), 'stream': stream} message = SimMessage(self.node.local_timestamp, self.node, lwb_slot.LWB_CONTENTION_HEADER_LENGTH, 0, self.node.lwb.base, SimMessageType.NOTIFICATION, content=content) return stream, message
def get_data(self, slot_size: int) -> Tuple[DataStream, SimMessage]: stream = self.select_data(slot_size=slot_size - lwb_slot.LWB_DATA_HEADER_LENGTH) if stream is not None: content = {'data': stream.get(), 'stream': copy(stream)} message = SimMessage(self.node.local_timestamp, self.node, stream.max_payload + lwb_slot.LWB_DATA_HEADER_LENGTH, 0, self.node.lwb.base, SimMessageType.DATA, content=content) return stream, message else: return None, None
def process_sync_slot(self, slot: 'lwb_slot.LWBSlot'): if self.node.role is sim_node.SimNodeRole.BASE: message = SimMessage(slot.slot_marker, self.node, slot.payload, modulation=slot.modulation, destination=None, type=SimMessageType.SYNC, power_level=slot.power_level) SimLWBSlot(self.node, slot, self.process_sync_slot_callback, master=self.node, message=message) else: SimLWBSlot(self.node, slot, self.process_sync_slot_callback, master=self.lwb.base, message=None)
def tx(self, source: 'sim_node.SimNode', modulation, band, message: SimMessage): power = lwb_slot.RADIO_POWERS[message.power_level] message = copy(message) message.hop_count += 1 message.tx_start = source.transform_local_to_global_timestamp( message.timestamp) self.mq.loc[len(self.mq)] = [ source, modulation, band, power, message.tx_start, message.tx_end, message, message.hash ] self.network.tracer.log_activity( TxActivity(message.tx_start, message.tx_end, source, RadioConfiguration.tx_energy( power, message.tx_end - message.tx_start), power, modulation, ack=(message.type is SimMessageType.GLORIA_ACK))) for rx_node_item_index, rx_node_item in self.rxq.iterrows(): if (rx_node_item is not None and rx_node_item['rx_start'] < message.tx_start and rx_node_item['modulation'] is modulation and rx_node_item['band'] is band): self.network.em.register_event( message.tx_end, rx_node_item['rx_node'], sim_event_type.SimEventType.TX_DONE_BEFORE_RX_TIMEOUT, rx_node_item['callback'], { 'source': source, 'message': message, 'rx': rx_node_item }, local=False)
def process_round_schedule_slot(self, slot: 'lwb_slot.LWBSlot'): if self.node.role is sim_node.SimNodeRole.BASE: round_schedule = self.lwb.schedule_manager.get_round_schedule( self.round) message = SimMessage(slot.slot_marker, self.node, slot.payload, modulation=slot.modulation, destination=None, type=SimMessageType.ROUND_SCHEDULE, content=round_schedule, power_level=slot.power_level) SimLWBSlot(self.node, slot, self.process_round_schedule_slot_callback, master=self.node, message=message) else: SimLWBSlot(self.node, slot, self.process_round_schedule_slot_callback, message=None)
def process_next_slot(self): self.slot_index += 1 if self.is_not_finished(): slot = self.flood.slots[self.slot_index] if slot.type in [ gloria_flood.GloriaSlotType.RX_ACK, gloria_flood.GloriaSlotType.TX_ACK ]: if self.tx_message is not None and self.tx_message.destination is self.node and self.ack_message is None: self.is_ack = True self.ack_message = SimMessage( slot.tx_marker, source=self.tx_message.source, payload=gloria.GLORIA_ACK_LENGTH, destination=self.tx_message.source, type=SimMessageType.GLORIA_ACK, power_level=self.tx_message.power_level, modulation=self.tx_message.modulation) self.node.mm.tx(self.node, self.flood.modulation, self.flood.band, self.ack_message) self.node.em.register_event( slot.tx_done_marker, self.node, sim_event_manager.SimEventType.TX_DONE, self.progress_gloria_flood) self.ack_counter += 1 elif self.ack_message is not None: self.ack_message.timestamp = slot.tx_marker self.node.mm.tx(self.node, self.flood.modulation, self.flood.band, self.ack_message) self.node.em.register_event( slot.tx_done_marker, self.node, sim_event_manager.SimEventType.TX_DONE, self.progress_gloria_flood) self.ack_counter += 1 else: self.node.mm.register_rx(self.node, slot.rx_marker, self.flood.modulation, self.flood.band, self.progress_gloria_flood) self.rx_timeout_event = self.node.em.register_event( slot.rx_timeout_marker, self.node, sim_event_manager.SimEventType.RX_TIMEOUT, self.progress_gloria_flood) elif (self.tx_message and self.retransmission_count > 0 and (int((self.slot_index - self.first_rx_slot_index) / 2) % 2 if self.flood.acked else int(self.slot_index - self.first_rx_slot_index) % 2)): self.tx_message.timestamp = slot.tx_marker self.node.mm.tx(self.node, self.flood.modulation, self.flood.band, self.tx_message) self.node.em.register_event( slot.tx_done_marker, self.node, sim_event_manager.SimEventType.TX_DONE, self.progress_gloria_flood) if (self.power_increase and self.tx_message.power_level < len(lwb_slot.RADIO_POWERS) - 1): self.tx_message.power_level += 1 self.retransmission_count -= 1 else: self.node.mm.register_rx(self.node, slot.rx_marker, self.flood.modulation, self.flood.band, self.progress_gloria_flood) self.rx_timeout_event = self.node.em.register_event( slot.rx_timeout_marker, self.node, sim_event_manager.SimEventType.RX_TIMEOUT, self.progress_gloria_flood) else: self.finished_callback(self.tx_message)