def test_clear(self, sim_engine): sim_engine = sim_engine( diff_config={ 'exec_numMotes': 2, 'sf_class': 'MSF', 'conn_class': 'Linear', 'secjoin_enabled': False }) root = sim_engine.motes[0] mote = sim_engine.motes[1] root_mac_addr = root.get_mac_addr() u.run_until_mote_is_ready_for_app(sim_engine, mote) cells = mote.tsch.get_cells(mac_addr=root_mac_addr, slotframe_handle=mote.sf.SLOTFRAME_HANDLE) assert len(cells) == 1 # mote should have a SHARED autonomous cell of the root assert cells[0].mac_addr == root_mac_addr assert d.CELLOPTION_TX in cells[0].options assert d.CELLOPTION_RX in cells[0].options assert d.CELLOPTION_SHARED in cells[0].options # keep the reference to the SHARED autonomous cell root_autonomous_cell = cells[0] # execute CLEAR (call the equivalent internal method of the # SF) mote.sf._clear_cells(root_mac_addr) # get the autonomous cell again cells = mote.tsch.get_cells(mac_addr=root_mac_addr, slotframe_handle=mote.sf.SLOTFRAME_HANDLE) assert len(cells) == 1 assert cells[0] == root_autonomous_cell
def test_parent_switch(self, sim_engine): sim_engine = sim_engine( diff_config={ 'exec_numSlotframesPerRun': 4000, 'exec_numMotes': 3, 'app_pkPeriod': 0, 'sf_class': 'MSF', 'conn_class': 'Linear' }) # for quick access root = sim_engine.motes[0] mote_1 = sim_engine.motes[1] mote_2 = sim_engine.motes[2] asn_at_end_of_simulation = ( sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun) # wait for hop_2 to get ready. this is when the network is ready to # operate. u.run_until_mote_is_ready_for_app(sim_engine, mote_2) assert sim_engine.getAsn() < asn_at_end_of_simulation # stop DIO (and EB) transmission sim_engine.settings.tsch_probBcast_ebProb = 0 # force mote_1 to switch its preferred parent old_parent = root new_parent = mote_2 # invalidate old_parent dio = old_parent.rpl._create_DIO() dio['mac'] = {'srcMac': old_parent.get_mac_addr()} dio['app']['rank'] = 65535 mote_1.rpl.action_receiveDIO(dio) # give a DIO from new_parent with a good rank dio = new_parent.rpl._create_DIO() dio['mac'] = {'srcMac': new_parent.get_mac_addr()} dio['app']['rank'] = 255 mote_1.rpl.action_receiveDIO(dio) # mote_1 should issue CLEAR to the old preferred parent and ADD to the # new one asn_start_testing = sim_engine.getAsn() u.run_until_end(sim_engine) logs = u.read_log_file(filter=[SimLog.LOG_SIXP_TX['type']], after_asn=asn_start_testing) def it_is_clear_request(packet): # return if the packet is a CLEAR request sent from mote_1 to # new_parent return ((packet['mac']['srcMac'] == mote_1.get_mac_addr()) and (packet['mac']['dstMac'] == old_parent.get_mac_addr()) and (packet['type'] == d.PKT_TYPE_SIXP) and (packet['app']['msgType'] == d.SIXP_MSG_TYPE_REQUEST) and (packet['app']['code'] == d.SIXP_CMD_CLEAR)) assert len([l for l in logs if it_is_clear_request(l['packet'])]) > 0
def test_no_available_cell(self, sim_engine, function_under_test): sim_engine = sim_engine( diff_config={ 'exec_numSlotframesPerRun': 1000, 'exec_numMotes': 2, 'app_pkPeriod': 0, 'sf_class': 'MSF', 'conn_class': 'Linear' }) # for quick access root = sim_engine.motes[0] hop_1 = sim_engine.motes[1] asn_at_end_of_simulation = ( sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun) # wait for hop_1 to get ready. u.run_until_mote_is_ready_for_app(sim_engine, hop_1) assert sim_engine.getAsn() < asn_at_end_of_simulation # fill up the hop_1's schedule channel_offset = 0 cell_options = [d.CELLOPTION_TX] used_slots = hop_1.tsch.get_busy_slots(hop_1.sf.SLOTFRAME_HANDLE) for _slot in range(sim_engine.settings.tsch_slotframeLength): if _slot in used_slots: continue else: hop_1.tsch.addCell(slotOffset=_slot, channelOffset=channel_offset, neighbor=root.get_mac_addr(), cellOptions=cell_options, slotframe_handle=hop_1.sf.SLOTFRAME_HANDLE) assert (len(hop_1.tsch.get_busy_slots(hop_1.sf.SLOTFRAME_HANDLE)) == sim_engine.settings.tsch_slotframeLength) # put dummy stats so that scheduling adaptation can be triggered hop_1.sf.num_cells_elapsed = 100 hop_1.sf.num_cells_used = hop_1.sf.num_cells_elapsed # trigger scheduling adaptation if function_under_test == 'adapt_to_traffic': hop_1.sf._adapt_to_traffic(root.id) elif function_under_test == 'relocate': relocating_cell = filter( lambda cell: cell.options == [d.CELLOPTION_TX], hop_1.tsch.get_cells(root.get_mac_addr(), hop_1.sf.SLOTFRAME_HANDLE))[0] hop_1.sf._request_relocating_cells(neighbor=root.get_mac_addr(), cell_options=[d.CELLOPTION_TX], num_relocating_cells=1, cell_list=[relocating_cell]) else: # not implemented assert False # make sure the log is written into the file SimEngine.SimLog.SimLog().flush() # MSF should output a "schedule-full" error in the log file logs = u.read_log_file( filter=[SimLog.LOG_MSF_ERROR_SCHEDULE_FULL['type']], after_asn=sim_engine.getAsn() - 1) assert len(logs) == 1 assert logs[0]['_mote_id'] == hop_1.id
def test_rank_computation(self, sim_engine): # https://tools.ietf.org/html/rfc8180#section-5.1.2 sim_engine = sim_engine( diff_config={ 'exec_numMotes': 6, 'exec_numSlotframesPerRun': 10000, 'app_pkPeriod': 0, 'secjoin_enabled': False, 'tsch_keep_alive_interval': 0, 'conn_class': 'Linear', 'sf_class': 'MSF' }) # shorthand motes = sim_engine.motes asn_at_end_of_simulation = ( sim_engine.settings.tsch_slotframeLength * sim_engine.settings.exec_numSlotframesPerRun) # get the network ready to be test u.run_until_mote_is_ready_for_app(sim_engine, motes[-1]) assert sim_engine.getAsn() < asn_at_end_of_simulation # set ETX=100/75 (numTx=100, numTxAck=75) for mote_id in range(1, len(motes)): mote = motes[mote_id] parent = motes[mote_id - 1] # inject DIO to the mote dio = parent.rpl._create_DIO() dio['mac'] = {'srcMac': parent.get_mac_addr()} mote.rpl.action_receiveDIO(dio) # set numTx and numTxAck preferred_parent = mote.rpl.of.preferred_parent autonomous_cell = mote.tsch.get_cells( mac_addr=preferred_parent['mac_addr'], slotframe_handle=mote.sf.SLOTFRAME_HANDLE)[0] preferred_parent['numTx'] = 99 preferred_parent['numTxAck'] = 74 # inform RPL of the 100th transmission that is success mote.rpl.of.update_etx(cell=autonomous_cell, mac_addr=preferred_parent['mac_addr'], isACKed=True) # test using rank values in Figure 4 of RFC 8180 assert motes[0].rpl.get_rank() == 256 assert motes[0].rpl.getDagRank() == 1 print motes[1].rpl.of.preferred_parent assert motes[1].rpl.get_rank() == 768 assert motes[1].rpl.getDagRank() == 3 assert motes[2].rpl.get_rank() == 1280 assert motes[2].rpl.getDagRank() == 5 assert motes[3].rpl.get_rank() == 1792 assert motes[3].rpl.getDagRank() == 7 assert motes[4].rpl.get_rank() == 2304 assert motes[4].rpl.getDagRank() == 9 assert motes[5].rpl.get_rank() == 2816 assert motes[5].rpl.getDagRank() == 11