[edk2-devel] [PATCH] IntelFsp2Pkg\Tools\ConfigEditor: Added new USF config workstream support Config Edit utility addition/changes.

Arun Sura posted 1 patch 5 months, 3 weeks ago
Failed in applying to current master (apply log)
IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py          | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py            | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml               | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md |   2 ++
4 files changed, 480 insertions(+), 55 deletions(-)
[edk2-devel] [PATCH] IntelFsp2Pkg\Tools\ConfigEditor: Added new USF config workstream support Config Edit utility addition/changes.
Posted by Arun Sura 5 months, 3 weeks ago
This patch is to enable config editor to have a new feature that can load
and view the configuration data of compiled VFR or HFR in form of YAML.
This can help users to understand and track the configuration data when
modifications are made.

Running Configuration Editor:
python ConfigEditor.py

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Duggapu Chinni B <chinni.b.duggapu@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Ray Han Lim Ng <ray.han.lim.ng@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Ted Kuo <ted.kuo@intel.com>
Cc: Ashraf Ali S <ashraf.ali.s@intel.com>
Cc: Susovan Mohapatra <susovan.mohapatra@intel.com>
Signed-off-by: Arun Sura <arun.surax.soundara.pandian@intel.com>
---
 IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py          | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
 IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py            | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
 IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml               | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md |   2 ++
 4 files changed, 480 insertions(+), 55 deletions(-)

diff --git a/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py b/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
index 5271504282..35c418a9a9 100644
--- a/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
+++ b/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
@@ -1015,6 +1015,10 @@ class application(tkinter.Frame):
                                      "Unsupported file '%s' !" % path)
                 return
 
+    # VFR Format Page modification
+    def page_construct(self):
+        self.left.bind("<<TreeviewSelect>>", self.on_config_page_select_change)
+
     def search_bar(self):
         # get data from text box
         self.search_text = self.edit.get()
@@ -1165,7 +1169,8 @@ class application(tkinter.Frame):
             page_id = next(iter(page))
             # Put CFG items into related page list
             self.page_list[page_id] = self.cfg_data_obj.get_cfg_list(page_id)
-            self.page_list[page_id].sort(key=lambda x: x['order'])
+            if self.mode == 'fsp':
+                self.page_list[page_id].sort(key=lambda x: x['order'])
             page_name = self.cfg_data_obj.get_page_title(page_id)
             child = self.left.insert(
                 parent, 'end',
@@ -1199,17 +1204,23 @@ class application(tkinter.Frame):
         for item in self.get_current_config_data():
             disp_list.append(item)
         row = 0
-        disp_list.sort(key=lambda x: x['order'])
-        for item in disp_list:
-            self.add_config_item(item, row)
-            row += 2
-        if self.invalid_values:
-            string = 'The following contails invalid options/values \n\n'
-            for i in self.invalid_values:
-                string += i + ": " + str(self.invalid_values[i]) + "\n"
-            reply = messagebox.showwarning('Warning!', string)
-            if reply == 'ok':
-                self.invalid_values.clear()
+        if self.mode == 'fsp':
+            disp_list.sort(key=lambda x: x['order'])
+            for item in disp_list:
+                self.add_config_item(item, row)
+                row += 2
+            if self.invalid_values:
+                string = 'The following contails invalid options/values \n\n'
+                for i in self.invalid_values:
+                    string += i + ": " + str(self.invalid_values[i]) + "\n"
+                reply = messagebox.showwarning('Warning!', string)
+                if reply == 'ok':
+                    self.invalid_values.clear()
+        elif self.mode == 'vfr':
+            for item in disp_list:
+                self.add_vfr_config_item(item, row)
+                row += 2
+
 
     fsp_version = ''
 
@@ -1219,16 +1230,19 @@ class application(tkinter.Frame):
             with open(file_name, "rb") as pkl_file:
                 gen_cfg_data.__dict__ = marshal.load(pkl_file)
             gen_cfg_data.prepare_marshal(False)
-        elif file_name.endswith('.yaml'):
+        elif file_name.endswith('.yaml') or file_name.endswith('.yml'):
             if gen_cfg_data.load_yaml(file_name) != 0:
                 raise Exception(gen_cfg_data.get_last_error())
         else:
             raise Exception('Unsupported file "%s" !' % file_name)
+
+        self.mode = gen_cfg_data.yaml_type
         # checking fsp version
-        if gen_cfg_data.detect_fsp():
-            self.fsp_version = '2.X'
-        else:
-            self.fsp_version = '1.X'
+        if gen_cfg_data.yaml_type == 'fsp':
+            if gen_cfg_data.detect_fsp():
+                self.fsp_version = '2.X'
+            else:
+                self.fsp_version = '1.X'
 
         return gen_cfg_data
 
@@ -1252,7 +1266,7 @@ class application(tkinter.Frame):
             elif ftype == 'bin':
                 question = 'All configuration will be reloaded from BIN file, \
                             continue ?'
-            elif ftype == 'yaml':
+            elif ftype == 'yaml' or ftype == 'yml':
                 question = ''
             elif ftype == 'bsf':
                 question = ''
@@ -1263,13 +1277,13 @@ class application(tkinter.Frame):
                 if reply == 'no':
                     return None
 
-        if ftype == 'yaml':
-            if self.mode == 'FSP':
+        if ftype == 'yaml' or ftype == 'yml':
+            if self.mode == 'fsp':
                 file_type = 'YAML'
                 file_ext = 'yaml'
             else:
                 file_type = 'YAML or PKL'
-                file_ext = 'pkl *.yaml'
+                file_ext = 'pkl *.yaml *.yml'
         else:
             file_type = ftype.upper()
             file_ext = ftype
@@ -1364,20 +1378,22 @@ class application(tkinter.Frame):
         self.left.delete(*self.left.get_children())
 
         self.cfg_data_obj = self.load_config_data(path)
-
-        self.update_last_dir(path)
-        self.org_cfg_data_bin = self.cfg_data_obj.generate_binary_array()
         self.build_config_page_tree(self.cfg_data_obj.get_cfg_page()['root'],
                                     '')
 
-        msg_string = 'Click YES if it is FULL FSP '\
-            + self.fsp_version + ' Binary'
-        reply = messagebox.askquestion('Form', msg_string)
-        if reply == 'yes':
-            self.load_from_bin()
+        self.update_last_dir(path)
+        if self.cfg_data_obj.yaml_type == 'fsp':
+            self.org_cfg_data_bin = self.cfg_data_obj.generate_binary_array()
 
-        for menu in self.menu_string:
-            self.file_menu.entryconfig(menu, state="normal")
+
+            msg_string = 'Click YES if it is FULL FSP '\
+                + self.fsp_version + ' Binary'
+            reply = messagebox.askquestion('Form', msg_string)
+            if reply == 'yes':
+                self.load_from_bin()
+
+            for menu in self.menu_string:
+                self.file_menu.entryconfig(menu, state="normal")
 
         return 0
 
@@ -1405,8 +1421,9 @@ class application(tkinter.Frame):
             return
 
         self.update_config_data_on_page()
-        new_data = self.cfg_data_obj.generate_binary_array()
-        self.cfg_data_obj.generate_delta_file_from_bin(path,
+        if self.mode == "fsp":
+            new_data = self.cfg_data_obj.generate_binary_array()
+            self.cfg_data_obj.generate_delta_file_from_bin(path,
                                                        self.org_cfg_data_bin,
                                                        new_data, full)
 
@@ -1526,6 +1543,13 @@ class application(tkinter.Frame):
             new_value = bytes_to_bracket_str(widget.get())
             self.set_config_item_value(item, new_value)
 
+    #YAML VFR Part Start
+    def update_vfr_config_data_from_widget(self, widget, args):
+
+        item = self.get_config_data_item_from_widget(widget)
+
+    #YAML VFR Part End
+
     def evaluate_condition(self, item):
         try:
             result = self.cfg_data_obj.evaluate_condition(item)
@@ -1535,6 +1559,132 @@ class application(tkinter.Frame):
             result = 1
         return result
 
+  #YAML VFR Part Start
+    def add_vfr_config_item(self, item, row):
+        parent = self.right_grid
+        widget = None
+        if item['type'] == 'string':
+            value = ''
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            txt_val = tkinter.StringVar()
+            widget = tkinter.Entry(parent, textvariable=txt_val)
+            txt_val.set(value)
+
+        elif item['type'] == 'text':
+            value = ''
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            txt_val = tkinter.StringVar()
+            widget = tkinter.Entry(parent, textvariable=txt_val)
+            txt_val.set(value)
+        elif item['type'] == 'label':
+            value = ''
+            name = tkinter.Label(parent, text=item['number'].split("#")[0] +" "+item['type'], anchor="w")
+            txt_val = tkinter.StringVar()
+            widget = tkinter.Entry(parent, textvariable=txt_val)
+            txt_val.set(value)
+
+        elif item['type'] == 'checkbox':
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            widget = tkinter.Checkbutton(parent, text= item['prompt'].split("#")[0], variable= 1)
+
+        elif item['type'] == 'subtitle':
+            value = ''
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            txt_val = tkinter.StringVar()
+            widget = tkinter.Entry(parent, textvariable=txt_val)
+            txt_val.set(value)
+
+        elif item['type'] == 'oneof':
+            OPTIONS = []
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            for key in item:
+                if key.startswith("option"):
+                    if type(item[key]) == type([]):
+                        for option_data in item[key]:
+                            OPTIONS.append(option_data['text'])
+                    else:
+                        OPTIONS.append(item[key]["text"])
+            txt_val = tkinter.StringVar()
+            txt_val.set(OPTIONS[0]) # set default value
+            widget = tkinter.OptionMenu(parent, txt_val, *OPTIONS)
+            txt_val.set(OPTIONS[0])
+
+        elif item['type'] == 'numeric':
+            value = 0
+            for key in item.keys():
+                if key == "value":
+                    value = item['value']
+                elif key == 'default':
+                    for dict_key in item['default']:
+                        if dict_key == "value":
+                            value = item['default']['value']
+                else:
+                    continue
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            txt_val = tkinter.StringVar()
+            widget = tkinter.Entry(parent, textvariable=txt_val)
+            txt_val.set(value)
+
+        elif item['type'] == 'orderedlist':
+            OPTIONS = []
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            for key in item:
+                if key.startswith("option"):
+                    if type(item[key]) == type([]):
+                        for option_data in item[key]:
+                            OPTIONS.append(option_data['text'])
+                    else:
+                        OPTIONS.append(item[key]["text"])
+            txt_val = tkinter.StringVar()
+            txt_val.set(OPTIONS[0]) # default value
+            widget = tkinter.OptionMenu(parent, txt_val, *OPTIONS)
+            txt_val.set(OPTIONS[0])
+
+        elif item['type'] == 'date':
+            value = ''
+            for key in item.keys():
+                if key == "value":
+                    value = item['value']
+                elif key == 'default':
+                    for dict_key in item['default']:
+                        if dict_key == "value":
+                            value = item['default']['value']
+                else:
+                    continue
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            txt_val = tkinter.StringVar()
+            widget = tkinter.Entry(parent, textvariable=txt_val)
+            txt_val.set(value)
+        elif item['type'] == 'time':
+            value = ''
+            for key in item.keys():
+                if key == "value":
+                    value = item['value']
+                elif key == 'default':
+                    for dict_key in item['default']:
+                        if dict_key == "value":
+                            value = item['default']['value']
+                else:
+                    continue
+            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +" "+item['type'], anchor="w")
+            txt_val = tkinter.StringVar()
+            widget = tkinter.Entry(parent, textvariable=txt_val)
+            txt_val.set(value)
+
+
+        if widget:
+            if item['type'] == 'string' or item['type'] == 'text' or item['type'] == 'numeric' or item['type'] == "oneof"\
+                or item['type'] == 'date' or item['type'] == 'time' or item['type'] == 'orderedlist' or item['type'] == 'label':# or item['type'] == 'goto'or item['type'] == 'checkbox':
+
+                if 'help' in item.keys():
+                    create_tool_tip(widget, item['help'].split("#")[0])
+
+            name.grid(row=row, column=0, padx=5, pady=5, sticky="nsew")
+            widget.grid(row=row + 1, rowspan=1, column=0,
+                        padx=5, pady=5, sticky="nsew")
+
+  #YAML VFR Part End
+
     def add_config_item(self, item, row):
         parent = self.right_grid
 
@@ -1611,9 +1761,15 @@ class application(tkinter.Frame):
                         padx=10, pady=5, sticky="nsew")
 
     def update_config_data_on_page(self):
-        self.walk_widgets_in_layout(self.right_grid,
-                                    self.update_config_data_from_widget)
 
+        if self.mode == "fsp":
+            self.walk_widgets_in_layout(self.right_grid,
+                                    self.update_config_data_from_widget)
+        elif self.mode == "vfr":
+            self.walk_widgets_in_layout(self.right_grid,
+                                    self.update_vfr_config_data_from_widget)
+        else:
+            print("WARNING: Invalid config file!!")
 
 if __name__ == '__main__':
     root = tkinter.Tk()
diff --git a/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py b/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
index 90d7a11184..095e425f6d 100644
--- a/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
+++ b/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
@@ -226,6 +226,7 @@ class CFG_YAML():
     TEMPLATE = 'template'
     CONFIGS = 'configs'
     VARIABLE = 'variable'
+    FORMSET = 'formset'
 
     def __init__(self):
         self.log_line = False
@@ -235,6 +236,7 @@ class CFG_YAML():
         self.var_dict = None
         self.def_dict = {}
         self.yaml_path = ''
+        self.yaml_type = 'fsp'
         self.lines = []
         self.full_lines = []
         self.index = 0
@@ -418,6 +420,7 @@ class CFG_YAML():
         last_indent = None
         key = ''
         temp_chk = {}
+        temp_data = []
 
         while True:
             line = self.get_line()
@@ -425,6 +428,9 @@ class CFG_YAML():
                 break
 
             curr_line = line.strip()
+            if curr_line == "## DO NOT REMOVE -- YAML Mode":
+                self.yaml_type = "vfr"
+
             if curr_line == '' or curr_line[0] == '#':
                 continue
 
@@ -482,9 +488,14 @@ class CFG_YAML():
                 return curr
 
             marker1 = curr_line[0]
-            marker2 = curr_line[-1]
             start = 1 if marker1 == '-' else 0
             pos = curr_line.find(': ')
+            if marker1 == '-':
+                marker2 = curr_line[curr_line.find(":")]
+                pos = -1
+            else:
+                marker2 = curr_line[-1]
+
             if pos > 0:
                 child = None
                 key = curr_line[start:pos].strip()
@@ -516,15 +527,31 @@ class CFG_YAML():
                     # special virtual nodes, rename to ensure unique key
                     key = '$ACTION_%04X' % self.index
                     self.index += 1
-                if key in curr:
-                    if key not in temp_chk:
-                        # check for duplicated keys at same level
-                        temp_chk[key] = 1
-                    else:
-                        raise Exception("Duplicated item '%s:%s' found !"
-                                        % (parent_name, key))
 
-                curr[key] = child
+                if self.yaml_type =='fsp':
+                    if key in curr:
+                        if key not in temp_chk:
+                            # check for duplicated keys at same level
+                            temp_chk[key] = 1
+                        else:
+                            raise Exception("Duplicated item '%s:%s' found !"
+                                            % (parent_name, key))
+
+                    curr[key] = child
+                if self.yaml_type == 'vfr':
+                    if key in curr.keys():
+                        if type(curr[key]) == type([]):
+                            temp_data = curr[key]
+                        else:
+                            temp_data.append(curr[key])
+
+                        temp_data.append(child)
+                        if level < 4:
+                            curr[key] = temp_data
+                        temp_data = []
+                    else:
+                        if level < 4:
+                            curr[key] = child
                 if self.var_dict is None and key == CFG_YAML.VARIABLE:
                     self.var_dict = child
                 if self.tmp_tree is None and key == CFG_YAML.TEMPLATE:
@@ -537,6 +564,8 @@ class CFG_YAML():
                 if self.tmp_tree and key == CFG_YAML.CONFIGS:
                     # apply template for the main configs
                     self.allow_template = True
+                if self.tmp_tree and key == CFG_YAML.FORMSET:
+                    self.allow_template = True
             else:
                 child = None
                 # - !include cfg_opt.yaml
@@ -550,8 +579,30 @@ class CFG_YAML():
         self.yaml_path = os.path.dirname(opt_file)
         self.load_file(opt_file)
         yaml_tree = self.parse()
-        self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
-        self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
+        for key in yaml_tree.keys():
+            if key.lower() == "configs":
+                self.yaml_type = 'fsp'
+                self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
+                self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
+                break
+            else:
+                self.cfg_tree = yaml_tree
+                break
+
+        if self.yaml_type == 'vfr':
+            formset_found = True
+            for key in yaml_tree.keys():
+                if key == CFG_YAML.FORMSET:
+                    self.cfg_tree = yaml_tree[CFG_YAML.FORMSET]
+                    formset_found = False
+                    break
+
+            if formset_found == True:
+                self.cfg_tree = yaml_tree
+        elif self.yaml_type == 'fsp':
+            self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
+            self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
+
         return self.cfg_tree
 
     def expand_yaml(self, opt_file):
@@ -594,9 +645,14 @@ class CGenYamlCfg:
         self._cfg_list = []
         self._cfg_page = {'root': {'title': '', 'child': []}}
         self._cur_page = ''
+        self._main_page = ''
         self._var_dict = {}
         self._def_dict = {}
         self._yaml_path = ''
+        self.yaml_type = ''
+        #Added to overcome duplicate formid
+        self.form_page_map = {}
+        self.formset_level = 0
 
     @staticmethod
     def deep_convert_dict(layer):
@@ -760,13 +816,22 @@ class CGenYamlCfg:
         return error
 
     def get_cfg_list(self, page_id=None):
+        cfgs = []
         if page_id is None:
             # return full list
             return self._cfg_list
         else:
-            # build a new list for items under a page ID
-            cfgs = [i for i in self._cfg_list if i['cname'] and
-                    (i['page'] == page_id)]
+            if self.yaml_type == 'fsp':
+                # build a new list for items under a page ID
+                cfgs = [i for i in self._cfg_list if i['cname'] and
+                        (i['page'] == page_id)]
+            #VFR YAML Support Start
+            elif self.yaml_type =='vfr':
+                for cfg in self._cfg_list:
+                    for i in cfg:
+                        if (i['page'] == page_id):
+                            cfgs.append(i)
+            #VFR YAML Support End
             return cfgs
 
     def get_cfg_page(self):
@@ -1002,6 +1067,9 @@ option format '%s' !" % option)
         def _locate_cfg_item(root, path, level=0):
             if len(path) == level:
                 return root
+            if type(root) == type([]):
+                for temp_root in root:
+                    return _locate_cfg_item(temp_root, path, level)
             next_root = root.get(path[level], None)
             if next_root is None:
                 if allow_exp:
@@ -1158,7 +1226,7 @@ option format '%s' !" % option)
 
         self.set_cur_page(item.get('page', ''))
 
-        if name[0] == '$':
+        if name != '' and name[0] == '$':
             # skip all virtual node
             return 0
 
@@ -1188,7 +1256,7 @@ option format '%s' !" % option)
             # define is length in bytes
             length = length * 8
 
-        if not name.isidentifier():
+        if name != '' and not name.isidentifier():
             raise Exception("Invalid config name '%s' for '%s' !" %
                             (name, '.'.join(path)))
 
@@ -1288,6 +1356,90 @@ option format '%s' !" % option)
                 raise SystemExit("Error: Bits length not aligned for %s !" %
                                  str(path))
 
+#EDK2 VFR YAML Support start
+
+    def build_formset_list(self, form_name='', top=None, parent_form='',path =[]):
+
+        if self.formset_level == 1:
+            self._cfg_page['root']['title'] = 'Platform'
+            self._cfg_page['root']['child'].append({form_name: {'title': form_name,
+                                                       'child': []}})
+            self._main_page = form_name
+
+        if top is None:
+            top = self._cfg_tree
+            form_name = "Formset"
+            self._cfg_page['root']['title'] = 'Formset'
+
+        is_leaf = True
+
+        if form_name == "form" or form_name == "formid":
+            self._cur_page = top["title"].split('#')[0]
+            self.form_page_map[top['formid'].split('#')[0]] = self._cur_page
+            for driver in self._cfg_page['root']['child']:
+                if list(driver.keys())[0] == self._main_page:
+                    driver[self._main_page]['child'].append({self._cur_page: {'title': self._cur_page, 'child': []}})
+
+        if form_name == "formmap":
+            self._cur_page = top["formid"].split('#')[0]
+            self.form_page_map[top['FormId'].split('#')[0]] = self._cur_page
+            self._cfg_page['root']['child'].append({self._cur_page: {'title': self._cur_page,
+                                                       'child': []}})
+
+
+        form_data = {}
+        temp_data = []
+
+        for key in top:
+            if key == 'include':
+                form_data['type'] = key
+                form_data["page"] = self._cur_page
+                continue
+            if type(top[key]) is list and self.formset_level <= 3:
+                self.formset_level += 1
+                path.append(key)
+                for data in top[key]:
+                    self.build_formset_list(key, data, key, path)
+                path.pop()
+                self.formset_level -= 1
+            elif type(top[key]) is OrderedDict and (self.formset_level <= 3):
+                if parent_form != '':
+                    self.formset_level += 1
+                    path.append(key)
+                    self.build_formset_list(key, top[key], form_name, path)
+                    path.pop()
+                    self.formset_level -= 1
+                else:
+                    self.formset_level += 1
+                    path.append(key)
+                    self.build_formset_list(key, top[key], key, path)
+                    path.pop()
+                    self.formset_level -= 1
+
+            else:
+                form_data["page"] = self._cur_page
+                form_data[key] = top[key]
+                form_data['path'] = ".".join(path)
+                if form_name != 'form' or form_name != "formid":
+                    form_data["type"] = form_name
+                else:
+                    form_data["type"] = " "
+                count = 0
+                if self._cfg_list != []:
+                    for cfg_name in self._cfg_list:
+                        for list_data in cfg_name:
+                            if key == list_data['type']:
+                                count +=1
+                    if count > 1:
+                        temp_data = cfg_name
+
+        if len(temp_data) != 0 or len(form_data)!=0:
+            temp_data.append(form_data)
+            self._cfg_list.append(temp_data)
+        return
+
+#EDK2 VFR YAML Support End
+
     def get_field_value(self, top=None):
         def _get_field_value(name, cfgs, level):
             if 'indx' in cfgs:
@@ -2196,10 +2348,14 @@ xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
         self.initialize()
         self._cfg_tree = cfg_yaml.load_yaml(cfg_file)
         self._def_dict = cfg_yaml.def_dict
+        self.yaml_type = cfg_yaml.yaml_type
         self._yaml_path = os.path.dirname(cfg_file)
-        self.build_cfg_list()
-        self.build_var_dict()
-        self.update_def_value()
+        if self.yaml_type == 'vfr':
+            self.build_formset_list()
+        elif self.yaml_type == 'fsp':
+            self.build_cfg_list()
+            self.build_var_dict()
+            self.update_def_value()
         return 0
 
 
@@ -2338,7 +2494,8 @@ def main():
     if dlt_file:
         gen_cfg_data.override_default_value(dlt_file)
 
-    gen_cfg_data.detect_fsp()
+    if gen_cfg_data.yaml_type == 'fsp':
+        gen_cfg_data.detect_fsp()
 
     if command == "GENBIN":
         if len(file_list) == 3:
diff --git a/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml b/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
new file mode 100644
index 0000000000..8345b3cf16
--- /dev/null
+++ b/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
@@ -0,0 +1,110 @@
+## DO NOT REMOVE -- YAML Mode
+
+BluetoothConnectionManager:
+  include:
+  - BluetoothConnectionManagerHii.h
+  - BluetoothConnectionManagerVfr.h
+
+  formset:
+    guid:  '{0x4f4ef7f0, 0xaa29, 0x4ce9, { 0xba, 0x41, 0x64, 0x3e, 0x1, 0x23, 0xa9, 0x9f }}'
+    help:  '0x0003 # will show the specific string instead of token here, pls ignore this issue'
+    title:  '0x0002 # will show the specific string instead of token here, pls ignore this issue'
+
+    - form:
+        formid:  2
+        title:  '0x0005 # will show the specific string instead of token here, pls ignore this issue'
+        - text:
+            help:  '0x0006 # will show the specific string instead of token here, pls ignore this issue'
+            prompt:  '0x0007 # will show the specific string instead of token here, pls ignore this issue'
+            text:  '0x0008 # will show the specific string instead of token here, pls ignore this issue'
+        - string:
+            questionid:  24578
+            varstoreid:  0  #  Optional Input
+            varname:  65535  # Question VarName
+            varoffset:  65535  # Question VarOffset
+            questionflags:  4 # Optional Input
+            prompt:  '0x000a # will show the specific string instead of token here, pls ignore this issue'
+            help:  '0x0009 # will show the specific string instead of token here, pls ignore this issue'
+            opcodeflags:  0x0  # optional input
+            minsize:  2
+            maxsize:  19
+        - subtitle:
+            prompt:  '0x0004 # will show the specific string instead of token here, pls ignore this issue'
+            flags:  0  # Optional Input
+        - goto:
+            questionid:  24577
+            varstoreid:  0  #  Optional Input
+            varname:  65535  # Question VarName
+            varoffset:  65535  # Question VarOffset
+            questionflags:  4 # Optional Input
+            prompt:  '0x0010 # will show the specific string instead of token here, pls ignore this issue'
+            help:  '0x0011 # will show the specific string instead of token here, pls ignore this issue'
+            formid:  0x3
+            question:  0x6001 #  Optional Input
+    - form:
+        formid:  3
+        title:  '0x0012 # will show the specific string instead of token here, pls ignore this issue'
+        - label:
+            number:  0x1500  # Number
+        - label:
+            number:  0x15ff  # Number
+        - subtitle:
+            prompt:  '0x0004 # will show the specific string instead of token here, pls ignore this issue'
+            flags:  0  # Optional Input
+        - subtitle:
+            prompt:  '0x0013 # will show the specific string instead of token here, pls ignore this issue'
+            flags:  0  # Optional Input
+        - label:
+            number:  0x1200  # Number
+        - label:
+            number:  0x12ff  # Number
+        - action:
+            questionid:  24579
+            varstoreid:  0  #  Optional Input
+            varname:  65535  # Question VarName
+            varoffset:  65535  # Question VarOffset
+            questionflags:  4 # Optional Input
+            prompt:  '0x0004 # will show the specific string instead of token here, pls ignore this issue'
+            help:  '0x0004 # will show the specific string instead of token here, pls ignore this issue'
+            config:  4  # QuestionConfig
+            - refreshguid:
+                guid:  '{0xf5e655d9, 0x2a6, 0x46f2, { 0x9e, 0x76, 0xb8, 0xbe, 0x8e, 0x60, 0xab, 0x22 }}'
+        - subtitle:
+            prompt:  '0x0014 # will show the specific string instead of token here, pls ignore this issue'
+            flags:  0  # Optional Input
+        - label:
+            number:  0x1300  # Number
+        - label:
+            number:  0x13ff  # Number
+    - form:
+        formid:  4
+        title:  '0x001c # will show the specific string instead of token here, pls ignore this issue'
+        - text:
+            condition:  'grayoutif TRUE'
+            help:  '0x0009 # will show the specific string instead of token here, pls ignore this issue'
+            prompt:  '0x000a # will show the specific string instead of token here, pls ignore this issue'
+            text:  '0x000b # will show the specific string instead of token here, pls ignore this issue'
+        - text:
+            condition:  'grayoutif TRUE'
+            help:  '0x0006 # will show the specific string instead of token here, pls ignore this issue'
+            prompt:  '0x0007 # will show the specific string instead of token here, pls ignore this issue'
+            text:  '0x000f # will show the specific string instead of token here, pls ignore this issue'
+        - text:
+            condition:  'grayoutif TRUE'
+            help:  '0x000c # will show the specific string instead of token here, pls ignore this issue'
+            prompt:  '0x000d # will show the specific string instead of token here, pls ignore this issue'
+            text:  '0x000e # will show the specific string instead of token here, pls ignore this issue'
+        - subtitle:
+            condition:  'grayoutif TRUE'
+            prompt:  '0x0004 # will show the specific string instead of token here, pls ignore this issue'
+            flags:  0  # Optional Input
+        - text:
+            condition:  'grayoutif TRUE'
+            help:  '0x001e # will show the specific string instead of token here, pls ignore this issue'
+            prompt:  '0x001d # will show the specific string instead of token here, pls ignore this issue'
+        - label:
+            condition:  'grayoutif TRUE'
+            number:  0x1400  # Number
+        - label:
+            condition:  'grayoutif TRUE'
+            number:  0x14ff  # Number
diff --git a/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md b/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
index da21df2432..721b2fdaf9 100644
--- a/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
+++ b/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
@@ -12,6 +12,8 @@ It supports the following options:
 ## 1. Open Config YAML file
 This option loads the YAML file for a FSP UPD into the ConfigEditor to change the desired configuration values.
 
+This option loads the YAML file for a VFR config data into the ConfigEditor to view the desired form values.
+
 #####Example:
 ```
 ![Example ConfigEditor 1](https://slimbootloader.github.io/_images/CfgEditOpen.png)
-- 
2.30.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110898): https://edk2.groups.io/g/devel/message/110898
Mute This Topic: https://groups.io/mt/102458734/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH] IntelFsp2Pkg\Tools\ConfigEditor: Added new USF config workstream support Config Edit utility addition/changes.
Posted by Chiu, Chasel 5 months, 3 weeks ago
Hi Arun,

I gave it a try and with test_vfr_yaml.yml there are just some label, numbers, string_index and empty blocks which look to me not very helpful for users to understand and track the configuration data.
Do we need to include certain string table file so the string_index can be more readable to users?

Some small feedbacks on coding style:
1. please run BaseTools/Scripts/PatchCheck.py to capture and resolve format issues.
2. please send V2 (or V3...) patch when you updated something so it will be easier to know this is same patch/fix but different versions (example: git format-patch -v2 -1)

Thanks,
Chasel


> -----Original Message-----
> From: Soundara Pandian, Arun SuraX <arun.surax.soundara.pandian@intel.com>
> Sent: Tuesday, November 7, 2023 8:53 PM
> To: devel@edk2.groups.io
> Cc: Soundara Pandian, Arun SuraX <arun.surax.soundara.pandian@intel.com>;
> Chiu, Chasel <chasel.chiu@intel.com>; Duggapu, Chinni B
> <chinni.b.duggapu@intel.com>; Desimone, Nathaniel L
> <nathaniel.l.desimone@intel.com>; Ng, Ray Han Lim
> <ray.han.lim.ng@intel.com>; Zeng, Star <star.zeng@intel.com>; Kuo, Ted
> <ted.kuo@intel.com>; S, Ashraf Ali <ashraf.ali.s@intel.com>; Mohapatra, Susovan
> <susovan.mohapatra@intel.com>
> Subject: [PATCH] IntelFsp2Pkg\Tools\ConfigEditor: Added new USF config
> workstream support Config Edit utility addition/changes.
> 
> This patch is to enable config editor to have a new feature that can load and view
> the configuration data of compiled VFR or HFR in form of YAML.
> This can help users to understand and track the configuration data when
> modifications are made.
> 
> Running Configuration Editor:
> python ConfigEditor.py
> 
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Cc: Duggapu Chinni B <chinni.b.duggapu@intel.com>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Cc: Ray Han Lim Ng <ray.han.lim.ng@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Ted Kuo <ted.kuo@intel.com>
> Cc: Ashraf Ali S <ashraf.ali.s@intel.com>
> Cc: Susovan Mohapatra <susovan.mohapatra@intel.com>
> Signed-off-by: Arun Sura <arun.surax.soundara.pandian@intel.com>
> ---
>  IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py          | 226
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
> -----------------------------
>  IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py            | 197
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++--------------------
>  IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml               | 110
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++
>  IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md |   2 ++
>  4 files changed, 480 insertions(+), 55 deletions(-)
> 
> diff --git a/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> b/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> index 5271504282..35c418a9a9 100644
> --- a/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> +++ b/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> @@ -1015,6 +1015,10 @@ class application(tkinter.Frame):
>                                       "Unsupported file '%s' !" % path)
>                  return
> 
> +    # VFR Format Page modification
> +    def page_construct(self):
> +        self.left.bind("<<TreeviewSelect>>",
> + self.on_config_page_select_change)
> +
>      def search_bar(self):
>          # get data from text box
>          self.search_text = self.edit.get() @@ -1165,7 +1169,8 @@ class
> application(tkinter.Frame):
>              page_id = next(iter(page))
>              # Put CFG items into related page list
>              self.page_list[page_id] = self.cfg_data_obj.get_cfg_list(page_id)
> -            self.page_list[page_id].sort(key=lambda x: x['order'])
> +            if self.mode == 'fsp':
> +                self.page_list[page_id].sort(key=lambda x: x['order'])
>              page_name = self.cfg_data_obj.get_page_title(page_id)
>              child = self.left.insert(
>                  parent, 'end',
> @@ -1199,17 +1204,23 @@ class application(tkinter.Frame):
>          for item in self.get_current_config_data():
>              disp_list.append(item)
>          row = 0
> -        disp_list.sort(key=lambda x: x['order'])
> -        for item in disp_list:
> -            self.add_config_item(item, row)
> -            row += 2
> -        if self.invalid_values:
> -            string = 'The following contails invalid options/values \n\n'
> -            for i in self.invalid_values:
> -                string += i + ": " + str(self.invalid_values[i]) + "\n"
> -            reply = messagebox.showwarning('Warning!', string)
> -            if reply == 'ok':
> -                self.invalid_values.clear()
> +        if self.mode == 'fsp':
> +            disp_list.sort(key=lambda x: x['order'])
> +            for item in disp_list:
> +                self.add_config_item(item, row)
> +                row += 2
> +            if self.invalid_values:
> +                string = 'The following contails invalid options/values \n\n'
> +                for i in self.invalid_values:
> +                    string += i + ": " + str(self.invalid_values[i]) + "\n"
> +                reply = messagebox.showwarning('Warning!', string)
> +                if reply == 'ok':
> +                    self.invalid_values.clear()
> +        elif self.mode == 'vfr':
> +            for item in disp_list:
> +                self.add_vfr_config_item(item, row)
> +                row += 2
> +
> 
>      fsp_version = ''
> 
> @@ -1219,16 +1230,19 @@ class application(tkinter.Frame):
>              with open(file_name, "rb") as pkl_file:
>                  gen_cfg_data.__dict__ = marshal.load(pkl_file)
>              gen_cfg_data.prepare_marshal(False)
> -        elif file_name.endswith('.yaml'):
> +        elif file_name.endswith('.yaml') or file_name.endswith('.yml'):
>              if gen_cfg_data.load_yaml(file_name) != 0:
>                  raise Exception(gen_cfg_data.get_last_error())
>          else:
>              raise Exception('Unsupported file "%s" !' % file_name)
> +
> +        self.mode = gen_cfg_data.yaml_type
>          # checking fsp version
> -        if gen_cfg_data.detect_fsp():
> -            self.fsp_version = '2.X'
> -        else:
> -            self.fsp_version = '1.X'
> +        if gen_cfg_data.yaml_type == 'fsp':
> +            if gen_cfg_data.detect_fsp():
> +                self.fsp_version = '2.X'
> +            else:
> +                self.fsp_version = '1.X'
> 
>          return gen_cfg_data
> 
> @@ -1252,7 +1266,7 @@ class application(tkinter.Frame):
>              elif ftype == 'bin':
>                  question = 'All configuration will be reloaded from BIN file, \
>                              continue ?'
> -            elif ftype == 'yaml':
> +            elif ftype == 'yaml' or ftype == 'yml':
>                  question = ''
>              elif ftype == 'bsf':
>                  question = ''
> @@ -1263,13 +1277,13 @@ class application(tkinter.Frame):
>                  if reply == 'no':
>                      return None
> 
> -        if ftype == 'yaml':
> -            if self.mode == 'FSP':
> +        if ftype == 'yaml' or ftype == 'yml':
> +            if self.mode == 'fsp':
>                  file_type = 'YAML'
>                  file_ext = 'yaml'
>              else:
>                  file_type = 'YAML or PKL'
> -                file_ext = 'pkl *.yaml'
> +                file_ext = 'pkl *.yaml *.yml'
>          else:
>              file_type = ftype.upper()
>              file_ext = ftype
> @@ -1364,20 +1378,22 @@ class application(tkinter.Frame):
>          self.left.delete(*self.left.get_children())
> 
>          self.cfg_data_obj = self.load_config_data(path)
> -
> -        self.update_last_dir(path)
> -        self.org_cfg_data_bin = self.cfg_data_obj.generate_binary_array()
>          self.build_config_page_tree(self.cfg_data_obj.get_cfg_page()['root'],
>                                      '')
> 
> -        msg_string = 'Click YES if it is FULL FSP '\
> -            + self.fsp_version + ' Binary'
> -        reply = messagebox.askquestion('Form', msg_string)
> -        if reply == 'yes':
> -            self.load_from_bin()
> +        self.update_last_dir(path)
> +        if self.cfg_data_obj.yaml_type == 'fsp':
> +            self.org_cfg_data_bin =
> + self.cfg_data_obj.generate_binary_array()
> 
> -        for menu in self.menu_string:
> -            self.file_menu.entryconfig(menu, state="normal")
> +
> +            msg_string = 'Click YES if it is FULL FSP '\
> +                + self.fsp_version + ' Binary'
> +            reply = messagebox.askquestion('Form', msg_string)
> +            if reply == 'yes':
> +                self.load_from_bin()
> +
> +            for menu in self.menu_string:
> +                self.file_menu.entryconfig(menu, state="normal")
> 
>          return 0
> 
> @@ -1405,8 +1421,9 @@ class application(tkinter.Frame):
>              return
> 
>          self.update_config_data_on_page()
> -        new_data = self.cfg_data_obj.generate_binary_array()
> -        self.cfg_data_obj.generate_delta_file_from_bin(path,
> +        if self.mode == "fsp":
> +            new_data = self.cfg_data_obj.generate_binary_array()
> +            self.cfg_data_obj.generate_delta_file_from_bin(path,
>                                                         self.org_cfg_data_bin,
>                                                         new_data, full)
> 
> @@ -1526,6 +1543,13 @@ class application(tkinter.Frame):
>              new_value = bytes_to_bracket_str(widget.get())
>              self.set_config_item_value(item, new_value)
> 
> +    #YAML VFR Part Start
> +    def update_vfr_config_data_from_widget(self, widget, args):
> +
> +        item = self.get_config_data_item_from_widget(widget)
> +
> +    #YAML VFR Part End
> +
>      def evaluate_condition(self, item):
>          try:
>              result = self.cfg_data_obj.evaluate_condition(item)
> @@ -1535,6 +1559,132 @@ class application(tkinter.Frame):
>              result = 1
>          return result
> 
> +  #YAML VFR Part Start
> +    def add_vfr_config_item(self, item, row):
> +        parent = self.right_grid
> +        widget = None
> +        if item['type'] == 'string':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'text':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +        elif item['type'] == 'label':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['number'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'checkbox':
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            widget = tkinter.Checkbutton(parent, text=
> + item['prompt'].split("#")[0], variable= 1)
> +
> +        elif item['type'] == 'subtitle':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'oneof':
> +            OPTIONS = []
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            for key in item:
> +                if key.startswith("option"):
> +                    if type(item[key]) == type([]):
> +                        for option_data in item[key]:
> +                            OPTIONS.append(option_data['text'])
> +                    else:
> +                        OPTIONS.append(item[key]["text"])
> +            txt_val = tkinter.StringVar()
> +            txt_val.set(OPTIONS[0]) # set default value
> +            widget = tkinter.OptionMenu(parent, txt_val, *OPTIONS)
> +            txt_val.set(OPTIONS[0])
> +
> +        elif item['type'] == 'numeric':
> +            value = 0
> +            for key in item.keys():
> +                if key == "value":
> +                    value = item['value']
> +                elif key == 'default':
> +                    for dict_key in item['default']:
> +                        if dict_key == "value":
> +                            value = item['default']['value']
> +                else:
> +                    continue
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'orderedlist':
> +            OPTIONS = []
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            for key in item:
> +                if key.startswith("option"):
> +                    if type(item[key]) == type([]):
> +                        for option_data in item[key]:
> +                            OPTIONS.append(option_data['text'])
> +                    else:
> +                        OPTIONS.append(item[key]["text"])
> +            txt_val = tkinter.StringVar()
> +            txt_val.set(OPTIONS[0]) # default value
> +            widget = tkinter.OptionMenu(parent, txt_val, *OPTIONS)
> +            txt_val.set(OPTIONS[0])
> +
> +        elif item['type'] == 'date':
> +            value = ''
> +            for key in item.keys():
> +                if key == "value":
> +                    value = item['value']
> +                elif key == 'default':
> +                    for dict_key in item['default']:
> +                        if dict_key == "value":
> +                            value = item['default']['value']
> +                else:
> +                    continue
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +        elif item['type'] == 'time':
> +            value = ''
> +            for key in item.keys():
> +                if key == "value":
> +                    value = item['value']
> +                elif key == 'default':
> +                    for dict_key in item['default']:
> +                        if dict_key == "value":
> +                            value = item['default']['value']
> +                else:
> +                    continue
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +
> +        if widget:
> +            if item['type'] == 'string' or item['type'] == 'text' or item['type'] ==
> 'numeric' or item['type'] == "oneof"\
> +                or item['type'] == 'date' or item['type'] == 'time' or item['type'] ==
> 'orderedlist' or item['type'] == 'label':# or item['type'] == 'goto'or item['type'] ==
> 'checkbox':
> +
> +                if 'help' in item.keys():
> +                    create_tool_tip(widget, item['help'].split("#")[0])
> +
> +            name.grid(row=row, column=0, padx=5, pady=5, sticky="nsew")
> +            widget.grid(row=row + 1, rowspan=1, column=0,
> +                        padx=5, pady=5, sticky="nsew")
> +
> +  #YAML VFR Part End
> +
>      def add_config_item(self, item, row):
>          parent = self.right_grid
> 
> @@ -1611,9 +1761,15 @@ class application(tkinter.Frame):
>                          padx=10, pady=5, sticky="nsew")
> 
>      def update_config_data_on_page(self):
> -        self.walk_widgets_in_layout(self.right_grid,
> -                                    self.update_config_data_from_widget)
> 
> +        if self.mode == "fsp":
> +            self.walk_widgets_in_layout(self.right_grid,
> +                                    self.update_config_data_from_widget)
> +        elif self.mode == "vfr":
> +            self.walk_widgets_in_layout(self.right_grid,
> +                                    self.update_vfr_config_data_from_widget)
> +        else:
> +            print("WARNING: Invalid config file!!")
> 
>  if __name__ == '__main__':
>      root = tkinter.Tk()
> diff --git a/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> b/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> index 90d7a11184..095e425f6d 100644
> --- a/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> +++ b/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> @@ -226,6 +226,7 @@ class CFG_YAML():
>      TEMPLATE = 'template'
>      CONFIGS = 'configs'
>      VARIABLE = 'variable'
> +    FORMSET = 'formset'
> 
>      def __init__(self):
>          self.log_line = False
> @@ -235,6 +236,7 @@ class CFG_YAML():
>          self.var_dict = None
>          self.def_dict = {}
>          self.yaml_path = ''
> +        self.yaml_type = 'fsp'
>          self.lines = []
>          self.full_lines = []
>          self.index = 0
> @@ -418,6 +420,7 @@ class CFG_YAML():
>          last_indent = None
>          key = ''
>          temp_chk = {}
> +        temp_data = []
> 
>          while True:
>              line = self.get_line()
> @@ -425,6 +428,9 @@ class CFG_YAML():
>                  break
> 
>              curr_line = line.strip()
> +            if curr_line == "## DO NOT REMOVE -- YAML Mode":
> +                self.yaml_type = "vfr"
> +
>              if curr_line == '' or curr_line[0] == '#':
>                  continue
> 
> @@ -482,9 +488,14 @@ class CFG_YAML():
>                  return curr
> 
>              marker1 = curr_line[0]
> -            marker2 = curr_line[-1]
>              start = 1 if marker1 == '-' else 0
>              pos = curr_line.find(': ')
> +            if marker1 == '-':
> +                marker2 = curr_line[curr_line.find(":")]
> +                pos = -1
> +            else:
> +                marker2 = curr_line[-1]
> +
>              if pos > 0:
>                  child = None
>                  key = curr_line[start:pos].strip() @@ -516,15 +527,31 @@ class
> CFG_YAML():
>                      # special virtual nodes, rename to ensure unique key
>                      key = '$ACTION_%04X' % self.index
>                      self.index += 1
> -                if key in curr:
> -                    if key not in temp_chk:
> -                        # check for duplicated keys at same level
> -                        temp_chk[key] = 1
> -                    else:
> -                        raise Exception("Duplicated item '%s:%s' found !"
> -                                        % (parent_name, key))
> 
> -                curr[key] = child
> +                if self.yaml_type =='fsp':
> +                    if key in curr:
> +                        if key not in temp_chk:
> +                            # check for duplicated keys at same level
> +                            temp_chk[key] = 1
> +                        else:
> +                            raise Exception("Duplicated item '%s:%s' found !"
> +                                            % (parent_name, key))
> +
> +                    curr[key] = child
> +                if self.yaml_type == 'vfr':
> +                    if key in curr.keys():
> +                        if type(curr[key]) == type([]):
> +                            temp_data = curr[key]
> +                        else:
> +                            temp_data.append(curr[key])
> +
> +                        temp_data.append(child)
> +                        if level < 4:
> +                            curr[key] = temp_data
> +                        temp_data = []
> +                    else:
> +                        if level < 4:
> +                            curr[key] = child
>                  if self.var_dict is None and key == CFG_YAML.VARIABLE:
>                      self.var_dict = child
>                  if self.tmp_tree is None and key == CFG_YAML.TEMPLATE:
> @@ -537,6 +564,8 @@ class CFG_YAML():
>                  if self.tmp_tree and key == CFG_YAML.CONFIGS:
>                      # apply template for the main configs
>                      self.allow_template = True
> +                if self.tmp_tree and key == CFG_YAML.FORMSET:
> +                    self.allow_template = True
>              else:
>                  child = None
>                  # - !include cfg_opt.yaml @@ -550,8 +579,30 @@ class CFG_YAML():
>          self.yaml_path = os.path.dirname(opt_file)
>          self.load_file(opt_file)
>          yaml_tree = self.parse()
> -        self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
> -        self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
> +        for key in yaml_tree.keys():
> +            if key.lower() == "configs":
> +                self.yaml_type = 'fsp'
> +                self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
> +                self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
> +                break
> +            else:
> +                self.cfg_tree = yaml_tree
> +                break
> +
> +        if self.yaml_type == 'vfr':
> +            formset_found = True
> +            for key in yaml_tree.keys():
> +                if key == CFG_YAML.FORMSET:
> +                    self.cfg_tree = yaml_tree[CFG_YAML.FORMSET]
> +                    formset_found = False
> +                    break
> +
> +            if formset_found == True:
> +                self.cfg_tree = yaml_tree
> +        elif self.yaml_type == 'fsp':
> +            self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
> +            self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
> +
>          return self.cfg_tree
> 
>      def expand_yaml(self, opt_file):
> @@ -594,9 +645,14 @@ class CGenYamlCfg:
>          self._cfg_list = []
>          self._cfg_page = {'root': {'title': '', 'child': []}}
>          self._cur_page = ''
> +        self._main_page = ''
>          self._var_dict = {}
>          self._def_dict = {}
>          self._yaml_path = ''
> +        self.yaml_type = ''
> +        #Added to overcome duplicate formid
> +        self.form_page_map = {}
> +        self.formset_level = 0
> 
>      @staticmethod
>      def deep_convert_dict(layer):
> @@ -760,13 +816,22 @@ class CGenYamlCfg:
>          return error
> 
>      def get_cfg_list(self, page_id=None):
> +        cfgs = []
>          if page_id is None:
>              # return full list
>              return self._cfg_list
>          else:
> -            # build a new list for items under a page ID
> -            cfgs = [i for i in self._cfg_list if i['cname'] and
> -                    (i['page'] == page_id)]
> +            if self.yaml_type == 'fsp':
> +                # build a new list for items under a page ID
> +                cfgs = [i for i in self._cfg_list if i['cname'] and
> +                        (i['page'] == page_id)]
> +            #VFR YAML Support Start
> +            elif self.yaml_type =='vfr':
> +                for cfg in self._cfg_list:
> +                    for i in cfg:
> +                        if (i['page'] == page_id):
> +                            cfgs.append(i)
> +            #VFR YAML Support End
>              return cfgs
> 
>      def get_cfg_page(self):
> @@ -1002,6 +1067,9 @@ option format '%s' !" % option)
>          def _locate_cfg_item(root, path, level=0):
>              if len(path) == level:
>                  return root
> +            if type(root) == type([]):
> +                for temp_root in root:
> +                    return _locate_cfg_item(temp_root, path, level)
>              next_root = root.get(path[level], None)
>              if next_root is None:
>                  if allow_exp:
> @@ -1158,7 +1226,7 @@ option format '%s' !" % option)
> 
>          self.set_cur_page(item.get('page', ''))
> 
> -        if name[0] == '$':
> +        if name != '' and name[0] == '$':
>              # skip all virtual node
>              return 0
> 
> @@ -1188,7 +1256,7 @@ option format '%s' !" % option)
>              # define is length in bytes
>              length = length * 8
> 
> -        if not name.isidentifier():
> +        if name != '' and not name.isidentifier():
>              raise Exception("Invalid config name '%s' for '%s' !" %
>                              (name, '.'.join(path)))
> 
> @@ -1288,6 +1356,90 @@ option format '%s' !" % option)
>                  raise SystemExit("Error: Bits length not aligned for %s !" %
>                                   str(path))
> 
> +#EDK2 VFR YAML Support start
> +
> +    def build_formset_list(self, form_name='', top=None, parent_form='',path =[]):
> +
> +        if self.formset_level == 1:
> +            self._cfg_page['root']['title'] = 'Platform'
> +            self._cfg_page['root']['child'].append({form_name: {'title': form_name,
> +                                                       'child': []}})
> +            self._main_page = form_name
> +
> +        if top is None:
> +            top = self._cfg_tree
> +            form_name = "Formset"
> +            self._cfg_page['root']['title'] = 'Formset'
> +
> +        is_leaf = True
> +
> +        if form_name == "form" or form_name == "formid":
> +            self._cur_page = top["title"].split('#')[0]
> +            self.form_page_map[top['formid'].split('#')[0]] = self._cur_page
> +            for driver in self._cfg_page['root']['child']:
> +                if list(driver.keys())[0] == self._main_page:
> +
> + driver[self._main_page]['child'].append({self._cur_page: {'title':
> + self._cur_page, 'child': []}})
> +
> +        if form_name == "formmap":
> +            self._cur_page = top["formid"].split('#')[0]
> +            self.form_page_map[top['FormId'].split('#')[0]] = self._cur_page
> +            self._cfg_page['root']['child'].append({self._cur_page: {'title':
> self._cur_page,
> +                                                       'child': []}})
> +
> +
> +        form_data = {}
> +        temp_data = []
> +
> +        for key in top:
> +            if key == 'include':
> +                form_data['type'] = key
> +                form_data["page"] = self._cur_page
> +                continue
> +            if type(top[key]) is list and self.formset_level <= 3:
> +                self.formset_level += 1
> +                path.append(key)
> +                for data in top[key]:
> +                    self.build_formset_list(key, data, key, path)
> +                path.pop()
> +                self.formset_level -= 1
> +            elif type(top[key]) is OrderedDict and (self.formset_level <= 3):
> +                if parent_form != '':
> +                    self.formset_level += 1
> +                    path.append(key)
> +                    self.build_formset_list(key, top[key], form_name, path)
> +                    path.pop()
> +                    self.formset_level -= 1
> +                else:
> +                    self.formset_level += 1
> +                    path.append(key)
> +                    self.build_formset_list(key, top[key], key, path)
> +                    path.pop()
> +                    self.formset_level -= 1
> +
> +            else:
> +                form_data["page"] = self._cur_page
> +                form_data[key] = top[key]
> +                form_data['path'] = ".".join(path)
> +                if form_name != 'form' or form_name != "formid":
> +                    form_data["type"] = form_name
> +                else:
> +                    form_data["type"] = " "
> +                count = 0
> +                if self._cfg_list != []:
> +                    for cfg_name in self._cfg_list:
> +                        for list_data in cfg_name:
> +                            if key == list_data['type']:
> +                                count +=1
> +                    if count > 1:
> +                        temp_data = cfg_name
> +
> +        if len(temp_data) != 0 or len(form_data)!=0:
> +            temp_data.append(form_data)
> +            self._cfg_list.append(temp_data)
> +        return
> +
> +#EDK2 VFR YAML Support End
> +
>      def get_field_value(self, top=None):
>          def _get_field_value(name, cfgs, level):
>              if 'indx' in cfgs:
> @@ -2196,10 +2348,14 @@ xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
>          self.initialize()
>          self._cfg_tree = cfg_yaml.load_yaml(cfg_file)
>          self._def_dict = cfg_yaml.def_dict
> +        self.yaml_type = cfg_yaml.yaml_type
>          self._yaml_path = os.path.dirname(cfg_file)
> -        self.build_cfg_list()
> -        self.build_var_dict()
> -        self.update_def_value()
> +        if self.yaml_type == 'vfr':
> +            self.build_formset_list()
> +        elif self.yaml_type == 'fsp':
> +            self.build_cfg_list()
> +            self.build_var_dict()
> +            self.update_def_value()
>          return 0
> 
> 
> @@ -2338,7 +2494,8 @@ def main():
>      if dlt_file:
>          gen_cfg_data.override_default_value(dlt_file)
> 
> -    gen_cfg_data.detect_fsp()
> +    if gen_cfg_data.yaml_type == 'fsp':
> +        gen_cfg_data.detect_fsp()
> 
>      if command == "GENBIN":
>          if len(file_list) == 3:
> diff --git a/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
> b/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
> new file mode 100644
> index 0000000000..8345b3cf16
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
> @@ -0,0 +1,110 @@
> +## DO NOT REMOVE -- YAML Mode
> +
> +BluetoothConnectionManager:
> +  include:
> +  - BluetoothConnectionManagerHii.h
> +  - BluetoothConnectionManagerVfr.h
> +
> +  formset:
> +    guid:  '{0x4f4ef7f0, 0xaa29, 0x4ce9, { 0xba, 0x41, 0x64, 0x3e, 0x1, 0x23, 0xa9,
> 0x9f }}'
> +    help:  '0x0003 # will show the specific string instead of token here, pls ignore
> this issue'
> +    title:  '0x0002 # will show the specific string instead of token here, pls ignore
> this issue'
> +
> +    - form:
> +        formid:  2
> +        title:  '0x0005 # will show the specific string instead of token here, pls
> ignore this issue'
> +        - text:
> +            help:  '0x0006 # will show the specific string instead of token here, pls
> ignore this issue'
> +            prompt:  '0x0007 # will show the specific string instead of token here, pls
> ignore this issue'
> +            text:  '0x0008 # will show the specific string instead of token here, pls
> ignore this issue'
> +        - string:
> +            questionid:  24578
> +            varstoreid:  0  #  Optional Input
> +            varname:  65535  # Question VarName
> +            varoffset:  65535  # Question VarOffset
> +            questionflags:  4 # Optional Input
> +            prompt:  '0x000a # will show the specific string instead of token here, pls
> ignore this issue'
> +            help:  '0x0009 # will show the specific string instead of token here, pls
> ignore this issue'
> +            opcodeflags:  0x0  # optional input
> +            minsize:  2
> +            maxsize:  19
> +        - subtitle:
> +            prompt:  '0x0004 # will show the specific string instead of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - goto:
> +            questionid:  24577
> +            varstoreid:  0  #  Optional Input
> +            varname:  65535  # Question VarName
> +            varoffset:  65535  # Question VarOffset
> +            questionflags:  4 # Optional Input
> +            prompt:  '0x0010 # will show the specific string instead of token here, pls
> ignore this issue'
> +            help:  '0x0011 # will show the specific string instead of token here, pls
> ignore this issue'
> +            formid:  0x3
> +            question:  0x6001 #  Optional Input
> +    - form:
> +        formid:  3
> +        title:  '0x0012 # will show the specific string instead of token here, pls
> ignore this issue'
> +        - label:
> +            number:  0x1500  # Number
> +        - label:
> +            number:  0x15ff  # Number
> +        - subtitle:
> +            prompt:  '0x0004 # will show the specific string instead of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - subtitle:
> +            prompt:  '0x0013 # will show the specific string instead of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - label:
> +            number:  0x1200  # Number
> +        - label:
> +            number:  0x12ff  # Number
> +        - action:
> +            questionid:  24579
> +            varstoreid:  0  #  Optional Input
> +            varname:  65535  # Question VarName
> +            varoffset:  65535  # Question VarOffset
> +            questionflags:  4 # Optional Input
> +            prompt:  '0x0004 # will show the specific string instead of token here, pls
> ignore this issue'
> +            help:  '0x0004 # will show the specific string instead of token here, pls
> ignore this issue'
> +            config:  4  # QuestionConfig
> +            - refreshguid:
> +                guid:  '{0xf5e655d9, 0x2a6, 0x46f2, { 0x9e, 0x76, 0xb8, 0xbe, 0x8e,
> 0x60, 0xab, 0x22 }}'
> +        - subtitle:
> +            prompt:  '0x0014 # will show the specific string instead of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - label:
> +            number:  0x1300  # Number
> +        - label:
> +            number:  0x13ff  # Number
> +    - form:
> +        formid:  4
> +        title:  '0x001c # will show the specific string instead of token here, pls ignore
> this issue'
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x0009 # will show the specific string instead of token here, pls
> ignore this issue'
> +            prompt:  '0x000a # will show the specific string instead of token here, pls
> ignore this issue'
> +            text:  '0x000b # will show the specific string instead of token here, pls
> ignore this issue'
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x0006 # will show the specific string instead of token here, pls
> ignore this issue'
> +            prompt:  '0x0007 # will show the specific string instead of token here, pls
> ignore this issue'
> +            text:  '0x000f # will show the specific string instead of token here, pls
> ignore this issue'
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x000c # will show the specific string instead of token here, pls
> ignore this issue'
> +            prompt:  '0x000d # will show the specific string instead of token here, pls
> ignore this issue'
> +            text:  '0x000e # will show the specific string instead of token here, pls
> ignore this issue'
> +        - subtitle:
> +            condition:  'grayoutif TRUE'
> +            prompt:  '0x0004 # will show the specific string instead of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x001e # will show the specific string instead of token here, pls
> ignore this issue'
> +            prompt:  '0x001d # will show the specific string instead of token here, pls
> ignore this issue'
> +        - label:
> +            condition:  'grayoutif TRUE'
> +            number:  0x1400  # Number
> +        - label:
> +            condition:  'grayoutif TRUE'
> +            number:  0x14ff  # Number
> diff --git a/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> b/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> index da21df2432..721b2fdaf9 100644
> --- a/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> +++ b/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> @@ -12,6 +12,8 @@ It supports the following options:
>  ## 1. Open Config YAML file
>  This option loads the YAML file for a FSP UPD into the ConfigEditor to change the
> desired configuration values.
> 
> +This option loads the YAML file for a VFR config data into the ConfigEditor to
> view the desired form values.
> +
>  #####Example:
>  ```
>  ![Example ConfigEditor
> 1](https://slimbootloader.github.io/_images/CfgEditOpen.png)
> --
> 2.30.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110930): https://edk2.groups.io/g/devel/message/110930
Mute This Topic: https://groups.io/mt/102458734/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH] IntelFsp2Pkg\Tools\ConfigEditor: Added new USF config workstream support Config Edit utility addition/changes.
Posted by Arun Sura 5 months, 3 weeks ago
Hi Chasel,

Sure, will work on the feedbacks. 

Thanks
Arun Sura S

-----Original Message-----
From: Chiu, Chasel <chasel.chiu@intel.com> 
Sent: Thursday, November 9, 2023 3:40 AM
To: Soundara Pandian, Arun SuraX <arun.surax.soundara.pandian@intel.com>; devel@edk2.groups.io
Cc: Duggapu, Chinni B <chinni.b.duggapu@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Ng, Ray Han Lim <ray.han.lim.ng@intel.com>; Zeng, Star <star.zeng@intel.com>; Kuo, Ted <ted.kuo@intel.com>; S, Ashraf Ali <ashraf.ali.s@intel.com>; Mohapatra, Susovan <susovan.mohapatra@intel.com>
Subject: RE: [PATCH] IntelFsp2Pkg\Tools\ConfigEditor: Added new USF config workstream support Config Edit utility addition/changes.


Hi Arun,

I gave it a try and with test_vfr_yaml.yml there are just some label, numbers, string_index and empty blocks which look to me not very helpful for users to understand and track the configuration data.
Do we need to include certain string table file so the string_index can be more readable to users?

Some small feedbacks on coding style:
1. please run BaseTools/Scripts/PatchCheck.py to capture and resolve format issues.
2. please send V2 (or V3...) patch when you updated something so it will be easier to know this is same patch/fix but different versions (example: git format-patch -v2 -1)

Thanks,
Chasel


> -----Original Message-----
> From: Soundara Pandian, Arun SuraX 
> <arun.surax.soundara.pandian@intel.com>
> Sent: Tuesday, November 7, 2023 8:53 PM
> To: devel@edk2.groups.io
> Cc: Soundara Pandian, Arun SuraX 
> <arun.surax.soundara.pandian@intel.com>;
> Chiu, Chasel <chasel.chiu@intel.com>; Duggapu, Chinni B 
> <chinni.b.duggapu@intel.com>; Desimone, Nathaniel L 
> <nathaniel.l.desimone@intel.com>; Ng, Ray Han Lim 
> <ray.han.lim.ng@intel.com>; Zeng, Star <star.zeng@intel.com>; Kuo, Ted 
> <ted.kuo@intel.com>; S, Ashraf Ali <ashraf.ali.s@intel.com>; 
> Mohapatra, Susovan <susovan.mohapatra@intel.com>
> Subject: [PATCH] IntelFsp2Pkg\Tools\ConfigEditor: Added new USF config 
> workstream support Config Edit utility addition/changes.
> 
> This patch is to enable config editor to have a new feature that can 
> load and view the configuration data of compiled VFR or HFR in form of YAML.
> This can help users to understand and track the configuration data 
> when modifications are made.
> 
> Running Configuration Editor:
> python ConfigEditor.py
> 
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Cc: Duggapu Chinni B <chinni.b.duggapu@intel.com>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Cc: Ray Han Lim Ng <ray.han.lim.ng@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Ted Kuo <ted.kuo@intel.com>
> Cc: Ashraf Ali S <ashraf.ali.s@intel.com>
> Cc: Susovan Mohapatra <susovan.mohapatra@intel.com>
> Signed-off-by: Arun Sura <arun.surax.soundara.pandian@intel.com>
> ---
>  IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py          | 226
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
> -----------------------------
>  IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py            | 197
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++--------------------
>  IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml               | 110
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++
>  IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md |   2 ++
>  4 files changed, 480 insertions(+), 55 deletions(-)
> 
> diff --git a/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> b/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> index 5271504282..35c418a9a9 100644
> --- a/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> +++ b/IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
> @@ -1015,6 +1015,10 @@ class application(tkinter.Frame):
>                                       "Unsupported file '%s' !" % path)
>                  return
> 
> +    # VFR Format Page modification
> +    def page_construct(self):
> +        self.left.bind("<<TreeviewSelect>>",
> + self.on_config_page_select_change)
> +
>      def search_bar(self):
>          # get data from text box
>          self.search_text = self.edit.get() @@ -1165,7 +1169,8 @@ 
> class
> application(tkinter.Frame):
>              page_id = next(iter(page))
>              # Put CFG items into related page list
>              self.page_list[page_id] = self.cfg_data_obj.get_cfg_list(page_id)
> -            self.page_list[page_id].sort(key=lambda x: x['order'])
> +            if self.mode == 'fsp':
> +                self.page_list[page_id].sort(key=lambda x: 
> + x['order'])
>              page_name = self.cfg_data_obj.get_page_title(page_id)
>              child = self.left.insert(
>                  parent, 'end',
> @@ -1199,17 +1204,23 @@ class application(tkinter.Frame):
>          for item in self.get_current_config_data():
>              disp_list.append(item)
>          row = 0
> -        disp_list.sort(key=lambda x: x['order'])
> -        for item in disp_list:
> -            self.add_config_item(item, row)
> -            row += 2
> -        if self.invalid_values:
> -            string = 'The following contails invalid options/values \n\n'
> -            for i in self.invalid_values:
> -                string += i + ": " + str(self.invalid_values[i]) + "\n"
> -            reply = messagebox.showwarning('Warning!', string)
> -            if reply == 'ok':
> -                self.invalid_values.clear()
> +        if self.mode == 'fsp':
> +            disp_list.sort(key=lambda x: x['order'])
> +            for item in disp_list:
> +                self.add_config_item(item, row)
> +                row += 2
> +            if self.invalid_values:
> +                string = 'The following contails invalid options/values \n\n'
> +                for i in self.invalid_values:
> +                    string += i + ": " + str(self.invalid_values[i]) + "\n"
> +                reply = messagebox.showwarning('Warning!', string)
> +                if reply == 'ok':
> +                    self.invalid_values.clear()
> +        elif self.mode == 'vfr':
> +            for item in disp_list:
> +                self.add_vfr_config_item(item, row)
> +                row += 2
> +
> 
>      fsp_version = ''
> 
> @@ -1219,16 +1230,19 @@ class application(tkinter.Frame):
>              with open(file_name, "rb") as pkl_file:
>                  gen_cfg_data.__dict__ = marshal.load(pkl_file)
>              gen_cfg_data.prepare_marshal(False)
> -        elif file_name.endswith('.yaml'):
> +        elif file_name.endswith('.yaml') or file_name.endswith('.yml'):
>              if gen_cfg_data.load_yaml(file_name) != 0:
>                  raise Exception(gen_cfg_data.get_last_error())
>          else:
>              raise Exception('Unsupported file "%s" !' % file_name)
> +
> +        self.mode = gen_cfg_data.yaml_type
>          # checking fsp version
> -        if gen_cfg_data.detect_fsp():
> -            self.fsp_version = '2.X'
> -        else:
> -            self.fsp_version = '1.X'
> +        if gen_cfg_data.yaml_type == 'fsp':
> +            if gen_cfg_data.detect_fsp():
> +                self.fsp_version = '2.X'
> +            else:
> +                self.fsp_version = '1.X'
> 
>          return gen_cfg_data
> 
> @@ -1252,7 +1266,7 @@ class application(tkinter.Frame):
>              elif ftype == 'bin':
>                  question = 'All configuration will be reloaded from BIN file, \
>                              continue ?'
> -            elif ftype == 'yaml':
> +            elif ftype == 'yaml' or ftype == 'yml':
>                  question = ''
>              elif ftype == 'bsf':
>                  question = ''
> @@ -1263,13 +1277,13 @@ class application(tkinter.Frame):
>                  if reply == 'no':
>                      return None
> 
> -        if ftype == 'yaml':
> -            if self.mode == 'FSP':
> +        if ftype == 'yaml' or ftype == 'yml':
> +            if self.mode == 'fsp':
>                  file_type = 'YAML'
>                  file_ext = 'yaml'
>              else:
>                  file_type = 'YAML or PKL'
> -                file_ext = 'pkl *.yaml'
> +                file_ext = 'pkl *.yaml *.yml'
>          else:
>              file_type = ftype.upper()
>              file_ext = ftype
> @@ -1364,20 +1378,22 @@ class application(tkinter.Frame):
>          self.left.delete(*self.left.get_children())
> 
>          self.cfg_data_obj = self.load_config_data(path)
> -
> -        self.update_last_dir(path)
> -        self.org_cfg_data_bin = self.cfg_data_obj.generate_binary_array()
>          self.build_config_page_tree(self.cfg_data_obj.get_cfg_page()['root'],
>                                      '')
> 
> -        msg_string = 'Click YES if it is FULL FSP '\
> -            + self.fsp_version + ' Binary'
> -        reply = messagebox.askquestion('Form', msg_string)
> -        if reply == 'yes':
> -            self.load_from_bin()
> +        self.update_last_dir(path)
> +        if self.cfg_data_obj.yaml_type == 'fsp':
> +            self.org_cfg_data_bin =
> + self.cfg_data_obj.generate_binary_array()
> 
> -        for menu in self.menu_string:
> -            self.file_menu.entryconfig(menu, state="normal")
> +
> +            msg_string = 'Click YES if it is FULL FSP '\
> +                + self.fsp_version + ' Binary'
> +            reply = messagebox.askquestion('Form', msg_string)
> +            if reply == 'yes':
> +                self.load_from_bin()
> +
> +            for menu in self.menu_string:
> +                self.file_menu.entryconfig(menu, state="normal")
> 
>          return 0
> 
> @@ -1405,8 +1421,9 @@ class application(tkinter.Frame):
>              return
> 
>          self.update_config_data_on_page()
> -        new_data = self.cfg_data_obj.generate_binary_array()
> -        self.cfg_data_obj.generate_delta_file_from_bin(path,
> +        if self.mode == "fsp":
> +            new_data = self.cfg_data_obj.generate_binary_array()
> +            self.cfg_data_obj.generate_delta_file_from_bin(path,
>                                                         self.org_cfg_data_bin,
>                                                         new_data, 
> full)
> 
> @@ -1526,6 +1543,13 @@ class application(tkinter.Frame):
>              new_value = bytes_to_bracket_str(widget.get())
>              self.set_config_item_value(item, new_value)
> 
> +    #YAML VFR Part Start
> +    def update_vfr_config_data_from_widget(self, widget, args):
> +
> +        item = self.get_config_data_item_from_widget(widget)
> +
> +    #YAML VFR Part End
> +
>      def evaluate_condition(self, item):
>          try:
>              result = self.cfg_data_obj.evaluate_condition(item)
> @@ -1535,6 +1559,132 @@ class application(tkinter.Frame):
>              result = 1
>          return result
> 
> +  #YAML VFR Part Start
> +    def add_vfr_config_item(self, item, row):
> +        parent = self.right_grid
> +        widget = None
> +        if item['type'] == 'string':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'text':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +        elif item['type'] == 'label':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['number'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'checkbox':
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            widget = tkinter.Checkbutton(parent, text= 
> + item['prompt'].split("#")[0], variable= 1)
> +
> +        elif item['type'] == 'subtitle':
> +            value = ''
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'oneof':
> +            OPTIONS = []
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            for key in item:
> +                if key.startswith("option"):
> +                    if type(item[key]) == type([]):
> +                        for option_data in item[key]:
> +                            OPTIONS.append(option_data['text'])
> +                    else:
> +                        OPTIONS.append(item[key]["text"])
> +            txt_val = tkinter.StringVar()
> +            txt_val.set(OPTIONS[0]) # set default value
> +            widget = tkinter.OptionMenu(parent, txt_val, *OPTIONS)
> +            txt_val.set(OPTIONS[0])
> +
> +        elif item['type'] == 'numeric':
> +            value = 0
> +            for key in item.keys():
> +                if key == "value":
> +                    value = item['value']
> +                elif key == 'default':
> +                    for dict_key in item['default']:
> +                        if dict_key == "value":
> +                            value = item['default']['value']
> +                else:
> +                    continue
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +        elif item['type'] == 'orderedlist':
> +            OPTIONS = []
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            for key in item:
> +                if key.startswith("option"):
> +                    if type(item[key]) == type([]):
> +                        for option_data in item[key]:
> +                            OPTIONS.append(option_data['text'])
> +                    else:
> +                        OPTIONS.append(item[key]["text"])
> +            txt_val = tkinter.StringVar()
> +            txt_val.set(OPTIONS[0]) # default value
> +            widget = tkinter.OptionMenu(parent, txt_val, *OPTIONS)
> +            txt_val.set(OPTIONS[0])
> +
> +        elif item['type'] == 'date':
> +            value = ''
> +            for key in item.keys():
> +                if key == "value":
> +                    value = item['value']
> +                elif key == 'default':
> +                    for dict_key in item['default']:
> +                        if dict_key == "value":
> +                            value = item['default']['value']
> +                else:
> +                    continue
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +        elif item['type'] == 'time':
> +            value = ''
> +            for key in item.keys():
> +                if key == "value":
> +                    value = item['value']
> +                elif key == 'default':
> +                    for dict_key in item['default']:
> +                        if dict_key == "value":
> +                            value = item['default']['value']
> +                else:
> +                    continue
> +            name = tkinter.Label(parent, text=item['prompt'].split("#")[0] +"
> "+item['type'], anchor="w")
> +            txt_val = tkinter.StringVar()
> +            widget = tkinter.Entry(parent, textvariable=txt_val)
> +            txt_val.set(value)
> +
> +
> +        if widget:
> +            if item['type'] == 'string' or item['type'] == 'text' or 
> + item['type'] ==
> 'numeric' or item['type'] == "oneof"\
> +                or item['type'] == 'date' or item['type'] == 'time' 
> + or item['type'] ==
> 'orderedlist' or item['type'] == 'label':# or item['type'] == 'goto'or 
> item['type'] ==
> 'checkbox':
> +
> +                if 'help' in item.keys():
> +                    create_tool_tip(widget, 
> + item['help'].split("#")[0])
> +
> +            name.grid(row=row, column=0, padx=5, pady=5, sticky="nsew")
> +            widget.grid(row=row + 1, rowspan=1, column=0,
> +                        padx=5, pady=5, sticky="nsew")
> +
> +  #YAML VFR Part End
> +
>      def add_config_item(self, item, row):
>          parent = self.right_grid
> 
> @@ -1611,9 +1761,15 @@ class application(tkinter.Frame):
>                          padx=10, pady=5, sticky="nsew")
> 
>      def update_config_data_on_page(self):
> -        self.walk_widgets_in_layout(self.right_grid,
> -                                    self.update_config_data_from_widget)
> 
> +        if self.mode == "fsp":
> +            self.walk_widgets_in_layout(self.right_grid,
> +                                    self.update_config_data_from_widget)
> +        elif self.mode == "vfr":
> +            self.walk_widgets_in_layout(self.right_grid,
> +                                    self.update_vfr_config_data_from_widget)
> +        else:
> +            print("WARNING: Invalid config file!!")
> 
>  if __name__ == '__main__':
>      root = tkinter.Tk()
> diff --git a/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> b/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> index 90d7a11184..095e425f6d 100644
> --- a/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> +++ b/IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
> @@ -226,6 +226,7 @@ class CFG_YAML():
>      TEMPLATE = 'template'
>      CONFIGS = 'configs'
>      VARIABLE = 'variable'
> +    FORMSET = 'formset'
> 
>      def __init__(self):
>          self.log_line = False
> @@ -235,6 +236,7 @@ class CFG_YAML():
>          self.var_dict = None
>          self.def_dict = {}
>          self.yaml_path = ''
> +        self.yaml_type = 'fsp'
>          self.lines = []
>          self.full_lines = []
>          self.index = 0
> @@ -418,6 +420,7 @@ class CFG_YAML():
>          last_indent = None
>          key = ''
>          temp_chk = {}
> +        temp_data = []
> 
>          while True:
>              line = self.get_line()
> @@ -425,6 +428,9 @@ class CFG_YAML():
>                  break
> 
>              curr_line = line.strip()
> +            if curr_line == "## DO NOT REMOVE -- YAML Mode":
> +                self.yaml_type = "vfr"
> +
>              if curr_line == '' or curr_line[0] == '#':
>                  continue
> 
> @@ -482,9 +488,14 @@ class CFG_YAML():
>                  return curr
> 
>              marker1 = curr_line[0]
> -            marker2 = curr_line[-1]
>              start = 1 if marker1 == '-' else 0
>              pos = curr_line.find(': ')
> +            if marker1 == '-':
> +                marker2 = curr_line[curr_line.find(":")]
> +                pos = -1
> +            else:
> +                marker2 = curr_line[-1]
> +
>              if pos > 0:
>                  child = None
>                  key = curr_line[start:pos].strip() @@ -516,15 +527,31 
> @@ class
> CFG_YAML():
>                      # special virtual nodes, rename to ensure unique key
>                      key = '$ACTION_%04X' % self.index
>                      self.index += 1
> -                if key in curr:
> -                    if key not in temp_chk:
> -                        # check for duplicated keys at same level
> -                        temp_chk[key] = 1
> -                    else:
> -                        raise Exception("Duplicated item '%s:%s' found !"
> -                                        % (parent_name, key))
> 
> -                curr[key] = child
> +                if self.yaml_type =='fsp':
> +                    if key in curr:
> +                        if key not in temp_chk:
> +                            # check for duplicated keys at same level
> +                            temp_chk[key] = 1
> +                        else:
> +                            raise Exception("Duplicated item '%s:%s' found !"
> +                                            % (parent_name, key))
> +
> +                    curr[key] = child
> +                if self.yaml_type == 'vfr':
> +                    if key in curr.keys():
> +                        if type(curr[key]) == type([]):
> +                            temp_data = curr[key]
> +                        else:
> +                            temp_data.append(curr[key])
> +
> +                        temp_data.append(child)
> +                        if level < 4:
> +                            curr[key] = temp_data
> +                        temp_data = []
> +                    else:
> +                        if level < 4:
> +                            curr[key] = child
>                  if self.var_dict is None and key == CFG_YAML.VARIABLE:
>                      self.var_dict = child
>                  if self.tmp_tree is None and key == CFG_YAML.TEMPLATE:
> @@ -537,6 +564,8 @@ class CFG_YAML():
>                  if self.tmp_tree and key == CFG_YAML.CONFIGS:
>                      # apply template for the main configs
>                      self.allow_template = True
> +                if self.tmp_tree and key == CFG_YAML.FORMSET:
> +                    self.allow_template = True
>              else:
>                  child = None
>                  # - !include cfg_opt.yaml @@ -550,8 +579,30 @@ class CFG_YAML():
>          self.yaml_path = os.path.dirname(opt_file)
>          self.load_file(opt_file)
>          yaml_tree = self.parse()
> -        self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
> -        self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
> +        for key in yaml_tree.keys():
> +            if key.lower() == "configs":
> +                self.yaml_type = 'fsp'
> +                self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
> +                self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
> +                break
> +            else:
> +                self.cfg_tree = yaml_tree
> +                break
> +
> +        if self.yaml_type == 'vfr':
> +            formset_found = True
> +            for key in yaml_tree.keys():
> +                if key == CFG_YAML.FORMSET:
> +                    self.cfg_tree = yaml_tree[CFG_YAML.FORMSET]
> +                    formset_found = False
> +                    break
> +
> +            if formset_found == True:
> +                self.cfg_tree = yaml_tree
> +        elif self.yaml_type == 'fsp':
> +            self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
> +            self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
> +
>          return self.cfg_tree
> 
>      def expand_yaml(self, opt_file):
> @@ -594,9 +645,14 @@ class CGenYamlCfg:
>          self._cfg_list = []
>          self._cfg_page = {'root': {'title': '', 'child': []}}
>          self._cur_page = ''
> +        self._main_page = ''
>          self._var_dict = {}
>          self._def_dict = {}
>          self._yaml_path = ''
> +        self.yaml_type = ''
> +        #Added to overcome duplicate formid
> +        self.form_page_map = {}
> +        self.formset_level = 0
> 
>      @staticmethod
>      def deep_convert_dict(layer):
> @@ -760,13 +816,22 @@ class CGenYamlCfg:
>          return error
> 
>      def get_cfg_list(self, page_id=None):
> +        cfgs = []
>          if page_id is None:
>              # return full list
>              return self._cfg_list
>          else:
> -            # build a new list for items under a page ID
> -            cfgs = [i for i in self._cfg_list if i['cname'] and
> -                    (i['page'] == page_id)]
> +            if self.yaml_type == 'fsp':
> +                # build a new list for items under a page ID
> +                cfgs = [i for i in self._cfg_list if i['cname'] and
> +                        (i['page'] == page_id)]
> +            #VFR YAML Support Start
> +            elif self.yaml_type =='vfr':
> +                for cfg in self._cfg_list:
> +                    for i in cfg:
> +                        if (i['page'] == page_id):
> +                            cfgs.append(i)
> +            #VFR YAML Support End
>              return cfgs
> 
>      def get_cfg_page(self):
> @@ -1002,6 +1067,9 @@ option format '%s' !" % option)
>          def _locate_cfg_item(root, path, level=0):
>              if len(path) == level:
>                  return root
> +            if type(root) == type([]):
> +                for temp_root in root:
> +                    return _locate_cfg_item(temp_root, path, level)
>              next_root = root.get(path[level], None)
>              if next_root is None:
>                  if allow_exp:
> @@ -1158,7 +1226,7 @@ option format '%s' !" % option)
> 
>          self.set_cur_page(item.get('page', ''))
> 
> -        if name[0] == '$':
> +        if name != '' and name[0] == '$':
>              # skip all virtual node
>              return 0
> 
> @@ -1188,7 +1256,7 @@ option format '%s' !" % option)
>              # define is length in bytes
>              length = length * 8
> 
> -        if not name.isidentifier():
> +        if name != '' and not name.isidentifier():
>              raise Exception("Invalid config name '%s' for '%s' !" %
>                              (name, '.'.join(path)))
> 
> @@ -1288,6 +1356,90 @@ option format '%s' !" % option)
>                  raise SystemExit("Error: Bits length not aligned for %s !" %
>                                   str(path))
> 
> +#EDK2 VFR YAML Support start
> +
> +    def build_formset_list(self, form_name='', top=None, parent_form='',path =[]):
> +
> +        if self.formset_level == 1:
> +            self._cfg_page['root']['title'] = 'Platform'
> +            self._cfg_page['root']['child'].append({form_name: {'title': form_name,
> +                                                       'child': []}})
> +            self._main_page = form_name
> +
> +        if top is None:
> +            top = self._cfg_tree
> +            form_name = "Formset"
> +            self._cfg_page['root']['title'] = 'Formset'
> +
> +        is_leaf = True
> +
> +        if form_name == "form" or form_name == "formid":
> +            self._cur_page = top["title"].split('#')[0]
> +            self.form_page_map[top['formid'].split('#')[0]] = self._cur_page
> +            for driver in self._cfg_page['root']['child']:
> +                if list(driver.keys())[0] == self._main_page:
> +
> + driver[self._main_page]['child'].append({self._cur_page: {'title':
> + self._cur_page, 'child': []}})
> +
> +        if form_name == "formmap":
> +            self._cur_page = top["formid"].split('#')[0]
> +            self.form_page_map[top['FormId'].split('#')[0]] = self._cur_page
> +            self._cfg_page['root']['child'].append({self._cur_page: {'title':
> self._cur_page,
> +                                                       'child': []}})
> +
> +
> +        form_data = {}
> +        temp_data = []
> +
> +        for key in top:
> +            if key == 'include':
> +                form_data['type'] = key
> +                form_data["page"] = self._cur_page
> +                continue
> +            if type(top[key]) is list and self.formset_level <= 3:
> +                self.formset_level += 1
> +                path.append(key)
> +                for data in top[key]:
> +                    self.build_formset_list(key, data, key, path)
> +                path.pop()
> +                self.formset_level -= 1
> +            elif type(top[key]) is OrderedDict and (self.formset_level <= 3):
> +                if parent_form != '':
> +                    self.formset_level += 1
> +                    path.append(key)
> +                    self.build_formset_list(key, top[key], form_name, path)
> +                    path.pop()
> +                    self.formset_level -= 1
> +                else:
> +                    self.formset_level += 1
> +                    path.append(key)
> +                    self.build_formset_list(key, top[key], key, path)
> +                    path.pop()
> +                    self.formset_level -= 1
> +
> +            else:
> +                form_data["page"] = self._cur_page
> +                form_data[key] = top[key]
> +                form_data['path'] = ".".join(path)
> +                if form_name != 'form' or form_name != "formid":
> +                    form_data["type"] = form_name
> +                else:
> +                    form_data["type"] = " "
> +                count = 0
> +                if self._cfg_list != []:
> +                    for cfg_name in self._cfg_list:
> +                        for list_data in cfg_name:
> +                            if key == list_data['type']:
> +                                count +=1
> +                    if count > 1:
> +                        temp_data = cfg_name
> +
> +        if len(temp_data) != 0 or len(form_data)!=0:
> +            temp_data.append(form_data)
> +            self._cfg_list.append(temp_data)
> +        return
> +
> +#EDK2 VFR YAML Support End
> +
>      def get_field_value(self, top=None):
>          def _get_field_value(name, cfgs, level):
>              if 'indx' in cfgs:
> @@ -2196,10 +2348,14 @@ xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
>          self.initialize()
>          self._cfg_tree = cfg_yaml.load_yaml(cfg_file)
>          self._def_dict = cfg_yaml.def_dict
> +        self.yaml_type = cfg_yaml.yaml_type
>          self._yaml_path = os.path.dirname(cfg_file)
> -        self.build_cfg_list()
> -        self.build_var_dict()
> -        self.update_def_value()
> +        if self.yaml_type == 'vfr':
> +            self.build_formset_list()
> +        elif self.yaml_type == 'fsp':
> +            self.build_cfg_list()
> +            self.build_var_dict()
> +            self.update_def_value()
>          return 0
> 
> 
> @@ -2338,7 +2494,8 @@ def main():
>      if dlt_file:
>          gen_cfg_data.override_default_value(dlt_file)
> 
> -    gen_cfg_data.detect_fsp()
> +    if gen_cfg_data.yaml_type == 'fsp':
> +        gen_cfg_data.detect_fsp()
> 
>      if command == "GENBIN":
>          if len(file_list) == 3:
> diff --git a/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
> b/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
> new file mode 100644
> index 0000000000..8345b3cf16
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/test_vfr_yaml.yml
> @@ -0,0 +1,110 @@
> +## DO NOT REMOVE -- YAML Mode
> +
> +BluetoothConnectionManager:
> +  include:
> +  - BluetoothConnectionManagerHii.h
> +  - BluetoothConnectionManagerVfr.h
> +
> +  formset:
> +    guid:  '{0x4f4ef7f0, 0xaa29, 0x4ce9, { 0xba, 0x41, 0x64, 0x3e, 
> + 0x1, 0x23, 0xa9,
> 0x9f }}'
> +    help:  '0x0003 # will show the specific string instead of token 
> + here, pls ignore
> this issue'
> +    title:  '0x0002 # will show the specific string instead of token 
> + here, pls ignore
> this issue'
> +
> +    - form:
> +        formid:  2
> +        title:  '0x0005 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +        - text:
> +            help:  '0x0006 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            prompt:  '0x0007 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            text:  '0x0008 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +        - string:
> +            questionid:  24578
> +            varstoreid:  0  #  Optional Input
> +            varname:  65535  # Question VarName
> +            varoffset:  65535  # Question VarOffset
> +            questionflags:  4 # Optional Input
> +            prompt:  '0x000a # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            help:  '0x0009 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            opcodeflags:  0x0  # optional input
> +            minsize:  2
> +            maxsize:  19
> +        - subtitle:
> +            prompt:  '0x0004 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - goto:
> +            questionid:  24577
> +            varstoreid:  0  #  Optional Input
> +            varname:  65535  # Question VarName
> +            varoffset:  65535  # Question VarOffset
> +            questionflags:  4 # Optional Input
> +            prompt:  '0x0010 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            help:  '0x0011 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            formid:  0x3
> +            question:  0x6001 #  Optional Input
> +    - form:
> +        formid:  3
> +        title:  '0x0012 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +        - label:
> +            number:  0x1500  # Number
> +        - label:
> +            number:  0x15ff  # Number
> +        - subtitle:
> +            prompt:  '0x0004 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - subtitle:
> +            prompt:  '0x0013 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - label:
> +            number:  0x1200  # Number
> +        - label:
> +            number:  0x12ff  # Number
> +        - action:
> +            questionid:  24579
> +            varstoreid:  0  #  Optional Input
> +            varname:  65535  # Question VarName
> +            varoffset:  65535  # Question VarOffset
> +            questionflags:  4 # Optional Input
> +            prompt:  '0x0004 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            help:  '0x0004 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            config:  4  # QuestionConfig
> +            - refreshguid:
> +                guid:  '{0xf5e655d9, 0x2a6, 0x46f2, { 0x9e, 0x76, 
> + 0xb8, 0xbe, 0x8e,
> 0x60, 0xab, 0x22 }}'
> +        - subtitle:
> +            prompt:  '0x0014 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - label:
> +            number:  0x1300  # Number
> +        - label:
> +            number:  0x13ff  # Number
> +    - form:
> +        formid:  4
> +        title:  '0x001c # will show the specific string instead of 
> + token here, pls ignore
> this issue'
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x0009 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            prompt:  '0x000a # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            text:  '0x000b # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x0006 # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            prompt:  '0x0007 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            text:  '0x000f # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x000c # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            prompt:  '0x000d # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            text:  '0x000e # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +        - subtitle:
> +            condition:  'grayoutif TRUE'
> +            prompt:  '0x0004 # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +            flags:  0  # Optional Input
> +        - text:
> +            condition:  'grayoutif TRUE'
> +            help:  '0x001e # will show the specific string instead of 
> + token here, pls
> ignore this issue'
> +            prompt:  '0x001d # will show the specific string instead 
> + of token here, pls
> ignore this issue'
> +        - label:
> +            condition:  'grayoutif TRUE'
> +            number:  0x1400  # Number
> +        - label:
> +            condition:  'grayoutif TRUE'
> +            number:  0x14ff  # Number
> diff --git a/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> b/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> index da21df2432..721b2fdaf9 100644
> --- a/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> +++ b/IntelFsp2Pkg/Tools/UserManuals/ConfigEditorUserManual.md
> @@ -12,6 +12,8 @@ It supports the following options:
>  ## 1. Open Config YAML file
>  This option loads the YAML file for a FSP UPD into the ConfigEditor 
> to change the desired configuration values.
> 
> +This option loads the YAML file for a VFR config data into the 
> +ConfigEditor to
> view the desired form values.
> +
>  #####Example:
>  ```
>  ![Example ConfigEditor
> 1](https://slimbootloader.github.io/_images/CfgEditOpen.png)
> --
> 2.30.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110947): https://edk2.groups.io/g/devel/message/110947
Mute This Topic: https://groups.io/mt/102458734/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-