sdbus++: support 'readonly' flag

The previous documentation of 'const' did not match the
specification at a D-Bus level nor the implementation in sdbus++.
Correct the documentation for 'const' and add a new 'readonly' flag
which enables the previously documented behavior for 'const.

This was reported by a user outside of the openbmc project which had
already been using the 'readonly' flag in their YAML to identify this
condition.  Previously, sdbus++ silently ignored flags it didn't
explicitly support but as of 20255a5fce55a0743dc3d307d1168f18ed553751
this turned into an error.

There are cases of interfaces in 'phosphor-dbus-interfaces' currently
using 'const' where they likely desire a 'readonly' instead.  We are
not changing the behavior of 'const' with this commit, so there would
be no regressions induced by this code change.

Resolves openbmc/sdbusplus#48.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I690cb424f5fd00da190343a345ae57ccae393041
diff --git a/docs/interface.md b/docs/interface.md
index 01e7f8a..13a5f7a 100644
--- a/docs/interface.md
+++ b/docs/interface.md
@@ -157,16 +157,25 @@
 default value of the property. See the `Methods` section above for more
 information on errors.
 
-The supported values for `flags` are `deprecated`, `hidden`, `unprivileged`,
-`const`, `emits_change`, `emits_invalidation`, `explicit` , which corresponds to
-`SD_BUS_VTABLE_DEPRECATED`, `SD_BUS_VTABLE_HIDDEN`,
-`SD_BUS_VTABLE_UNPRIVILEGED`, `SD_BUS_VTABLE_PROPERTY_CONST`,
-`SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE`,
-`SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION` and
-`SD_BUS_VTABLE_PROPERTY_EXPLICIT`, respectively.  The flag `const ` makes the
-property read-only via D-Bus but still writable by the app implementing
-it. Moreover, if no flags have been specified for a property, `emits_change`
-will be added by default.
+The supported values for `flags` are and their equivalent sd-bus flag setting:
+
+* `deprecated` - SD_BUS_VTABLE_DEPRECATED
+* `hidden` - SD_BUS_VTABLE_HIDDEN
+* `unprivileged` - SD_BUS_VTABLE_UNPRIVILEGED
+* `const` - SD_BUS_VTABLE_PROPERTY_CONST
+* `emits_change` - SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
+* `emits_invalidation` - SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
+* `explicit` - SD_BUS_VTABLE_PROPERTY_EXPLICIT
+* `readonly` - (N/A)
+
+If no flag is given, a property will default to `emits_change`.
+
+Both `const` and `readonly` prevent D-Bus clients from being able to write
+to a property.  `const` is a D-Bus indication that the property can never
+change, while `readonly` properties can be changed by the D-Bus server itself.
+As examples, the `Version` property on a software object might be appropriate
+to be `const` and the `Value` property on a sensor object would likely be
+`readonly`.
 
 Example:
 ```
diff --git a/test/server/Test.interface.yaml b/test/server/Test.interface.yaml
index d015c99..7daea7d 100644
--- a/test/server/Test.interface.yaml
+++ b/test/server/Test.interface.yaml
@@ -3,3 +3,12 @@
 properties:
     - name: SomeValue
       type: int64
+    - name: ReadonlyValue
+      type: int64
+      flags:
+          - readonly
+          - emits_change
+    - name: ConstValue
+      type: int64
+      flags:
+          - const
diff --git a/tools/sdbusplus/property.py b/tools/sdbusplus/property.py
index 75fcff9..e412b60 100644
--- a/tools/sdbusplus/property.py
+++ b/tools/sdbusplus/property.py
@@ -195,18 +195,21 @@
     def or_cpp_flags(self, flags):
         """Return the corresponding ORed cpp flags."""
         flags_dict = {
-            "deprecated": "vtable::common_::deprecated",
-            "hidden": "vtable::common_::hidden",
-            "unprivileged": "vtable::common_::unprivileged",
             "const": "vtable::property_::const_",
+            "deprecated": "vtable::common_::deprecated",
             "emits_change": "vtable::property_::emits_change",
             "emits_invalidation": "vtable::property_::emits_invalidation",
-            "explicit": "vtable::property_::explicit_"}
+            "explicit": "vtable::property_::explicit_",
+            "hidden": "vtable::common_::hidden",
+            "readonly": False,
+            "unprivileged": "vtable::common_::unprivileged",
+            }
 
         cpp_flags = []
         for flag in flags:
             try:
-                cpp_flags.append(flags_dict[flag])
+                if flags_dict[flag]:
+                    cpp_flags.append(flags_dict[flag])
             except KeyError:
                 raise ValueError("Invalid flag \"{}\"".format(flag))
 
diff --git a/tools/sdbusplus/templates/interface.server.cpp.mako b/tools/sdbusplus/templates/interface.server.cpp.mako
index 9acfa2f..c936151 100644
--- a/tools/sdbusplus/templates/interface.server.cpp.mako
+++ b/tools/sdbusplus/templates/interface.server.cpp.mako
@@ -148,7 +148,7 @@
                      details::${classname}::_property_${p.name}
                         .data(),
                      _callback_get_${p.name},
-        % if 'const' not in p.flags:
+        % if 'const' not in p.flags and 'readonly' not in p.flags:
                      _callback_set_${p.name},
         % endif
         % if not p.cpp_flags: