change to appropriate toolbar when join session, emane config, emane model config

This commit is contained in:
Huy Pham 2019-11-05 14:25:25 -08:00
parent 68da6c0c14
commit 20637da140
7 changed files with 217 additions and 110 deletions

View file

@ -7,6 +7,7 @@ from tkinter import ttk
class ConfigType(enum.Enum):
STRING = 10
BOOL = 11
EMANECONFIG = 7
def create_config(master, config, padx=2, pady=2):
@ -52,8 +53,13 @@ def create_config(master, config, padx=2, pady=2):
else:
value.set("Off")
elif config_type == ConfigType.STRING:
value.set(option.value)
entry = tk.Entry(frame, textvariable=value)
entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif config_type == ConfigType.EMANECONFIG:
value.set(option.value)
entry = tk.Entry(frame, textvariable=value, bg="white")
entry.grid(row=index, column=1, sticky="ew", pady=pady)
else:
logging.error("unhandled config option type: %s", config_type)
values[key] = value
@ -68,7 +74,6 @@ def create_config(master, config, padx=2, pady=2):
canvas.bind(
"<Configure>", lambda event: canvas.itemconfig(frame_id, width=event.width)
)
return values

View file

@ -80,6 +80,7 @@ class CoreClient:
self.core_mapping = CoreToCanvasMapping()
self.wlanconfig_management = WlanNodeConfig()
self.mobilityconfig_management = MobilityNodeConfig()
self.emane_config = None
def handle_events(self, event):
logging.info("event: %s", event)
@ -110,11 +111,15 @@ class CoreClient:
self.nodes.clear()
self.edges.clear()
self.hooks.clear()
self.wlanconfig_management.configurations.clear()
self.mobilityconfig_management.configurations.clear()
self.emane_config = None
# get session data
response = self.client.get_session(self.session_id)
logging.info("joining session(%s): %s", self.session_id, response)
session = response.session
session_state = session.state
self.client.events(self.session_id, self.handle_events)
# get hooks
@ -140,6 +145,11 @@ class CoreClient:
config = {x: node_config[x].value for x in node_config}
self.mobilityconfig_management.configurations[node_id] = config
# get emane config
response = self.client.get_emane_config(self.session_id)
logging.info("emane config: %s", response)
self.emane_config = response.config
# determine next node id and reusable nodes
max_id = 1
for node in session.nodes:
@ -154,6 +164,14 @@ class CoreClient:
# draw session
self.app.canvas.canvas_reset_and_redraw(session)
# draw tool bar appropritate with session state
if session_state == core_pb2.SessionState.RUNTIME:
self.app.core_editbar.destroy_children_widgets()
self.app.core_editbar.create_runtime_toolbar()
else:
self.app.core_editbar.destroy_children_widgets()
self.app.core_editbar.create_toolbar()
def create_new_session(self):
"""
Create a new session
@ -298,6 +316,7 @@ class CoreClient:
links,
hooks=list(self.hooks.values()),
wlan_configs=wlan_configs,
emane_config=emane_config,
)
logging.debug("Start session %s, result: %s", self.session_id, response.result)

View file

@ -7,18 +7,6 @@ from coretk.graph import GraphMode
from coretk.images import ImageEnum, Images
from coretk.tooltip import CreateToolTip
# from enum import Enum
# class SessionStateEnum(Enum):
# NONE = "none"
# DEFINITION = "definition"
# CONFIGURATION = "configuration"
# RUNTIME = "runtime"
# DATACOLLECT = "datacollect"
# SHUTDOWN = "shutdown"
# INSTANTIATION = "instantiation"
class CoreToolbar(object):
"""

View file

@ -3,6 +3,8 @@ CoreToolbar help to draw on canvas, and make grpc client call
"""
from core.api.grpc.client import core_pb2
# from coretk import configutils
class CoreToolbarHelp:
def __init__(self, app):
@ -85,6 +87,15 @@ class CoreToolbarHelp:
links = self.get_link_list()
wlan_configs = self.get_wlan_configuration_list()
mobility_configs = self.get_mobility_configuration_list()
# get emane config
pb_emane_config = self.app.core.emane_config
emane_config = {x: pb_emane_config[x].value for x in pb_emane_config}
self.app.core.start_session(
nodes, links, wlan_configs=wlan_configs, mobility_configs=mobility_configs
nodes,
links,
wlan_configs=wlan_configs,
mobility_configs=mobility_configs,
emane_config=emane_config,
)

View file

@ -5,11 +5,15 @@ emane configuration
import logging
import tkinter as tk
import webbrowser
from tkinter import ttk
from coretk import configutils
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.mobilityconfig import MobilityConfiguration
from coretk.images import ImageEnum, Images
PAD_X = 2
PAD_Y = 2
class EmaneConfiguration(Dialog):
def __init__(self, master, app, canvas_node):
@ -20,6 +24,13 @@ class EmaneConfiguration(Dialog):
self.radiovar.set(1)
self.columnconfigure(0, weight=1)
# list(string) of emane models
self.emane_models = None
self.emane_dialog = Dialog(self, app, "emane configuration", modal=False)
self.emane_model_dialog = None
self.emane_model_combobox = None
# draw
self.node_name_and_image()
self.emane_configuration()
@ -27,8 +38,10 @@ class EmaneConfiguration(Dialog):
self.emane_options()
self.draw_apply_and_cancel()
def browse_emane_wiki(self):
webbrowser.open_new("https://github.com/adjacentlink/emane/wiki")
self.values = None
self.options = app.core.emane_config
self.model_options = None
self.model_values = None
def create_text_variable(self, val):
"""
@ -52,20 +65,109 @@ class EmaneConfiguration(Dialog):
e = tk.Entry(f, textvariable=self.create_text_variable(""), bg="white")
e.grid(row=0, column=1, padx=2, pady=2)
om = tk.OptionMenu(
f,
self.create_text_variable("None"),
"(none)",
"core1",
"core2",
command=self.choose_core,
)
om.grid(row=0, column=2, padx=2, pady=2)
cbb = ttk.Combobox(f, values=["(none)", "core1", "core2"], state="readonly")
cbb.current(0)
cbb.grid(row=0, column=2, padx=2, pady=2)
b = tk.Button(f, image=self.canvas_node.image)
b.grid(row=0, column=3, padx=2, pady=2)
f.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
f.grid(row=0, column=0, sticky="nsew")
def save_emane_option(self):
configutils.parse_config(self.options, self.values)
self.emane_dialog.destroy()
def draw_emane_options(self):
if not self.emane_dialog.winfo_exists():
self.emane_dialog = Dialog(
self, self.app, "emane configuration", modal=False
)
b1 = tk.Button(self.emane_dialog, text="Appy", command=self.save_emane_option)
b2 = tk.Button(
self.emane_dialog, text="Cancel", command=self.emane_dialog.destroy
)
if self.options is None:
session_id = self.app.core.session_id
response = self.app.core.client.get_emane_config(session_id)
logging.info("emane config: %s", response)
self.options = response.config
self.values = configutils.create_config(
self.emane_dialog, self.options, PAD_X, PAD_Y
)
b1.grid(row=1, column=0)
b2.grid(row=1, column=1)
self.emane_dialog.show()
def save_emane_model_options(self):
"""
configure the node's emane model on the fly
:return: nothing
"""
# get model name
model_name = self.emane_models[self.emane_model_combobox.current()]
# parse configuration
configutils.parse_config(self.model_options, self.model_values)
config = {x: self.model_options[x].value for x in self.model_options}
# add string emane_ infront for grpc call
response = self.app.core.client.set_emane_model_config(
self.app.core.session_id,
self.canvas_node.core_id,
"emane_" + model_name,
config,
)
logging.info(
"emaneconfig.py config emane model (%s), result: %s",
self.canvas_node.core_id,
response,
)
self.emane_model_dialog.destroy()
def draw_model_options(self):
"""
draw emane model configuration
:return: nothing
"""
# get model name
model_name = self.emane_models[self.emane_model_combobox.current()]
# create the dialog and the necessry widget
if not self.emane_model_dialog or not self.emane_model_dialog.winfo_exists():
self.emane_model_dialog = Dialog(
self, self.app, model_name + " configuration", modal=False
)
b1 = tk.Button(
self.emane_model_dialog, text="Apply", command=self.save_emane_model_options
)
b2 = tk.Button(
self.emane_model_dialog,
text="Cancel",
command=self.emane_model_dialog.destroy,
)
# query for configurations
session_id = self.app.core.session_id
# add string emane_ before model name for grpc call
response = self.app.core.client.get_emane_model_config(
session_id, self.canvas_node.core_id, "emane_" + model_name
)
logging.info("emane model config %s", response)
self.model_options = response.config
self.model_values = configutils.create_config(
self.emane_model_dialog, self.model_options, PAD_X, PAD_Y
)
b1.grid(row=1, column=0, sticky="nsew")
b2.grid(row=1, column=1, sticky="nsew")
self.emane_model_dialog.show()
def draw_option_buttons(self, parent):
f = tk.Frame(parent, bg="#d9d9d9")
@ -73,60 +175,53 @@ class EmaneConfiguration(Dialog):
f.columnconfigure(1, weight=1)
b = tk.Button(
f,
text="model options",
text=self.emane_models[0] + " options",
image=Images.get(ImageEnum.EDITNODE),
compound=tk.RIGHT,
bg="#d9d9d9",
state=tk.DISABLED,
command=self.draw_model_options,
)
b.grid(row=0, column=0, padx=10, pady=2, sticky=tk.N + tk.S + tk.E + tk.W)
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(
f,
text="EMANE options",
image=Images.get(ImageEnum.EDITNODE),
compound=tk.RIGHT,
bg="#d9d9d9",
command=self.draw_emane_options,
)
b.grid(row=0, column=1, padx=10, pady=2, sticky=tk.N + tk.S + tk.E + tk.W)
f.grid(row=4, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(row=4, column=0, sticky="nsew")
def radiobutton_text(self, val):
def combobox_select(self, event):
"""
get appropriate text based on radio value
update emane model options button
:return: the text value to configure button
:param event:
:return: nothing
"""
if val == 1:
return "none"
elif val == 2:
return "rfpipe options"
elif val == 3:
return "ieee80211abg options"
elif val == 4:
return "commeffect options"
elif val == 5:
return "bypass options"
elif val == 6:
return "tdma options"
else:
logging.debug("emaneconfig.py invalid radio value")
return ""
# get model name
model_name = self.emane_models[self.emane_model_combobox.current()]
def click_radio_button(self):
print(type(self.radiovar.get()))
# get the button and configure button text
config_frame = self.grid_slaves(row=2, column=0)[0]
option_button_frame = config_frame.grid_slaves(row=4, column=0)[0]
b = option_button_frame.grid_slaves(row=0, column=0)[0]
text = self.radiobutton_text(self.radiovar.get())
if text == "none":
state = tk.DISABLED
else:
state = tk.NORMAL
b.config(text=text, state=state)
# b.config(text=)
b.config(text=model_name + " options")
def draw_emane_models(self, parent):
models = ["none", "rfpipe", "ieee80211abg", "commeffect", "bypass", "tdma"]
"""
create a combobox that has all the known emane models
:param parent: parent
:return: nothing
"""
# query for all the known model names
session_id = self.app.core.session_id
response = self.app.core.client.get_emane_models(session_id)
self.emane_models = [x.split("_")[1] for x in response.models]
# create combo box and its binding
f = tk.Frame(
parent,
bg="#d9d9d9",
@ -135,20 +230,12 @@ class EmaneConfiguration(Dialog):
highlightthickness=0.5,
bd=0,
)
value = 1
for m in models:
b = tk.Radiobutton(
f,
text=m,
variable=self.radiovar,
indicatoron=True,
value=value,
bg="#d9d9d9",
highlightthickness=0,
command=self.click_radio_button,
)
b.grid(sticky=tk.W)
value = value + 1
self.emane_model_combobox = ttk.Combobox(
f, values=self.emane_models, state="readonly"
)
self.emane_model_combobox.grid()
self.emane_model_combobox.current(0)
self.emane_model_combobox.bind("<<ComboboxSelected>>", self.combobox_select)
f.grid(row=3, column=0, sticky=tk.W + tk.E)
def draw_text_label_and_entry(self, parent, label_text, entry_text):
@ -164,11 +251,19 @@ class EmaneConfiguration(Dialog):
lbl.grid(row=0, column=0)
e = tk.Entry(f, textvariable=var, bg="white")
e.grid(row=0, column=1)
f.grid(stick=tk.W)
f.grid(stick=tk.W, padx=2, pady=2)
def emane_configuration(self):
"""
draw the main frame for emane configuration
:return: nothing
"""
# draw label
lbl = tk.Label(self, text="Emane")
lbl.grid(row=1, column=0)
# main frame that has emane wiki, a short description, emane models and the configure buttons
f = tk.Frame(
self,
bg="#d9d9d9",
@ -187,7 +282,9 @@ class EmaneConfiguration(Dialog):
compound=tk.RIGHT,
relief=tk.RAISED,
bg="#d9d9d9",
command=self.browse_emane_wiki,
command=lambda: webbrowser.open_new(
"https://github.com/adjacentlink/emane/wiki"
),
)
b.grid(row=0, column=0, sticky=tk.W)
@ -197,54 +294,47 @@ class EmaneConfiguration(Dialog):
"\nusing pluggable MAC and PHY modules. Refer to the wiki for configuration option details",
bg="#d9d9d9",
)
lbl.grid(row=1, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
lbl.grid(row=1, column=0, sticky="nsew")
lbl = tk.Label(f, text="EMANE Models", bg="#d9d9d9")
lbl.grid(row=2, column=0, sticky=tk.W)
self.draw_option_buttons(f)
self.draw_emane_models(f)
f.grid(row=2, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
self.draw_option_buttons(f)
f.grid(row=2, column=0, sticky="nsew")
def draw_ip_subnets(self):
self.draw_text_label_and_entry(self, "IPv4 subnet", "")
self.draw_text_label_and_entry(self, "IPv6 subnet", "")
def click_ns2_mobility_script(self):
dialog = MobilityConfiguration(self, self.app, self.canvas_node)
dialog.show()
def emane_options(self):
"""
create wireless node options
:return:
"""
f = tk.Frame(self)
f = tk.Frame(self, bg="#d9d9d9")
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
f.columnconfigure(2, weight=1)
b = tk.Button(
f,
text="ns-2 mobility script...",
command=lambda: self.click_ns2_mobility_script(),
)
# b.pack(side=tk.LEFT, padx=1)
b.grid(row=0, column=0, padx=10, pady=2, sticky=tk.N + tk.S + tk.E + tk.W)
b = tk.Button(f, text="Link to all routers")
b.grid(row=0, column=1, padx=10, pady=2, sticky=tk.N + tk.S + tk.E + tk.W)
# b.pack(side=tk.LEFT, padx=1)
b = tk.Button(f, text="Choose WLAN members")
b.grid(row=0, column=2, padx=10, pady=2, sticky=tk.N + tk.S + tk.E + tk.W)
# b.pack(side=tk.LEFT, padx=1)
f.grid(row=5, column=0, sticky=tk.N + tk.S + tk.E + tk.W)
b = tk.Button(f, text="Link to all routers", bg="#d9d9d9")
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(f, text="Choose WLAN members", bg="#d9d9d9")
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(row=5, column=0, sticky="nsew")
def apply(self):
# save emane configuration
self.app.core.emane_config = self.options
self.destroy()
def draw_apply_and_cancel(self):
f = tk.Frame(self, bg="#d9d9d9")
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
b = tk.Button(f, text="Apply", bg="#d9d9d9")
b.grid(row=0, column=0, padx=10, pady=2, sticky=tk.N + tk.S + tk.E + tk.W)
b = tk.Button(f, text="Apply", bg="#d9d9d9", command=self.apply)
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(f, text="Cancel", bg="#d9d9d9", command=self.destroy)
b.grid(row=0, column=1, padx=10, pady=2, sticky=tk.N + tk.S + tk.E + tk.W)
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(sticky=tk.N + tk.S + tk.E + tk.W)
f.grid(sticky="nsew")

View file

@ -223,12 +223,6 @@ class CanvasGraph(tk.Canvas):
for i in self.find_withtag("node"):
self.lift(i)
# def delete_components(self):
# tags = ["node", "edge", "linkinfo", "nodename"]
# for i in tags:
# for id in self.find_withtag(i):
# self.delete(id)
def canvas_xy(self, event):
"""
Convert window coordinate to canvas coordinate

View file

@ -14,7 +14,7 @@
}
},
"root": {
"level": "INFO",
"level": "DEBUG",
"handlers": ["console"]
}
}