From d0c92a2a41154e496bb08ff2d6b69ef479f6e929 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Mon, 13 Apr 2020 21:53:22 +0800 Subject: [PATCH 01/16] add doc for package otns_main --- otns_main/otns_main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/otns_main/otns_main.go b/otns_main/otns_main.go index 6f24efff..8b1125e7 100644 --- a/otns_main/otns_main.go +++ b/otns_main/otns_main.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package otns_main implements the main entry for OTNS simulation programs. package otns_main import ( @@ -55,6 +56,7 @@ import ( "github.com/simonlingoogle/go-simplelogger" ) +// MainArgs defines all parameters of the Main entry. type MainArgs struct { Speed string BinDir string @@ -82,6 +84,8 @@ func parseArgs() { flag.Args() } +// Main is the main entry of an OTNS simulation program. +// It parses arguments, creates simulation, dispatcher and visualizer, and runs them. func Main(visualizerCreator func(ctx *progctx.ProgCtx, args *MainArgs) visualize.Visualizer) { parseArgs() From dbe0697dd91e47b9918ca988eaf7b1268847adb4 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Mon, 13 Apr 2020 22:00:38 +0800 Subject: [PATCH 02/16] add doc for package otns_main --- otns_main/otns_main.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/otns_main/otns_main.go b/otns_main/otns_main.go index 8b1125e7..0d862ba8 100644 --- a/otns_main/otns_main.go +++ b/otns_main/otns_main.go @@ -24,7 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. -// Package otns_main implements the main entry for OTNS simulation programs. +// Package otns_main implements the main entry for an OTNS programs. package otns_main import ( @@ -56,15 +56,15 @@ import ( "github.com/simonlingoogle/go-simplelogger" ) -// MainArgs defines all parameters of the Main entry. +// MainArgs defines all parameters of the an OTNS program. type MainArgs struct { - Speed string - BinDir string - AutoGo bool - ReadOnly bool - LogLevel string - OpenWeb bool - RawMode bool + Speed string // the simulating speed (default: 1) + BinDir string // the path to directory containing OpenThread binaries (defualt: ".") + AutoGo bool // simulation automatically goes in time (default: true) + ReadOnly bool // whether or not the simulation can be altered in web visualization (default: false) + LogLevel string // specify logging level (default: warn) + OpenWeb bool // open web browser (default: true) + RawMode bool // use raw mode (default: false) } var ( From 54ba9f4d9567b7a49d9dcba78540e1cdc94db562 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Mon, 13 Apr 2020 22:03:40 +0800 Subject: [PATCH 03/16] add doc for cmd/otns --- cmd/otns/otns.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/otns/otns.go b/cmd/otns/otns.go index e8ff803f..7118fc78 100644 --- a/cmd/otns/otns.go +++ b/cmd/otns/otns.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// otns is a program that simulates Thread networks with OpenThread virtual time simulations. package main import ( From 4c395914d9204a307c54dfece063219944d00154 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Mon, 13 Apr 2020 22:29:41 +0800 Subject: [PATCH 04/16] add doc for package cli --- cli/ast.go | 33 +------- cli/cli_test.go | 124 ++++++++++++++-------------- cli/{CmdRunner.go => cmd_runner.go} | 78 ++++++++--------- cli/runner.go | 30 +++++-- otns_main/otns_main.go | 8 +- 5 files changed, 126 insertions(+), 147 deletions(-) rename cli/{CmdRunner.go => cmd_runner.go} (85%) diff --git a/cli/ast.go b/cli/ast.go index a618bd8e..2e6c37b7 100644 --- a/cli/ast.go +++ b/cli/ast.go @@ -33,7 +33,7 @@ import ( ) //noinspection GoStructTag -type Command struct { +type command struct { Add *AddCmd ` @@` //nolint CountDown *CountDownCmd `| @@` //nolint Counters *CountersCmd `| @@` //nolint @@ -56,33 +56,6 @@ type Command struct { Web *WebCmd `| @@` //nolint } -//noinspection GoStructTag -type FullScreen struct { - FullScreen struct{} `"fs"` //nolint -} - -//noinspection GoStructTag -type RadioRange struct { - Val int `"rr" @Int` //nolint -} - -//noinspection GoStructTag -type FieldWidth struct { - Val int `"fw" @Int` //nolint -} - -//noinspection GoStructTag -type FieldHeight struct { - Val int `"fh" @Int` //nolint -} - -//noinspection GoStructTag -type VisualizeArg struct { - Flag struct{} `"v"` //nolint - None *NoneFlag `( @@` //nolint - Gui *GuiFlag `| @@ )` //nolint -} - //noinspection GoStructTag type DebugCmd struct { Cmd struct{} `"debug"` //nolint @@ -317,10 +290,10 @@ type GuiFlag struct { } var ( - commandParser = participle.MustBuild(&Command{}) + commandParser = participle.MustBuild(&command{}) ) -func ParseBytes(b []byte, cmd *Command) error { +func parseCmdBytes(b []byte, cmd *command) error { err := commandParser.ParseBytes(b, cmd) return err } diff --git a/cli/cli_test.go b/cli/cli_test.go index 73b45b83..e0a88094 100644 --- a/cli/cli_test.go +++ b/cli/cli_test.go @@ -33,89 +33,89 @@ import ( ) func TestParseBytes(t *testing.T) { - var cmd Command - err := ParseBytes([]byte("wrongcmd"), &cmd) + var cmd command + err := parseCmdBytes([]byte("wrongcmd"), &cmd) assert.NotNil(t, err) - assert.Nil(t, ParseBytes([]byte("add router"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add router"), &cmd)) assert.True(t, cmd.Add != nil && cmd.Add.Type.Val == "router") - assert.Nil(t, ParseBytes([]byte("add med"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add med"), &cmd)) assert.True(t, cmd.Add != nil && cmd.Add.Type.Val == "med") - assert.Nil(t, ParseBytes([]byte("add sed"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add sed"), &cmd)) assert.True(t, cmd.Add != nil && cmd.Add.Type.Val == "sed") - assert.Nil(t, ParseBytes([]byte("add fed"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add fed"), &cmd)) assert.True(t, cmd.Add != nil && cmd.Add.Type.Val == "fed") - assert.Nil(t, ParseBytes([]byte("add router x 100 y 200"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add router x 100 y 200"), &cmd)) assert.True(t, *cmd.Add.X == 100 && *cmd.Add.Y == 200) - assert.Nil(t, ParseBytes([]byte("add router id 100"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add router id 100"), &cmd)) assert.True(t, cmd.Add.Id.Val == 100) - assert.Nil(t, ParseBytes([]byte("add router rr 1234"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add router rr 1234"), &cmd)) assert.True(t, cmd.Add.RadioRange.Val == 1234) - assert.Nil(t, ParseBytes([]byte("add router x 1 y 2 id 3 rr 1234"), &cmd)) - assert.Nil(t, ParseBytes([]byte("add router rr 1234 id 3 y 2 x 1"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add router x 1 y 2 id 3 rr 1234"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("add router rr 1234 id 3 y 2 x 1"), &cmd)) - assert.True(t, ParseBytes([]byte("countdown 3"), &cmd) == nil && cmd.CountDown != nil) - assert.True(t, ParseBytes([]byte("countdown 3 \"abc\""), &cmd) == nil && cmd.CountDown != nil) + assert.True(t, parseCmdBytes([]byte("countdown 3"), &cmd) == nil && cmd.CountDown != nil) + assert.True(t, parseCmdBytes([]byte("countdown 3 \"abc\""), &cmd) == nil && cmd.CountDown != nil) - assert.True(t, ParseBytes([]byte("counters"), &cmd) == nil && cmd.Counters != nil) + assert.True(t, parseCmdBytes([]byte("counters"), &cmd) == nil && cmd.Counters != nil) - assert.True(t, ParseBytes([]byte("del 1"), &cmd) == nil && cmd.Del != nil) - assert.True(t, ParseBytes([]byte("del 1 2"), &cmd) == nil && cmd.Del != nil) - assert.True(t, ParseBytes([]byte("del 1 2 3"), &cmd) == nil && cmd.Del != nil) - assert.True(t, ParseBytes([]byte("del"), &cmd) != nil) + assert.True(t, parseCmdBytes([]byte("del 1"), &cmd) == nil && cmd.Del != nil) + assert.True(t, parseCmdBytes([]byte("del 1 2"), &cmd) == nil && cmd.Del != nil) + assert.True(t, parseCmdBytes([]byte("del 1 2 3"), &cmd) == nil && cmd.Del != nil) + assert.True(t, parseCmdBytes([]byte("del"), &cmd) != nil) - assert.True(t, ParseBytes([]byte("demo_legend \"title\" 100 200"), &cmd) == nil && cmd.DemoLegend != nil) + assert.True(t, parseCmdBytes([]byte("demo_legend \"title\" 100 200"), &cmd) == nil && cmd.DemoLegend != nil) - assert.True(t, ParseBytes([]byte("exit"), &cmd) == nil && cmd.Exit != nil) + assert.True(t, parseCmdBytes([]byte("exit"), &cmd) == nil && cmd.Exit != nil) - assert.Nil(t, ParseBytes([]byte("go 1"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("go 1"), &cmd)) assert.NotNil(t, cmd.Go) - assert.Nil(t, ParseBytes([]byte("go 1.1"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("go 1.1"), &cmd)) assert.NotNil(t, cmd.Go) - assert.Nil(t, ParseBytes([]byte("go ever"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("go ever"), &cmd)) assert.NotNil(t, cmd.Go) - assert.Nil(t, ParseBytes([]byte("go 100 speed 0.5"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("go 100 speed 0.5"), &cmd)) assert.NotNil(t, cmd.Go) - assert.Nil(t, ParseBytes([]byte("go 100 speed 2"), &cmd)) + assert.Nil(t, parseCmdBytes([]byte("go 100 speed 2"), &cmd)) assert.NotNil(t, cmd.Go) - assert.True(t, ParseBytes([]byte("joins"), &cmd) == nil && cmd.Joins != nil) - - assert.True(t, ParseBytes([]byte("move 1 200 300"), &cmd) == nil && cmd.Move != nil) - - assert.True(t, ParseBytes([]byte("node 1 \"cmd\""), &cmd) == nil && cmd.Node != nil, cmd.Node.Command != nil) - assert.True(t, ParseBytes([]byte("node 1"), &cmd) == nil && cmd.Node != nil && cmd.Node.Command == nil) - - assert.True(t, ParseBytes([]byte("nodes"), &cmd) == nil && cmd.Nodes != nil) - - assert.True(t, ParseBytes([]byte("partitions"), &cmd) == nil && cmd.Partitions != nil) - assert.True(t, ParseBytes([]byte("pts"), &cmd) == nil && cmd.Partitions != nil) - - assert.True(t, ParseBytes([]byte("ping 1 2"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 2 any"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 2 mleid"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 2 aloc"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 2 rloc"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 2 linklocal"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 \"2001::1\""), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 2 datasize 100"), &cmd) == nil && cmd.Ping != nil && cmd.Ping.DataSize.Val == 100) - assert.True(t, ParseBytes([]byte("ping 1 2 interval 6"), &cmd) == nil && cmd.Ping != nil && cmd.Ping.Interval.Val == 6) - assert.True(t, ParseBytes([]byte("ping 1 2 hoplimit 3"), &cmd) == nil && cmd.Ping != nil && cmd.Ping.HopLimit.Val == 3) - assert.True(t, ParseBytes([]byte("ping 1 2 datasize 20 interval 3 hoplimit 60"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("ping 1 2 datasize 20 hoplimit 60 interval 3"), &cmd) == nil && cmd.Ping != nil) - assert.True(t, ParseBytes([]byte("pings"), &cmd) == nil && cmd.Pings != nil) - - assert.True(t, ParseBytes([]byte("plr"), &cmd) == nil && cmd.Plr != nil && cmd.Plr.Val == nil) - assert.True(t, ParseBytes([]byte("plr 1"), &cmd) == nil && cmd.Plr != nil && *cmd.Plr.Val == 1) - assert.True(t, ParseBytes([]byte("radio 1 on"), &cmd) == nil && cmd.Radio != nil) - assert.True(t, ParseBytes([]byte("radio 1 off"), &cmd) == nil && cmd.Radio != nil) - assert.True(t, ParseBytes([]byte("radio 1 2 3 on"), &cmd) == nil && cmd.Radio != nil) - assert.True(t, ParseBytes([]byte("radio 4 5 6 off"), &cmd) == nil && cmd.Radio != nil) - assert.True(t, ParseBytes([]byte("radio 4 5 6 ft 10 60"), &cmd) == nil && cmd.Radio != nil) - assert.True(t, ParseBytes([]byte("scan 1"), &cmd) == nil && cmd.Scan != nil) - assert.True(t, ParseBytes([]byte("speed"), &cmd) == nil && cmd.Speed != nil && cmd.Speed.Speed == nil) - assert.True(t, ParseBytes([]byte("speed 1"), &cmd) == nil && cmd.Speed != nil && *cmd.Speed.Speed == 1) - assert.True(t, ParseBytes([]byte("web"), &cmd) == nil && cmd.Web != nil) + assert.True(t, parseCmdBytes([]byte("joins"), &cmd) == nil && cmd.Joins != nil) + + assert.True(t, parseCmdBytes([]byte("move 1 200 300"), &cmd) == nil && cmd.Move != nil) + + assert.True(t, parseCmdBytes([]byte("node 1 \"cmd\""), &cmd) == nil && cmd.Node != nil, cmd.Node.Command != nil) + assert.True(t, parseCmdBytes([]byte("node 1"), &cmd) == nil && cmd.Node != nil && cmd.Node.Command == nil) + + assert.True(t, parseCmdBytes([]byte("nodes"), &cmd) == nil && cmd.Nodes != nil) + + assert.True(t, parseCmdBytes([]byte("partitions"), &cmd) == nil && cmd.Partitions != nil) + assert.True(t, parseCmdBytes([]byte("pts"), &cmd) == nil && cmd.Partitions != nil) + + assert.True(t, parseCmdBytes([]byte("ping 1 2"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 2 any"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 2 mleid"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 2 aloc"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 2 rloc"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 2 linklocal"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 \"2001::1\""), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 2 datasize 100"), &cmd) == nil && cmd.Ping != nil && cmd.Ping.DataSize.Val == 100) + assert.True(t, parseCmdBytes([]byte("ping 1 2 interval 6"), &cmd) == nil && cmd.Ping != nil && cmd.Ping.Interval.Val == 6) + assert.True(t, parseCmdBytes([]byte("ping 1 2 hoplimit 3"), &cmd) == nil && cmd.Ping != nil && cmd.Ping.HopLimit.Val == 3) + assert.True(t, parseCmdBytes([]byte("ping 1 2 datasize 20 interval 3 hoplimit 60"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("ping 1 2 datasize 20 hoplimit 60 interval 3"), &cmd) == nil && cmd.Ping != nil) + assert.True(t, parseCmdBytes([]byte("pings"), &cmd) == nil && cmd.Pings != nil) + + assert.True(t, parseCmdBytes([]byte("plr"), &cmd) == nil && cmd.Plr != nil && cmd.Plr.Val == nil) + assert.True(t, parseCmdBytes([]byte("plr 1"), &cmd) == nil && cmd.Plr != nil && *cmd.Plr.Val == 1) + assert.True(t, parseCmdBytes([]byte("radio 1 on"), &cmd) == nil && cmd.Radio != nil) + assert.True(t, parseCmdBytes([]byte("radio 1 off"), &cmd) == nil && cmd.Radio != nil) + assert.True(t, parseCmdBytes([]byte("radio 1 2 3 on"), &cmd) == nil && cmd.Radio != nil) + assert.True(t, parseCmdBytes([]byte("radio 4 5 6 off"), &cmd) == nil && cmd.Radio != nil) + assert.True(t, parseCmdBytes([]byte("radio 4 5 6 ft 10 60"), &cmd) == nil && cmd.Radio != nil) + assert.True(t, parseCmdBytes([]byte("scan 1"), &cmd) == nil && cmd.Scan != nil) + assert.True(t, parseCmdBytes([]byte("speed"), &cmd) == nil && cmd.Speed != nil && cmd.Speed.Speed == nil) + assert.True(t, parseCmdBytes([]byte("speed 1"), &cmd) == nil && cmd.Speed != nil && *cmd.Speed.Speed == 1) + assert.True(t, parseCmdBytes([]byte("web"), &cmd) == nil && cmd.Web != nil) } func TestContextlessCommandPat(t *testing.T) { diff --git a/cli/CmdRunner.go b/cli/cmd_runner.go similarity index 85% rename from cli/CmdRunner.go rename to cli/cmd_runner.go index 515e9953..9848d5dd 100644 --- a/cli/CmdRunner.go +++ b/cli/cmd_runner.go @@ -27,7 +27,6 @@ package cli import ( - "context" "fmt" "reflect" "strings" @@ -45,37 +44,37 @@ import ( "github.com/simonlingoogle/go-simplelogger" ) -type CommandContext struct { - context.Context - *Command - rt *CmdRunner - err error +// commandContext is the context of an executing command. +type commandContext struct { + *command // the executing command + rt *cmdRunner + err error } -func (cc *CommandContext) outputf(format string, args ...interface{}) { +func (cc *commandContext) outputf(format string, args ...interface{}) { fmt.Printf(format, args...) } -func (cc *CommandContext) errorf(format string, args ...interface{}) { +func (cc *commandContext) errorf(format string, args ...interface{}) { cc.err = errors.Errorf(format, args...) } -func (cc *CommandContext) error(err error) { +func (cc *commandContext) error(err error) { cc.err = err } -func (cc *CommandContext) Err() error { +func (cc *commandContext) Err() error { return cc.err } -type CmdRunner struct { +type cmdRunner struct { sim *simulation.Simulation ctx *progctx.ProgCtx } -func (rt *CmdRunner) Execute(cmd *Command) (cc *CommandContext) { - cc = &CommandContext{ - Command: cmd, +func (rt *cmdRunner) Execute(cmd *command) (cc *commandContext) { + cc = &commandContext{ + command: cmd, rt: rt, } @@ -137,7 +136,7 @@ func (rt *CmdRunner) Execute(cmd *Command) (cc *CommandContext) { return } -func (rt *CmdRunner) executeGo(cc *CommandContext, cmd *GoCmd) { +func (rt *cmdRunner) executeGo(cc *commandContext, cmd *GoCmd) { if cmd.Speed != nil { rt.postAsyncWait(func(sim *simulation.Simulation) { sim.SetSpeed(*cmd.Speed) @@ -161,7 +160,7 @@ func (rt *CmdRunner) executeGo(cc *CommandContext, cmd *GoCmd) { } } -func (rt *CmdRunner) executeSpeed(cc *CommandContext, cmd *SpeedCmd) { +func (rt *cmdRunner) executeSpeed(cc *commandContext, cmd *SpeedCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { if cmd.Speed == nil && cmd.Max == nil { cc.outputf("%v\n", sim.GetSpeed()) @@ -173,7 +172,7 @@ func (rt *CmdRunner) executeSpeed(cc *CommandContext, cmd *SpeedCmd) { }) } -func (rt *CmdRunner) postAsyncWait(f func(sim *simulation.Simulation)) { +func (rt *cmdRunner) postAsyncWait(f func(sim *simulation.Simulation)) { done := make(chan struct{}) rt.sim.PostAsync(false, func() { f(rt.sim) @@ -182,7 +181,7 @@ func (rt *CmdRunner) postAsyncWait(f func(sim *simulation.Simulation)) { <-done } -func (rt *CmdRunner) executeAddNode(cc *CommandContext, cmd *AddCmd) { +func (rt *cmdRunner) executeAddNode(cc *commandContext, cmd *AddCmd) { simplelogger.Infof("Add: %#v", *cmd) cfg := simulation.DefaultNodeConfig() if cmd.X != nil { @@ -231,7 +230,7 @@ func (rt *CmdRunner) executeAddNode(cc *CommandContext, cmd *AddCmd) { }) } -func (rt *CmdRunner) executeDelNode(cc *CommandContext, cmd *DelCmd) { +func (rt *cmdRunner) executeDelNode(cc *commandContext, cmd *DelCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { for _, sel := range cmd.Nodes { node, _ := rt.getNode(sim, &sel) @@ -245,7 +244,7 @@ func (rt *CmdRunner) executeDelNode(cc *CommandContext, cmd *DelCmd) { }) } -func (rt *CmdRunner) executeExit(cc *CommandContext, cmd *ExitCmd) { +func (rt *cmdRunner) executeExit(cc *commandContext, cmd *ExitCmd) { if enterNodeContext(InvalidNodeId) { return } @@ -256,7 +255,7 @@ func (rt *CmdRunner) executeExit(cc *CommandContext, cmd *ExitCmd) { rt.ctx.Cancel("exit") } -func (rt *CmdRunner) executePing(cc *CommandContext, cmd *PingCmd) { +func (rt *cmdRunner) executePing(cc *commandContext, cmd *PingCmd) { simplelogger.Debugf("ping %#v", cmd) rt.postAsyncWait(func(sim *simulation.Simulation) { src, _ := rt.getNode(sim, &cmd.Src) @@ -308,7 +307,7 @@ func (rt *CmdRunner) executePing(cc *CommandContext, cmd *PingCmd) { }) } -func (rt *CmdRunner) getNode(sim *simulation.Simulation, sel *NodeSelector) (*simulation.Node, *dispatcher.Node) { +func (rt *cmdRunner) getNode(sim *simulation.Simulation, sel *NodeSelector) (*simulation.Node, *dispatcher.Node) { if sel.Id > 0 { return sim.Nodes()[sel.Id], sim.Dispatcher().Nodes()[sel.Id] } @@ -316,7 +315,7 @@ func (rt *CmdRunner) getNode(sim *simulation.Simulation, sel *NodeSelector) (*si panic("node selector not implemented") } -func (rt *CmdRunner) getAddrs(node *simulation.Node, addrType *AddrType) []string { +func (rt *cmdRunner) getAddrs(node *simulation.Node, addrType *AddrType) []string { if node == nil { return nil } @@ -345,7 +344,7 @@ func (rt *CmdRunner) getAddrs(node *simulation.Node, addrType *AddrType) []strin return addrs } -func (rt *CmdRunner) executeDebug(cc *CommandContext, cmd *DebugCmd) { +func (rt *cmdRunner) executeDebug(cc *commandContext, cmd *DebugCmd) { simplelogger.Infof("debug %#v", *cmd) if cmd.Echo != nil { @@ -357,7 +356,7 @@ func (rt *CmdRunner) executeDebug(cc *CommandContext, cmd *DebugCmd) { } } -func (rt *CmdRunner) executeNode(cc *CommandContext, cmd *NodeCmd) { +func (rt *cmdRunner) executeNode(cc *commandContext, cmd *NodeCmd) { contextNodeId := InvalidNodeId rt.postAsyncWait(func(sim *simulation.Simulation) { node, _ := rt.getNode(sim, &cmd.Node) @@ -389,13 +388,13 @@ func (rt *CmdRunner) executeNode(cc *CommandContext, cmd *NodeCmd) { } } -func (rt *CmdRunner) executeDemoLegend(cc *CommandContext, cmd *DemoLegendCmd) { +func (rt *cmdRunner) executeDemoLegend(cc *commandContext, cmd *DemoLegendCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { sim.ShowDemoLegend(cmd.X, cmd.Y, cmd.Title) }) } -func (rt *CmdRunner) executeCountDown(cc *CommandContext, cmd *CountDownCmd) { +func (rt *cmdRunner) executeCountDown(cc *commandContext, cmd *CountDownCmd) { title := "%v" if cmd.Text != nil { title = *cmd.Text @@ -405,7 +404,7 @@ func (rt *CmdRunner) executeCountDown(cc *CommandContext, cmd *CountDownCmd) { }) } -func (rt *CmdRunner) executeRadio(cc *CommandContext, radio *RadioCmd) { +func (rt *cmdRunner) executeRadio(cc *commandContext, radio *RadioCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { for _, sel := range radio.Nodes { node, dnode := rt.getNode(sim, &sel) @@ -432,13 +431,13 @@ func (rt *CmdRunner) executeRadio(cc *CommandContext, radio *RadioCmd) { }) } -func (rt *CmdRunner) executeMoveNode(cc *CommandContext, cmd *Move) { +func (rt *cmdRunner) executeMoveNode(cc *commandContext, cmd *Move) { rt.postAsyncWait(func(sim *simulation.Simulation) { sim.MoveNodeTo(cmd.Target.Id, cmd.X, cmd.Y) }) } -func (rt *CmdRunner) executeLsNodes(cc *CommandContext, cmd *NodesCmd) { +func (rt *cmdRunner) executeLsNodes(cc *commandContext, cmd *NodesCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { for nodeid := range sim.Nodes() { dnode := sim.Dispatcher().GetNode(nodeid) @@ -450,7 +449,7 @@ func (rt *CmdRunner) executeLsNodes(cc *CommandContext, cmd *NodesCmd) { }) } -func (rt *CmdRunner) executeLsPartitions(cc *CommandContext) { +func (rt *cmdRunner) executeLsPartitions(cc *commandContext) { pars := map[uint32][]NodeId{} rt.postAsyncWait(func(sim *simulation.Simulation) { @@ -472,7 +471,7 @@ func (rt *CmdRunner) executeLsPartitions(cc *CommandContext) { } } -func (rt *CmdRunner) executeCollectPings(cc *CommandContext, pings *PingsCmd) { +func (rt *cmdRunner) executeCollectPings(cc *commandContext, pings *PingsCmd) { allPings := make(map[NodeId][]*dispatcher.PingResult) rt.postAsyncWait(func(sim *simulation.Simulation) { d := sim.Dispatcher() @@ -491,7 +490,7 @@ func (rt *CmdRunner) executeCollectPings(cc *CommandContext, pings *PingsCmd) { } } -func (rt *CmdRunner) executeCollectJoins(cc *CommandContext, joins *JoinsCmd) { +func (rt *cmdRunner) executeCollectJoins(cc *commandContext, joins *JoinsCmd) { allJoins := make(map[NodeId][]*dispatcher.JoinResult) rt.postAsyncWait(func(sim *simulation.Simulation) { @@ -511,7 +510,7 @@ func (rt *CmdRunner) executeCollectJoins(cc *CommandContext, joins *JoinsCmd) { } } -func (rt *CmdRunner) executeCounters(cc *CommandContext, counters *CountersCmd) { +func (rt *cmdRunner) executeCounters(cc *commandContext, counters *CountersCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { d := sim.Dispatcher() countersVal := reflect.ValueOf(d.Counters) @@ -524,13 +523,13 @@ func (rt *CmdRunner) executeCounters(cc *CommandContext, counters *CountersCmd) }) } -func (rt *CmdRunner) executeWeb(cc *CommandContext, webcmd *WebCmd) { +func (rt *cmdRunner) executeWeb(cc *commandContext, webcmd *WebCmd) { if err := web.OpenWeb(rt.ctx); err != nil { cc.error(err) } } -func (rt *CmdRunner) executePlr(cc *CommandContext, cmd *PlrCmd) { +func (rt *cmdRunner) executePlr(cc *commandContext, cmd *PlrCmd) { if cmd.Val == nil { // get PLR var plr float64 @@ -550,7 +549,7 @@ func (rt *CmdRunner) executePlr(cc *CommandContext, cmd *PlrCmd) { } } -func (rt *CmdRunner) executeScan(cc *CommandContext, cmd *ScanCmd) { +func (rt *cmdRunner) executeScan(cc *commandContext, cmd *ScanCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { node, _ := rt.getNode(sim, &cmd.Node) if node == nil { @@ -574,8 +573,9 @@ func (rt *CmdRunner) executeScan(cc *CommandContext, cmd *ScanCmd) { } } -func NewCmdRunner(ctx *progctx.ProgCtx, sim *simulation.Simulation) *CmdRunner { - r := &CmdRunner{ +// newCmdRunner creates a command runner for a simulation. +func newCmdRunner(ctx *progctx.ProgCtx, sim *simulation.Simulation) *cmdRunner { + r := &cmdRunner{ ctx: ctx, sim: sim, } diff --git a/cli/runner.go b/cli/runner.go index 090091a0..a21b468c 100644 --- a/cli/runner.go +++ b/cli/runner.go @@ -24,11 +24,15 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package cli implements the OTNS-CLI. It parses and executes CLI commands. package cli import ( "fmt" + "github.com/openthread/ot-ns/progctx" + "github.com/openthread/ot-ns/simulation" . "github.com/openthread/ot-ns/types" + "github.com/pkg/errors" "github.com/simonlingoogle/go-simplelogger" "io" "os" @@ -39,7 +43,7 @@ import ( ) const ( - Prompt = "> " + prompt = "> " // the default CLI prompt ) var ( @@ -56,19 +60,27 @@ func enterNodeContext(nodeid NodeId) bool { contextNodeId = nodeid if nodeid == InvalidNodeId { - readlineInstance.SetPrompt(Prompt) + readlineInstance.SetPrompt(prompt) } else { - readlineInstance.SetPrompt(fmt.Sprintf("node %d%s", contextNodeId, Prompt)) + readlineInstance.SetPrompt(fmt.Sprintf("node %d%s", contextNodeId, prompt)) } return true } -func Run(cr *CmdRunner) error { - ctx := cr.ctx +// Run runs the CLI console. +func Run(ctx *progctx.ProgCtx, sim *simulation.Simulation) { + var err error + defer ctx.Cancel(errors.Wrapf(err, "console exit")) ctx.WaitAdd("cli", 1) defer ctx.WaitDone("cli") + err = run(ctx, sim) +} + +func run(ctx *progctx.ProgCtx, sim *simulation.Simulation) error { + cr := newCmdRunner(ctx, sim) + stdinFd := int(os.Stdin.Fd()) stdinIsTerminal := readline.IsTerminal(stdinFd) if stdinIsTerminal { @@ -95,7 +107,7 @@ func Run(cr *CmdRunner) error { } l, err := readline.NewEx(&readline.Config{ - Prompt: Prompt, + Prompt: prompt, HistoryFile: "/tmp/otns-cmds.tmp", InterruptPrompt: "^C", EOFPrompt: "exit", @@ -146,7 +158,7 @@ func Run(cr *CmdRunner) error { if contextNodeId != InvalidNodeId && !isContextlessCommand(line) { // run the command in node context - cmd := &Command{ + cmd := &command{ Node: &NodeCmd{ Node: NodeSelector{Id: contextNodeId}, Command: &line, @@ -165,8 +177,8 @@ func Run(cr *CmdRunner) error { } } else { // run the OTNS-CLI command - cmd := &Command{} - if err := ParseBytes([]byte(line), cmd); err != nil { + cmd := &command{} + if err := parseCmdBytes([]byte(line), cmd); err != nil { if _, err := fmt.Fprintf(os.Stdout, "Error: %v\n", err); err != nil { return err } diff --git a/otns_main/otns_main.go b/otns_main/otns_main.go index 0d862ba8..20dfe2c0 100644 --- a/otns_main/otns_main.go +++ b/otns_main/otns_main.go @@ -41,8 +41,6 @@ import ( "github.com/openthread/ot-ns/web" - "github.com/pkg/errors" - "github.com/openthread/ot-ns/progctx" "github.com/openthread/ot-ns/visualize" @@ -115,11 +113,7 @@ func Main(visualizerCreator func(ctx *progctx.ProgCtx, args *MainArgs) visualize sim := createSimulation(ctx) sim.SetVisualizer(vis) go sim.Run() - rt := cli.NewCmdRunner(ctx, sim) - go func() { - err := cli.Run(rt) - ctx.Cancel(errors.Wrapf(err, "console exit")) - }() + go cli.Run(ctx, sim) go func() { err := webSite.Serve() From ef2b70a1e086c7fe989951c8a6989d24aa04a804 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Mon, 13 Apr 2020 22:52:22 +0800 Subject: [PATCH 05/16] add doc for package cli --- cli/ast.go | 92 ++++++++++++++++++++--------------------------- cli/cmd_runner.go | 2 +- cli/runner.go | 4 ++- 3 files changed, 43 insertions(+), 55 deletions(-) diff --git a/cli/ast.go b/cli/ast.go index 2e6c37b7..26c12437 100644 --- a/cli/ast.go +++ b/cli/ast.go @@ -24,6 +24,8 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// This file defines the format of all CLI commands and their flags. + package cli import ( @@ -32,7 +34,6 @@ import ( "github.com/alecthomas/participle" ) -//noinspection GoStructTag type command struct { Add *AddCmd ` @@` //nolint CountDown *CountDownCmd `| @@` //nolint @@ -43,7 +44,7 @@ type command struct { Exit *ExitCmd `| @@` //nolint Go *GoCmd `| @@` //nolint Joins *JoinsCmd `| @@` //nolint - Move *Move `| @@` //nolint + Move *MoveCmd `| @@` //nolint Node *NodeCmd `| @@` //nolint Nodes *NodesCmd `| @@` //nolint Partitions *PartitionsCmd `| @@` //nolint @@ -56,14 +57,14 @@ type command struct { Web *WebCmd `| @@` //nolint } -//noinspection GoStructTag +// DebugCmd defines the `debug` command format. type DebugCmd struct { Cmd struct{} `"debug"` //nolint Fail *string `[ @"fail" ]` //nolint Echo *string `[ "echo" @String ]` //nolint } -//noinspection GoStructTag +// GoCmd defines the `go` command format. type GoCmd struct { Cmd struct{} `"go"` //nolint Seconds float64 `( (@Int|@Float)` //nolint @@ -71,7 +72,7 @@ type GoCmd struct { Speed *float64 `[ "speed" (@Int|@Float) ]` //nolint } -//noinspection GoStructTag +// NodeSelector defines the node selector format. type NodeSelector struct { Id int `@Int` //nolint } @@ -80,37 +81,37 @@ func (ns *NodeSelector) String() string { return strconv.Itoa(ns.Id) } -//noinspection GoStructTag +// Ipv6Address defines the IPv6 address format. type Ipv6Address struct { Addr string `@String` //nolint } -//noinspection GoStructTag +// AddrType defines the `address type` flag format for specifying address type. type AddrType struct { Type string `@( "any" | "mleid" | "rloc" | "aloc" | "linklocal" )` //nolint } -//noinspection GoStructTag +// DataSizeFlag defines the `datasize` flag format for specifying data size. type DataSizeFlag struct { Val int `("datasize"|"ds") @Int` //nolint } -//noinspection GoStructTag +// IntervalFlag defines the `interval` flag format for specifying time interval. type IntervalFlag struct { Val int `("interval"|"itv") @Int` //nolint } -//noinspection GoStructTag +// CountFlag defines the `count` flag format for specifying count. type CountFlag struct { Val int `("count" | "c") @Int` //nolint } -//noinspection GoStructTag +// HopLimitFlag defines the `hop limit` flag format for specifying hop limit. type HopLimitFlag struct { Val int `("hoplimit" | "hl") @Int` //nolint } -//noinspection GoStructTag +// PingCmd defines the `ping` command format. type PingCmd struct { Cmd struct{} `"ping"` //nolint Src NodeSelector `@@` //nolint @@ -123,14 +124,14 @@ type PingCmd struct { HopLimit *HopLimitFlag `| @@ )*` //nolint } -//noinspection GoStructTag +// NodeCmd defines `node` command format. type NodeCmd struct { Cmd struct{} `"node"` //nolint Node NodeSelector `@@` //nolint Command *string `[ @String ]` //nolint } -//noinspection GoStructTag +// DemoLegendCmd defines the `demo_legend` command format. type DemoLegendCmd struct { Cmd struct{} `"demo_legend"` //nolint Title string `@String` //nolint @@ -138,27 +139,27 @@ type DemoLegendCmd struct { Y int `@Int` //nolint } -//noinspection GoStructTag +// CountDownCmd defines the `countdown` command format. type CountDownCmd struct { Cmd struct{} `"countdown"` //nolint Seconds int `@Int` //nolint Text *string `[ @String ]` //nolint } -//noinspection GoStructTag +// ScanCmd defines the `scan` command format. type ScanCmd struct { Cmd struct{} `"scan"` //nolint Node NodeSelector `@@` // nolint } -//noinspection GoStructTag +// SpeedCmd defines the `speed` command format. type SpeedCmd struct { Cmd struct{} `"speed"` //nolint Max *MaxSpeedFlag `( @@` //nolint Speed *float64 `| [ (@Int|@Float) ] )` //nolint } -//noinspection GoStructTag +// AddCmd defines the `add` command format. type AddCmd struct { Cmd struct{} `"add"` //nolint Type NodeType `@@` //nolint @@ -168,53 +169,48 @@ type AddCmd struct { RadioRange *RadioRangeFlag `|@@ )*` //nolint } -//noinspection GoStructTag +// RadioRangeFlag defines the `radio range` flag format. type RadioRangeFlag struct { Val int `"rr" @Int` //nolint } -//noinspection MaxSpeedFlag +// MaxSpeedFlag defines the `max speed` flag format. type MaxSpeedFlag struct { Dummy struct{} `( "max" | "inf")` //nolint } -//noinspection GoStructTag +// NodeType defines the `node type` flag for specifying node types. type NodeType struct { Val string `@("router"|"fed"|"med"|"sed")` //nolint } -//noinspection GoStructTag +// AddNodeId defines the `id` flag format for specifying node ID. type AddNodeId struct { Val int `"id" @Int` //nolint } -//noinspection GoStructTag +// DelCmd defines the `del` command format. type DelCmd struct { Cmd struct{} `"del"` //nolint Nodes []NodeSelector `( @@ )+` //nolint } -//noinspection GoStructTag +// EverFlag defines the `ever` flag format. type EverFlag struct { Dummy struct{} `"ever"` //nolint } -//noinspection GoStructTag -type Empty struct { - Empty struct{} `""` //nolint -} - -//noinspection GoStructTag +// ExitCmd defines the `exit` command format. type ExitCmd struct { Cmd struct{} `"exit"` //nolint } -//noinspection GoStructTag +// WebCmd defines the `web` command format. type WebCmd struct { Cmd struct{} `"web"` //nolint } -//noinspection GoStructTag +// RadioCmd defines the `radio` command format. type RadioCmd struct { Cmd struct{} `"radio"` //nolint Nodes []NodeSelector `( @@ )+` //nolint @@ -223,72 +219,62 @@ type RadioCmd struct { FailTime *FailTimeParams `| @@ )` //nolint } -//noinspection GoStructTag +// OnFlag defines the `on` flag format. type OnFlag struct { Dummy struct{} `"on"` //nolint } -//noinspection GoStructTag +// OffFlag defines the `off` flag format. type OffFlag struct { Dummy struct{} `"off"` //nolint } -//noinspection GoStructTag -type Move struct { +// MoveCmd defines the `move` command format. +type MoveCmd struct { Cmd struct{} `"move"` //nolint Target NodeSelector `@@` //nolint X int `@Int` //nolint Y int `@Int` //nolint } -//noinspection GoStructTag +// NodesCmd defines the `nodes` command format. type NodesCmd struct { Cmd struct{} `"nodes"` //nolint } -//noinspection GoStructTag +// PartitionsCmd defines the `partitions` command format. type PartitionsCmd struct { Cmd struct{} `( "partitions" | "pts")` //nolint } -//noinspection GoStructTag +// PingsCmd defines the `pings` command format. type PingsCmd struct { Cmd struct{} `"pings"` //nolint } -//noinspection GoStructTag +// JoinsCmd defines the `joins` command format. type JoinsCmd struct { Cmd struct{} `"joins"` //nolint } -//noinspection GoStructTag +// CountersCmd defies the `counters` command format. type CountersCmd struct { Cmd struct{} `"counters"` //nolint } -//noinspection GoStructTag +// PlrCmd defines the `plr` command format. type PlrCmd struct { Cmd struct{} `"plr"` //nolint Val *float64 `[ (@Int|@Float) ]` //nolint } -//noinspection GoStructTag +// FailTimeParams defines the fail time parameters format. type FailTimeParams struct { Dummy struct{} `"ft"` //nolint FailDuration float64 `(@Int|@Float)` //nolint FailInterval float64 `(@Int|@Float)` //nolint } -//noinspection GoStructTag -type NoneFlag struct { - Dummy struct{} `"none"` //nolint -} - -//noinspection GoStructTag -type GuiFlag struct { - Dummy struct{} `"gui"` //nolint -} - var ( commandParser = participle.MustBuild(&command{}) ) diff --git a/cli/cmd_runner.go b/cli/cmd_runner.go index 9848d5dd..9961e82a 100644 --- a/cli/cmd_runner.go +++ b/cli/cmd_runner.go @@ -431,7 +431,7 @@ func (rt *cmdRunner) executeRadio(cc *commandContext, radio *RadioCmd) { }) } -func (rt *cmdRunner) executeMoveNode(cc *commandContext, cmd *Move) { +func (rt *cmdRunner) executeMoveNode(cc *commandContext, cmd *MoveCmd) { rt.postAsyncWait(func(sim *simulation.Simulation) { sim.MoveNodeTo(cmd.Target.Id, cmd.X, cmd.Y) }) diff --git a/cli/runner.go b/cli/runner.go index a21b468c..0b0132a1 100644 --- a/cli/runner.go +++ b/cli/runner.go @@ -70,7 +70,9 @@ func enterNodeContext(nodeid NodeId) bool { // Run runs the CLI console. func Run(ctx *progctx.ProgCtx, sim *simulation.Simulation) { var err error - defer ctx.Cancel(errors.Wrapf(err, "console exit")) + defer func() { + ctx.Cancel(errors.Wrapf(err, "console exit")) + }() ctx.WaitAdd("cli", 1) defer ctx.WaitDone("cli") From 738c9bc0ed5f643b667ddfca5bb2548468640046 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Mon, 13 Apr 2020 23:13:15 +0800 Subject: [PATCH 06/16] add doc for dissectpkt package --- dissectpkt/dissectpkt.go | 12 ++++------- dissectpkt/wpan/wpan.go | 45 +++++++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/dissectpkt/dissectpkt.go b/dissectpkt/dissectpkt.go index 47a6c760..1d5ef678 100644 --- a/dissectpkt/dissectpkt.go +++ b/dissectpkt/dissectpkt.go @@ -24,23 +24,19 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package dissectpkt provides utilities for dissecting packets. package dissectpkt import ( "github.com/openthread/ot-ns/dissectpkt/wpan" ) -type WpanFrameType int - -const ( - MLE WpanFrameType = iota - MAC = iota -) - +// PktInfo contains all packet information. type PktInfo struct { - MacFrame *wpan.MacFrame + MacFrame *wpan.MacFrame // MAC frame information } +// Dissect dissects a MAC frame and returns the packet information. func Dissect(data []byte) *PktInfo { macFrame := wpan.Dissect(data) diff --git a/dissectpkt/wpan/wpan.go b/dissectpkt/wpan/wpan.go index b8f32ab7..78ef59a1 100644 --- a/dissectpkt/wpan/wpan.go +++ b/dissectpkt/wpan/wpan.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package wpan provides utilities for dissecting WPAN frames. package wpan import ( @@ -31,77 +32,92 @@ import ( "fmt" ) +// FrameType is the type for MAC frame types. type FrameType = uint16 const ( - FrameTypeBeacon FrameType = 0 - FrameTypeData FrameType = 1 - FrameTypeAck FrameType = 2 - FrameTypeCommand FrameType = 3 + FrameTypeBeacon FrameType = 0 // Beacon + FrameTypeData FrameType = 1 // Data + FrameTypeAck FrameType = 2 // ACK + FrameTypeCommand FrameType = 3 // Command ) const ( - DstAddrModeNone = 0 - DstAddrModeReserved = 1 - DstAddrModeShort = 2 - DstAddrModeExtended = 3 + DstAddrModeNone = 0 // Address mode: None + DstAddrModeReserved = 1 // Address mode: Reserved + DstAddrModeShort = 2 // Address mode: Short + DstAddrModeExtended = 3 // Address mode: Extended ) +// FrameControl is the type for MAC FrameControl. type FrameControl uint16 +// String converts FrameControl to hex string. func (fc FrameControl) String() string { return fmt.Sprintf("0x%04x", uint16(fc)) } +// FrameType returns the Frame Type. func (fc FrameControl) FrameType() FrameType { return FrameType(fc & 0x0007) } +// SecurityEnabled returns if MAC Security is set. func (fc FrameControl) SecurityEnabled() bool { return (fc & 0x0008) != 0 } +// FramePending returns if Frame Pending is set. func (fc FrameControl) FramePending() bool { return (fc & 0x0010) != 0 } +// AckRequest returns if ACK Request is set. func (fc FrameControl) AckRequest() bool { return (fc & 0x0020) != 0 } +// PanidCompression returns if Pan ID compression is set. func (fc FrameControl) PanidCompression() bool { return (fc & 0x0040) != 0 } +// IEPresent returns if IE Present is set. func (fc FrameControl) IEPresent() bool { return (fc & 0x0200) != 0 } +// DstAddrMode returns the Destination Address Mode. func (fc FrameControl) DstAddrMode() uint16 { return uint16((fc & 0x0c00) >> 10) } +// SourceAddrMode returns the Source Address Mode. func (fc FrameControl) SourceAddrMode() uint16 { return uint16((fc & 0xc000) >> 14) } +// FrameVersion returns the Frame Version. func (fc FrameControl) FrameVersion() uint16 { return uint16((fc & 0x3000) >> 12) } +// Dissect dissects the data bytes as Frame Control. func (fc *FrameControl) Dissect(bytes []byte) { *fc = FrameControl(binary.LittleEndian.Uint16(bytes)) } +// MacFrame defines the MAC Frame information. type MacFrame struct { - Channel uint8 - FrameControl FrameControl - Seq uint8 - DstPanId uint16 - DstAddrShort uint16 - DstAddrExtended uint64 + Channel uint8 // Channel + FrameControl FrameControl // Frame Control + Seq uint8 // Sequence + DstPanId uint16 // Destination Pan ID + DstAddrShort uint16 // Destination Short Address + DstAddrExtended uint64 // Destination Extended Address } +// String returns a string representing the MAC frame. func (f *MacFrame) String() string { if f.FrameControl.FrameType() == FrameTypeAck { return fmt.Sprintf("ACK,FC:%s,Seq:%d", f.FrameControl, f.Seq) @@ -120,6 +136,7 @@ func (f *MacFrame) String() string { return fmt.Sprintf("MAC,FC:%s,Seq:%d,Dst:%s", f.FrameControl, f.Seq, dstAddrS) } +// Dissect dissects the frame data and returns the MAC Frame information. func Dissect(data []byte) *MacFrame { frame := &MacFrame{} frame.Channel = data[0] From b21a1cf9398cbe5fb8657e9802d39949da1c96a3 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Mon, 13 Apr 2020 23:18:15 +0800 Subject: [PATCH 07/16] doc otoutfilter --- otoutfilter/OTOutFilter.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/otoutfilter/OTOutFilter.go b/otoutfilter/OTOutFilter.go index 8ae8c633..9b4953ee 100644 --- a/otoutfilter/OTOutFilter.go +++ b/otoutfilter/OTOutFilter.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package otoutfilter implements an output filter to make it easier to parse output from OpenThread CLI programs. package otoutfilter import ( @@ -129,6 +130,9 @@ func (cc *otOutFilter) printLog(logStr string) { } } +// NewOTOutFilter filters the output from OpenThread CLI program by removing prompt "> " and logs. +// It returns a Reader for reading the filtered output. +// It also redirect OpenThread CLI logs according to their logging level. func NewOTOutFilter(reader io.Reader, logPrintPrefix string) io.Reader { return &otOutFilter{subr: reader, logPrintPrefix: logPrintPrefix} } From 6130f6d8101f727c74e76696f3060af904e9115a Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 00:11:07 +0800 Subject: [PATCH 08/16] doc pcap --- pcap/PcapFile.go | 6 ++++++ progctx/progctx.go | 1 + 2 files changed, 7 insertions(+) diff --git a/pcap/PcapFile.go b/pcap/PcapFile.go index 35343fd2..b315b203 100644 --- a/pcap/PcapFile.go +++ b/pcap/PcapFile.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package pcap implements PCAP file generating. package pcap import ( @@ -41,10 +42,12 @@ const ( pcapFrameHeaderSize = 16 ) +// File represents a PCAP file. type File struct { fd *os.File } +// NewFile creates a new empty PCAP file. func NewFile(filename string) (*File, error) { fd, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) if err != nil { @@ -63,6 +66,7 @@ func NewFile(filename string) (*File, error) { return pf, nil } +// AppendFrame appends a new packet frame to the PCAP file. func (pf *File) AppendFrame(ustime uint64, frame []byte) error { var header [pcapFrameHeaderSize]byte sec := uint32(ustime / 1000000) @@ -83,10 +87,12 @@ func (pf *File) AppendFrame(ustime uint64, frame []byte) error { return err } +// Sync commits the current contents of the PCAP file to stable storage. func (pf *File) Sync() error { return pf.fd.Sync() } +// Close closes the PCAP file. func (pf *File) Close() error { return pf.fd.Close() } diff --git a/progctx/progctx.go b/progctx/progctx.go index 88464239..eeb62ef8 100644 --- a/progctx/progctx.go +++ b/progctx/progctx.go @@ -113,6 +113,7 @@ func (ctx *ProgCtx) Defer(f func()) { ctx.deferred = append(ctx.deferred, f) } +// New creates a new ProgCtx from the parent context. func New(parent context.Context) *ProgCtx { if parent == nil { parent = context.Background() From 2f9bf6ed03d7649884b8320b4da2ff0fafcb1eb8 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 12:10:26 +0800 Subject: [PATCH 09/16] doc web --- web/site/site.go | 2 ++ web/web.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/web/site/site.go b/web/site/site.go index b3da1b2d..4c2cf879 100644 --- a/web/site/site.go +++ b/web/site/site.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package web_site implements a web server for hosting OTNS-Web site. package web_site import ( @@ -36,6 +37,7 @@ import ( "github.com/simonlingoogle/go-simplelogger" ) +// Serve runs a local server for hosting the OTNS-Web site. func Serve() error { assetDir := os.Getenv("HOME") diff --git a/web/web.go b/web/web.go index 734abbbb..a5991318 100644 --- a/web/web.go +++ b/web/web.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package web implements utilities for OTNS-Web. package web import ( @@ -39,6 +40,7 @@ var ( grpcWebProxyProc *exec.Cmd ) +// OpenWeb opens a web browser for visualization. func OpenWeb(ctx *progctx.ProgCtx) error { if err := assureGrpcWebProxyRunning(ctx); err != nil { simplelogger.Errorf("start grpcwebproxy failed: %v", err) From a9225c4110a54b5486f946412de4e78b28c36f85 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 12:13:40 +0800 Subject: [PATCH 10/16] doc types --- types/types.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/types/types.go b/types/types.go index 92682d1c..103efa95 100644 --- a/types/types.go +++ b/types/types.go @@ -24,23 +24,25 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package types defines the common types used in OTNS. package types type NodeId = int const ( - MaxNodeId NodeId = 0xffff - InvalidNodeId NodeId = 0 - BroadcastNodeId NodeId = -1 + InvalidNodeId NodeId = 0 // invalid node ID. + BroadcastNodeId NodeId = -1 // node ID for broadcasting messages. ) +// NodeMode defines node mode. type NodeMode struct { - RxOnWhenIdle bool - SecureDataRequests bool - FullThreadDevice bool - FullNetworkData bool + RxOnWhenIdle bool // radio RX on when idle + SecureDataRequests bool // secure data requests + FullThreadDevice bool // full Thread device + FullNetworkData bool // full network data } +// DefaultNodeMode returns a default NodeMode. func DefaultNodeMode() NodeMode { return NodeMode{ RxOnWhenIdle: true, From 32570d37c0d4fe7a87d596e671317e2f3ff1c6fc Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 13:31:35 +0800 Subject: [PATCH 11/16] doc types --- progctx/progctx.go | 22 ++++++++++++++++------ types/types.go | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/progctx/progctx.go b/progctx/progctx.go index eeb62ef8..282f20bc 100644 --- a/progctx/progctx.go +++ b/progctx/progctx.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package progctx implements utilities for managing the context of a program. package progctx import ( @@ -34,15 +35,17 @@ import ( "github.com/simonlingoogle/go-simplelogger" ) +// ProgCtx represent the context of a program during it's lifetime. type ProgCtx struct { - context.Context - wg sync.WaitGroup - cancel context.CancelFunc - routinesLock sync.Mutex - routines map[string]int - deferred []func() + context.Context // the inner context of the program + wg sync.WaitGroup + cancel context.CancelFunc + routinesLock sync.Mutex + routines map[string]int + deferred []func() } +// WaitCount returns the number of goroutines to wait for. func (ctx *ProgCtx) WaitCount() int { ctx.routinesLock.Lock() defer ctx.routinesLock.Unlock() @@ -54,6 +57,8 @@ func (ctx *ProgCtx) WaitCount() int { return total } +// Cancel cancel the program context with a given error. +// It is only effective the first time it's called. func (ctx *ProgCtx) Cancel(err interface{}) { if ctx.Err() != nil { return @@ -76,6 +81,7 @@ func (ctx *ProgCtx) Cancel(err interface{}) { } } +// WaitAdd adds a new goroutine to wait for. func (ctx *ProgCtx) WaitAdd(name string, delta int) { ctx.routinesLock.Lock() ctx.routines[name] += delta @@ -84,6 +90,7 @@ func (ctx *ProgCtx) WaitAdd(name string, delta int) { ctx.wg.Add(delta) } +// WaitDone notifies that a goroutine has finished. func (ctx *ProgCtx) WaitDone(name string) { ctx.routinesLock.Lock() defer ctx.routinesLock.Unlock() @@ -97,6 +104,7 @@ func (ctx *ProgCtx) WaitDone(name string) { ctx.wg.Done() } +// Wait waits for all goroutines to finish. func (ctx *ProgCtx) Wait() { ctx.routinesLock.Lock() simplelogger.Infof("program context waiting routines: %v", ctx.routines) @@ -105,6 +113,8 @@ func (ctx *ProgCtx) Wait() { ctx.wg.Wait() } +// Defer registers a function to be called when the program context is cancelled. +// The function will be called when `Cancel` is first called. func (ctx *ProgCtx) Defer(f func()) { if ctx.Err() != nil { panic(errors.Errorf("Can not `Defer` after context is done")) diff --git a/types/types.go b/types/types.go index 103efa95..fdc02883 100644 --- a/types/types.go +++ b/types/types.go @@ -27,6 +27,7 @@ // Package types defines the common types used in OTNS. package types +// NodeId represents a node ID which starts from 1. type NodeId = int const ( From d8cf51789e22e2fae18d37beb4aec795acd4f4e1 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 14:24:40 +0800 Subject: [PATCH 12/16] doc threadconst --- threadconst/threadconst.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/threadconst/threadconst.go b/threadconst/threadconst.go index b43504f4..bf2a8e3c 100644 --- a/threadconst/threadconst.go +++ b/threadconst/threadconst.go @@ -24,9 +24,10 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package threadconst defines Thread related constants. package threadconst const ( - InvalidRloc16 uint16 = 0xfffe - BroadcastRloc16 uint16 = 0xffff + InvalidRloc16 uint16 = 0xfffe // Invalid RLOC16 + BroadcastRloc16 uint16 = 0xffff // The broadcast RLOC16 ) From 66acb772ee85a48eeec2bda3b9ac6472086f76df Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 18:13:42 +0800 Subject: [PATCH 13/16] doc simulation --- simulation/node.go | 8 +++++--- simulation/node_config.go | 25 +++++++------------------ simulation/simulation.go | 1 + 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/simulation/node.go b/simulation/node.go index a092615e..c2d19ae8 100644 --- a/simulation/node.go +++ b/simulation/node.go @@ -24,6 +24,8 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// This file implements the Node that manages a OpenThread virtual time simulation instance. + package simulation import ( @@ -45,11 +47,11 @@ import ( ) const ( - DefaultCommandTimeout = time.Second * 10 + DefaultCommandTimeout = time.Second * 10 // Default node command timeout ) var ( - DoneOrErrorRegexp = regexp.MustCompile(`(Done|Error \d+: .*)`) + doneOrErrorRegexp = regexp.MustCompile(`(Done|Error \d+: .*)`) ) func newNode(s *Simulation, id NodeId, cfg *NodeConfig) (*Node, error) { @@ -176,7 +178,7 @@ func (node *Node) CommandExpectNone(cmd string, timeout time.Duration) { func (node *Node) Command(cmd string, timeout time.Duration) []string { _, _ = node.Input.Write([]byte(cmd + "\n")) node.expectLine(cmd, timeout) - output := node.expectLine(DoneOrErrorRegexp, timeout) + output := node.expectLine(doneOrErrorRegexp, timeout) var result string output, result = output[:len(output)-1], output[len(output)-1] diff --git a/simulation/node_config.go b/simulation/node_config.go index 08dac997..58035723 100644 --- a/simulation/node_config.go +++ b/simulation/node_config.go @@ -26,17 +26,14 @@ package simulation -import ( - "runtime" -) - +// NodeConfig represents the node configuration. type NodeConfig struct { - ID int - X, Y int - IsMtd bool - IsRouter bool - RxOffWhenIdle bool - RadioRange int + ID int // Node ID (default: next available) + X, Y int // Node position: (X, Y) (default: 0, 0) + IsMtd bool // Whether the node is MTD (default: false) + IsRouter bool // Whether the node is Router (default: true) + RxOffWhenIdle bool // RX off when idle (default: false) + RadioRange int // Node radio range (default: 160) } func DefaultNodeConfig() *NodeConfig { @@ -50,11 +47,3 @@ func DefaultNodeConfig() *NodeConfig { RadioRange: 160, } } - -func (nc *NodeConfig) Executive() string { - if runtime.GOOS == "windows" { - return "ot-cli-ftd.exe" - } else { - return "ot-cli-ftd" - } -} diff --git a/simulation/simulation.go b/simulation/simulation.go index bce32a5d..b1fe4464 100644 --- a/simulation/simulation.go +++ b/simulation/simulation.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package simulation implements utilities for running a simulation. package simulation import ( From e0f6fc2b6fa824bb886271725357582e119b1075 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 21:38:19 +0800 Subject: [PATCH 14/16] doc simulation --- simulation/node.go | 112 ++++++++++++++++++++++++----- simulation/simulation.go | 39 ++++++---- simulation/simulationController.go | 1 + simulation/simulation_config.go | 26 +++---- 4 files changed, 135 insertions(+), 43 deletions(-) diff --git a/simulation/node.go b/simulation/node.go index c2d19ae8..b2795a37 100644 --- a/simulation/node.go +++ b/simulation/node.go @@ -103,9 +103,10 @@ func newNode(s *Simulation, id NodeId, cfg *NodeConfig) (*Node, error) { return n, nil } +// Node represents a running OpenThread virtual time simulation instance. type Node struct { - S *Simulation - Id int + S *Simulation // The simulation of node + Id int // The node ID cfg *NodeConfig cmd *exec.Cmd @@ -116,16 +117,19 @@ type Node struct { pendingLines chan string } +// String returns a string representing the node. func (node *Node) String() string { return fmt.Sprintf("Node<%d>", node.Id) } +// SetupNetworkParameters sets the network related configuration on node according to the simulation. func (node *Node) SetupNetworkParameters(sim *Simulation) { node.SetMasterKey(node.S.MasterKey()) node.SetPanid(node.S.Panid()) node.SetChannel(node.S.Channel()) } +// Start starts the Thread stack on the node. func (node *Node) Start() { node.IfconfigUp() node.ThreadStart() @@ -135,16 +139,19 @@ func (node *Node) Start() { node.GetMasterKey(), node.GetMode()) } +// IsFED returns if the node is Full Thread Device. func (node *Node) IsFED() bool { return !node.cfg.IsMtd } +// Stop stops the Thread stack on the node. func (node *Node) Stop() { node.ThreadStop() node.IfconfigDown() simplelogger.Debugf("%v - stopped, state = %s", node, node.GetState()) } +// Exit terminates the node process. func (node *Node) Exit() error { _, _ = node.Input.Write([]byte("exit\n")) node.expectEOF(DefaultCommandTimeout) @@ -155,14 +162,15 @@ func (node *Node) Exit() error { return err } +// AssurePrompt make sure that the node CLI is interactive. func (node *Node) AssurePrompt() { _, _ = node.Input.Write([]byte("\n")) - if found, _ := node.TryExpectLine("", time.Second); found { + if found, _ := node.tryExpectLine("", time.Second); found { return } _, _ = node.Input.Write([]byte("\n")) - if found, _ := node.TryExpectLine("", time.Second); found { + if found, _ := node.tryExpectLine("", time.Second); found { return } @@ -170,11 +178,14 @@ func (node *Node) AssurePrompt() { node.expectLine("", DefaultCommandTimeout) } +// CommandExpectNone sends a command to node CLI but does not expect any output. func (node *Node) CommandExpectNone(cmd string, timeout time.Duration) { _, _ = node.Input.Write([]byte(cmd + "\n")) node.expectLine(cmd, timeout) } +// Command sends a command to node CLI and captures all output until `Done` or `Error ...` +// It returns all output (not including `Done`) as a slice of strings. func (node *Node) Command(cmd string, timeout time.Duration) []string { _, _ = node.Input.Write([]byte(cmd + "\n")) node.expectLine(cmd, timeout) @@ -188,6 +199,7 @@ func (node *Node) Command(cmd string, timeout time.Duration) []string { return output } +// CommandExpectString sends a command to node CLI and expects output of a line of string. func (node *Node) CommandExpectString(cmd string, timeout time.Duration) string { output := node.Command(cmd, timeout) if len(output) != 1 { @@ -197,6 +209,7 @@ func (node *Node) CommandExpectString(cmd string, timeout time.Duration) string return output[0] } +// CommandExpectInt sends a command to node CLI and expects output of an integer. func (node *Node) CommandExpectInt(cmd string, timeout time.Duration) int { s := node.CommandExpectString(cmd, DefaultCommandTimeout) var iv int64 @@ -214,6 +227,7 @@ func (node *Node) CommandExpectInt(cmd string, timeout time.Duration) int { return int(iv) } +// CommandExpectHex sends a command to node CLI and expects output as a hexadecimal integer. func (node *Node) CommandExpectHex(cmd string, timeout time.Duration) int { s := node.CommandExpectString(cmd, DefaultCommandTimeout) var iv int64 @@ -227,15 +241,18 @@ func (node *Node) CommandExpectHex(cmd string, timeout time.Duration) int { return int(iv) } +// SetChannel sets the node radio channel. func (node *Node) SetChannel(ch int) { simplelogger.AssertTrue(11 <= ch && ch <= 26) node.Command(fmt.Sprintf("channel %d", ch), DefaultCommandTimeout) } +// GetChannel gets the node radio channel. func (node *Node) GetChannel() int { return node.CommandExpectInt("channel", DefaultCommandTimeout) } +// GetChildList gets the child list. func (node *Node) GetChildList() (childlist []int) { s := node.CommandExpectString("child list", DefaultCommandTimeout) ss := strings.Split(s, " ") @@ -250,42 +267,47 @@ func (node *Node) GetChildList() (childlist []int) { return } -func (node *Node) GetChildTable() { - // todo: not implemented yet -} - +// GetChildTimeout gets the child timeout. func (node *Node) GetChildTimeout() int { return node.CommandExpectInt("childtimeout", DefaultCommandTimeout) } +// SetChildTimeout sets the child timeout. func (node *Node) SetChildTimeout(timeout int) { node.Command(fmt.Sprintf("childtimeout %d", timeout), DefaultCommandTimeout) } +// GetContextReuseDelay gets the context reuse delay. func (node *Node) GetContextReuseDelay() int { return node.CommandExpectInt("contextreusedelay", DefaultCommandTimeout) } +// SetContextReuseDelay sets the context reuse delay. func (node *Node) SetContextReuseDelay(delay int) { node.Command(fmt.Sprintf("contextreusedelay %d", delay), DefaultCommandTimeout) } +// GetNetworkName gets the network name. func (node *Node) GetNetworkName() string { return node.CommandExpectString("networkname", DefaultCommandTimeout) } +// SetNetworkName sets the network name. func (node *Node) SetNetworkName(name string) { node.Command(fmt.Sprintf("networkname %s", name), DefaultCommandTimeout) } +// GetEui64 gets the EUI64. func (node *Node) GetEui64() string { return node.CommandExpectString("eui64", DefaultCommandTimeout) } +// SetEui64 sets the EUI64. func (node *Node) SetEui64(eui64 string) { node.Command(fmt.Sprintf("eui64 %s", eui64), DefaultCommandTimeout) } +// GetExtAddr gets the Extended Address. func (node *Node) GetExtAddr() uint64 { s := node.CommandExpectString("extaddr", DefaultCommandTimeout) v, err := strconv.ParseUint(s, 16, 64) @@ -293,127 +315,155 @@ func (node *Node) GetExtAddr() uint64 { return v } +// SetExtAddr sets the Extended Address. func (node *Node) SetExtAddr(extaddr uint64) { node.Command(fmt.Sprintf("extaddr %016x", extaddr), DefaultCommandTimeout) } +// GetExtPanid gets the Extended Pan ID. func (node *Node) GetExtPanid() string { return node.CommandExpectString("extpanid", DefaultCommandTimeout) } +// SetExtPanid sets the Extended Pan ID. func (node *Node) SetExtPanid(extpanid string) { node.Command(fmt.Sprintf("extpanid %s", extpanid), DefaultCommandTimeout) } +// GetIfconfig gets `ifconfig` result. func (node *Node) GetIfconfig() string { return node.CommandExpectString("ifconfig", DefaultCommandTimeout) } +// IfconfigUp turns on the Thread network interface. func (node *Node) IfconfigUp() { node.Command("ifconfig up", DefaultCommandTimeout) } +// IfconfigDown turns off the Thread network interface. func (node *Node) IfconfigDown() { node.Command("ifconfig down", DefaultCommandTimeout) } +// GetIpAddr gets all IPv6 addresses. func (node *Node) GetIpAddr() []string { // todo: parse IPv6 addresses addrs := node.Command("ipaddr", DefaultCommandTimeout) return addrs } +// GetIpAddrLinkLocal gets all link-local IPv6 addresses func (node *Node) GetIpAddrLinkLocal() []string { // todo: parse IPv6 addresses addrs := node.Command("ipaddr linklocal", DefaultCommandTimeout) return addrs } +// GetIpAddrLinkLocal gets all MLEID IPv6 addresses. func (node *Node) GetIpAddrMleid() []string { // todo: parse IPv6 addresses addrs := node.Command("ipaddr mleid", DefaultCommandTimeout) return addrs } +// GetIpAddrRloc gets all RLOC IPv6 addresses. func (node *Node) GetIpAddrRloc() []string { addrs := node.Command("ipaddr rloc", DefaultCommandTimeout) return addrs } +// GetIpMaddr gets all multicast IPv6 addresses. func (node *Node) GetIpMaddr() []string { // todo: parse IPv6 addresses addrs := node.Command("ipmaddr", DefaultCommandTimeout) return addrs } +// GetIpMaddrPromiscuous gets if `ipmaddr promiscuous` is enabled. func (node *Node) GetIpMaddrPromiscuous() bool { return node.CommandExpectEnabledOrDisabled("ipmaddr promiscuous", DefaultCommandTimeout) } +// IpMaddrPromiscuousEnable enables `ipmaddr promiscuous`. func (node *Node) IpMaddrPromiscuousEnable() { node.Command("ipmaddr promiscuous enable", DefaultCommandTimeout) } +// IpMaddrPromiscuousDisable disables `ipmaddr promiscuous`. func (node *Node) IpMaddrPromiscuousDisable() { node.Command("ipmaddr promiscuous disable", DefaultCommandTimeout) } +// GetPromiscuous checks if `promiscuous` is enabled. func (node *Node) GetPromiscuous() bool { return node.CommandExpectEnabledOrDisabled("promiscuous", DefaultCommandTimeout) } +// PromiscuousEnable enables `promiscuous`. func (node *Node) PromiscuousEnable() { node.Command("promiscuous enable", DefaultCommandTimeout) } +// PromiscuousDisable disables `promiscuous`. func (node *Node) PromiscuousDisable() { node.Command("promiscuous disable", DefaultCommandTimeout) } +// GetRouterEligible gets if `routereligible` is enabled. func (node *Node) GetRouterEligible() bool { return node.CommandExpectEnabledOrDisabled("routereligible", DefaultCommandTimeout) } +// RouterEligibleEnable enables `routereligible`. func (node *Node) RouterEligibleEnable() { node.Command("routereligible enable", DefaultCommandTimeout) } +// RouterEligibleDisable disables `routereligible`. func (node *Node) RouterEligibleDisable() { node.Command("routereligible disable", DefaultCommandTimeout) } +// GetJoinerPort gets the joiner port. func (node *Node) GetJoinerPort() int { return node.CommandExpectInt("joinerport", DefaultCommandTimeout) } +// SetJoinerPort sets the joiner port. func (node *Node) SetJoinerPort(port int) { node.Command(fmt.Sprintf("joinerport %d", port), DefaultCommandTimeout) } +// GetKeySequenceCounter gets the Key Sequence Counter. func (node *Node) GetKeySequenceCounter() int { return node.CommandExpectInt("keysequence counter", DefaultCommandTimeout) } +// SetKeySequenceCounter sets the Key Sequence Counter. func (node *Node) SetKeySequenceCounter(counter int) { node.Command(fmt.Sprintf("keysequence counter %d", counter), DefaultCommandTimeout) } +// GetKeySequenceGuardTime gets the Key Sequence Guard Time. func (node *Node) GetKeySequenceGuardTime() int { return node.CommandExpectInt("keysequence guardtime", DefaultCommandTimeout) } +// SetKeySequenceGuardTime sets the Key Sequence Guard Time. func (node *Node) SetKeySequenceGuardTime(guardtime int) { node.Command(fmt.Sprintf("keysequence guardtime %d", guardtime), DefaultCommandTimeout) } +// LeaderData represents the Leader Data. type LeaderData struct { - PartitionID int - Weighting int - DataVersion int - StableDataVersion int - LeaderRouterID int + PartitionID int // Partition ID + Weighting int // Weighting + DataVersion int // Data version + StableDataVersion int // Stable data version + LeaderRouterID int // Leader router ID } +// GetLeaderData gets the Leader Data. func (node *Node) GetLeaderData() (leaderData LeaderData) { var err error output := node.Command("leaderdata", DefaultCommandTimeout) @@ -446,22 +496,27 @@ func (node *Node) GetLeaderData() (leaderData LeaderData) { return } +// GetLeaderPartitionId gets the leader partition ID. func (node *Node) GetLeaderPartitionId() int { return node.CommandExpectInt("leaderpartitionid", DefaultCommandTimeout) } +// SetLeaderPartitionId sets the leader partition ID. func (node *Node) SetLeaderPartitionId(partitionid int) { node.Command(fmt.Sprintf("leaderpartitionid 0x%x", partitionid), DefaultCommandTimeout) } +// GetLeaderWeight gets the leader weight. func (node *Node) GetLeaderWeight() int { return node.CommandExpectInt("leaderweight", DefaultCommandTimeout) } +// SetLeaderWeight sets the leader weight. func (node *Node) SetLeaderWeight(weight int) { node.Command(fmt.Sprintf("leaderweight 0x%x", weight), DefaultCommandTimeout) } +// FactoryReset factory resets the node. func (node *Node) FactoryReset() { simplelogger.Warnf("%v - factoryreset", node) _, _ = node.Input.Write([]byte("factoryreset\n")) @@ -469,6 +524,7 @@ func (node *Node) FactoryReset() { simplelogger.Debugf("%v - ready", node) } +// Reset resets the node. func (node *Node) Reset() { simplelogger.Warnf("%v - reset", node) _, _ = node.Input.Write([]byte("reset\n")) @@ -476,75 +532,94 @@ func (node *Node) Reset() { simplelogger.Debugf("%v - ready", node) } +// GetMasterKey gets the Master Key. func (node *Node) GetMasterKey() string { return node.CommandExpectString("masterkey", DefaultCommandTimeout) } +// SetMasterKey sets the Master Key. func (node *Node) SetMasterKey(key string) { node.Command(fmt.Sprintf("masterkey %s", key), DefaultCommandTimeout) } +// GetMode gets the node mode. func (node *Node) GetMode() string { // todo: return Mode type rather than just string return node.CommandExpectString("mode", DefaultCommandTimeout) } +// SetMode sets the node mode. func (node *Node) SetMode(mode string) { node.Command(fmt.Sprintf("mode %s", mode), DefaultCommandTimeout) } +// GetPanid gets the Pan ID. func (node *Node) GetPanid() uint16 { // todo: return Mode type rather than just string return uint16(node.CommandExpectInt("panid", DefaultCommandTimeout)) } +// SetPanid sets the Pan ID. func (node *Node) SetPanid(panid uint16) { node.Command(fmt.Sprintf("panid 0x%x", panid), DefaultCommandTimeout) } +// GetRloc16 gets the RLOC16. func (node *Node) GetRloc16() uint16 { return uint16(node.CommandExpectHex("rloc16", DefaultCommandTimeout)) } +// GetRouterSelectionJitter gets the Router Selection Jitter. func (node *Node) GetRouterSelectionJitter() int { return node.CommandExpectInt("routerselectionjitter", DefaultCommandTimeout) } +// SetRouterSelectionJitter sets the Router Selection Jitter. func (node *Node) SetRouterSelectionJitter(timeout int) { node.Command(fmt.Sprintf("routerselectionjitter %d", timeout), DefaultCommandTimeout) } +// GetRouterUpgradeThreshold gets the Router Upgrade Threshold. func (node *Node) GetRouterUpgradeThreshold() int { return node.CommandExpectInt("routerupgradethreshold", DefaultCommandTimeout) } +// SetRouterUpgradeThreshold sets the Router Upgrade Threshold. func (node *Node) SetRouterUpgradeThreshold(timeout int) { node.Command(fmt.Sprintf("routerupgradethreshold %d", timeout), DefaultCommandTimeout) } +// GetRouterDowngradeThreshold gets the Router Downgrade Threshold. func (node *Node) GetRouterDowngradeThreshold() int { return node.CommandExpectInt("routerdowngradethreshold", DefaultCommandTimeout) } +// SetRouterDowngradeThreshold sets the Router Downgrade Threshold. func (node *Node) SetRouterDowngradeThreshold(timeout int) { node.Command(fmt.Sprintf("routerdowngradethreshold %d", timeout), DefaultCommandTimeout) } +// GetState gets the node state. func (node *Node) GetState() string { return node.CommandExpectString("state", DefaultCommandTimeout) } +// ThreadStart starts the Thread stack on node. func (node *Node) ThreadStart() { node.Command("thread start", DefaultCommandTimeout) } + +// ThreadStop stops the Thread stack on node. func (node *Node) ThreadStop() { node.Command("thread stop", DefaultCommandTimeout) } +// GetVersion gets the node version. func (node *Node) GetVersion() string { return node.CommandExpectString("version", DefaultCommandTimeout) } +// GetSingleton gets if it's a singleton partition. func (node *Node) GetSingleton() bool { s := node.CommandExpectString("singleton", DefaultCommandTimeout) if s == "true" { @@ -589,7 +664,7 @@ func (node *Node) lineReader() { } } -func (node *Node) TryExpectLine(line interface{}, timeout time.Duration) (bool, []string) { +func (node *Node) tryExpectLine(line interface{}, timeout time.Duration) (bool, []string) { var outputLines []string deadline := time.After(timeout) @@ -623,7 +698,7 @@ func (node *Node) TryExpectLine(line interface{}, timeout time.Duration) (bool, } func (node *Node) expectLine(line interface{}, timeout time.Duration) []string { - found, output := node.TryExpectLine(line, timeout) + found, output := node.tryExpectLine(line, timeout) if !found { simplelogger.Panicf("expect line timeout: %#v", line) } @@ -649,6 +724,8 @@ func (node *Node) expectEOF(timeout time.Duration) { } } +// CommandExpectEnabledOrDisabled sends a command to node CLI and expects output of "Enabled" or "Disabled" +// It converts "Enabled" to true and "Disabled" to false. func (node *Node) CommandExpectEnabledOrDisabled(cmd string, timeout time.Duration) bool { output := node.CommandExpectString(cmd, timeout) if output == "Enabled" { @@ -661,6 +738,7 @@ func (node *Node) CommandExpectEnabledOrDisabled(cmd string, timeout time.Durati return false } +// Ping pings the destination address. func (node *Node) Ping(addr string, payloadSize int, count int, interval int, hopLimit int) { cmd := fmt.Sprintf("ping %s %d %d %d %d", addr, payloadSize, count, interval, hopLimit) _, _ = node.Input.Write([]byte(cmd + "\n")) @@ -686,10 +764,6 @@ func (node *Node) isLineMatch(line string, _expectedLine interface{}) bool { return false } -func (node *Node) DumpStat() string { - return fmt.Sprintf("extaddr %016x, addr %04x, state %-6s", node.GetExtAddr(), node.GetRloc16(), node.GetState()) -} - func (node *Node) setupMode() { if node.cfg.IsRouter { // routers should be full functional and rx always on diff --git a/simulation/simulation.go b/simulation/simulation.go index b1fe4464..07ecf71a 100644 --- a/simulation/simulation.go +++ b/simulation/simulation.go @@ -29,7 +29,6 @@ package simulation import ( "os" - "sort" "time" "github.com/openthread/ot-ns/progctx" @@ -41,6 +40,7 @@ import ( "github.com/simonlingoogle/go-simplelogger" ) +// Simulation manages a running simulation. type Simulation struct { ctx *progctx.ProgCtx cfg *Config @@ -50,6 +50,7 @@ type Simulation struct { rawMode bool } +// NewSimulation creates a new simulation. func NewSimulation(ctx *progctx.ProgCtx, cfg *Config) (*Simulation, error) { s := &Simulation{ ctx: ctx, @@ -69,6 +70,7 @@ func NewSimulation(ctx *progctx.ProgCtx, cfg *Config) (*Simulation, error) { return s, nil } +// AddNode adds a new node to the simulation. func (s *Simulation) AddNode(cfg *NodeConfig) (*Node, error) { if cfg == nil { cfg = DefaultNodeConfig() @@ -116,6 +118,7 @@ func (s *Simulation) genNodeId() NodeId { return nodeid } +// Run runs the simulation until exit. func (s *Simulation) Run() { s.ctx.WaitAdd("simulation", 1) defer s.ctx.WaitDone("simulation") @@ -124,22 +127,27 @@ func (s *Simulation) Run() { s.d.Run() } +// Nodes returns all nodes of the simulation. func (s *Simulation) Nodes() map[NodeId]*Node { return s.nodes } +// MasterKey returns the default Master Key of the simulation. func (s *Simulation) MasterKey() string { return s.cfg.MasterKey } +// Panid gets the default Pan ID of the simulation. func (s *Simulation) Panid() uint16 { return s.cfg.Panid } +// Channel gets the default channel of the simulation. func (s *Simulation) Channel() int { return s.cfg.Channel } +// Stop stops the simulation. func (s *Simulation) Stop() { simplelogger.Infof("stopping simulation ...") for _, node := range s.nodes { @@ -151,10 +159,12 @@ func (s *Simulation) Stop() { s.d.Stop() } +// BinDir gets the binary directory for searching OpenThread executables. func (s *Simulation) BinDir() string { return s.cfg.BinDir } +// SetVisualizer sets the visualizer for the simulation. func (s *Simulation) SetVisualizer(vis visualize.Visualizer) { simplelogger.AssertNotNil(vis) s.vis = vis @@ -162,35 +172,31 @@ func (s *Simulation) SetVisualizer(vis visualize.Visualizer) { vis.SetController(NewSimulationController(s)) } +// OnNodeFail notifies the simulation of the failed node. +// It is part of the implementation of dispatcher.CallbackHandler. func (s *Simulation) OnNodeFail(nodeid NodeId) { node := s.nodes[nodeid] simplelogger.AssertNotNil(node) } +// OnNodeRecover notifies the simulation of the recovered node. +// It is part of the implementation of dispatcher.CallbackHandler. func (s *Simulation) OnNodeRecover(nodeid NodeId) { node := s.nodes[nodeid] simplelogger.AssertNotNil(node) } +// PostAsync posts a asynchronous task to be executed in the simulation goroutine. func (s *Simulation) PostAsync(trivial bool, f func()) { s.d.PostAsync(trivial, f) } +// Dispatcher gets the dispatcher of the simulation. func (s *Simulation) Dispatcher() *dispatcher.Dispatcher { return s.d } -func (s *Simulation) VisitNodesInOrder(cb func(node *Node)) { - var nodeids []NodeId - for nodeid := range s.nodes { - nodeids = append(nodeids, nodeid) - } - sort.Ints(nodeids) - for _, nodeid := range nodeids { - cb(s.nodes[nodeid]) - } -} - +// MoveNodeTo moves a node to the target position. func (s *Simulation) MoveNodeTo(nodeid NodeId, x, y int) { dn := s.d.GetNode(nodeid) if dn == nil { @@ -200,6 +206,7 @@ func (s *Simulation) MoveNodeTo(nodeid NodeId, x, y int) { s.d.SetNodePos(nodeid, x, y) } +// DeleteNode deletes a node from the simulation. func (s *Simulation) DeleteNode(nodeid NodeId) error { node := s.nodes[nodeid] if node == nil { @@ -213,26 +220,34 @@ func (s *Simulation) DeleteNode(nodeid NodeId) error { return nil } +// SetNodeFailed sets if the node radio is failed. func (s *Simulation) SetNodeFailed(id NodeId, failed bool) { s.d.SetNodeFailed(id, failed) } +// ShowDemoLegend shows a demo legend in the visualization. +// It is not implemented yet. func (s *Simulation) ShowDemoLegend(x int, y int, title string) { s.vis.ShowDemoLegend(x, y, title) } +// SetSpeed sets the simulating speed. func (s *Simulation) SetSpeed(speed float64) { s.d.SetSpeed(speed) } +// GetSpeed gets the simulating speed. func (s *Simulation) GetSpeed() float64 { return s.Dispatcher().GetSpeed() } +// CountDown shows a count down in the visualization. func (s *Simulation) CountDown(duration time.Duration, text string) { s.vis.CountDown(duration, text) } +// Go continues the simulation for a given time duration in simulating time. +// It returns a channel for notifying that the duration is elapsed in simulation. func (s *Simulation) Go(duration time.Duration) <-chan struct{} { return s.d.Go(duration) } diff --git a/simulation/simulationController.go b/simulation/simulationController.go index 4aaf5cd9..d3f4464f 100644 --- a/simulation/simulationController.go +++ b/simulation/simulationController.go @@ -113,6 +113,7 @@ func (r readonlySimulationController) CtrlDeleteNode(nodeid NodeId) error { return readonlySimulationError } +// NewSimulationController creates a simulation controller for simulation management in visualization. func NewSimulationController(sim *Simulation) visualize.SimulationController { if !sim.cfg.ReadOnly { return &simulationController{sim} diff --git a/simulation/simulation_config.go b/simulation/simulation_config.go index e499347a..3a1cde72 100644 --- a/simulation/simulation_config.go +++ b/simulation/simulation_config.go @@ -27,23 +27,25 @@ package simulation const ( - DefaultNetworkName = "OTSIM" - DefaultMasterKey = "00112233445566778899aabbccddeeff" - DefaultPanid = 0xface - DefaultChannel = 11 + DefaultNetworkName = "OTSIM" // The default network name + DefaultMasterKey = "00112233445566778899aabbccddeeff" // The default Master Key + DefaultPanid = 0xface // The default Pan ID + DefaultChannel = 11 // The default channel ) +// Config represents a simulation configuration. type Config struct { - NetworkName string - MasterKey string - Panid uint16 - Channel int - BinDir string - Speed float64 - ReadOnly bool - RawMode bool + NetworkName string // Network Name + MasterKey string // Master Key + Panid uint16 // Pan ID + Channel int // Channel + BinDir string // OpenThread Binary Directory + Speed float64 // Simulating speed + ReadOnly bool // If the simulation is readonly + RawMode bool // If the simulation is using raw mode } +// DefaultConfig returns the default configuration for a simulation. func DefaultConfig() *Config { return &Config{ NetworkName: DefaultNetworkName, From 3facb66803c76c5471c80553bf2a518deb6b9ea0 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 23:06:47 +0800 Subject: [PATCH 15/16] doc visualize --- dispatcher/dispatcher.go | 2 +- types/types.go | 11 ++++++ visualize/SimulationController.go | 6 ++++ visualize/grpc/grpcField.go | 3 +- visualize/grpc/grpcNode.go | 5 ++- visualize/grpc/grpcSimCtrl.go | 1 + visualize/grpc/grpcVisualizer.go | 4 ++- visualize/multi/multiVisualizer.go | 3 +- visualize/nopVisualizer.go | 1 + visualize/types.go | 58 +++++++++++++++--------------- 10 files changed, 58 insertions(+), 36 deletions(-) diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 8aac4a14..8821c377 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -715,7 +715,7 @@ func (d *Dispatcher) handleStatusPush(srcid NodeId, data string) { if sp[0] == "role" { role, err := strconv.Atoi(sp[1]) simplelogger.PanicIfError(err) - d.vis.SetNodeRole(srcid, visualize.OtDeviceRole(role)) + d.vis.SetNodeRole(srcid, OtDeviceRole(role)) } else if sp[0] == "rloc16" { rloc16, err := strconv.Atoi(sp[1]) simplelogger.PanicIfError(err) diff --git a/types/types.go b/types/types.go index fdc02883..f1b82e37 100644 --- a/types/types.go +++ b/types/types.go @@ -52,3 +52,14 @@ func DefaultNodeMode() NodeMode { FullNetworkData: true, } } + +// OtDeviceRole represents the device role. +type OtDeviceRole int + +const ( + OtDeviceRoleDisabled OtDeviceRole = 0 // The Thread stack is disabled. + OtDeviceRoleDetached OtDeviceRole = 1 // Not currently participating in a Thread network/partition. + OtDeviceRoleChild OtDeviceRole = 2 // The Thread Child role. + OtDeviceRoleRouter OtDeviceRole = 3 // The Thread Router role. + OtDeviceRoleLeader OtDeviceRole = 4 // The Thread Leader role. +) diff --git a/visualize/SimulationController.go b/visualize/SimulationController.go index 6cd43508..bb5c1a28 100644 --- a/visualize/SimulationController.go +++ b/visualize/SimulationController.go @@ -30,10 +30,16 @@ import ( . "github.com/openthread/ot-ns/types" ) +// SimulationController defines the interfaces for operating the simulation in visualization. type SimulationController interface { + // CtrlAddNode notifies the simulation to add a new node. CtrlAddNode(x, y int, router bool, mode NodeMode) error + // CtrlMoveNodeTo notifies the simulation to move node to a given position. CtrlMoveNodeTo(nodeid NodeId, x, y int) error + // CtrlDeleteNode notifies the simulation to delete a node. CtrlDeleteNode(nodeid NodeId) error + // CtrlSetNodeFailed notifies the simulation to set node failed. CtrlSetNodeFailed(nodeid NodeId, failed bool) error + // CtrlSetSpeed notifies the simulation to set speed. CtrlSetSpeed(speed float64) error } diff --git a/visualize/grpc/grpcField.go b/visualize/grpc/grpcField.go index a0986ef5..dd7f3a0c 100644 --- a/visualize/grpc/grpcField.go +++ b/visualize/grpc/grpcField.go @@ -28,7 +28,6 @@ package visualize_grpc import ( . "github.com/openthread/ot-ns/types" - "github.com/openthread/ot-ns/visualize" "github.com/simonlingoogle/go-simplelogger" ) @@ -50,7 +49,7 @@ func (f *grpcField) setNodeRloc16(id NodeId, rloc16 uint16) { f.nodes[id].rloc16 = rloc16 } -func (f *grpcField) setNodeRole(id NodeId, role visualize.OtDeviceRole) { +func (f *grpcField) setNodeRole(id NodeId, role OtDeviceRole) { f.nodes[id].role = role } diff --git a/visualize/grpc/grpcNode.go b/visualize/grpc/grpcNode.go index 6538e888..3aabd98b 100644 --- a/visualize/grpc/grpcNode.go +++ b/visualize/grpc/grpcNode.go @@ -29,7 +29,6 @@ package visualize_grpc import ( "github.com/openthread/ot-ns/threadconst" . "github.com/openthread/ot-ns/types" - "github.com/openthread/ot-ns/visualize" ) type grpcNode struct { @@ -40,7 +39,7 @@ type grpcNode struct { radioRange int mode NodeMode rloc16 uint16 - role visualize.OtDeviceRole + role OtDeviceRole partitionId uint32 failed bool parent uint64 @@ -57,7 +56,7 @@ func newGprcNode(id NodeId, extaddr uint64, x int, y int, radioRange int, mode N radioRange: radioRange, mode: mode, rloc16: threadconst.InvalidRloc16, - role: visualize.OtDeviceRoleDisabled, + role: OtDeviceRoleDisabled, partitionId: 0, failed: false, parent: 0, diff --git a/visualize/grpc/grpcSimCtrl.go b/visualize/grpc/grpcSimCtrl.go index 56c0ede2..6a438807 100644 --- a/visualize/grpc/grpcSimCtrl.go +++ b/visualize/grpc/grpcSimCtrl.go @@ -85,6 +85,7 @@ func (gsc *grpcSimCtrl) CtrlDeleteNode(nodeid NodeId) error { return err } +// NewGrpcSimulationController creates a Simulation Controller from a gRPC visualization client. func NewGrpcSimulationController(ctx context.Context, client pb.VisualizeGrpcServiceClient) visualize.SimulationController { return &grpcSimCtrl{ ctx: ctx, diff --git a/visualize/grpc/grpcVisualizer.go b/visualize/grpc/grpcVisualizer.go index d8acff2f..156c8847 100644 --- a/visualize/grpc/grpcVisualizer.go +++ b/visualize/grpc/grpcVisualizer.go @@ -90,7 +90,7 @@ func (gv *grpcVisualizer) SetNodeRloc16(nodeid NodeId, rloc16 uint16) { }}}, false) } -func (gv *grpcVisualizer) SetNodeRole(nodeid NodeId, role visualize.OtDeviceRole) { +func (gv *grpcVisualizer) SetNodeRole(nodeid NodeId, role OtDeviceRole) { gv.f.setNodeRole(nodeid, role) gv.server.SendEvent(&pb.VisualizeEvent{Type: &pb.VisualizeEvent_SetNodeRole{SetNodeRole: &pb.SetNodeRoleEvent{ NodeId: int32(nodeid), @@ -348,6 +348,8 @@ func (gv *grpcVisualizer) prepareStream(stream *grpcStream) error { return nil } +// NewGrpcVisualizer creates a gRPC visualization server. +// The gRPC visualization server accepts gRPC connections and sends visualization events to these clients. func NewGrpcVisualizer(address string) visualize.Visualizer { gsv := &grpcVisualizer{ simctrl: nil, diff --git a/visualize/multi/multiVisualizer.go b/visualize/multi/multiVisualizer.go index 5467d4af..38580ee6 100644 --- a/visualize/multi/multiVisualizer.go +++ b/visualize/multi/multiVisualizer.go @@ -75,7 +75,7 @@ func (mv *multiVisualizer) SetNodeRloc16(nodeid NodeId, rloc16 uint16) { } } -func (mv *multiVisualizer) SetNodeRole(nodeid NodeId, role visualize.OtDeviceRole) { +func (mv *multiVisualizer) SetNodeRole(nodeid NodeId, role OtDeviceRole) { for _, v := range mv.vs { v.SetNodeRole(nodeid, role) } @@ -171,6 +171,7 @@ func (mv *multiVisualizer) SetParent(id NodeId, extaddr uint64) { } } +// NewMultiVisualizer combines multiple Visualizer as one Visualizer. func NewMultiVisualizer(vs ...visualize.Visualizer) visualize.Visualizer { return &multiVisualizer{vs: vs} } diff --git a/visualize/nopVisualizer.go b/visualize/nopVisualizer.go index 6f6fa124..59d43263 100644 --- a/visualize/nopVisualizer.go +++ b/visualize/nopVisualizer.go @@ -112,6 +112,7 @@ func (nv nopVisualizer) OnNodeRecover(NodeId) { } +// NewNopVisualizer creates a visualizer of no visualization. func NewNopVisualizer() Visualizer { return nopVisualizer{} } diff --git a/visualize/types.go b/visualize/types.go index 86ec4d90..4d6aacee 100644 --- a/visualize/types.go +++ b/visualize/types.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package visualize implements the web visualization. package visualize import ( @@ -34,41 +35,63 @@ import ( . "github.com/openthread/ot-ns/types" ) +// Visualizer defines the interface of a visualizer. type Visualizer interface { + // Run runs the visualizer. Run() + // Stop stops the visualizer. Stop() - + // AddNode adds a new node. AddNode(nodeid NodeId, extaddr uint64, x int, y int, radioRange int, mode NodeMode) + // SetNodeRloc16 sets the node RLOC16. SetNodeRloc16(nodeid NodeId, rloc16 uint16) + // SetNodeRole sets the node role. SetNodeRole(nodeid NodeId, role OtDeviceRole) Send(srcid NodeId, dstid NodeId, mvinfo *MsgVisualizeInfo) + // SetNodePartitionId sets the node partition ID. SetNodePartitionId(nodeid NodeId, parid uint32) + // SetSpeed sets the simulating speed. SetSpeed(speed float64) + // AdvanceTime sets time to new timestamp. AdvanceTime(ts uint64, speed float64) - + // OnNodeFail notifies of a failed node. OnNodeFail(nodeId NodeId) + // OnNodeRecover notifies of a recovered node. OnNodeRecover(nodeId NodeId) + // SetController sets the simulation controller. SetController(ctrl SimulationController) + // SetNodePos SetNodePos(nodeid NodeId, x, y int) + // DeleteNode deletes a node. DeleteNode(id NodeId) + // AddRouterTable adds a new router to the router table of a node. AddRouterTable(id NodeId, extaddr uint64) + // RemoveRouterTable removes a router from the router table of a node. RemoveRouterTable(id NodeId, extaddr uint64) + // AddChildTable adds a child to the child table of a node. AddChildTable(id NodeId, extaddr uint64) + // RemoveChildTable removes a child from the child table of a node. RemoveChildTable(id NodeId, extaddr uint64) + // ShowDemoLegend shows the demo legend. ShowDemoLegend(x int, y int, title string) + // CountDown creates a new countdown with specified text and duration. CountDown(duration time.Duration, text string) + // SetParent sets the parent of a node. SetParent(id NodeId, extaddr uint64) + // OnExtAddrChange notifies of Extended Address change of a node. OnExtAddrChange(id NodeId, extaddr uint64) } +// MsgVisualizeInfo contains visualization information of a message. type MsgVisualizeInfo struct { - Channel uint8 - FrameControl wpan.FrameControl - Seq uint8 - DstAddrShort uint16 - DstAddrExtended uint64 + Channel uint8 // Message channel + FrameControl wpan.FrameControl // WPAN Frame Control + Seq uint8 // WPAN Sequence + DstAddrShort uint16 // Destination Short Address + DstAddrExtended uint64 // Destination Extended Address } +// MsgVisualizeInfo returns a short string label for the message. func (info *MsgVisualizeInfo) Label() string { frameType := info.FrameControl.FrameType() if frameType == wpan.FrameTypeAck { @@ -79,24 +102,3 @@ func (info *MsgVisualizeInfo) Label() string { return fmt.Sprintf("MLE%03d", info.Seq) } } - -func (info *MsgVisualizeInfo) FormatDstAddr() interface{} { - dstaddrmode := info.FrameControl.DstAddrMode() - if dstaddrmode == wpan.DstAddrModeShort { - return fmt.Sprintf("%04x", info.DstAddrShort) - } else if dstaddrmode == wpan.DstAddrModeExtended { - return fmt.Sprintf("%016x", info.DstAddrExtended) - } else { - return "@" - } -} - -type OtDeviceRole int - -const ( - OtDeviceRoleDisabled OtDeviceRole = 0 ///< The Thread stack is disabled. - OtDeviceRoleDetached OtDeviceRole = 1 ///< Not currently participating in a Thread network/partition. - OtDeviceRoleChild OtDeviceRole = 2 ///< The Thread Child role. - OtDeviceRoleRouter OtDeviceRole = 3 ///< The Thread Router role. - OtDeviceRoleLeader OtDeviceRole = 4 ///< The Thread Leader role. -) From c8ee66b9cd97645c7af21f20eeb4556091bbd629 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 14 Apr 2020 23:40:14 +0800 Subject: [PATCH 16/16] doc dispatcher --- dispatcher/Node.go | 48 ++++++++------ dispatcher/alarm_mgr.go | 6 +- dispatcher/dispatcher.go | 66 +++++++++++++------ .../{FailureCtrl.go => failure_ctrl.go} | 21 +++--- ...ilureCtrl_test.go => failure_ctrl_test.go} | 0 dispatcher/send_queue.go | 2 +- dispatcher/send_queue_test.go | 2 +- dispatcher/types.go | 38 ----------- types/types.go | 12 ++++ 9 files changed, 104 insertions(+), 91 deletions(-) rename dispatcher/{FailureCtrl.go => failure_ctrl.go} (82%) rename dispatcher/{FailureCtrl_test.go => failure_ctrl_test.go} (100%) delete mode 100644 dispatcher/types.go diff --git a/dispatcher/Node.go b/dispatcher/Node.go index fc55cc45..79a86be9 100644 --- a/dispatcher/Node.go +++ b/dispatcher/Node.go @@ -47,10 +47,12 @@ type pingRequest struct { Dst string DataSize int } + +// PingResult represents a `ping` result. type PingResult struct { - Dst string - DataSize int - Delay uint64 + Dst string // Ping destination + DataSize int // Ping data size + Delay uint64 // Ping delay } type joinerSession struct { @@ -59,23 +61,25 @@ type joinerSession struct { StopTime uint64 } +// JoinResult represents a `join` result type JoinResult struct { - JoinDuration uint64 - SessionDuration uint64 + JoinDuration uint64 // Join duration or 0 if join failed + SessionDuration uint64 // Session duration } +// Node represents a node in dispatcher. type Node struct { - D *Dispatcher - Id NodeId - X, Y int - PartitionId uint32 - ExtAddr uint64 - Rloc16 uint16 - CreateTime uint64 - CurTime uint64 + D *Dispatcher // Dispatcher + Id NodeId // Node ID + X, Y int // Position + PartitionId uint32 // partition ID + ExtAddr uint64 // Extended Address + Rloc16 uint16 // RLOC16 + CreateTime uint64 // Create time + CurTime uint64 // Current time addr *net.UDPAddr - failureCtrl *FailureCtrl + failureCtrl *failureCtrl isFailed bool radioRange int pendingPings []*pingRequest @@ -109,10 +113,12 @@ func newNode(d *Dispatcher, nodeid NodeId, extaddr uint64, x, y int, radioRange return nc } +// String returns a string representation of the node. func (node *Node) String() string { return fmt.Sprintf("Node<%016x@%d,%d>", node.ExtAddr, node.X, node.Y) } +// Send sends a radio event to the node. func (node *Node) Send(elapsed uint64, data []byte) { msg := make([]byte, len(data)+11) binary.LittleEndian.PutUint64(msg[:8], elapsed) @@ -124,12 +130,14 @@ func (node *Node) Send(elapsed uint64, data []byte) { node.SendMessage(msg) } +// SendMessage sends a event to the node. func (node *Node) SendMessage(msg []byte) { n, err := node.D.udpln.WriteToUDP(msg, node.addr) simplelogger.AssertEqual(n, len(msg)) simplelogger.AssertNil(err, err) } +// GetDistanceTo gets the distance to another node. func (node *Node) GetDistanceTo(other *Node) (dist int) { dx := other.X - node.X dy := other.Y - node.Y @@ -137,10 +145,12 @@ func (node *Node) GetDistanceTo(other *Node) (dist int) { return } +// IsFailed returns if the node is failed. func (node *Node) IsFailed() bool { return node.isFailed } +// Fail set the node as failed. func (node *Node) Fail() { if !node.isFailed { node.isFailed = true @@ -149,6 +159,7 @@ func (node *Node) Fail() { } } +// Recover set the node as not failed. func (node *Node) Recover() { if node.isFailed { node.isFailed = false @@ -157,12 +168,7 @@ func (node *Node) Recover() { } } -func (node *Node) DumpStat() string { - d := node.D - alarmTs := d.alarmMgr.GetTimestamp(node.Id) - return fmt.Sprintf("CurTime=%v, AlarmTs=%v, Failed=%-5v, RecoverTS=%v", node.CurTime, alarmTs, node.isFailed, node.failureCtrl.recoverTs) -} - +// SetFailTime sets the fail time configuration. func (node *Node) SetFailTime(failTime FailTime) { node.failureCtrl.SetFailTime(failTime) } @@ -214,12 +220,14 @@ func (node *Node) addPingResult(dst string, datasize int, delay uint64) { } } +// CollectPings return the collected ping results func (node *Node) CollectPings() []*PingResult { ret := node.pingResults node.pingResults = nil return ret } +// CollectJoins return the collected join results. func (node *Node) CollectJoins() []*JoinResult { ret := node.joinResults node.joinResults = nil diff --git a/dispatcher/alarm_mgr.go b/dispatcher/alarm_mgr.go index f512488c..62634764 100644 --- a/dispatcher/alarm_mgr.go +++ b/dispatcher/alarm_mgr.go @@ -89,7 +89,7 @@ func newAlarmMgr() *alarmMgr { } func (am *alarmMgr) SetNotified(id NodeId) { - am.SetTimestamp(id, Ever) + am.SetTimestamp(id, ever) } func (am *alarmMgr) AddNode(nodeid NodeId) { @@ -98,7 +98,7 @@ func (am *alarmMgr) AddNode(nodeid NodeId) { e = &alarmEvent{ NodeId: nodeid, - Timestamp: Ever, + Timestamp: ever, } heap.Push(&am.q, e) am.events[nodeid] = e @@ -131,7 +131,7 @@ func (am *alarmMgr) NextAlarm() *alarmEvent { func (am *alarmMgr) NextTimestamp() uint64 { if len(am.q) == 0 { - return Ever + return ever } return am.q[0].Timestamp diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 8821c377..2d8de0a2 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -24,6 +24,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// Package dispatcher implements the virtual time event dispatcher. package dispatcher import ( @@ -50,12 +51,13 @@ import ( ) const ( - Ever uint64 = math.MaxUint64 / 2 + // MaxSimulateSpeed is the max simulating time + MaxSimulateSpeed = 1000000 ) const ( - ProcessEventTimeErrorUs = 0 - MaxSimulateSpeed = 1000000 + ever uint64 = math.MaxUint64 / 2 + processEventTimeErrorUs uint64 = 0 ) type pcapFrameItem struct { @@ -63,18 +65,23 @@ type pcapFrameItem struct { Data []byte } +// Config represents a Dispatcher config. type Config struct { Speed float64 } +// DefaultConfig returns the default Dispatcher config. func DefaultConfig() *Config { return &Config{ Speed: 1, } } +// CallbackHandler defines the callback interface of the Dispatcher. type CallbackHandler interface { + // OnNodeFail notifies of a failed node. OnNodeFail(nodeid NodeId) + // OnNodeRecover notifies of a recovered node. OnNodeRecover(nodeid NodeId) } @@ -83,6 +90,7 @@ type goDuration struct { done chan struct{} } +// Dispatcher receives events from nodes and dispatches events according to their timestamps. type Dispatcher struct { ctx *progctx.ProgCtx cfg Config @@ -90,7 +98,7 @@ type Dispatcher struct { udpln *net.UDPConn eventChan chan *event waitGroup sync.WaitGroup - CurTime uint64 + CurTime uint64 // The current time. pauseTime uint64 alarmMgr *alarmMgr sendQueue *sendQueue @@ -109,22 +117,22 @@ type Dispatcher struct { goDurationChan chan goDuration globalPacketLossRatio float64 + // Counters records the dispatcher runtime counts. Counters struct { - // Event counters - AlarmEvents uint64 - RadioEvents uint64 - StatusPushEvents uint64 - // Packet dispatching counters - DispatchByExtAddrSucc uint64 - DispatchByExtAddrFail uint64 - DispatchByShortAddrSucc uint64 - DispatchByShortAddrFail uint64 - DispatchAllInRange uint64 + AlarmEvents uint64 // Alarm event count + RadioEvents uint64 // Radio event count + StatusPushEvents uint64 // Status push event count + DispatchByExtAddrSucc uint64 // Packet count dispatched by Extended Address successfully + DispatchByExtAddrFail uint64 // Packet count dispatched by Extended Address unsuccessfully + DispatchByShortAddrSucc uint64 // Packet count dispatched by Short Address successfully + DispatchByShortAddrFail uint64 // Packet count dispatched by Short Address unsuccessfully + DispatchAllInRange uint64 // Packet count dispatched to all nodes in range } watchingNodes map[NodeId]struct{} stopped bool } +// NewDispatcher creates a new Dispatcher. func NewDispatcher(ctx *progctx.ProgCtx, cfg *Config, cbHandler CallbackHandler) *Dispatcher { udpAddr, err := net.ResolveUDPAddr("udp4", "127.0.0.1:9000") simplelogger.FatalIfError(err, err) @@ -172,6 +180,7 @@ func NewDispatcher(ctx *progctx.ProgCtx, cfg *Config, cbHandler CallbackHandler) return d } +// Stop stops the Dispatcher. func (d *Dispatcher) Stop() { if d.stopped { return @@ -182,10 +191,12 @@ func (d *Dispatcher) Stop() { d.waitGroup.Wait() } +// Nodes returns all nodes of the Dispatcher. func (d *Dispatcher) Nodes() map[NodeId]*Node { return d.nodes } +// Go continues the dispatcher for a given duration. func (d *Dispatcher) Go(duration time.Duration) <-chan struct{} { done := make(chan struct{}) d.goDurationChan <- goDuration{ @@ -195,6 +206,7 @@ func (d *Dispatcher) Go(duration time.Duration) <-chan struct{} { return done } +// Run runs the Dispatcher until exit. func (d *Dispatcher) Run() { d.ctx.WaitAdd("dispatcher", 1) defer d.ctx.WaitDone("dispatcher") @@ -226,8 +238,8 @@ loop: simplelogger.AssertTrue(d.CurTime == d.pauseTime) oldPauseTime := d.pauseTime d.pauseTime += uint64(duration.duration / time.Microsecond) - if d.pauseTime > Ever || d.pauseTime < oldPauseTime { - d.pauseTime = Ever + if d.pauseTime > ever || d.pauseTime < oldPauseTime { + d.pauseTime = ever } simplelogger.AssertTrue(d.CurTime <= d.pauseTime) @@ -292,7 +304,7 @@ func (d *Dispatcher) handleRecvEvent(evt *event) { delay := evt.Delay var evtTime uint64 if delay >= 2147483647 { - evtTime = Ever + evtTime = ever } else { evtTime = d.CurTime + evt.Delay } @@ -394,9 +406,9 @@ func (d *Dispatcher) processNextEvent() bool { simplelogger.AssertTrue(nextAlarmTime >= d.CurTime && nextSendtime >= d.CurTime) var procUntilTime uint64 if nextAlarmTime <= nextSendtime { - procUntilTime = nextAlarmTime + ProcessEventTimeErrorUs + procUntilTime = nextAlarmTime + processEventTimeErrorUs } else { - procUntilTime = nextSendtime + ProcessEventTimeErrorUs + procUntilTime = nextSendtime + processEventTimeErrorUs } if procUntilTime > d.pauseTime { @@ -688,12 +700,14 @@ func (d *Dispatcher) pcapFrameWriter() { } } +// SetVisualizer sets the Visualizer. func (d *Dispatcher) SetVisualizer(vis visualize.Visualizer) { simplelogger.AssertNotNil(vis) d.vis = vis d.vis.SetSpeed(d.speed) } +// GetVisualizer gets the current Visualizer. func (d *Dispatcher) GetVisualizer() visualize.Visualizer { return d.vis } @@ -780,6 +794,7 @@ func (d *Dispatcher) handleStatusPush(srcid NodeId, data string) { } } +// AddNode adds a new node to the Dispatcher. func (d *Dispatcher) AddNode(nodeid NodeId, extaddr uint64, x, y int, radioRange int, mode NodeMode) { simplelogger.AssertNil(d.nodes[nodeid]) simplelogger.Infof("dispatcher add node %d", nodeid) @@ -829,6 +844,7 @@ func (d *Dispatcher) advanceTime(ts uint64) { } } +// PostAsync posts an asynchronous task to be executed in the Dispatcher's goroutine. func (d *Dispatcher) PostAsync(trivial bool, task func()) { if trivial { select { @@ -862,10 +878,12 @@ loop: } } +// WatchNode sets the node as watched. func (d *Dispatcher) WatchNode(nodeid NodeId) { d.watchingNodes[nodeid] = struct{}{} } +// UnwatchNode sets the node as unwatched. func (d *Dispatcher) UnwatchNode(nodeid NodeId) { delete(d.watchingNodes, nodeid) } @@ -875,14 +893,17 @@ func (d *Dispatcher) isWatching(nodeid NodeId) bool { return ok } +// GetAliveCount gets the number of alive nodes. func (d *Dispatcher) GetAliveCount() int { return len(d.aliveNodes) } +// GetNode gets the node of a given ID. func (d *Dispatcher) GetNode(id NodeId) *Node { return d.nodes[id] } +// GetFailedCount gets the number of failed nodes. func (d *Dispatcher) GetFailedCount() int { failCount := 0 for _, dn := range d.nodes { @@ -893,6 +914,7 @@ func (d *Dispatcher) GetFailedCount() int { return failCount } +// SetNodePos sets the node position. func (d *Dispatcher) SetNodePos(id NodeId, x, y int) { node := d.nodes[id] simplelogger.AssertNotNil(node) @@ -901,6 +923,7 @@ func (d *Dispatcher) SetNodePos(id NodeId, x, y int) { d.vis.SetNodePos(id, x, y) } +// DeleteNode deletes the node. func (d *Dispatcher) DeleteNode(id NodeId) { node := d.nodes[id] simplelogger.AssertNotNil(node) @@ -919,6 +942,7 @@ func (d *Dispatcher) DeleteNode(id NodeId) { d.vis.DeleteNode(id) } +// SetNodeFailed sets the node as failed or recovered. func (d *Dispatcher) SetNodeFailed(id NodeId, fail bool) { node := d.nodes[id] simplelogger.AssertNotNil(node) @@ -933,6 +957,7 @@ func (d *Dispatcher) SetNodeFailed(id NodeId, fail bool) { } } +// SetSpeed sets the simulating speed. func (d *Dispatcher) SetSpeed(f float64) { ns := d.normalizeSpeed(f) if ns == d.speed { @@ -955,14 +980,17 @@ func (d *Dispatcher) normalizeSpeed(f float64) float64 { return f } +// GetSpeed gets the simulating speed. func (d *Dispatcher) GetSpeed() float64 { return d.speed } +// GetGlobalMessageDropRatio gets the Global Message Drop Ratio. func (d *Dispatcher) GetGlobalMessageDropRatio() float64 { return d.globalPacketLossRatio } +// SetGlobalPacketLossRatio sets the Global Message Drop Ratio func (d *Dispatcher) SetGlobalPacketLossRatio(plr float64) { if plr > 1 { plr = 1 diff --git a/dispatcher/FailureCtrl.go b/dispatcher/failure_ctrl.go similarity index 82% rename from dispatcher/FailureCtrl.go rename to dispatcher/failure_ctrl.go index cef2f8a3..bd7aa47a 100644 --- a/dispatcher/FailureCtrl.go +++ b/dispatcher/failure_ctrl.go @@ -32,34 +32,37 @@ import ( "github.com/simonlingoogle/go-simplelogger" ) +// FailTime represents a node fail time configuration. type FailTime struct { - FailDuration uint64 - FailInterval uint64 + FailDuration uint64 // Expected fail duration (us) + FailInterval uint64 // Expected fail interval (us) } +// CanFail returns if the node can ever fail using this configuration. func (ft FailTime) CanFail() bool { return ft.FailDuration > 0 } var ( + // NonFailTime is a fail time configuration that never fail. NonFailTime = FailTime{0, 0} ) -type FailureCtrl struct { +type failureCtrl struct { owner *Node failTime FailTime recoverTs uint64 elapsedTimeAccum uint64 } -func newFailureCtrl(owner *Node, failTime FailTime) *FailureCtrl { - return &FailureCtrl{ +func newFailureCtrl(owner *Node, failTime FailTime) *failureCtrl { + return &failureCtrl{ owner: owner, failTime: failTime, } } -func (fc *FailureCtrl) SetFailTime(failTime FailTime) { +func (fc *failureCtrl) SetFailTime(failTime FailTime) { fc.failTime = failTime if !failTime.CanFail() && fc.owner.IsFailed() { fc.recoverTs = 0 @@ -67,7 +70,7 @@ func (fc *FailureCtrl) SetFailTime(failTime FailTime) { } } -func (fc *FailureCtrl) OnTimeAdvanced(oldTime uint64) { +func (fc *failureCtrl) OnTimeAdvanced(oldTime uint64) { if !fc.failTime.CanFail() { return } @@ -91,7 +94,7 @@ func (fc *FailureCtrl) OnTimeAdvanced(oldTime uint64) { } } -func (fc *FailureCtrl) tryRecoverNode() { +func (fc *failureCtrl) tryRecoverNode() { simplelogger.AssertTrue(fc.owner.IsFailed()) if fc.owner.CurTime >= fc.recoverTs { fc.recoverTs = 0 @@ -99,7 +102,7 @@ func (fc *FailureCtrl) tryRecoverNode() { } } -func (fc *FailureCtrl) failNode() { +func (fc *failureCtrl) failNode() { simplelogger.AssertTrue(!fc.owner.IsFailed()) fc.recoverTs = fc.owner.CurTime + fc.failTime.FailDuration diff --git a/dispatcher/FailureCtrl_test.go b/dispatcher/failure_ctrl_test.go similarity index 100% rename from dispatcher/FailureCtrl_test.go rename to dispatcher/failure_ctrl_test.go diff --git a/dispatcher/send_queue.go b/dispatcher/send_queue.go index bbfc1f2d..22180484 100644 --- a/dispatcher/send_queue.go +++ b/dispatcher/send_queue.go @@ -68,7 +68,7 @@ func (sq sendQueue) NextTimestamp() uint64 { if len(sq.q) > 0 { return sq.q[0].Timestamp } else { - return Ever + return ever } } diff --git a/dispatcher/send_queue_test.go b/dispatcher/send_queue_test.go index 3d1c54f5..49aded73 100644 --- a/dispatcher/send_queue_test.go +++ b/dispatcher/send_queue_test.go @@ -51,7 +51,7 @@ func TestSendQueue_Len(t *testing.T) { func TestSendQueue_NextTimestamp(t *testing.T) { q := newSendQueue() - assert.Equal(t, Ever, q.NextTimestamp()) + assert.Equal(t, ever, q.NextTimestamp()) q.Add(2, 2, nil) assert.Equal(t, uint64(2), q.NextTimestamp()) q.Add(1, 1, nil) diff --git a/dispatcher/types.go b/dispatcher/types.go deleted file mode 100644 index 94264732..00000000 --- a/dispatcher/types.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2020, The OTNS Authors. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holder nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -package dispatcher - -type OtJoinerState int - -const ( - OtJoinerStateIdle OtJoinerState = 0 - OtJoinerStateDiscover OtJoinerState = 1 - OtJoinerStateConnect OtJoinerState = 2 - OtJoinerStateConnected OtJoinerState = 3 - OtJoinerStateEntrust OtJoinerState = 4 - OtJoinerStateJoined OtJoinerState = 5 -) diff --git a/types/types.go b/types/types.go index f1b82e37..21f88456 100644 --- a/types/types.go +++ b/types/types.go @@ -63,3 +63,15 @@ const ( OtDeviceRoleRouter OtDeviceRole = 3 // The Thread Router role. OtDeviceRoleLeader OtDeviceRole = 4 // The Thread Leader role. ) + +// OtJoinerState represents a joiner state. +type OtJoinerState int + +const ( + OtJoinerStateIdle OtJoinerState = 0 // Joiner is idle + OtJoinerStateDiscover OtJoinerState = 1 // Joiner is discovering + OtJoinerStateConnect OtJoinerState = 2 // Joiner is connecting + OtJoinerStateConnected OtJoinerState = 3 // Joiner is connected + OtJoinerStateEntrust OtJoinerState = 4 // Joiner is entrusted + OtJoinerStateJoined OtJoinerState = 5 // Joiner is joined +)