sdbus++: complete server support for enumerations

Perform final type conversion using 'convert*' functions to change
between dbus strings and C++ enumerations for methods, properties,
and signals.

Change-Id: I22e8fd424eeecac176c64fcc3e7a5d3caf05804a
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/tools/sdbusplus/property.py b/tools/sdbusplus/property.py
index 0297e79..fed9782 100644
--- a/tools/sdbusplus/property.py
+++ b/tools/sdbusplus/property.py
@@ -44,6 +44,19 @@
             return "std::string"
         return self.cppTypeName
 
+    def enum_namespace(self, interface):
+        if not self.is_enum():
+            return ""
+        l = self.cppTypeParam(interface).split("::")[0:-1]
+        if len(l) != 0:
+            return "::".join(l) + "::"
+        return ""
+
+    def enum_name(self, interface):
+        if not self.is_enum():
+            return ""
+        return self.cppTypeParam(interface).split("::")[-1]
+
     def parse_cpp_type(self, typeName):
         if not typeName:
             return None
diff --git a/tools/sdbusplus/templates/interface.mako.server.cpp b/tools/sdbusplus/templates/interface.mako.server.cpp
index efcc7c0..faaed4d 100644
--- a/tools/sdbusplus/templates/interface.mako.server.cpp
+++ b/tools/sdbusplus/templates/interface.mako.server.cpp
@@ -47,10 +47,12 @@
         const char* property, sd_bus_message* reply, void* context,
         sd_bus_error* error)
 {
+    using sdbusplus::server::binding::details::convertForMessage;
+
     auto m = message::message(sd_bus_message_ref(reply));
 
     auto o = static_cast<${classname}*>(context);
-    m.append(o->${p.camelCase}());
+    m.append(convertForMessage(o->${p.camelCase}()));
 
     return true;
 }
@@ -78,7 +80,12 @@
 
     ${p.cppTypeMessage(interface.name)} v{};
     m.read(v);
+    % if p.is_enum():
+    o->${p.camelCase}(${p.enum_namespace(interface.name)}\
+convert${p.enum_name(interface.name)}FromString(v));
+    % else:
     o->${p.camelCase}(v);
+    % endif
 
     return true;
 }
diff --git a/tools/sdbusplus/templates/method.mako.prototype.hpp b/tools/sdbusplus/templates/method.mako.prototype.hpp
index 96e7390..7d295eb 100644
--- a/tools/sdbusplus/templates/method.mako.prototype.hpp
+++ b/tools/sdbusplus/templates/method.mako.prototype.hpp
@@ -13,18 +13,20 @@
         return ",\n            ".\
             join([ parameter(p, defaultValue) for p in method.parameters ])
 
-    def parameters_as_local():
-        return "{};\n    ".join([ parameter(p) for p in method.parameters ])
+    def parameters_as_local(as_param=True):
+        return "{};\n    ".join([ parameter(p,as_param=as_param)
+                for p in method.parameters ])
 
-    def parameters_as_list():
-        return ", ".join([ p.camelCase for p in method.parameters ])
+    def parameters_as_list(transform=lambda p: p.camelCase):
+        return ", ".join([ transform(p) for p in method.parameters ])
 
     def parameters_types_as_list():
         return ", ".join([ p.cppTypeMessage(interface.name)
                 for p in method.parameters ])
 
-    def parameter(p, defaultValue=False):
-        r = "%s %s" % (p.cppTypeParam(interface.name), p.camelCase)
+    def parameter(p, defaultValue=False, as_param=True):
+        r = "%s %s" % (p.cppTypeParam(interface.name) if as_param else \
+                p.cppTypeMessage(interface.name), p.camelCase)
         if defaultValue:
             r += default_value(p)
         return r
@@ -33,8 +35,9 @@
         return ", ".join([ (r.cppTypeParam(interface.name) if as_param else
                 r.cppTypeMessage(interface.name)) for r in method.returns ])
 
-    def returns_as_tuple_index(tuple):
-        return ", ".join([ "std::move(std::get<%d>(%s))" % (i,tuple) \
+    def returns_as_tuple_index(tuple, pre="", post=""):
+        return ", ".join([ "%sstd::move(std::get<%d>(%s))%s" %\
+                (pre,i,tuple,post) \
                 for i in range(len(method.returns))])
 
     def default_value(p):
@@ -61,6 +64,15 @@
         l.pop() # Remove "Error"
         return '/'.join(l) + '/error.hpp';
 
+    def enum_convert(p):
+        if not p.is_enum():
+            return p.camelCase
+        else:
+            return "%sconvert%sFromString(%s)" % \
+                (p.enum_namespace(interface.name),
+                 p.enum_name(interface.name),
+                 p.camelCase)
+
 %>
 ###
 ### Emit 'header'
@@ -109,6 +121,8 @@
 int ${interface_name()}::_callback_${ method.CamelCase }(
         sd_bus_message* msg, void* context, sd_bus_error* error)
 {
+    using sdbusplus::server::binding::details::convertForMessage;
+
     try
     {
         ### Need to add a ref to msg since we attached it to an
@@ -116,7 +130,7 @@
         auto m = message::message(sd_bus_message_ref(msg));
 
     % if len(method.parameters) != 0:
-        ${parameters_as_local()}{};
+        ${parameters_as_local(as_param=False)}{};
 
         m.read(${parameters_as_list()});
     % endif
@@ -125,15 +139,16 @@
     % if len(method.returns) != 0:
         auto r = \
     %endif
-        o->${ method.camelCase }(${parameters_as_list()});
+        o->${ method.camelCase }(${parameters_as_list(transform=enum_convert)});
 
         auto reply = m.new_method_return();
     % if len(method.returns) == 0:
         // No data to append on reply.
     % elif len(method.returns) == 1:
-        reply.append(std::move(r));
+        reply.append(convertForMessage(std::move(r)));
     % else:
-        reply.append(${returns_as_tuple_index("r")});
+        reply.append(\
+${returns_as_tuple_index("r",pre="convertForMessage(",post=")")});
     % endif
 
         reply.method_return();
diff --git a/tools/sdbusplus/templates/signal.mako.prototype.hpp b/tools/sdbusplus/templates/signal.mako.prototype.hpp
index eb5ffca..e547310 100644
--- a/tools/sdbusplus/templates/signal.mako.prototype.hpp
+++ b/tools/sdbusplus/templates/signal.mako.prototype.hpp
@@ -9,8 +9,9 @@
             r += default_value(p)
         return r
 
-    def parameters_as_list():
-        return ", ".join([ p.camelCase for p in signal.properties ])
+    def parameters_as_list(pre="", post=""):
+        return ", ".join([ "%s%s%s" % (pre, p.camelCase, post)
+                for p in signal.properties ])
 
     def parameters_types_as_list():
         return ", ".join([ p.cppTypeMessage(interface.name)
@@ -55,10 +56,12 @@
 void ${interface_name()}::${ signal.camelCase }(
             ${ parameters() })
 {
+    using sdbusplus::server::binding::details::convertForMessage;
+
     auto& i = _${"_".join(interface.name.split('.'))}_interface;
     auto m = i.new_signal("${ signal.name }");
 
-    m.append(${ parameters_as_list() });
+    m.append(${ parameters_as_list(pre="convertForMessage(", post=")") });
     m.signal_send();
 }