commit c2e6aad09f893e4c8cb5cb9243c32a0d6d0d1e12 Author: Loic Guegan Date: Thu Jun 9 21:48:32 2022 +0200 Init ESDS repository diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aabeefd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +esds.debug diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ad4a8e --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ + +# ESDS: An Extensible Simulator For Distributed Systems and Cyber-Physical Systems + +**What is ESDS ?** +It is a short learning curve and coarse-grain network simulator. It contains the essential building blocks for the simulation of *Cyber-Physical Systems* (CPS) and *Wireless Sensors Networks* (WSN) scenarios. It was originally designed to improve node implementation flexibility/faithfulness and mitigate the learning curve compare to existing network simulators. + +**What ESDS does not implements?** +- Network protocols (such as IP/TCP/UDP) +- Wireless physical layer models +- Routing algorithms +- And much more! + +**Features:** +- The implementation of node behavior can be any python file that you have wrote +- Wireless interferences detection (not modelization) +- Simulation can be interrupted at constant intervals to perform custom actions (such as implement nodes mobility) + +**Current API:** +- `api.args` +- `api.send(interface, data,size, dst)` +- `api.sendt(interface, data,size, dst,timeout)` +- `api.receive(interface)` +- `api.receivet(interface,timeout)` +- `api.clock()` +- `api.log(msg)` +- `api.wait(duration)` +- `api.turn_off(duration)` +- *More details in [example/sender.py](example/sender.py)* + +**Documentation:** cf. `example/` and `tests/` diff --git a/esds.py b/esds.py new file mode 100644 index 0000000..cb81fc1 --- /dev/null +++ b/esds.py @@ -0,0 +1,581 @@ +#!/usr/bin/env python + +import numpy as np +import threading,importlib,queue,sys,time + +class Node: + available_node_id=0 + def __init__(self,src): + """ + + """ + self.node_id=Node.available_node_id + Node.available_node_id+=1 # Refresh node id + self.src=src # Store the node source code + self.args=None # Store the node arguments (passed through Simulator.create_node() + self.rargs=None # Store the requests arguments + self.plugins=list() # Contains all registered node plugins + self.rqueue=queue.Queue() # Receive simulator acknowledgments + self.chest={"state":"running", "turned_on":True, "request": None, "interfaces":{"wlan0":queue.Queue(), "eth0":queue.Queue()}, "interfaces_queue_size":{"wlan0":0,"eth0":0}} + self.chest_lock=threading.Lock() # To access/modify self.chest + + def plugin_register(self,plugin): + self.plugins.append(plugin) + + def plugin_notify(self,reason,args): + """ + This function strives to avoid using Python specific features + """ + for p in self.plugins: + if reason == "receive_return" or reason == "receivet_return": + p.on_receive_return(args[0],args[1],args[2],args[3]) + if reason == "send_call": + p.on_send_call(args[0],args[1],args[2],args[3]) + if reason == "send_return": + p.on_send_return(args[0],args[1],args[2],args[3],args[4]) + if reason == "terminated": + p.on_terminated() + + def __getitem__(self,key): + self.chest_lock.acquire() + value=self.chest[key] + self.chest_lock.release() + return value + + def __setitem__(self,key,value): + self.chest_lock.acquire() + value=self.chest[key]=value + self.chest_lock.release() + + def log(self,msg): + self.rargs=msg + self["request"]="log" + self["state"]="call" + self.wait_ack(["log"]) + + def read(self, register): + self["request"]="read" + self.rargs=register + self["state"]="call" + ack=self.wait_ack(["read"]) + return ack[1] + + def wait(self,duration): + self.rargs=duration + self["request"]="timeout_add" + self["state"]="call" + self.wait_ack(["timeout_add"]) + self["state"]="pending" + self.wait_ack(["timeout"]) + + def wait_end(self): + self["request"]="wait_end" + self["state"]="request" + self.wait_ack(["wait_end"]) + self.wait_ack(["sim_end"]) + + def turn_off(self): + self["turned_on"]=False + self["request"]="turn_off" + self["state"]="call" + self.wait_ack(["turn_off"]) + + def turn_on(self): + self["turned_on"]=True + self["request"]="turn_on" + self["state"]="call" + self.wait_ack(["turn_on"]) + + def send(self, interface, data, datasize, dst): + self.plugin_notify("send_call",(interface,data,datasize,dst)) + self.rargs=(interface, data, datasize, dst) + self["request"]="send" + self["state"]="request" + ack=self.wait_ack(["send","send_cancel"]) + self.plugin_notify("send_return",(interface,data,datasize,dst,ack[1])) + return ack[1] + + def receive(self,interface): + self["request"]="receive" + self.rargs=interface + self["state"]="request" + self.wait_ack(["receive"]) + data,start_at,end_at=self["interfaces"][interface].get() + self.plugin_notify("receive_return",(interface,data,start_at,end_at)) + return (0,data) + + def sendt(self, interface, data, datasize, dst, timeout): + self.rargs=timeout + self["request"]="timeout_add" + self["state"]="call" + self.wait_ack(["timeout_add"]) + self.rargs=(interface, data, datasize, dst) + self["request"]="send" + self["state"]="request" + ack=self.wait_ack(["send","timeout","send_cancel"]) + if ack[0] == "timeout": + self["request"]="send_cancel" + self["state"]="call" + self.wait_ack(["send_cancel"]) + return -1 + self["request"]="timeout_remove" + self["state"]="call" + self.wait_ack(["timeout_remove"]) + return ack[1] + + def receivet(self,interface, timeout): + self.rargs=timeout + self["request"]="timeout_add" + self["state"]="call" + self.wait_ack(["timeout_add"]) + self["request"]="receive" + self.rargs=interface + self["state"]="request" + ack=self.wait_ack(["receive","timeout"]) + if ack[0] == "timeout": + return (-1,None) + self["request"]="timeout_remove" + self["state"]="call" + self.wait_ack(["timeout_remove"]) + data,start_at,end_at=self["interfaces"][interface].get() + self.plugin_notify("receivet_return",(interface,data,start_at,end_at)) + return (0,data) + + def wait_ack(self, ack_types): + """ + Wait for specific acks from the request queue (rqueue) + """ + ack_buffer=list() # To filter ack + ack=None + while True: + ack=self.rqueue.get() # Wait for simulator acknowledgments + if ack[0] not in ack_types: + ack_buffer.append(ack) + else: + break + # Push back the filtered ack + for cur_ack in ack_buffer: + self.rqueue.put(cur_ack) + return(ack) + + def sync(self): + """ + Wait until node stop running + """ + while self["state"] == "running": + pass + + def run(self,args): + """ + Load and run the user program + """ + self.node=importlib.import_module(self.src) + self.args=args # Allow access to arguments + self.node.execute(self) + self["state"]="terminated" + +class Simulator: + """ + Flow-Level Discrete Event Simulator for Cyber-Physical Systems + The general format for an event is (type,timestamp,event,priority) + Event types: + - 0 send (0,timestamp,(src,dst,interface,data,datasize,duration,datasize_remaining), 1) + - 1 timeout (1,timestamp,node_id,4) + - 2 breakpoint_manual (3,timestamp,0,0) + - 3 breakpoint_auto (4,timestamp,0,0) + + Very important: when the simulator wakes up a node (changing is state to running) + data that should be received by that node on the current simulated time SHOULD be in the queue! + Thus, the send event must be handle before the other event (priority equals to 1). Otherwise plugings such as the power states + one may not gives accurate results because of missing entries in the nodes received queues. + """ + + def __init__(self,B,L): + self.B=B + self.L=L + self.nodes=list() + self.sharing=np.zeros(len(B)) + self.events=np.empty((0,4),dtype=object) + self.events_dirty=True # For optimization reasons + self.startat=-1 + self.time=0 + self.debug_file_path="./esds.debug" + self.precision=".3f" + self.interferences=True + self.wait_end_nodes=list() # Keep track of nodes that wait for the end of the simulation + self.time_truncated=format(self.time,self.precision) # Truncated version is used in log print + + def update_network(self,B,L): + for event in self.events: + if int(event[0]) == 0: + cur_event=event[2] + ts=float(event[1]) + src_id,dst_id,interface, data, datasize,duration, datasize_remaining,start_at=cur_event + new_bw=B[int(src_id),int(dst_id)] + old_bw=self.B[int(src_id),int(dst_id)] + new_lat=L[int(src_id),int(dst_id)] + old_lat=self.L[int(src_id),int(dst_id)] + if new_bw != old_bw or new_lat != old_lat: + new_datasize_remaining=float(datasize_remaining)*((ts-self.time)/float(duration)) + if new_datasize_remaining > 0: + latency_factor=new_datasize_remaining/float(datasize) + if interface == "wlan0": + new_duration=new_datasize_remaining*8/new_bw+new_lat*latency_factor + else: + new_duration=new_datasize_remaining*8/(new_bw/self.sharing[int(dst_id)])+new_lat*latency_factor + +# print("DataSize {}B | DataSize Remaining {}B | Old duration {}s | New duration {}s | Latency {}s".format(datasize,new_datasize_remaining,duration,new_duration,new_lat)) + event[1]=self.time+new_duration + event[2][6]=new_datasize_remaining + event[2][5]=new_duration + self.B=B + self.L=L + + def debug(self): + """ + Log all the informations for debugging + """ + stdout_save = sys.stdout + with open(self.debug_file_path, "a") as debug_file: + sys.stdout = debug_file + print("-----------------------------------------------") + print("Started since {}s".format(round(time.time()-self.startat,2))) + print("Simulated time {}s (or more precisely {}s)".format(self.time_truncated,self.time)) + states=dict() + timeout_mode=list() + sharing=dict() + for node in self.nodes: + s=node["state"] + states[s]=states[s]+1 if s in states else 1 + if self.sharing[node.node_id] > 0: + sharing["n"+str(node.node_id)]=str(int(self.sharing[node.node_id])) + print("Node number per state: ",end="") + for key in states: + print(key+"="+str(states[key]), end=" ") + print("\nNode sharing: ",end="") + for node_id in sharing: + print(node_id+"="+sharing[node_id], end=" ") + print("\nIds of node in timeout mode: ", end="") + for n in timeout_mode: + print(n,end=" ") + print("\nSorted events list:") + print(self.events) + sys.stdout = stdout_save + + def create_node(self, src, args=None): + """ + Create a node thread and run it + """ + node=Node(src) + self.nodes.append(node) + thread=threading.Thread(target=node.run, daemon=False,args=[args]) + thread.start() + + def log(self,msg,node=None): + src = "esds" if node is None else "n"+str(node) + print("[t="+str(self.time_truncated)+",src="+src+"] "+msg) + + def sort_events(self): + """ + Sort the events by timestamp and priorities + """ + sorted_indexes=np.lexsort((self.events[:,3],self.events[:,1])) + self.events=self.events[sorted_indexes] + + def sync_node(self,node): + """ + Process all call request and wait for Node.sync() to return + """ + node.sync() + while node["state"] == "call": + if node["request"] == "log": + self.log(node.rargs,node=node.node_id) + node["state"]="running" + node.rqueue.put(("log",0)) + elif node["request"] == "timeout_add": + self.add_event(1,self.time+node.rargs,node.node_id,priority=3) + node["state"]="running" + node.rqueue.put(("timeout_add",0)) + elif node["request"] == "timeout_remove": + selector=list() + for event in self.events: + if event[0] == 1 and event[2]==node.node_id: + selector.append(True) + else: + selector.append(False) + self.events=self.events[~np.array(selector)] + node["state"]="running" + node.rqueue.put(("timeout_remove",0)) + elif node["request"] == "read": + node["state"]="running" + if node.rargs == "clock": + node.rqueue.put(("read",self.time)) + elif node.rargs == "wlan0_ncom": + count=0 + # Count number of communication on wlan0 + for event in self.events: + if event[0] == 0 and event[2][1] == node.node_id and event[2][2] == "wlan0": + count+=1 + node.rqueue.put(("read",count)) + elif node.rargs == "eth0_ncom": + count=0 + # Count number of communication on eth0 + for event in self.events: + if event[0] == 0 and event[2][1] == node.node_id and event[2][2] == "eth0": + count+=1 + node.rqueue.put(("read",count)) + else: + node.rqueue.put(("read",0)) # Always return 0 if register is unknown + elif node["request"] == "turn_on": + node["state"]="running" + node.rqueue.put(("turn_on",0)) + self.log("Turned on",node=node.node_id) + elif node["request"] == "turn_off": + selector_wlan0=list() + selector_other=list() + for event in self.events: + if event[0]==0 and int(event[2][1])==node.node_id: + if event[2][2] == "wlan0": + selector_wlan0.append(True) + selector_other.append(False) + else: + selector_wlan0.append(False) + selector_other.append(True) + else: + selector_wlan0.append(False) + selector_other.append(False) + # Informed sender to cancel send + for event in self.events[selector_other]: + sender=self.nodes[int(event[2][0])] + sender["state"]="running" + sender.rqueue.put(("send_cancel",2)) + # Remove communications + if(len(self.events) != 0): + self.events=self.events[~(np.array(selector_wlan0)|np.array(selector_other))] + self.sharing[node.node_id]=0 # Sharing goes back to zero + node["state"]="running" + node.rqueue.put(("turn_off",0)) + self.log("Turned off",node=node.node_id) + elif node["request"] == "send_cancel": + selector=list() + for event in self.events: + if event[0]==0 and int(event[2][0]) == node.node_id: + selector.append(True) + if event[2][2] != "wlan0": + self.update_sharing(int(event[2][1]),-1) + else: + selector.append(False) + self.events=self.events[~np.array(selector)] + node["state"]="running" + node.rqueue.put(("send_cancel",0)) + node.sync() + + def update_sharing(self, dst, amount): + """ + Manage bandwidth sharing on wired interfaces + """ + sharing=self.sharing[dst] + new_sharing=sharing+amount + for event in self.events: + if event[0] == 0 and event[2][2] != "wlan0" and int(event[2][1]) == dst: + remaining=event[1]-self.time + if remaining > 0: + remaining=remaining/sharing if sharing>1 else remaining # First restore sharing + remaining=remaining*new_sharing if new_sharing > 1 else remaining # Then apply new sharing + event[2][5]=remaining # Update duration + event[1]=self.time+remaining # Update timestamp + self.sharing[dst]=new_sharing + self.sort_events() + + def handle_interferences(self,sender,receiver): + """ + Interferences are detected by looking for conflicts between + new events and existing events. + """ + status=False + selector=list() + notify=set() + for event in self.events: + event_type=event[0] + com=event[2] + if event_type==0 and com[2] == "wlan0": + com_sender=int(com[0]) + com_receiver=int(com[1]) + select=False + if receiver==com_sender: + status=True + notify.add(receiver) + elif receiver==com_receiver: + status=True + select=True + notify.add(receiver) + if sender==com_receiver and com_sender != com_receiver: + select=True + notify.add(sender) + selector.append(select) + else: + selector.append(False) + if len(selector) != 0: + self.events=self.events[~np.array(selector)] + for node in notify: + self.log("Interferences on wlan0",node=node) + return status + + def sync_event(self, node): + """ + Collect events from the nodes + """ + if node["state"] == "request": + if node["request"] == "send": + node["state"]="pending" + interface, data, datasize, dst=node.rargs + self.communicate(interface, node.node_id, dst, data, datasize) + elif node["request"] == "receive": + interface=node.rargs + if node["interfaces_queue_size"][interface] > 0: + node["interfaces_queue_size"][interface]-=1 + node.rqueue.put(("receive",0)) + node["state"]="running" + # Do not forget to collect the next event. This is the only request which is processed here + self.sync_node(node) + self.sync_event(node) + elif node["request"] == "wait_end": + node["state"]="pending" + node.rqueue.put(("wait_end",0)) + self.wait_end_nodes.append(node.node_id) + + def communicate(self, interface, src, dst, data, datasize): + """ + Create communication event between src and dst + """ + nsrc=self.nodes[src] + if interface=="wlan0": + self.log("Send "+str(datasize)+" bytes on "+interface,node=src) + for dst in self.list_receivers(nsrc): + if self.nodes[dst]["turned_on"]: + duration=datasize*8/self.B[src,dst]+self.L[src,dst] + if src == dst: + self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time)) + elif not self.interferences: + self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time)) + elif not self.handle_interferences(src,dst): + self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time)) + else: + if self.nodes[dst]["turned_on"]: + self.log("Send "+str(datasize)+" bytes to n"+str(dst)+" on "+interface,node=src) + self.update_sharing(dst,1) # Update sharing first + # Note that in the following we send more data than expected to handle bandwidth sharing (datasize*8*sharing): + duration=datasize*8/(self.B[src,dst]/self.sharing[dst])+self.L[src,dst] + self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time)) + else: + nsrc["state"]="request" # Try later when node is on + + + def list_receivers(self,node): + """ + Deduce reachable receivers from the bandwidth matrix + """ + selector = self.B[node.node_id,] > 0 + return np.arange(0,selector.shape[0])[selector] + + + def add_event(self,event_type,event_ts,event,priority=1): + """ + Call this function with sort=True the least amount of time possible + """ + self.events=np.concatenate([self.events,[np.array([event_type,event_ts,np.array(event,dtype=object),priority],dtype=object)]]) # Add new events + self.sort_events() + + def run(self, breakpoints=[],breakpoint_callback=lambda s:None,breakpoints_every=None,debug=False,interferences=True): + """ + Run the simulation with the created nodes + """ + ##### Setup simulation + self.startat=time.time() + self.interferences=interferences + for bp in breakpoints: + self.add_event(2,bp,0,0) + if breakpoints_every != None: + self.add_event(3,breakpoints_every,0,0) + if debug: + with open(self.debug_file_path, "w") as f: + f.write("Python version {}\n".format(sys.version)) + f.write("Simulation started at {}\n".format(self.startat)) + f.write("Number of nodes is "+str(len(self.nodes))+"\n") + f.write("Manual breakpoints list: "+str(breakpoints)+"\n") + f.write("Breakpoints every "+str(breakpoints_every)+"s\n") + ##### Simulation loop + while True: + # Synchronize every nodes + for node in self.nodes: + self.sync_node(node) + # Manage events + for node in self.nodes: + self.sync_event(node) + # Generate debug logs + if debug: + self.debug() + # Simulation end + if len(self.events) <= 0 or len(self.events) == 1 and self.events[0,0] == 3: + # Notify nodes that wait for the end of the simulation + # Note that we do not allow them to create new events (even if they try, they will not be processed) + for node_id in self.wait_end_nodes: + self.nodes[node_id].rqueue.put(("sim_end",0)) + self.nodes[node_id]["state"]="running" + self.sync_node(self.nodes[node_id]) # Allow them for make call requests (printing logs for example) + break # End the event processing loop + + # Update simulation time + self.time=self.events[0,1] + self.time_truncated=format(self.time,self.precision) # refresh truncated time + + # Process events + while len(self.events) > 0 and self.events[0,1] == self.time: + event_type=int(self.events[0,0]) + ts=self.events[0,1] + event=self.events[0,2] + self.events=np.delete(self.events,0,0) # Consume events NOW! not at the end of the loop (event list may change in between) + if event_type == 0: + src_id,dst_id,interface, data, datasize,duration,datasize_remaining,start_at=event + src=self.nodes[int(src_id)] + dst=self.nodes[int(dst_id)] + if interface == "wlan0": + if src.node_id != dst.node_id: + dst["interfaces"][interface].put((data,start_at,self.time)) + dst["interfaces_queue_size"][interface]+=1 + self.log("Receive "+str(datasize)+" bytes on "+interface,node=int(dst_id)) + # If node is receiving makes it consume (this way if there is a timeout, it will be removed!) + if dst["state"] == "request" and dst["request"] == "receive": + dst["interfaces_queue_size"][interface]-=1 + dst.rqueue.put(("receive",0)) + dst["state"]="running" + self.sync_node(dst) + else: + src["state"]="running" + src.rqueue.put(("send",0)) + else: + dst["interfaces"][interface].put((data,start_at,self.time)) + dst["interfaces_queue_size"][interface]+=1 + self.update_sharing(dst.node_id,-1) + self.log("Receive "+str(datasize)+" bytes on "+interface,node=int(dst_id)) + # If node is receiving makes it consume (this way if there is a timeout, it will be removed!) + if dst["state"] == "request" and dst["request"] == "receive": + dst["interfaces_queue_size"][interface]-=1 + dst.rqueue.put(("receive",0)) + dst["state"]="running" + self.sync_node(dst) + src["state"]="running" + src.rqueue.put(("send",0)) + elif event_type == 1: + node=self.nodes[int(event)] + node["state"]="running" + node.rqueue.put(("timeout",0)) + self.sync_node(node) + elif event_type == 2 or event_type == 3: + breakpoint_callback(self) + if event_type == 3: + self.add_event(3,self.time+breakpoints_every,0,0) + + ##### Simulation ends + self.log("Simulation ends") + diff --git a/example/receiver.py b/example/receiver.py new file mode 100644 index 0000000..a2ed690 --- /dev/null +++ b/example/receiver.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import sys, random, time + +lr=random.Random(6) + +def execute(api): + uptime=api.args + endoff=0 + for i in range(0,24): + startoff=random.randint(0,3600-uptime) + api.turn_off() + api.wait(startoff+endoff) + api.turn_on() + wakeat=api.read("clock") + wakeuntil=wakeat+uptime + # Receive until uptime seconds if elapsed + while api.read("clock") < wakeuntil: + code, data=api.receivet("wlan0",wakeuntil-api.read("clock")) + if code == 0: + api.log("Receive "+data) + api.log("Was up for {}s".format(api.read("clock")-wakeat)) + endoff=3600*(i+1)-api.read("clock") + api.turn_off() + api.wait(endoff) + api.turn_on() + + diff --git a/example/sender.py b/example/sender.py new file mode 100644 index 0000000..8389c95 --- /dev/null +++ b/example/sender.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +###################### +# _ ____ ___ # +# / \ | _ \_ _| # +# / _ \ | |_) | | # +# / ___ \| __/| | # +# /_/ \_\_| |___| # +# # +###################### +# api.args # Contains node arguments +# api.send(interface, data,size, dst) # If interface is "wlan0" dst is not used +# api.sendt(interface, data,size, dst,timeout) # Similar to api.send() but with timeout +# api.receive(interface) # Receive the data by returning the following tuple (code,data) if code is 0 receive succeed +# api.receivet(interface,timeout) # Similar to api.receive() but with timeout +# api.read(register) # Read from the simulator registers (ex: clock) +# api.log(msg) # Print log in the simulation console +# api.wait(duration) # Wait for "duration" seconds of simulated time +# api.turn_off(duration) # Turn the node off for "duration" seconds (no data can be receive during this time period) + +import sys, random + +# Note that the following is required to have different instance from thread to thread +lr=random.Random(6) + +def execute(api): + uptime=api.args + endoff=0 + for i in range(0,24): + startoff=random.randint(0,3600-uptime) + api.turn_off() + api.wait(startoff+endoff) + api.turn_on() + wakeat=api.read("clock") + wakeuntil=wakeat+uptime + # Send until uptime seconds if elapsed + while api.read("clock") < wakeuntil: + api.sendt("wlan0","hello",10,None, wakeuntil-api.read("clock")) + api.log("Was up for {}s".format(api.read("clock")-wakeat)) + endoff=3600*(i+1)-api.read("clock") + api.turn_off() + api.wait(endoff) + api.turn_on() + + + + diff --git a/example/simulator.py b/example/simulator.py new file mode 100755 index 0000000..9b00887 --- /dev/null +++ b/example/simulator.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../") +import esds + +# Use numpy to construct bandwidth and latencies matrix +import numpy as np + +##### Scenario +# The simulated scenario comprises 1 that wakes up randomly +# for a duration called "uptime" every hour. The sender try to transmit +# his data during that uptime. Other nodes are receivers that have similar +# random wake up parterns and strive to receive data from the sender. + +##### Bandwidth matrix +# Bandwidth value can be 0 for unreachable nodes +# Diagonal entries impact the transmission duration for wireless transmissions (wlan0) +n=2 # Number of nodes including the sender +B=np.full((n,n),5) # 5Mbps + +##### Latency matrix +# If the latency entries match one with a bandwidth of 0 +# then it will be ignore since node is unreachable. +L=np.full((n,n),0) # 0s + +##### Create the simulator +s=esds.Simulator(B,L) + +##### Instantiate nodes +uptime=180 # 180s uptime +s.create_node("sender",args=uptime) # Load sender.py for the first node with 5 as argument (first row in B and L) + +# Aguments can be passed to nodes via: s.create_node("sender",args="my argument") +for n in range(0,n-1): # Load receiver.py for the remaining nodes + s.create_node("receiver",args=uptime) + +##### Run the simulation +#s.run(debug=True) # Generate a "esds.debug" file +s.run() diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..5f4407f --- /dev/null +++ b/icon.svg @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/__init__.py b/plugins/__init__.py new file mode 100644 index 0000000..abb734a --- /dev/null +++ b/plugins/__init__.py @@ -0,0 +1 @@ +__all__ = [ "node_plugin", "power_states" ] diff --git a/plugins/node_plugin.py b/plugins/node_plugin.py new file mode 100644 index 0000000..325ff8a --- /dev/null +++ b/plugins/node_plugin.py @@ -0,0 +1,29 @@ +class NodePlugin: + """ + Node plugins get register to the node API get notified when events occurs. + The call and return suffixes are used for methods that are called at the beginning + and the end, respectively, of API calls triggered by the node source code. + + Changing this API could brake most of the node plugins. + """ + + def __init__(self,plugin_name,api): + self.api=api + self.plugin_name=plugin_name + api.plugin_register(self) + + def on_send_call(self,interface,data,datasize,dst): + pass + + def on_send_return(self,interface,data,datasize,dst,code): + pass + + def on_receive_return(self,interface,data,start_at,end_at): + pass + + def on_terminated(self): + pass + + def log(self,msg): + self.api.log(self.plugin_name+"(NP) "+msg) + diff --git a/plugins/operating_states.py b/plugins/operating_states.py new file mode 100644 index 0000000..400aa1b --- /dev/null +++ b/plugins/operating_states.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +from plugins.node_plugin import * + +###################### +# _ ____ ___ # +# / \ | _ \_ _| # +# / _ \ | |_) | | # +# / ___ \| __/| | # +# /_/ \_\_| |___| # +# # +###################### + +# import plugins.operating_states as op +# # Load the directional transition graph from graph.txt starting at the "vertex1" state +# opstate=op.OperatingStates(api,"graph.txt","vertex1") +# Format of the graph.txt file consists in one edge per line +# that consists on the source vertex and destination vertex sperated by a space +# As an example: +# vertex1 vertex2 +# vertex1 vertex3 +# vertex3 vertex2 +# vertex2 vertex1 +# +# opstate.register_callback(boom) +# # On each state transition boom will be called as boom(src_state,dst_state) +# # This way the boom callback can contains power_state transitions for examples +# opstate.goto("vertex2") # works +# opstate.goto("vertex3") # wont work +# opstate.goto("vertex1") # work since we are on vertex2 + +class OperatingStates(NodePlugin): + """ + OperatingStates plugin + """ + def __init__(self,api, state_file, initial_state): + self.transitions=list() + self.callbacks=list() + self.state=initial_state + with open(state_file) as fp: + for i, line in enumerate(fp): + self.transitions.append(line) + super().__init__("OperatingStates",api) + + def goto(self,state): + if (self.state+" "+state) in self.transitions: + old_state=self.state + self.state=state + for c in self.callbacks: + c(old_state,state) + else: + self.log("Invalid transition "+self.state+" => "+state) + + def get_state(self): + return(self.state) + + def register_callback(self,callback): + """ + The callback will be called on each state transition + Callback takes two arguments which are: + - The source state + - The destination state + """ + self.callbacks.append(callback) + + diff --git a/plugins/power_states.py b/plugins/power_states.py new file mode 100644 index 0000000..c8e9d0e --- /dev/null +++ b/plugins/power_states.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +from plugins.node_plugin import * + +# PowerStates allows you to measure the energy consumption of a +# node that go through several power states during the simulation +# Two version of Powerstates is provided by mean of two classes: +# - Powerstates: Allow you to set power to any user's defined values +# - PowerstatesFromFile: Allow you to set power from states defined in a file + +###################### +# _ ____ ___ # +# / \ | _ \_ _| # +# / _ \ | |_) | | # +# / ___ \| __/| | # +# /_/ \_\_| |___| # +# # +###################### + +# #Regarding PowerStates: +# import Powerstates as ps +# pstates=ps.PowerStates(,) +# pstates.set_power() # Switch the power consumption to +# pstates.report_energy() # Display the current node energy consumption up to the current simulated time +# pstates.report_power_changes() # Display all the power changes up to the current simulated time + +# #Regarding PowerStatesFromFile: +# #Format of is one per line that follow this format ::...: +# #Each line can corresponds to one node +# import Powerstates as ps +# pstates=ps.PowerStatesFromFile(,,) # Create a power states on node using line of file +# pstates.set_state() # Switch to the power states +# pstates.report_energy() # Display the current node energy consumption up to the current simulated time +# pstates.report_power_changes() # Display all the power changes up to the current simulated time +# pstates.report_state_changes() # Display all the states changes up to the current simulated time + + +class PowerStates(NodePlugin): + """ + PowerStates model the energy consumed by the various changes of power consumption of a node over time. + """ + def __init__(self,node,power_init): + self.node=node + self.clock=self.node.clock() + self.energy=0 + self.power=power_init + self.power_changes=dict() + self.set_power(power_init) + super().__init__("Powerstates",api) + + + def set_power(self,power_watt): + cur_clock=self.node.clock() + self.energy+=self.power*(cur_clock-self.clock) + self.clock=cur_clock + if self.power != power_watt: + self.power_changes[cur_clock]=power_watt + self.power=power_watt + return cur_clock + + def report_energy(self): + self.set_power(self.power) + self.node.log("[PowerStates Plugin] Consumed "+str(self.energy) +"J") + + def report_power_changes(self): + self.set_power(self.power) + for key in self.power_changes.keys(): + self.node.log("[PowerStates Plugin] At t="+str(key)+" power is "+str(self.power_changes[key])+"W") + + + +class PowerStatesFromFile(PowerStates): + """ + A version of Powerstates that load the power values from a file. + """ + def __init__(self,node,state_file,entry_line=1): + self.node=node + self.state_changes=dict() + self.states=[] + self.state=0 + with open(state_file) as fp: + for i, line in enumerate(fp): + if i+1 == entry_line: + self.states=line.split(":") + self.states=[float(i) for i in self.states] + assert len(self.states) > 0 + super().__init__(node,self.states[0]) + self.set_state(0) + + def set_state(self,state_id): + assert state_id < len(self.states) + clock=super().set_power(self.states[state_id]) + if self.state != state_id: + self.state_changes[clock]=state_id + self.state=state_id + + + def report_state_changes(self): + self.set_state(self.state) + for key in self.state_changes.keys(): + self.node.log("[PowerStates Plugin] At t="+str(key)+" state is "+str(self.state_changes[key])) + + +class PowerStatesComms(NodePlugin): + """ + Monitor the energy consumed by the network interfaces by mean of power states. + Note that for finer grained predictions, bytes and packet power consumption must be accounted. + Which is not the case with these power states. + """ + + def __init__(self,api): + super().__init__("PowerStatesComms",api) + self.energy_dynamic=0.0 # Store the dynamic part of the energy consumption + self.power=dict() # Store the power states + self.tx_clock=0 # Dynamic clock (store the time at which a the last tx starts + self.idle_clock=api.clock() # Store the start time (to compute the idle part of the energy consumption) + + def on_receive_return(self,interface,data,start_at,end_at): + duration=float(end_at)-float(start_at) + self.energy_dynamic+=self.power[interface]["rx"]*duration + + def on_send_call(self,interface,data,datasize,dst): + self.tx_clock=self.api.clock() + + def on_send_return(self,interface,data,datasize,dst,code): + clock=self.api.clock() + duration=(clock-float(self.tx_clock)) + self.energy_dynamic+=self.power[interface]["tx"]*duration + self.tx_clock=clock # Any value could be use here + + def set_power(self,interface,idle,tx,rx): + self.power[interface]=dict() + self.power[interface]["idle"]=idle + self.power[interface]["rx"]=rx + self.power[interface]["tx"]=tx + + def get_idle(self): + clock=self.api.clock() + idle=0 + for interface in self.power.keys(): + idle+=(clock-self.idle_clock)*self.power[interface]["idle"] + return idle + + def get_receive_queue_energy(self,interface): + """ + Not that call to on_receive_return may not have happened yet (or never). + Thus we should manually compute the energy consumption stored in each queues of the node. + """ + energy=0 + # For each interface we should check if there is received data that has not been consumed + for data in list(self.api["interfaces"][interface].queue): + start_at=float(data[1]) + end_at=float(data[2]) + energy+=(end_at-start_at)*self.power[interface]["rx"] + return energy + + def get_energy(self): + queue_energy=0 + for interface in self.power.keys(): + queue_energy+=self.get_receive_queue_energy(interface) + return self.get_idle()+self.energy_dynamic+queue_energy + + def report_energy(self): + self.log("Communications consumed "+str(round(self.get_energy(),2))+"J") diff --git a/plugins/wireless_area.py b/plugins/wireless_area.py new file mode 100644 index 0000000..b2e2432 --- /dev/null +++ b/plugins/wireless_area.py @@ -0,0 +1,71 @@ +import math +import numpy as np + +class WirelessArea: + + def __init__(self): + self.nodes=list() + + def dump_nodes(self): + i=0 + for node in self.nodes: + x,y,z,com_range=node + print("Node {} at ({},{},{}) with a communication range of {}m".format(i,x,y,z,com_range)) + i+=1 + + def dump_infos(self): + print("Number of nodes {}".format(len(self.nodes))) + adjacency=self.generate_adjacency_matrix(fill_diagonal=False) + print("Nodes average degree is {}".format(np.mean(np.sum(adjacency,axis=0)))) + x = [node[0] for node in self.nodes] + y = [node[1] for node in self.nodes] + z = [node[2] for node in self.nodes] + com_range = [node[3] for node in self.nodes] + print("Nodes locations ranges: x in [{},{}] y in [{},{}] z in [{},{}]".format(min(x),max(x),min(y),max(y),min(z),max(z))) + print("Node communication ranges in [{},{}]".format(min(com_range),max(com_range))) + + def add_node(self,x,y,z,com_range): + self.nodes.append((x,y,z,com_range)) + + def get_neighbours(self,node_id): + node=self.nodes[node_id] + neighbours=list() + for i in range(0,len(self.nodes)): + if i != node_id: + neighbour=self.nodes[i] + if math.dist(node[0:3],neighbour[0:3]) <= node[3]: + neighbours.append(i) + return neighbours + + def generate_dot(self,filepath): + is_strict=False + com_range=self.nodes[0][3] + for node in self.nodes: + if node[3] != com_range: + is_strict=True + break + + with open(filepath, "w") as f: + if is_strict: + f.write("digraph G {\n") + else: + f.write("strict graph G {\n") + for i in range(0,len(self.nodes)): + neighbours=self.get_neighbours(i) + for n in neighbours: + if is_strict: + f.write("{}->{}\n".format(i,n)) + else: + f.write("{}--{}\n".format(i,n)) + f.write("}") + + def generate_adjacency_matrix(self,fill_diagonal=True): + matrix=np.full((len(self.nodes),len(self.nodes)),0) + if fill_diagonal: + np.fill_diagonal(matrix,1) # Required by ESDS + for i in range(0,len(self.nodes)): + neighbours=self.get_neighbours(i) + for n in neighbours: + matrix[i,n]=1 + return matrix + diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..9cf09c6 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,6 @@ +# Tests +**Test folders names convention:** +- **m** senders and **n** receivers is written `sr` *(ex: 1s5r)* +- **n** nodes is written `n` *(ex: 5n)* +- Tests names follow the following format `_<m>s<n>r` or `<title>_<n>n` *(ex: simple_send_rcv_1s5r, ping_pong_2n)* +- Tests that test **elementary API functions** should start with the **simple** keyword diff --git a/tests/hidden_node_2s1r/out b/tests/hidden_node_2s1r/out new file mode 100644 index 0000000..0922147 --- /dev/null +++ b/tests/hidden_node_2s1r/out @@ -0,0 +1,4 @@ +[t=0.000,src=n0] Send 1 bytes on wlan0 +[t=0.000,src=n2] Send 1 bytes on wlan0 +[t=0.000,src=n1] Interferences on wlan0 +[t=1.000,src=esds] Simulation ends diff --git a/tests/hidden_node_2s1r/receiver.py b/tests/hidden_node_2s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/hidden_node_2s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/hidden_node_2s1r/sender.py b/tests/hidden_node_2s1r/sender.py new file mode 100644 index 0000000..80f0fc2 --- /dev/null +++ b/tests/hidden_node_2s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("wlan0","Hello World!",1,1) diff --git a/tests/hidden_node_2s1r/simulator.py b/tests/hidden_node_2s1r/simulator.py new file mode 100755 index 0000000..63ca502 --- /dev/null +++ b/tests/hidden_node_2s1r/simulator.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),8) + +# Hide the nodes from each others +B[0,2]=0 +B[2,0]=0 + +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") +s.create_node("sender") + +s.run() diff --git a/tests/mobility_eth0_bandwidth_1s1r/out b/tests/mobility_eth0_bandwidth_1s1r/out new file mode 100644 index 0000000..e0a3d04 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_1s1r/out @@ -0,0 +1,4 @@ +[t=0.000,src=n0] Send 1 bytes to n1 on eth0 +[t=0.500,src=esds] Network update! +[t=0.750,src=n1] Receive 1 bytes on eth0 +[t=0.750,src=esds] Simulation ends diff --git a/tests/mobility_eth0_bandwidth_1s1r/receiver.py b/tests/mobility_eth0_bandwidth_1s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_1s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/mobility_eth0_bandwidth_1s1r/sender.py b/tests/mobility_eth0_bandwidth_1s1r/sender.py new file mode 100644 index 0000000..753ccce --- /dev/null +++ b/tests/mobility_eth0_bandwidth_1s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("eth0","Hello World!",1,1) diff --git a/tests/mobility_eth0_bandwidth_1s1r/simulator.py b/tests/mobility_eth0_bandwidth_1s1r/simulator.py new file mode 100755 index 0000000..f7a0072 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_1s1r/simulator.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +########## Scenario ########## +# Notations: +# - Remaining communication duration (last communication ends minus current simulated time) = C +# - Last communication duration (previous row) = U +# - Last remaining data size (previous row) = D +# - Current remaining data (current row) = R +# - Initial data size (first row) = I +# - Bandwidth = BW +# - Latency = L +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | 0 | 0 | 8 | 8 | 1 | 1 | +# | 0.5 | 0 | 16 | C/U*D = 4 | R/I * L + R/BW = 0.25 | 0.75 | +# | 0.75 | 0 | 16 | | | | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +############################## + +B=np.full((2,2),8) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") + +def callback(simulator): + simulator.log("Network update!") + simulator.update_network(simulator.B*2,simulator.L) + +s.run(breakpoints_every=1/2,breakpoint_callback=callback) diff --git a/tests/mobility_eth0_bandwidth_2s1r/out b/tests/mobility_eth0_bandwidth_2s1r/out new file mode 100644 index 0000000..7138457 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_2s1r/out @@ -0,0 +1,6 @@ +[t=0.000,src=n0] Send 1 bytes to n2 on eth0 +[t=0.000,src=n1] Send 1 bytes to n2 on eth0 +[t=1.000,src=esds] Network update! +[t=1.500,src=n2] Receive 1 bytes on eth0 +[t=1.500,src=n2] Receive 1 bytes on eth0 +[t=1.500,src=esds] Simulation ends diff --git a/tests/mobility_eth0_bandwidth_2s1r/receiver.py b/tests/mobility_eth0_bandwidth_2s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_2s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/mobility_eth0_bandwidth_2s1r/sender.py b/tests/mobility_eth0_bandwidth_2s1r/sender.py new file mode 100644 index 0000000..273cdc2 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_2s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("eth0","Hello World!",1,2) diff --git a/tests/mobility_eth0_bandwidth_2s1r/simulator.py b/tests/mobility_eth0_bandwidth_2s1r/simulator.py new file mode 100755 index 0000000..ba876d8 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_2s1r/simulator.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +########## Scenario ########## +# Notations: +# - Remaining communication duration (last communication ends minus current simulated time) = C +# - Last communication duration (previous row) = U +# - Last remaining data size (previous row) = D +# - Current remaining data (current row) = R +# - Initial data size (first row) = I +# - Bandwidth = BW +# - Latency = L +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +# | This table is the same for both sender | | | | | | +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communication duration(s) | Communcation ends at(s) | +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +# | 0 | 0 | 8/2 | 8 | 2 | 2 | +# | 1 | 0 | 16/2 | C/U*D = 4 | 0.5 | 1.5 | +# | 1.5 | 0 | 16/2 | 0 | | | +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +############################## + +B=np.full((3,3),8) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("sender") +s.create_node("receiver") + +def callback(simulator): + simulator.log("Network update!") + simulator.update_network(simulator.B*2,simulator.L) + +s.run(breakpoints_every=1,breakpoint_callback=callback,debug=True) diff --git a/tests/mobility_eth0_bandwidth_2s1r/yoctosim.debug b/tests/mobility_eth0_bandwidth_2s1r/yoctosim.debug new file mode 100644 index 0000000..b0e4327 --- /dev/null +++ b/tests/mobility_eth0_bandwidth_2s1r/yoctosim.debug @@ -0,0 +1,37 @@ +Python version 3.10.5 (main, Jun 6 2022, 18:49:26) [GCC 12.1.0] +Simulation started at 1654802959.3233912 +Number of nodes is 3 +Manual breakpoints list: [] +Breakpoints every 1s +----------------------------------------------- +Started since 0.04s +Simulated time 0.000s (or more precisely 0s) +Node number per state: pending=2 terminated=1 +Node sharing: n2=2 +Ids of node in timeout mode: +Sorted events list: +[[3 1 array(0, dtype=object) 0] + [0 2.0 array([0, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object) + 1] + [0 2.0 array([1, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object) + 1]] +----------------------------------------------- +Started since 0.04s +Simulated time 1.000s (or more precisely 1s) +Node number per state: pending=2 terminated=1 +Node sharing: n2=2 +Ids of node in timeout mode: +Sorted events list: +[[0 1.5 + array([0, 2, 'eth0', 'Hello World!', 1, 0.5, 0.5, 0], dtype=object) 1] + [0 1.5 + array([1, 2, 'eth0', 'Hello World!', 1, 0.5, 0.5, 0], dtype=object) 1] + [3 2 array(0, dtype=object) 0]] +----------------------------------------------- +Started since 0.05s +Simulated time 1.500s (or more precisely 1.5s) +Node number per state: terminated=3 +Node sharing: +Ids of node in timeout mode: +Sorted events list: +[[3 2 array(0, dtype=object) 0]] diff --git a/tests/mobility_eth0_latency_1s1r/out b/tests/mobility_eth0_latency_1s1r/out new file mode 100644 index 0000000..ef56e0f --- /dev/null +++ b/tests/mobility_eth0_latency_1s1r/out @@ -0,0 +1,5 @@ +[t=0.000,src=n0] Send 1 bytes to n1 on eth0 +[t=0.500,src=esds] Network update! +[t=1.000,src=esds] Network update! +[t=1.333,src=n1] Receive 1 bytes on eth0 +[t=1.333,src=esds] Simulation ends diff --git a/tests/mobility_eth0_latency_1s1r/receiver.py b/tests/mobility_eth0_latency_1s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/mobility_eth0_latency_1s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/mobility_eth0_latency_1s1r/sender.py b/tests/mobility_eth0_latency_1s1r/sender.py new file mode 100644 index 0000000..753ccce --- /dev/null +++ b/tests/mobility_eth0_latency_1s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("eth0","Hello World!",1,1) diff --git a/tests/mobility_eth0_latency_1s1r/simulator.py b/tests/mobility_eth0_latency_1s1r/simulator.py new file mode 100755 index 0000000..525bb66 --- /dev/null +++ b/tests/mobility_eth0_latency_1s1r/simulator.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +########## Scenario ########## +# Notations: +# - Remaining communication duration (last communication ends minus current simulated time) = C +# - Last communication duration (previous row) = U +# - Last remaining data size (previous row) = D +# - Current remaining data (current row) = R +# - Initial data size (first row) = I +# - Bandwidth = BW +# - Latency = L +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | 0 | 0 | 8 | 8 | 1 | 1 | +# | 0.5 | 0.5 | 8 | C/U*D = 4 | R/I * L + R/BW = 0.75 | 1.25 | +# | 1 | 1 | 8 | C/U*D = 1.33 | R/I * L + R/BW = 0.33 | 1.33 | +# | 1.33 | 1 | 8 | | | | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +############################## + +B=np.full((2,2),8) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") + +def callback(simulator): + simulator.log("Network update!") + simulator.update_network(simulator.B,simulator.L+1/2) + +s.run(breakpoints_every=1/2,breakpoint_callback=callback) diff --git a/tests/mobility_eth0_latency_2s1r/out b/tests/mobility_eth0_latency_2s1r/out new file mode 100644 index 0000000..41d59fc --- /dev/null +++ b/tests/mobility_eth0_latency_2s1r/out @@ -0,0 +1,7 @@ +[t=0.000,src=n0] Send 1 bytes to n2 on eth0 +[t=0.000,src=n1] Send 1 bytes to n2 on eth0 +[t=1.000,src=esds] Network update! +[t=2.000,src=esds] Network update! +[t=2.300,src=n2] Receive 1 bytes on eth0 +[t=2.300,src=n2] Receive 1 bytes on eth0 +[t=2.300,src=esds] Simulation ends diff --git a/tests/mobility_eth0_latency_2s1r/receiver.py b/tests/mobility_eth0_latency_2s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/mobility_eth0_latency_2s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/mobility_eth0_latency_2s1r/sender.py b/tests/mobility_eth0_latency_2s1r/sender.py new file mode 100644 index 0000000..273cdc2 --- /dev/null +++ b/tests/mobility_eth0_latency_2s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("eth0","Hello World!",1,2) diff --git a/tests/mobility_eth0_latency_2s1r/simulator.py b/tests/mobility_eth0_latency_2s1r/simulator.py new file mode 100755 index 0000000..101004b --- /dev/null +++ b/tests/mobility_eth0_latency_2s1r/simulator.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +########## Scenario ########## +# Notations: +# - Remaining communication duration (last communication ends minus current simulated time) = C +# - Last communication duration (previous row) = U +# - Last remaining data size (previous row) = D +# - Current remaining data (current row) = R +# - Initial data size (first row) = I +# - Bandwidth = BW +# - Latency = L +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +# | This table is the same for both sender | | | | | | +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communication duration(s) | Communcation ends at(s) | +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +# | 0 | 0 | 8/2 | 8 | 2 | 2 | +# | 1 | 0.5 | 8/2 | C/U*D=4 | R/BW + R/I*L = 1.25 | 2.25 | +# | 2 | 1 | 8/2 | C/U*D=0.8 | R/BW + R/I*L = 0.3 | 2.3 | +# | 2.3 | 1 | 8/2 | 0 | | | +# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------| +############################## + +B=np.full((3,3),8) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("sender") +s.create_node("receiver") + +def callback(simulator): + simulator.log("Network update!") + simulator.update_network(simulator.B,simulator.L+0.5) + +s.run(breakpoints_every=1,breakpoint_callback=callback,debug=True) diff --git a/tests/mobility_eth0_latency_2s1r/yoctosim.debug b/tests/mobility_eth0_latency_2s1r/yoctosim.debug new file mode 100644 index 0000000..efe50d9 --- /dev/null +++ b/tests/mobility_eth0_latency_2s1r/yoctosim.debug @@ -0,0 +1,51 @@ +Python version 3.10.5 (main, Jun 6 2022, 18:49:26) [GCC 12.1.0] +Simulation started at 1654802960.9297695 +Number of nodes is 3 +Manual breakpoints list: [] +Breakpoints every 1s +----------------------------------------------- +Started since 0.08s +Simulated time 0.000s (or more precisely 0s) +Node number per state: pending=2 terminated=1 +Node sharing: n2=2 +Ids of node in timeout mode: +Sorted events list: +[[3 1 array(0, dtype=object) 0] + [0 2.0 array([0, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object) + 1] + [0 2.0 array([1, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object) + 1]] +----------------------------------------------- +Started since 0.08s +Simulated time 1.000s (or more precisely 1s) +Node number per state: pending=2 terminated=1 +Node sharing: n2=2 +Ids of node in timeout mode: +Sorted events list: +[[3 2 array(0, dtype=object) 0] + [0 2.25 + array([0, 2, 'eth0', 'Hello World!', 1, 1.25, 0.5, 0], dtype=object) 1] + [0 2.25 + array([1, 2, 'eth0', 'Hello World!', 1, 1.25, 0.5, 0], dtype=object) 1]] +----------------------------------------------- +Started since 0.08s +Simulated time 2.000s (or more precisely 2s) +Node number per state: pending=2 terminated=1 +Node sharing: n2=2 +Ids of node in timeout mode: +Sorted events list: +[[0 2.3 + array([0, 2, 'eth0', 'Hello World!', 1, 0.30000000000000004, 0.1, 0], + dtype=object) 1] + [0 2.3 + array([1, 2, 'eth0', 'Hello World!', 1, 0.30000000000000004, 0.1, 0], + dtype=object) 1] + [3 3 array(0, dtype=object) 0]] +----------------------------------------------- +Started since 0.09s +Simulated time 2.300s (or more precisely 2.3s) +Node number per state: terminated=3 +Node sharing: +Ids of node in timeout mode: +Sorted events list: +[[3 3 array(0, dtype=object) 0]] diff --git a/tests/mobility_wlan0_bandwidth_1s1r/out b/tests/mobility_wlan0_bandwidth_1s1r/out new file mode 100644 index 0000000..95cdeeb --- /dev/null +++ b/tests/mobility_wlan0_bandwidth_1s1r/out @@ -0,0 +1,4 @@ +[t=0.000,src=n0] Send 1 bytes on wlan0 +[t=0.500,src=esds] Network update! +[t=0.750,src=n1] Receive 1 bytes on wlan0 +[t=0.750,src=esds] Simulation ends diff --git a/tests/mobility_wlan0_bandwidth_1s1r/receiver.py b/tests/mobility_wlan0_bandwidth_1s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/mobility_wlan0_bandwidth_1s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/mobility_wlan0_bandwidth_1s1r/sender.py b/tests/mobility_wlan0_bandwidth_1s1r/sender.py new file mode 100644 index 0000000..80f0fc2 --- /dev/null +++ b/tests/mobility_wlan0_bandwidth_1s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("wlan0","Hello World!",1,1) diff --git a/tests/mobility_wlan0_bandwidth_1s1r/simulator.py b/tests/mobility_wlan0_bandwidth_1s1r/simulator.py new file mode 100755 index 0000000..f7a0072 --- /dev/null +++ b/tests/mobility_wlan0_bandwidth_1s1r/simulator.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +########## Scenario ########## +# Notations: +# - Remaining communication duration (last communication ends minus current simulated time) = C +# - Last communication duration (previous row) = U +# - Last remaining data size (previous row) = D +# - Current remaining data (current row) = R +# - Initial data size (first row) = I +# - Bandwidth = BW +# - Latency = L +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | 0 | 0 | 8 | 8 | 1 | 1 | +# | 0.5 | 0 | 16 | C/U*D = 4 | R/I * L + R/BW = 0.25 | 0.75 | +# | 0.75 | 0 | 16 | | | | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +############################## + +B=np.full((2,2),8) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") + +def callback(simulator): + simulator.log("Network update!") + simulator.update_network(simulator.B*2,simulator.L) + +s.run(breakpoints_every=1/2,breakpoint_callback=callback) diff --git a/tests/mobility_wlan0_latency_1s1r/out b/tests/mobility_wlan0_latency_1s1r/out new file mode 100644 index 0000000..b1a2b0f --- /dev/null +++ b/tests/mobility_wlan0_latency_1s1r/out @@ -0,0 +1,5 @@ +[t=0.000,src=n0] Send 1 bytes on wlan0 +[t=0.500,src=esds] Network update! +[t=1.000,src=esds] Network update! +[t=1.333,src=n1] Receive 1 bytes on wlan0 +[t=1.333,src=esds] Simulation ends diff --git a/tests/mobility_wlan0_latency_1s1r/receiver.py b/tests/mobility_wlan0_latency_1s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/mobility_wlan0_latency_1s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/mobility_wlan0_latency_1s1r/sender.py b/tests/mobility_wlan0_latency_1s1r/sender.py new file mode 100644 index 0000000..80f0fc2 --- /dev/null +++ b/tests/mobility_wlan0_latency_1s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("wlan0","Hello World!",1,1) diff --git a/tests/mobility_wlan0_latency_1s1r/simulator.py b/tests/mobility_wlan0_latency_1s1r/simulator.py new file mode 100755 index 0000000..525bb66 --- /dev/null +++ b/tests/mobility_wlan0_latency_1s1r/simulator.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +########## Scenario ########## +# Notations: +# - Remaining communication duration (last communication ends minus current simulated time) = C +# - Last communication duration (previous row) = U +# - Last remaining data size (previous row) = D +# - Current remaining data (current row) = R +# - Initial data size (first row) = I +# - Bandwidth = BW +# - Latency = L +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +# | 0 | 0 | 8 | 8 | 1 | 1 | +# | 0.5 | 0.5 | 8 | C/U*D = 4 | R/I * L + R/BW = 0.75 | 1.25 | +# | 1 | 1 | 8 | C/U*D = 1.33 | R/I * L + R/BW = 0.33 | 1.33 | +# | 1.33 | 1 | 8 | | | | +# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------| +############################## + +B=np.full((2,2),8) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") + +def callback(simulator): + simulator.log("Network update!") + simulator.update_network(simulator.B,simulator.L+1/2) + +s.run(breakpoints_every=1/2,breakpoint_callback=callback) diff --git a/tests/run.sh b/tests/run.sh new file mode 100755 index 0000000..8720736 --- /dev/null +++ b/tests/run.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +wai=$(dirname $(readlink -f "$0")) # Current script directory +tests=$(find ${wai}/ -maxdepth 1 -mindepth 1 -type d) # Find tests +out=$(mktemp) +test_timeout=20 + +for test in ${tests} +do + printf "%-50s%s %s" "- $(basename $test)" "=>" + cd $test + timeout $test_timeout ./simulator.py &> "$out" + + # Ensure timeout + if [ $? -eq 124 ] + then + echo -e "${RED}${BOLD}failed${NC}" + echo "------------- Test timeout (should not exceed ${test_timeout}s) -------------" + cat "$out"; + rm "$out" + exit 2 + fi + + # Ensure test output + if $(diff "$out" ./out &>/dev/null) + then + echo -e "${GREEN}${BOLD}passed${NC}" + else + echo -e "${RED}${BOLD}failed${NC}" + echo "------------- Expected -------------" + cat out + echo "------------- Got -------------" + cat "$out"; + rm "$out" + exit 1 + fi + + # Prepare for next test + cd - &>/dev/null +done + +rm "$out" diff --git a/tests/simple_breakpoints_auto_1n/node.py b/tests/simple_breakpoints_auto_1n/node.py new file mode 100644 index 0000000..e812c01 --- /dev/null +++ b/tests/simple_breakpoints_auto_1n/node.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +def execute(api): + if api.node_id == 0: + api.send("eth0","Hello",5,1) + else: + api.receive("eth0") + diff --git a/tests/simple_breakpoints_auto_1n/out b/tests/simple_breakpoints_auto_1n/out new file mode 100644 index 0000000..e8fce88 --- /dev/null +++ b/tests/simple_breakpoints_auto_1n/out @@ -0,0 +1,9 @@ +[t=0.000,src=n0] Send 5 bytes to n1 on eth0 +[t=3.300,src=esds] Hello Callback! +[t=6.600,src=esds] Hello Callback! +[t=9.900,src=esds] Hello Callback! +[t=13.200,src=esds] Hello Callback! +[t=16.500,src=esds] Hello Callback! +[t=19.800,src=esds] Hello Callback! +[t=20.000,src=n1] Receive 5 bytes on eth0 +[t=20.000,src=esds] Simulation ends diff --git a/tests/simple_breakpoints_auto_1n/simulator.py b/tests/simple_breakpoints_auto_1n/simulator.py new file mode 100755 index 0000000..c5e3b02 --- /dev/null +++ b/tests/simple_breakpoints_auto_1n/simulator.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +n=2 +B=np.full((2,2),n) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("node") +s.create_node("node") + +def callback(simulator): + simulator.log("Hello Callback!") + +s.run(breakpoints_every=3.3,breakpoint_callback=callback) diff --git a/tests/simple_breakpoints_manual_1n/node.py b/tests/simple_breakpoints_manual_1n/node.py new file mode 100644 index 0000000..f8c5633 --- /dev/null +++ b/tests/simple_breakpoints_manual_1n/node.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.log("Running") diff --git a/tests/simple_breakpoints_manual_1n/out b/tests/simple_breakpoints_manual_1n/out new file mode 100644 index 0000000..40c44b7 --- /dev/null +++ b/tests/simple_breakpoints_manual_1n/out @@ -0,0 +1,7 @@ +[t=0.000,src=n0] Running +[t=0.000,src=n1] Running +[t=1.000,src=esds] Hello Callback! +[t=2.000,src=esds] Hello Callback! +[t=3.000,src=esds] Hello Callback! +[t=10.000,src=esds] Hello Callback! +[t=10.000,src=esds] Simulation ends diff --git a/tests/simple_breakpoints_manual_1n/simulator.py b/tests/simple_breakpoints_manual_1n/simulator.py new file mode 100755 index 0000000..a0d0d2b --- /dev/null +++ b/tests/simple_breakpoints_manual_1n/simulator.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +n=2 +B=np.full((n,n),n) +L=np.full((n,n),0) +s=esds.Simulator(B,L) + +s.create_node("node") +s.create_node("node") + +def callback(simulator): + simulator.log("Hello Callback!") + +s.run(breakpoints=[1,2,3,10],breakpoint_callback=callback) diff --git a/tests/simple_breakpoints_manual_no_callback_1n/node.py b/tests/simple_breakpoints_manual_no_callback_1n/node.py new file mode 100644 index 0000000..f8c5633 --- /dev/null +++ b/tests/simple_breakpoints_manual_no_callback_1n/node.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.log("Running") diff --git a/tests/simple_breakpoints_manual_no_callback_1n/out b/tests/simple_breakpoints_manual_no_callback_1n/out new file mode 100644 index 0000000..defce2c --- /dev/null +++ b/tests/simple_breakpoints_manual_no_callback_1n/out @@ -0,0 +1,3 @@ +[t=0.000,src=n0] Running +[t=0.000,src=n1] Running +[t=10.000,src=esds] Simulation ends diff --git a/tests/simple_breakpoints_manual_no_callback_1n/simulator.py b/tests/simple_breakpoints_manual_no_callback_1n/simulator.py new file mode 100755 index 0000000..93b1fef --- /dev/null +++ b/tests/simple_breakpoints_manual_no_callback_1n/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +n=2 +B=np.full((n,n),n) +L=np.full((n,n),0) +s=esds.Simulator(B,L) + +s.create_node("node") +s.create_node("node") + +s.run(breakpoints=[1,2,3,10]) diff --git a/tests/simple_log_5n/node.py b/tests/simple_log_5n/node.py new file mode 100644 index 0000000..053c9fd --- /dev/null +++ b/tests/simple_log_5n/node.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +def execute(api): + api.log("A") + api.log("B") + api.log("C") + api.log("D") diff --git a/tests/simple_log_5n/out b/tests/simple_log_5n/out new file mode 100644 index 0000000..7d89c56 --- /dev/null +++ b/tests/simple_log_5n/out @@ -0,0 +1,21 @@ +[t=0.000,src=n0] A +[t=0.000,src=n0] B +[t=0.000,src=n0] C +[t=0.000,src=n0] D +[t=0.000,src=n1] A +[t=0.000,src=n1] B +[t=0.000,src=n1] C +[t=0.000,src=n1] D +[t=0.000,src=n2] A +[t=0.000,src=n2] B +[t=0.000,src=n2] C +[t=0.000,src=n2] D +[t=0.000,src=n3] A +[t=0.000,src=n3] B +[t=0.000,src=n3] C +[t=0.000,src=n3] D +[t=0.000,src=n4] A +[t=0.000,src=n4] B +[t=0.000,src=n4] C +[t=0.000,src=n4] D +[t=0.000,src=esds] Simulation ends diff --git a/tests/simple_log_5n/simulator.py b/tests/simple_log_5n/simulator.py new file mode 100755 index 0000000..184340a --- /dev/null +++ b/tests/simple_log_5n/simulator.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((5,5),5) +L=np.full((5,5),0) +s=esds.Simulator(B,L) + +s.create_node("node") +s.create_node("node") +s.create_node("node") +s.create_node("node") +s.create_node("node") + +s.run() diff --git a/tests/simple_read_clock_2n/node.py b/tests/simple_read_clock_2n/node.py new file mode 100644 index 0000000..79a0b78 --- /dev/null +++ b/tests/simple_read_clock_2n/node.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +def execute(api): + api.log("Clock is {}s".format(api.read("clock"))) + api.wait(5698.1256) + api.log("Clock is {}s".format(api.read("clock"))) + api.log("Clock is {}s".format(api.read("clock"))) diff --git a/tests/simple_read_clock_2n/out b/tests/simple_read_clock_2n/out new file mode 100644 index 0000000..4fa7877 --- /dev/null +++ b/tests/simple_read_clock_2n/out @@ -0,0 +1,7 @@ +[t=0.000,src=n0] Clock is 0s +[t=0.000,src=n1] Clock is 0s +[t=5698.126,src=n0] Clock is 5698.1256s +[t=5698.126,src=n0] Clock is 5698.1256s +[t=5698.126,src=n1] Clock is 5698.1256s +[t=5698.126,src=n1] Clock is 5698.1256s +[t=5698.126,src=esds] Simulation ends diff --git a/tests/simple_read_clock_2n/simulator.py b/tests/simple_read_clock_2n/simulator.py new file mode 100755 index 0000000..b2c042c --- /dev/null +++ b/tests/simple_read_clock_2n/simulator.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((2,2),2) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("node") +s.create_node("node") + +s.run() diff --git a/tests/simple_read_eth0_ncom_2s1r/out b/tests/simple_read_eth0_ncom_2s1r/out new file mode 100644 index 0000000..087e62b --- /dev/null +++ b/tests/simple_read_eth0_ncom_2s1r/out @@ -0,0 +1,9 @@ +[t=0.000,src=n2] eth0 is 0 +[t=624.000,src=n2] eth0 is 0 +[t=1248.000,src=n0] Send 50 bytes to n2 on eth0 +[t=1249.000,src=n2] eth0 is 1 +[t=1249.000,src=n1] Send 50 bytes to n2 on eth0 +[t=1250.000,src=n2] eth0 is 2 +[t=1513.667,src=n2] Receive 50 bytes on eth0 +[t=1514.667,src=n2] Receive 50 bytes on eth0 +[t=1514.667,src=esds] Simulation ends diff --git a/tests/simple_read_eth0_ncom_2s1r/receiver.py b/tests/simple_read_eth0_ncom_2s1r/receiver.py new file mode 100644 index 0000000..819fc84 --- /dev/null +++ b/tests/simple_read_eth0_ncom_2s1r/receiver.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +def execute(api): + api.log("eth0 is {}".format(api.read("eth0_ncom"))) + api.wait(624) + api.log("eth0 is {}".format(api.read("eth0_ncom"))) + api.wait(624) + # Now we are at 624*2=1248 (first sender start a communication) + api.wait(1) # Let the communication starts + api.log("eth0 is {}".format(api.read("eth0_ncom"))) # Should print 1 + api.wait(1) # Now second sender start a communication + api.log("eth0 is {}".format(api.read("eth0_ncom"))) # Should print 2 diff --git a/tests/simple_read_eth0_ncom_2s1r/sender.py b/tests/simple_read_eth0_ncom_2s1r/sender.py new file mode 100644 index 0000000..7c9259a --- /dev/null +++ b/tests/simple_read_eth0_ncom_2s1r/sender.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +def execute(api): + api.wait(1248) + if api.node_id==0: + api.send("eth0","hello",50,2) + else: + api.wait(1) + api.send("eth0","hello",50,2) diff --git a/tests/simple_read_eth0_ncom_2s1r/simulator.py b/tests/simple_read_eth0_ncom_2s1r/simulator.py new file mode 100755 index 0000000..5294b9d --- /dev/null +++ b/tests/simple_read_eth0_ncom_2s1r/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),3) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("sender") +s.create_node("receiver") + +s.run(interferences=False) diff --git a/tests/simple_read_wlan0_ncom_2s1r/out b/tests/simple_read_wlan0_ncom_2s1r/out new file mode 100644 index 0000000..93543eb --- /dev/null +++ b/tests/simple_read_wlan0_ncom_2s1r/out @@ -0,0 +1,11 @@ +[t=0.000,src=n2] wlan0 is 0 +[t=624.000,src=n2] wlan0 is 0 +[t=1248.000,src=n0] Send 50 bytes on wlan0 +[t=1249.000,src=n2] wlan0 is 1 +[t=1249.000,src=n1] Send 50 bytes on wlan0 +[t=1250.000,src=n2] wlan0 is 2 +[t=1381.333,src=n1] Receive 50 bytes on wlan0 +[t=1381.333,src=n2] Receive 50 bytes on wlan0 +[t=1382.333,src=n0] Receive 50 bytes on wlan0 +[t=1382.333,src=n2] Receive 50 bytes on wlan0 +[t=1382.333,src=esds] Simulation ends diff --git a/tests/simple_read_wlan0_ncom_2s1r/receiver.py b/tests/simple_read_wlan0_ncom_2s1r/receiver.py new file mode 100644 index 0000000..9f652aa --- /dev/null +++ b/tests/simple_read_wlan0_ncom_2s1r/receiver.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +def execute(api): + api.log("wlan0 is {}".format(api.read("wlan0_ncom"))) + api.wait(624) + api.log("wlan0 is {}".format(api.read("wlan0_ncom"))) + api.wait(624) + # Now we are at 624*2=1248 (first sender start a communication) + api.wait(1) # Let the communication starts + api.log("wlan0 is {}".format(api.read("wlan0_ncom"))) # Should print 1 + api.wait(1) # Second sender start a communication + api.log("wlan0 is {}".format(api.read("wlan0_ncom"))) # Should print 2 diff --git a/tests/simple_read_wlan0_ncom_2s1r/sender.py b/tests/simple_read_wlan0_ncom_2s1r/sender.py new file mode 100644 index 0000000..b89e5e2 --- /dev/null +++ b/tests/simple_read_wlan0_ncom_2s1r/sender.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +def execute(api): + api.wait(1248) + if api.node_id==0: + api.send("wlan0","hello",50,None) + else: + api.wait(1) + api.send("wlan0","hello",50,None) diff --git a/tests/simple_read_wlan0_ncom_2s1r/simulator.py b/tests/simple_read_wlan0_ncom_2s1r/simulator.py new file mode 100755 index 0000000..5294b9d --- /dev/null +++ b/tests/simple_read_wlan0_ncom_2s1r/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),3) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("sender") +s.create_node("receiver") + +s.run(interferences=False) diff --git a/tests/simple_receivet_eth0_1s1r/out b/tests/simple_receivet_eth0_1s1r/out new file mode 100644 index 0000000..98756b5 --- /dev/null +++ b/tests/simple_receivet_eth0_1s1r/out @@ -0,0 +1,8 @@ +[t=0.000,src=n0] Send 1 bytes to n1 on eth0 +[t=1.000,src=n1] Receive 1 bytes on eth0 +[t=1.000,src=n1] Received: Hello World! +[t=1.000,src=n0] Send 1 bytes to n1 on eth0 +[t=1.500,src=n1] Receive failed code=-1 +[t=2.000,src=n1] Receive 1 bytes on eth0 +[t=2.000,src=n1] Received: Hello World! +[t=2.000,src=esds] Simulation ends diff --git a/tests/simple_receivet_eth0_1s1r/receiver.py b/tests/simple_receivet_eth0_1s1r/receiver.py new file mode 100644 index 0000000..515ff6a --- /dev/null +++ b/tests/simple_receivet_eth0_1s1r/receiver.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +def receivet(node,timeout): + ##### Simple receive + code, data=node.receivet("eth0",timeout) + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + node.log(msg) + +def execute(api): + # Should works + receivet(api,2) + # Should failed + receivet(api,0.5) # At t=1.5s + # Should works (priorities says that communications should occurs before timeout) + receivet(api,0.5) # At t=2s (timeout+receive should occur) diff --git a/tests/simple_receivet_eth0_1s1r/sender.py b/tests/simple_receivet_eth0_1s1r/sender.py new file mode 100644 index 0000000..0b6bdb6 --- /dev/null +++ b/tests/simple_receivet_eth0_1s1r/sender.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +def execute(api): + api.send("eth0","Hello World!",1,1) + api.send("eth0","Hello World!",1,1) + diff --git a/tests/simple_receivet_eth0_1s1r/simulator.py b/tests/simple_receivet_eth0_1s1r/simulator.py new file mode 100755 index 0000000..5ec9a25 --- /dev/null +++ b/tests/simple_receivet_eth0_1s1r/simulator.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((2,2),8) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") + +s.run(debug=True) diff --git a/tests/simple_receivet_eth0_1s1r/yoctosim.debug b/tests/simple_receivet_eth0_1s1r/yoctosim.debug new file mode 100644 index 0000000..9d879f4 --- /dev/null +++ b/tests/simple_receivet_eth0_1s1r/yoctosim.debug @@ -0,0 +1,43 @@ +Python version 3.10.5 (main, Jun 6 2022, 18:49:26) [GCC 12.1.0] +Simulation started at 1654802960.7880125 +Number of nodes is 2 +Manual breakpoints list: [] +Breakpoints every Nones +----------------------------------------------- +Started since 0.02s +Simulated time 0.000s (or more precisely 0s) +Node number per state: pending=1 request=1 +Node sharing: n1=1 +Ids of node in timeout mode: +Sorted events list: +[[0 1.0 array([0, 1, 'eth0', 'Hello World!', 1, 1.0, 1, 0], dtype=object) + 1] + [1 2 array(1, dtype=object) 3]] +----------------------------------------------- +Started since 0.04s +Simulated time 1.000s (or more precisely 1.0s) +Node number per state: pending=1 request=1 +Node sharing: n1=1 +Ids of node in timeout mode: +Sorted events list: +[[1 1.5 array(1, dtype=object) 3] + [0 2.0 + array([0, 1, 'eth0', 'Hello World!', 1, 1.0, 1, 1.0], dtype=object) 1]] +----------------------------------------------- +Started since 0.06s +Simulated time 1.500s (or more precisely 1.5s) +Node number per state: pending=1 request=1 +Node sharing: n1=1 +Ids of node in timeout mode: +Sorted events list: +[[0 2.0 + array([0, 1, 'eth0', 'Hello World!', 1, 1.0, 1, 1.0], dtype=object) 1] + [1 2.0 array(1, dtype=object) 3]] +----------------------------------------------- +Started since 0.08s +Simulated time 2.000s (or more precisely 2.0s) +Node number per state: terminated=2 +Node sharing: +Ids of node in timeout mode: +Sorted events list: +[] diff --git a/tests/simple_send_eth0_1s1r/out b/tests/simple_send_eth0_1s1r/out new file mode 100644 index 0000000..1634d95 --- /dev/null +++ b/tests/simple_send_eth0_1s1r/out @@ -0,0 +1,11 @@ +[t=0.000,src=n0] Send 1 bytes to n1 on eth0 +[t=1.000,src=n1] Receive 1 bytes on eth0 +[t=1.000,src=n1] Received: Hello World! +[t=1.000,src=n0] Send 1 bytes to n1 on eth0 +[t=2.000,src=n1] Receive 1 bytes on eth0 +[t=3.000,src=n0] Send 1 bytes to n1 on eth0 +[t=3.000,src=n1] Received: Hello World! +[t=3.000,src=n1] Turned off +[t=4.000,src=n1] Turned on +[t=5.000,src=n1] Receive failed code=-1 +[t=5.000,src=esds] Simulation ends diff --git a/tests/simple_send_eth0_1s1r/receiver.py b/tests/simple_send_eth0_1s1r/receiver.py new file mode 100644 index 0000000..96305bf --- /dev/null +++ b/tests/simple_send_eth0_1s1r/receiver.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +def execute(api): + ##### Simple receive + code, data=api.receive("eth0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + api.log(msg) + ##### Test if we still receive the data when we are not receiving + api.wait(2) + code, data=api.receive("eth0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + api.log(msg) + ##### Ensure data is not receive when turned off + api.turn_off() + api.wait(1) + api.turn_on() + code, data=api.receivet("eth0",1) + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + api.log(msg) + diff --git a/tests/simple_send_eth0_1s1r/sender.py b/tests/simple_send_eth0_1s1r/sender.py new file mode 100644 index 0000000..9f4aa85 --- /dev/null +++ b/tests/simple_send_eth0_1s1r/sender.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +def execute(api): + api.send("eth0","Hello World!",1,1) + api.send("eth0","Hello World!",1,1) + api.wait(1) # Goto 3 seconds + api.send("eth0","Hello World!",1,1) diff --git a/tests/simple_send_eth0_1s1r/simulator.py b/tests/simple_send_eth0_1s1r/simulator.py new file mode 100755 index 0000000..f5f6ca6 --- /dev/null +++ b/tests/simple_send_eth0_1s1r/simulator.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((2,2),8) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") + +s.run() diff --git a/tests/simple_send_eth0_2s1r/out b/tests/simple_send_eth0_2s1r/out new file mode 100644 index 0000000..4a5ebb8 --- /dev/null +++ b/tests/simple_send_eth0_2s1r/out @@ -0,0 +1,7 @@ +[t=0.000,src=n0] Send 1 bytes to n2 on eth0 +[t=0.000,src=n1] Send 1 bytes to n2 on eth0 +[t=2.000,src=n2] Receive 1 bytes on eth0 +[t=2.000,src=n2] Received: Hello World from 0! +[t=2.000,src=n2] Receive 1 bytes on eth0 +[t=2.000,src=n2] Received: Hello World from 1! +[t=2.000,src=esds] Simulation ends diff --git a/tests/simple_send_eth0_2s1r/receiver.py b/tests/simple_send_eth0_2s1r/receiver.py new file mode 100644 index 0000000..2f268fd --- /dev/null +++ b/tests/simple_send_eth0_2s1r/receiver.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +def execute(api): + ##### Simple receive from node 0 + code, data=api.receive("eth0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + api.log(msg) + + ##### Simple receive from node 1 + code, data=api.receive("eth0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + api.log(msg) + diff --git a/tests/simple_send_eth0_2s1r/sender.py b/tests/simple_send_eth0_2s1r/sender.py new file mode 100644 index 0000000..90daae5 --- /dev/null +++ b/tests/simple_send_eth0_2s1r/sender.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + api.send("eth0","Hello World from {}!".format(api.node_id),1,2) + diff --git a/tests/simple_send_eth0_2s1r/simulator.py b/tests/simple_send_eth0_2s1r/simulator.py new file mode 100755 index 0000000..9faaf3d --- /dev/null +++ b/tests/simple_send_eth0_2s1r/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),8) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("sender") +s.create_node("receiver") + +s.run() diff --git a/tests/simple_send_eth0_3s1r/out b/tests/simple_send_eth0_3s1r/out new file mode 100644 index 0000000..8cf82a6 --- /dev/null +++ b/tests/simple_send_eth0_3s1r/out @@ -0,0 +1,40 @@ +[t=0.000,src=n0] Send 1 bytes to n3 on eth0 +[t=0.000,src=n1] Send 1 bytes to n3 on eth0 +[t=0.000,src=n2] Send 1 bytes to n3 on eth0 +[t=3.000,src=n3] Receive 1 bytes on eth0 +[t=3.000,src=n3] Received: Hello World from 0! +[t=3.000,src=n3] Receive 1 bytes on eth0 +[t=3.000,src=n3] Received: Hello World from 1! +[t=3.000,src=n3] Receive 1 bytes on eth0 +[t=3.000,src=n3] Received: Hello World from 2! +[t=3.000,src=n0] Send 2 bytes to n3 on eth0 +[t=3.000,src=n1] Send 1 bytes to n3 on eth0 +[t=3.000,src=n2] Send 1 bytes to n3 on eth0 +[t=6.000,src=n3] Receive 1 bytes on eth0 +[t=6.000,src=n3] Received: Hello World from 1! +[t=6.000,src=n3] Receive 1 bytes on eth0 +[t=6.000,src=n3] Received: Hello World from 2! +[t=7.000,src=n3] Receive 2 bytes on eth0 +[t=7.000,src=n3] Received: Hello World from 0! +[t=7.000,src=n0] Send 2 bytes to n3 on eth0 +[t=7.000,src=n1] Send 2 bytes to n3 on eth0 +[t=7.000,src=n2] Send 1 bytes to n3 on eth0 +[t=10.000,src=n3] Receive 1 bytes on eth0 +[t=10.000,src=n3] Received: Hello World from 2! +[t=12.000,src=n3] Receive 2 bytes on eth0 +[t=12.000,src=n3] Received: Hello World from 0! +[t=12.000,src=n3] Receive 2 bytes on eth0 +[t=12.000,src=n3] Received: Hello World from 1! +[t=12.000,src=n0] Send 1 bytes to n3 on eth0 +[t=12.000,src=n1] Send 2 bytes to n3 on eth0 +[t=12.000,src=n2] Send 3 bytes to n3 on eth0 +[t=15.000,src=n3] Receive 1 bytes on eth0 +[t=15.000,src=n3] Received: Hello World from 0! +[t=17.000,src=n3] Receive 2 bytes on eth0 +[t=17.000,src=n3] Received: Hello World from 1! +[t=18.000,src=n3] Receive 3 bytes on eth0 +[t=18.000,src=n3] Received: Hello World from 2! +[t=18.000,src=n0] Send 5 bytes to n3 on eth0 +[t=23.000,src=n3] Receive 5 bytes on eth0 +[t=23.000,src=n3] Received: Hello World from 0! +[t=23.000,src=esds] Simulation ends diff --git a/tests/simple_send_eth0_3s1r/receiver.py b/tests/simple_send_eth0_3s1r/receiver.py new file mode 100644 index 0000000..4516d7a --- /dev/null +++ b/tests/simple_send_eth0_3s1r/receiver.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +def receive(node, n): + for i in range(0,n): + code, data=node.receive("eth0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + node.log(msg) + +def execute(api): + # Receive the first 3 send that should end at 3s + receive(api,3) + # Receive the first 3 send that should end at 7s + receive(api,3) + # Receive the first 3 send that should end at 12s + receive(api,3) + # Receive the first 3 send that should end at 18s + receive(api,3) + # Should ends at 23s + receive(api,1) diff --git a/tests/simple_send_eth0_3s1r/sender.py b/tests/simple_send_eth0_3s1r/sender.py new file mode 100644 index 0000000..d3c7bf2 --- /dev/null +++ b/tests/simple_send_eth0_3s1r/sender.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Node that bandwidths at setup in a way that 1 byte is send in 1 seconds with no sharing + +def execute(api): + # Should be completed at 3s (bandwidth divided by 3) + api.send("eth0","Hello World from {}!".format(api.node_id),1,3) # Shoud lasts 3s + + # These send should start at 3s and be completed at 7s + if api.node_id==0: + api.send("eth0","Hello World from {}!".format(api.node_id),2,3) # Should lasts 3s + 1s = 4s + else: + api.send("eth0","Hello World from {}!".format(api.node_id),1,3) # Should lasts 3s + api.wait(1) # Sync with node 0 at 7s + + # Those sends should start at 7s and be completed at 12s + if api.node_id<=1: + api.send("eth0","Hello World from {}!".format(api.node_id),2,3) # Should last 3s + 2s = 5s + # Completed at 12s since 3 nodes are sharing the bandwidth up to 10s + # then the 2 two remaining node send their last byte up to 12s + else: + api.send("eth0","Hello World from {}!".format(api.node_id),1,3) # Should last 3s + # Completed at 10s (3 nodes are sharing the bandwidth) + api.wait(2) # Sync with node 0-1 at 12s + + # Should start at 12s + # Node 0 sends 1 byte, node 1 sends 2 byte and node 2 sends 3 + # These send should end at 18s + api.send("eth0","Hello World from {}!".format(api.node_id),api.node_id+1,3) # Should lasts 3s, 5s and 6s + + # Finally a single send from node 0 + if api.node_id==0: + api.wait(3) # Since node 0 send ends at 15s we sync it to 18s + api.send("eth0","Hello World from {}!".format(api.node_id),5,3) # Should takes 5 seconds (ends at 23s) + + + diff --git a/tests/simple_send_eth0_3s1r/simulator.py b/tests/simple_send_eth0_3s1r/simulator.py new file mode 100755 index 0000000..4a5aede --- /dev/null +++ b/tests/simple_send_eth0_3s1r/simulator.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((4,4),8) +L=np.full((4,4),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("sender") +s.create_node("sender") +s.create_node("receiver") + +s.run() diff --git a/tests/simple_send_wlan0_1s2r/out b/tests/simple_send_wlan0_1s2r/out new file mode 100644 index 0000000..98cc425 --- /dev/null +++ b/tests/simple_send_wlan0_1s2r/out @@ -0,0 +1,16 @@ +[t=0.000,src=n0] Send 1 bytes on wlan0 +[t=1.000,src=n1] Receive 1 bytes on wlan0 +[t=1.000,src=n1] Received: Hello World! +[t=1.000,src=n2] Receive 1 bytes on wlan0 +[t=1.000,src=n2] Received: Hello World! +[t=1.000,src=n2] Turned off +[t=1.000,src=n0] Send 1 bytes on wlan0 +[t=2.000,src=n1] Receive 1 bytes on wlan0 +[t=2.000,src=n1] Received: Hello World! +[t=2.000,src=n2] Turned on +[t=2.000,src=n0] Send 1 bytes on wlan0 +[t=2.500,src=n2] Turned off +[t=3.000,src=n1] Receive 1 bytes on wlan0 +[t=3.000,src=n1] Received: Hello World! +[t=3.000,src=n2] Turned on +[t=3.000,src=esds] Simulation ends diff --git a/tests/simple_send_wlan0_1s2r/receiver.py b/tests/simple_send_wlan0_1s2r/receiver.py new file mode 100644 index 0000000..5b86500 --- /dev/null +++ b/tests/simple_send_wlan0_1s2r/receiver.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +def receive(node): + ##### Simple receive + code, data=node.receive("wlan0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + node.log(msg) + + +def execute(api): + # Should works for all receivers + receive(api) + + if api.node_id == 1: + receive(api) # Should works + else: + api.turn_off() + api.wait(1) # Node 2 should not receive anything during 1s + api.turn_on() + + + if api.node_id == 1: + receive(api) # Should works + else: + api.wait(0.5) # Check if started communication get cancelled on turning off + api.turn_off() # Node 2 should not receive anything + api.wait(0.5) # Node 2 should not receive anything during 0.5s + api.turn_on() + diff --git a/tests/simple_send_wlan0_1s2r/sender.py b/tests/simple_send_wlan0_1s2r/sender.py new file mode 100644 index 0000000..ef1517b --- /dev/null +++ b/tests/simple_send_wlan0_1s2r/sender.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +def execute(api): + api.send("wlan0","Hello World!",1,1) + api.send("wlan0","Hello World!",1,1) + api.send("wlan0","Hello World!",1,1) diff --git a/tests/simple_send_wlan0_1s2r/simulator.py b/tests/simple_send_wlan0_1s2r/simulator.py new file mode 100755 index 0000000..3f53e63 --- /dev/null +++ b/tests/simple_send_wlan0_1s2r/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),8) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") +s.create_node("receiver") + +s.run() diff --git a/tests/simple_send_wlan0_2s1r/out b/tests/simple_send_wlan0_2s1r/out new file mode 100644 index 0000000..788ee42 --- /dev/null +++ b/tests/simple_send_wlan0_2s1r/out @@ -0,0 +1,6 @@ +[t=0.000,src=n0] Send 1 bytes on wlan0 +[t=0.000,src=n1] Send 1 bytes on wlan0 +[t=0.000,src=n0] Interferences on wlan0 +[t=0.000,src=n1] Interferences on wlan0 +[t=0.000,src=n2] Interferences on wlan0 +[t=1.000,src=esds] Simulation ends diff --git a/tests/simple_send_wlan0_2s1r/receiver.py b/tests/simple_send_wlan0_2s1r/receiver.py new file mode 100644 index 0000000..0b48f12 --- /dev/null +++ b/tests/simple_send_wlan0_2s1r/receiver.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +def execute(api): + pass + diff --git a/tests/simple_send_wlan0_2s1r/sender.py b/tests/simple_send_wlan0_2s1r/sender.py new file mode 100644 index 0000000..80f0fc2 --- /dev/null +++ b/tests/simple_send_wlan0_2s1r/sender.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +def execute(api): + api.send("wlan0","Hello World!",1,1) diff --git a/tests/simple_send_wlan0_2s1r/simulator.py b/tests/simple_send_wlan0_2s1r/simulator.py new file mode 100755 index 0000000..9faaf3d --- /dev/null +++ b/tests/simple_send_wlan0_2s1r/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),8) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("sender") +s.create_node("receiver") + +s.run() diff --git a/tests/simple_sendt_eth0_1s1r/out b/tests/simple_sendt_eth0_1s1r/out new file mode 100644 index 0000000..e6d70d5 --- /dev/null +++ b/tests/simple_sendt_eth0_1s1r/out @@ -0,0 +1,11 @@ +[t=0.000,src=n0] Send 1 bytes to n1 on eth0 +[t=1.000,src=n1] Receive 1 bytes on eth0 +[t=1.000,src=n1] Received: Hello World! +[t=1.000,src=n0] Send worked! +[t=1.000,src=n0] Send 1 bytes to n1 on eth0 +[t=1.500,src=n0] Send failed +[t=1.500,src=n0] Send 1 bytes to n1 on eth0 +[t=2.500,src=n1] Receive 1 bytes on eth0 +[t=2.500,src=n1] Received: Hello World! +[t=2.500,src=n0] Send worked! +[t=2.500,src=esds] Simulation ends diff --git a/tests/simple_sendt_eth0_1s1r/receiver.py b/tests/simple_sendt_eth0_1s1r/receiver.py new file mode 100644 index 0000000..0d8561e --- /dev/null +++ b/tests/simple_sendt_eth0_1s1r/receiver.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +def receive(node): + ##### Simple receive + code, data=node.receive("eth0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + node.log(msg) + +def execute(api): + receive(api) + receive(api) diff --git a/tests/simple_sendt_eth0_1s1r/sender.py b/tests/simple_sendt_eth0_1s1r/sender.py new file mode 100644 index 0000000..ee2ea9d --- /dev/null +++ b/tests/simple_sendt_eth0_1s1r/sender.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +def sendt(node,timeout): + code=node.sendt("eth0","Hello World!",1,1,timeout) + msg="Send worked!" if code == 0 else "Send failed" + node.log(msg) + +def execute(api): + # Should work + sendt(api,2) + # Should not work + sendt(api,0.5) + # Should work + sendt(api,2) diff --git a/tests/simple_sendt_eth0_1s1r/simulator.py b/tests/simple_sendt_eth0_1s1r/simulator.py new file mode 100755 index 0000000..f5f6ca6 --- /dev/null +++ b/tests/simple_sendt_eth0_1s1r/simulator.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((2,2),8) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") + +s.run() diff --git a/tests/simple_sendt_wlan0_1s2r/out b/tests/simple_sendt_wlan0_1s2r/out new file mode 100644 index 0000000..5a4f82c --- /dev/null +++ b/tests/simple_sendt_wlan0_1s2r/out @@ -0,0 +1,7 @@ +[t=0.000,src=n0] Send 1 bytes on wlan0 +[t=1.000,src=n1] Receive 1 bytes on wlan0 +[t=1.000,src=n1] Received: Hello World! +[t=1.000,src=n2] Receive 1 bytes on wlan0 +[t=1.000,src=n2] Received: Hello World! +[t=1.000,src=n0] Send 1 bytes on wlan0 +[t=1.500,src=esds] Simulation ends diff --git a/tests/simple_sendt_wlan0_1s2r/receiver.py b/tests/simple_sendt_wlan0_1s2r/receiver.py new file mode 100644 index 0000000..eca49ad --- /dev/null +++ b/tests/simple_sendt_wlan0_1s2r/receiver.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +def receive(node): + ##### Simple receive + code, data=node.receive("wlan0") + msg="Received: "+data if code == 0 else "Receive failed code="+str(code) + node.log(msg) + + +def execute(api): + # Should works for all receivers + receive(api) + diff --git a/tests/simple_sendt_wlan0_1s2r/sender.py b/tests/simple_sendt_wlan0_1s2r/sender.py new file mode 100644 index 0000000..fe2dc1a --- /dev/null +++ b/tests/simple_sendt_wlan0_1s2r/sender.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +def execute(api): + # Should works + api.sendt("wlan0","Hello World!",1,1,2) + # Should not work + api.sendt("wlan0","Hello World!",1,1,0.5) + diff --git a/tests/simple_sendt_wlan0_1s2r/simulator.py b/tests/simple_sendt_wlan0_1s2r/simulator.py new file mode 100755 index 0000000..3f53e63 --- /dev/null +++ b/tests/simple_sendt_wlan0_1s2r/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),8) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("sender") +s.create_node("receiver") +s.create_node("receiver") + +s.run() diff --git a/tests/simple_wait_2n/node.py b/tests/simple_wait_2n/node.py new file mode 100644 index 0000000..86b06de --- /dev/null +++ b/tests/simple_wait_2n/node.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +def execute(api): + api.log("Before wait") + api.wait(2) + api.log("After wait") + api.log("Before wait") + api.wait(3) + api.log("After wait") diff --git a/tests/simple_wait_2n/out b/tests/simple_wait_2n/out new file mode 100644 index 0000000..8a694cc --- /dev/null +++ b/tests/simple_wait_2n/out @@ -0,0 +1,9 @@ +[t=0.000,src=n0] Before wait +[t=0.000,src=n1] Before wait +[t=2.000,src=n0] After wait +[t=2.000,src=n0] Before wait +[t=2.000,src=n1] After wait +[t=2.000,src=n1] Before wait +[t=5.000,src=n0] After wait +[t=5.000,src=n1] After wait +[t=5.000,src=esds] Simulation ends diff --git a/tests/simple_wait_2n/simulator.py b/tests/simple_wait_2n/simulator.py new file mode 100755 index 0000000..b2c042c --- /dev/null +++ b/tests/simple_wait_2n/simulator.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((2,2),2) +L=np.full((2,2),0) +s=esds.Simulator(B,L) + +s.create_node("node") +s.create_node("node") + +s.run() diff --git a/tests/simple_wait_end_3n/node.py b/tests/simple_wait_end_3n/node.py new file mode 100644 index 0000000..a8fbcd7 --- /dev/null +++ b/tests/simple_wait_end_3n/node.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +def execute(api): + wait=api.node_id + api.log("Before wait for "+str(wait)+"s") + api.wait(wait) # Since 3 nodes max(wait)==2 + + # Ensure that wait end return back when simulation ends + api.wait_end() + api.log("Terminated") diff --git a/tests/simple_wait_end_3n/out b/tests/simple_wait_end_3n/out new file mode 100644 index 0000000..321b0c2 --- /dev/null +++ b/tests/simple_wait_end_3n/out @@ -0,0 +1,7 @@ +[t=0.000,src=n0] Before wait for 0s +[t=0.000,src=n1] Before wait for 1s +[t=0.000,src=n2] Before wait for 2s +[t=2.000,src=n0] Terminated +[t=2.000,src=n1] Terminated +[t=2.000,src=n2] Terminated +[t=2.000,src=esds] Simulation ends diff --git a/tests/simple_wait_end_3n/simulator.py b/tests/simple_wait_end_3n/simulator.py new file mode 100755 index 0000000..d4c9ec4 --- /dev/null +++ b/tests/simple_wait_end_3n/simulator.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Load ESDS +import sys +sys.path.append("../../") +import esds +import numpy as np + +B=np.full((3,3),2) +L=np.full((3,3),0) +s=esds.Simulator(B,L) + +s.create_node("node") +s.create_node("node") +s.create_node("node") + +s.run()