From e1357356e6fadfa876ef26ed4c44808d4e4e963e Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Thu, 27 Jul 2023 11:01:38 -0700 Subject: [PATCH] Made changes to address issue #14. * I now calculate output channels that are unused in the transitions and ensure that these are subscribed to and that they lead to off_script. * I now use the fully qualified name for a channel including the 'in' and 'out' in the gen.xml file. In the internal data structures it isn't clear when this is a 'channel' or not, esp. intermediate representation. * This now means that the b2x tests pass for the battery monitor. --- examples/bmon/gen.xml | 6 +-- internal/gen/config/cpp/context.go | 13 +++++++ internal/gen/config/cpp/cpp.go | 39 ++++++++++++++++++- .../gen/cpp/embed/templates/base/stm.cpp.tmpl | 11 ++++++ .../gen/cpp/embed/templates/ros/main.cpp.tmpl | 3 ++ internal/gen/cpp/func.go | 27 +++++++++++++ 6 files changed, 94 insertions(+), 5 deletions(-) diff --git a/examples/bmon/gen.xml b/examples/bmon/gen.xml index ba3c360..1cc37f4 100644 --- a/examples/bmon/gen.xml +++ b/examples/bmon/gen.xml @@ -4,7 +4,7 @@ - + @@ -23,8 +23,8 @@ - - + + diff --git a/internal/gen/config/cpp/context.go b/internal/gen/config/cpp/context.go index ad95263..47a468a 100644 --- a/internal/gen/config/cpp/context.go +++ b/internal/gen/config/cpp/context.go @@ -3,6 +3,7 @@ package cpp import ( "github.com/UoY-RoboStar/rtcg/internal/stm" "github.com/UoY-RoboStar/rtcg/internal/testlang/rstype" + "github.com/UoY-RoboStar/rtcg/internal/testlang/channel" ) // Context contains any context derived from the C++ generator config. @@ -10,9 +11,11 @@ import ( // This is common to multiple different generators that consider C++ config. type Context struct { Includes []Include // Includes contains the user-configured includes. + Channels []channel.Channel // All channels ChannelTypes map[string]ChannelType // ChannelTypes contains the calculated channel types. HasConversion bool // HasConversion is true if there is a convert.cpp file. ChannelTopics map[string]string // Mapping from channel name to topic. + // ChannelIO map[string] // Indicates whether a channel is input or output. } // Process processes a config into a Context. @@ -20,9 +23,11 @@ type Context struct { func (c *Config) Process(types stm.TypeMap) Context { ctx := Context{ Includes: c.Includes, + Channels: c.getChannels(), ChannelTypes: make(map[string]ChannelType, len(types)), ChannelTopics: c.ChannelTopicMap(), HasConversion: false, +// ChannelIO: c.ChannelIO(), } overrides := c.ChannelMap() @@ -50,3 +55,11 @@ type ChannelType struct { func (t ChannelType) HasOverride() bool { return t.Override != "" } + +// // ChannelIO defines whether a channel is input or output +// type ChannelIO uint8 + +// const ( +// input ChannelIO = iota +// utput ChannelIO = iota +// ) \ No newline at end of file diff --git a/internal/gen/config/cpp/cpp.go b/internal/gen/config/cpp/cpp.go index 0fb5ae4..ec4f541 100644 --- a/internal/gen/config/cpp/cpp.go +++ b/internal/gen/config/cpp/cpp.go @@ -4,6 +4,7 @@ package cpp import ( "github.com/UoY-RoboStar/rtcg/internal/gen/config/catkin" "github.com/UoY-RoboStar/rtcg/internal/gen/config/makefile" + "github.com/UoY-RoboStar/rtcg/internal/testlang/channel" ) // Config contains configuration for a C++ generator. @@ -41,12 +42,35 @@ func WithChannel(name, ty string) Option { } } +func (c *Config) getChannels() []channel.Channel { + + //carray := make([]channel.Channel, len(c.Channels)) + var carray []channel.Channel + + for _, chi := range c.Channels { + ach := new(channel.Channel) + err := ach.UnmarshalText([]byte(chi.Name)) + if (err == nil) { + carray = append(carray, *ach) + } + } + + return carray +} + // ChannelMap gets the Channels field of this Config as a map from channel names to type overrides. func (c *Config) ChannelMap() map[string]string { cmap := make(map[string]string, len(c.Channels)) for _, over := range c.Channels { - cmap[over.Name] = over.Type + + // Create object and parse + chp := new(channel.Channel) + err := chp.UnmarshalText([]byte(over.Name)) + + if err == nil { + cmap[chp.Name] = over.Type + } } return cmap @@ -57,12 +81,23 @@ func (c *Config) ChannelTopicMap() map[string]string { cmap := make(map[string]string, len(c.Channels)) for _, over := range c.Channels { - cmap[over.Name] = over.Topic + + // Create object and parse + chp := new(channel.Channel) + err := chp.UnmarshalText([]byte(over.Name)) + + if err == nil { + cmap[chp.Name] = over.Topic + } else { + cmap[over.Name] = over.Topic + } } return cmap } +// ChannelIO gets the Channel types + // Include captures a custom include header. type Include struct { diff --git a/internal/gen/cpp/embed/templates/base/stm.cpp.tmpl b/internal/gen/cpp/embed/templates/base/stm.cpp.tmpl index 3cbedd5..c152a77 100644 --- a/internal/gen/cpp/embed/templates/base/stm.cpp.tmpl +++ b/internal/gen/cpp/embed/templates/base/stm.cpp.tmpl @@ -28,6 +28,9 @@ public: {{- range .Transitions.Out }} void {{ cppCallbackName .Channel.Name }}(const {{ cppChannelMsgType .Channel.Name }} msg); {{- end }} +{{- range cppOtherOutChannels .Transitions.Out .Channels }} + void {{ cppCallbackName .Name }}(const {{ cppChannelMsgType .Name }} msg); +{{- end }} private: Verdict verdict_; State state_ = {{ (index .Stm.States 0).ID | cppStateEnum }}; @@ -131,6 +134,14 @@ void StateMachine::{{ cppCallbackName .Channel.Name }}(const {{ cppChannelMsgTyp } {{- end }} +{{- range cppOtherOutChannels .Transitions.Out .Channels }} + +void StateMachine::{{ cppCallbackName .Name }}(const {{ cppChannelMsgType .Name }} msg) +{ + ROS_INFO_STREAM("Unexpected message for {{ . }}." << std::endl); + end(rtcg::Status::OFF_SCRIPT); +} +{{- end }} // // State machine entry functions diff --git a/internal/gen/cpp/embed/templates/ros/main.cpp.tmpl b/internal/gen/cpp/embed/templates/ros/main.cpp.tmpl index fb6bae6..edba1bb 100644 --- a/internal/gen/cpp/embed/templates/ros/main.cpp.tmpl +++ b/internal/gen/cpp/embed/templates/ros/main.cpp.tmpl @@ -64,6 +64,9 @@ const int INPUT_DELAY_SEC = 3; {{ range .Transitions.Out }} auto {{ template "subscriber_name" . }} = nh.subscribe("{{ cppChannelTopicName $.ChannelTopics .Channel.Name }}", 10, &StateMachine::{{ cppCallbackName .Channel.Name }}, &stm); {{- end }} +{{- range cppOtherOutChannels .Transitions.Out .Channels }} + auto {{ toLowerUnderscored .Name }}_sub = nh.subscribe("{{ cppChannelTopicName $.ChannelTopics .Name }}", 10, &StateMachine::{{ cppCallbackName .Name }}, &stm); +{{- end }} // Timers auto timeout_timer = nh.createTimer(ros::Duration(TIMEOUT_SEC), &StateMachine::timeoutCallback, &stm); diff --git a/internal/gen/cpp/func.go b/internal/gen/cpp/func.go index ffc2959..9470915 100644 --- a/internal/gen/cpp/func.go +++ b/internal/gen/cpp/func.go @@ -5,10 +5,12 @@ import ( "strings" "text/template" + "github.com/UoY-RoboStar/rtcg/internal/stm/transition" "github.com/UoY-RoboStar/rtcg/internal/strmanip" "github.com/UoY-RoboStar/rtcg/internal/testlang" "github.com/UoY-RoboStar/rtcg/internal/testlang/rstype" "github.com/UoY-RoboStar/rtcg/internal/testlang/value" + "github.com/UoY-RoboStar/rtcg/internal/testlang/channel" ) // Funcs gets the C++ function map. @@ -18,6 +20,7 @@ func Funcs() template.FuncMap { "cppChannelMsgType": ChannelMsgType, "cppChannelValueType": ChannelValueType, "cppChannelTopicName": ChannelTopicName, + "cppOtherOutChannels": OtherOutChannels, "cppConvertFrom": ConvertFrom, "cppConvertTo": ConvertTo, "cppEnumField": EnumField, @@ -136,3 +139,27 @@ const ( testEnumName = "Test" // testEnumName is the name in the C++ code for the test enum. outcomeEnumName = "Outcome" // outcomeEnumName is the name in the C++ code for the outcome enum. ) + +func OtherOutChannels(tagg []transition.AggregateSet, channels []channel.Channel) []channel.Channel { + + var carray []channel.Channel + + for _, c := range channels { + + if (c.IsOut()) { + var inside = false + + for _, t := range tagg { + if t.Channel == c { + inside = true + } + } + + if !inside { + carray = append(carray, c) + } + } + } + + return carray +} \ No newline at end of file