#include "FishEyeStateRoutingModule.h" #include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "RTC.h" #include #include #include FishEyeStateRoutingModule *fishEyeStateRoutingModule; /* * check if Extension is enabled */ FishEyeStateRoutingModule::FishEyeStateRoutingModule() : ProtobufModule("fishEyeStateRouting", meshtastic_PortNum_FISHEYESTATEROUTING_APP, &meshtastic_FishEyeStateRouting_msg), concurrency::OSThread("FishEyeStateRoutingModule") { if(!(moduleConfig.fish_eye_state_routing.enabled && config.network.routingAlgorithm == meshtastic_Config_RoutingConfig_FishEyeState && moduleConfig.has_neighbor_info && moduleConfig.neighbor_info.enabled)){ LOG_DEBUG("FishEyeStateRouting Module is disabled"); disable(); nextLSPPckg = UINT32_MAX; }else { nextLSPPckg = getTime() + moduleConfig.neighbor_info.update_interval; } } /* * Compare two meshtastic_FishEyeStateRouting Structs * Criteria: Neighbor cout, Node ID, neighbors list (only by ID) */ bool FishEyeStateRoutingModule::isequal(const meshtastic_FishEyeStateRouting &s1, const meshtastic_FishEyeStateRouting &s2){ if((s1.neighbors_count == s2.neighbors_count) && (s1.node_id == s2.node_id)){ bool diff = false; for(int i = 0; i < s1.neighbors_count; i++){ if(s1.neighbors[i].node_id != s2.neighbors[i].node_id){ diff = true; break; } } return !diff; } return false; } /* * returns next-Hop for a Message to a given NodeID, if Node is unknwon BroadcastID is returned */ uint32_t FishEyeStateRoutingModule::getNextHopForID(uint32_t dest){ if (dest == nodeDB->getNodeNum()){ return dest;} auto it = NextHopTable.find(dest); if(it == NextHopTable.end()){ return NODENUM_BROADCAST; }else{ return it->second; } } /* * handels incomming LSP-Packages */ bool FishEyeStateRoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_FishEyeStateRouting *lsp) { if(lsp->node_id == nodeDB->getNodeNum()){return true;} // Don't calculate Path to us auto it = LSPDB.find(lsp->node_id); if(it != LSPDB.end()){ //Node already in LSPDB if(it->second.LSP.creation < lsp->creation){ bool diff = isequal(it->second.LSP,*lsp); it->second.LSP = *lsp; it->second.LSP.traveledHops += 1; if(it->second.forwarded){ //calculate Timeout it->second.forwarded = false; it->second.timeout = (uint32_t) (((int64_t) getTime()) + (((int64_t) moduleConfig.neighbor_info.update_interval) *((int64_t) std::pow((int64_t) it->second.LSP.traveledHops, alpha)))); }else{ it->second.timeout = min(it->second.timeout, (uint32_t) (((int64_t) getTime()) + (((int64_t) moduleConfig.neighbor_info.update_interval) *((int64_t) std::pow((int64_t) it->second.LSP.traveledHops, alpha))))); } if(!diff && moduleConfig.fish_eye_state_routing.enabled){calcNextHop();} } }else{ //Node not in LSPDB LSPDBEntry entry; //create a new LSPDB entry entry.forwarded = false; entry.LSP = *lsp; entry.LSP.traveledHops += 1; entry.timeout = (uint32_t) (((int64_t) getTime()) + (((int64_t) moduleConfig.neighbor_info.update_interval) *((int64_t) std::pow((int64_t) entry.LSP.traveledHops, alpha)))); LSPDB.insert(std::make_pair(entry.LSP.node_id,entry)); if(moduleConfig.fish_eye_state_routing.enabled){calcNextHop();} } char * logout = ""; sprintf(logout, "Received LSP-Pckg of Node %u: ",lsp->node_id); for(int i = 0; i< lsp->neighbors_count; i++){ sprintf(logout,"%u, ", lsp->neighbors[i].node_id); } LOG_DEBUG(logout); return true; } /* * sends the initial LSP-Package */ void FishEyeStateRoutingModule::sendInitialLSP(){ LOG_DEBUG("Sending own Neighborhood ..."); meshtastic_FishEyeStateRouting LSPInfo; LSPInfo.creation = getTime(); LSPInfo.node_id = nodeDB->getNodeNum(); LSPInfo.traveledHops = 0; LSPInfo.neighbors_count = neighborhood.size(); for(int i = 0; i < neighborhood.size(); i++){ meshtastic_Neighbor entry; entry.last_rx_time = 0; entry.node_broadcast_interval_secs = 0; entry.snr = 0; entry.node_id = neighborhood[i].node_id; LSPInfo.neighbors[i] = entry; } meshtastic_MeshPacket *p = allocDataProtobuf(LSPInfo); p->to = NODENUM_BROADCAST; p->decoded.want_response = false; p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; p->decoded.portnum = meshtastic_PortNum_FISHEYESTATEROUTING_APP; service->sendToMesh(p,RX_SRC_LOCAL,true); nextLSPPckg = getTime() + moduleConfig.neighbor_info.update_interval; } /* * Prints the Entrys of the LSP-Database */ void FishEyeStateRoutingModule::printLSPDB(){ printf("LSPDB:\n"); for(auto etr : LSPDB){ printf("Node: %u, Neighbors: %u: ", etr.first -16,etr.second.LSP.neighbors_count); for(int i = 0; i< etr.second.LSP.neighbors_count;i++){ printf("%u, ", etr.second.LSP.neighbors[i].node_id -16); } printf(" Timeout: %u, forwarded: %u\n",((int64_t) etr.second.timeout) - ((int64_t) getTime()),etr.second.forwarded); } printf("Total: %i\n",LSPDB.size()); } /* * broadcast all Packages, that weren't broadcastet and whose timeout is expired */ int32_t FishEyeStateRoutingModule::runOnce(){ if(((int64_t) getTime()) > ((int64_t) nextLSPPckg)){ sendInitialLSP(); } //printLSPDB(); auto it = LSPDB.begin(); uint32_t min = UINT32_MAX; while (it != LSPDB.end()) //iterate over every Entry { if(((((int64_t) getTime())-((int64_t) it->second.timeout)) >= 0) && (!(it->second.forwarded))){ //Timeout expired? meshtastic_MeshPacket *p = allocDataProtobuf(it->second.LSP); p->to = NODENUM_BROADCAST; p->decoded.want_response = false; p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; p->decoded.portnum = meshtastic_PortNum_FISHEYESTATEROUTING_APP; service->sendToMesh(p,RX_SRC_LOCAL,true); it->second.forwarded = true; char * logout = ""; sprintf(logout,"Forwarded LSP-Package of Node %u", it->second.LSP.node_id); LOG_DEBUG(logout); }else if((getTime() < it->second.timeout) && (!(it->second.forwarded)) && (it->second.timeout < min)){ min = it->second.timeout; } ++it; } if (min != UINT32_MAX){ return ((int32_t) (((int64_t) min) - ((int64_t) getTime()))) * 1000; // We need seconds here } return{300000}; } bool FishEyeStateRoutingModule::setOwnNeighborhood(meshtastic_NeighborInfo Ninfo){ bool diff = false; for(int i = 0; i n){ bool diff = false; for(int i = 0; igetNodeNum(); std::queue waitingqueue; //unprocessed Nodes std::set alreadyProcessed; for(auto nbr : neighborhood){ //add our neighborhood nodeIDwithPrev entry; entry.nodeID = nbr.node_id; entry.prev = ownID; waitingqueue.push(entry); } alreadyProcessed.insert(ownID); while(waitingqueue.size() != 0){ nodeIDwithPrev n = waitingqueue.front(); if(alreadyProcessed.find(n.nodeID) == alreadyProcessed.end()){ uint32_t nextHopForN; //calculate NextHop if(n.prev == ownID){ nextHopForN = n.nodeID; }else{ auto it = NextHopTable.find(n.prev); if(it == NextHopTable.end()){ nextHopForN = NODENUM_BROADCAST; }else{ nextHopForN = it->second; } } alreadyProcessed.insert(n.nodeID); //Node we just Handeled ist now Porcessed if(NextHopTable.find(n.nodeID) == NextHopTable.end()){ //insert NextHop in Storage NextHopTable.insert(std::make_pair(n.nodeID,nextHopForN)); }else{ NextHopTable.find(n.nodeID)->second = nextHopForN; } auto it = LSPDB.find(n.nodeID); //discover new Nodes and push them in waitingqueue, if we haven't processed them yet (e.g. they aren't in the alreadyProcessed-Set) if(it != LSPDB.end()){ for(int i = 0; i < (it->second.LSP.neighbors_count); i++){ if(alreadyProcessed.find(it->second.LSP.neighbors[i].node_id) == alreadyProcessed.end()){ nodeIDwithPrev entry; entry.nodeID = it->second.LSP.neighbors[i].node_id; entry.prev = n.nodeID; waitingqueue.push(entry); } } } } waitingqueue.pop(); } return true; }