summaryrefslogtreecommitdiffstats
path: root/control
diff options
context:
space:
mode:
authorMatthew Barth <msbarth@us.ibm.com>2019-02-14 14:24:46 -0600
committerMatthew Barth <msbarth@us.ibm.com>2019-02-14 14:44:17 -0600
commit7883f58ab2edf8d9f8882463a68f50bef6f49013 (patch)
treea1422e76d2e30785b187ebb3bf5d9d4764a98ca4 /control
parent1b3e960219c8d7d4add71c862cd8756104615251 (diff)
downloadphosphor-fan-presence-7883f58ab2edf8d9f8882463a68f50bef6f49013.tar.gz
phosphor-fan-presence-7883f58ab2edf8d9f8882463a68f50bef6f49013.zip
Parse and generate zone interfaces
Interfaces can optionally be defined on each zone to include setting properties under those interfaces when fan control initializes the zone. Setting the property values here allows them to be initialized to a default value or set of values. Change-Id: I75d51a05caa9e5662a0608d285fd388acc8593e2 Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
Diffstat (limited to 'control')
-rwxr-xr-xcontrol/gen-fan-zone-defs.py155
-rw-r--r--control/templates/fan_zone_defs.mako.cpp32
2 files changed, 187 insertions, 0 deletions
diff --git a/control/gen-fan-zone-defs.py b/control/gen-fan-zone-defs.py
index fdbdab8..7db3d95 100755
--- a/control/gen-fan-zone-defs.py
+++ b/control/gen-fan-zone-defs.py
@@ -13,6 +13,114 @@ from mako.template import Template
from mako.lookup import TemplateLookup
+def parse_cpp_type(typeName):
+ """
+ Take a list of dbus types from YAML and convert it to a recursive cpp
+ formed data structure. Each entry of the original list gets converted
+ into a tuple consisting of the type name and a list with the params
+ for this type,
+ e.g.
+ ['dict', ['string', 'dict', ['string', 'int64']]]
+ is converted to
+ [('dict', [('string', []), ('dict', [('string', []),
+ ('int64', [])]]]
+ """
+
+ if not typeName:
+ return None
+
+ # Type names are _almost_ valid YAML. Insert a , before each [
+ # and then wrap it in a [ ] and it becomes valid YAML (assuming
+ # the user gave us a valid typename).
+ typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
+ typeTuple = preprocess_yaml_type_array(typeArray).pop(0)
+ return get_cpp_type(typeTuple)
+
+
+def preprocess_yaml_type_array(typeArray):
+ """
+ Flattens an array type into a tuple list that can be used to get the
+ supported cpp type from each element.
+ """
+
+ result = []
+
+ for i in range(len(typeArray)):
+ # Ignore lists because we merge them with the previous element
+ if type(typeArray[i]) is list:
+ continue
+
+ # If there is a next element and it is a list, merge it with the
+ # current element.
+ if i < len(typeArray)-1 and type(typeArray[i+1]) is list:
+ result.append(
+ (typeArray[i],
+ preprocess_yaml_type_array(typeArray[i+1])))
+ else:
+ result.append((typeArray[i], []))
+
+ return result
+
+
+def get_cpp_type(typeTuple):
+ """
+ Take a list of dbus types and perform validity checking, such as:
+ [ variant [ dict [ int32, int32 ], double ] ]
+ This function then converts the type-list into a C++ type string.
+ """
+
+ propertyMap = {
+ 'byte': {'cppName': 'uint8_t', 'params': 0},
+ 'boolean': {'cppName': 'bool', 'params': 0},
+ 'int16': {'cppName': 'int16_t', 'params': 0},
+ 'uint16': {'cppName': 'uint16_t', 'params': 0},
+ 'int32': {'cppName': 'int32_t', 'params': 0},
+ 'uint32': {'cppName': 'uint32_t', 'params': 0},
+ 'int64': {'cppName': 'int64_t', 'params': 0},
+ 'uint64': {'cppName': 'uint64_t', 'params': 0},
+ 'double': {'cppName': 'double', 'params': 0},
+ 'string': {'cppName': 'std::string', 'params': 0},
+ 'array': {'cppName': 'std::vector', 'params': 1},
+ 'dict': {'cppName': 'std::map', 'params': 2}}
+
+ if len(typeTuple) != 2:
+ raise RuntimeError("Invalid typeTuple %s" % typeTuple)
+
+ first = typeTuple[0]
+ entry = propertyMap[first]
+
+ result = entry['cppName']
+
+ # Handle 0-entry parameter lists.
+ if (entry['params'] == 0):
+ if (len(typeTuple[1]) != 0):
+ raise RuntimeError("Invalid typeTuple %s" % typeTuple)
+ else:
+ return result
+
+ # Get the parameter list
+ rest = typeTuple[1]
+
+ # Confirm parameter count matches.
+ if (entry['params'] != -1) and (entry['params'] != len(rest)):
+ raise RuntimeError("Invalid entry count for %s : %s" %
+ (first, rest))
+
+ # Parse each parameter entry, if appropriate, and create C++ template
+ # syntax.
+ result += '<'
+ if entry.get('noparse'):
+ # Do not parse the parameter list, just use the first element
+ # of each tuple and ignore possible parameters
+ result += ", ".join([e[0] for e in rest])
+ else:
+ result += ", ".join(map(lambda e: get_cpp_type(e),
+ rest))
+ result += '>'
+
+ return result
+
+
def convertToMap(listOfDict):
"""
Converts a list of dictionary entries to a std::map initialization list.
@@ -575,6 +683,46 @@ def getFansInZone(zone_num, profiles, fan_data):
return fans
+def getIfacesInZone(zone_ifaces):
+ """
+ Parse given interfaces for a zone for associating a zone with an interface
+ and set any properties listed to defined values upon fan control starting
+ on the zone.
+ """
+
+ ifaces = []
+ for i in zone_ifaces:
+ iface = {}
+ # Interface name not needed yet for fan zones but
+ # may be necessary as more interfaces are extended by the zones
+ iface['name'] = i['name']
+
+ if ('properties' in i) and \
+ (i['properties'] is not None):
+ props = []
+ for p in i['properties']:
+ prop = {}
+ prop['name'] = str(p['name']).lower()
+ prop['type'] = parse_cpp_type(p['type'])
+ vals = []
+ for v in p['values']:
+ val = v['value']
+ if (val is not None):
+ if (isinstance(val, bool)):
+ # Convert True/False to 'true'/'false'
+ val = 'true' if val else 'false'
+ elif (isinstance(val, str)):
+ # Wrap strings with double-quotes
+ val = "\"" + val + "\""
+ vals.append(val)
+ prop['values'] = vals
+ props.append(prop)
+ iface['props'] = props
+ ifaces.append(iface)
+
+ return ifaces
+
+
def getConditionInZoneConditions(zone_condition, zone_conditions_data):
"""
Parses the zone conditions definition YAML files to find the condition
@@ -661,6 +809,11 @@ def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
else:
profiles = z['cooling_profiles']
+ # 'interfaces' is optional (no default)
+ if ('interfaces' in z) and \
+ (z['interfaces'] is not None):
+ ifaces = getIfacesInZone(z['interfaces'])
+
fans = getFansInZone(z['zone'], profiles, fan_data)
events = getEventsInZone(z['zone'], group['zone_conditions'],
events_data)
@@ -668,6 +821,8 @@ def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
if len(fans) == 0:
sys.exit("Didn't find any fans in zone " + str(zone['num']))
+ if (ifaces):
+ zone['ifaces'] = ifaces
zone['fans'] = fans
zone['events'] = events
zones.append(zone)
diff --git a/control/templates/fan_zone_defs.mako.cpp b/control/templates/fan_zone_defs.mako.cpp
index a73449f..cb46986 100644
--- a/control/templates/fan_zone_defs.mako.cpp
+++ b/control/templates/fan_zone_defs.mako.cpp
@@ -45,6 +45,38 @@ const std::vector<ZoneGroup> Manager::_zoneLayouts
${zone['default_floor']},
${zone['increase_delay']},
${zone['decrease_interval']},
+ std::vector<ZoneHandler>{
+ %if ('ifaces' in zone) and \
+ (zone['ifaces'] is not None):
+ %for i in zone['ifaces']:
+ %if ('props' in i) and \
+ (i['props'] is not None):
+ %for p in i['props']:
+ ZoneHandler{
+ make_zoneHandler(handler::setZoneProperty(
+ &Zone::${p['name']},
+ static_cast<${p['type']}>(
+ %if "vector" in p['type'] or "map" in p['type']:
+ ${p['type']}{
+ %endif
+ %for i, v in enumerate(p['values']):
+ %if (i+1) != len(p['values']):
+ ${v},
+ %else:
+ ${v}
+ %endif
+ %endfor
+ %if "vector" in p['type'] or "map" in p['type']:
+ }
+ %endif
+ )
+ ))
+ },
+ %endfor
+ %endif
+ %endfor
+ %endif
+ },
std::vector<FanDefinition>{
%for fan in zone['fans']:
FanDefinition{
OpenPOWER on IntegriCloud