diff --git a/cmake/metadata.cmake b/cmake/metadata.cmake index 0c18ae0662..e0810a3f84 100644 --- a/cmake/metadata.cmake +++ b/cmake/metadata.cmake @@ -55,11 +55,18 @@ add_custom_target(metadata_parameters --src-path `find ${PX4_SOURCE_DIR}/src -maxdepth 4 -type d` --inject-xml ${PX4_SOURCE_DIR}/src/lib/parameters/parameters_injected.xml --markdown ${PX4_BINARY_DIR}/docs/parameters.md + + COMMAND ${PYTHON_EXECUTABLE} ${PX4_SOURCE_DIR}/src/lib/parameters/px_process_params.py + --src-path `find ${PX4_SOURCE_DIR}/src -maxdepth 4 -type d` + --inject-xml ${PX4_SOURCE_DIR}/src/lib/parameters/parameters_injected.xml + --json ${PX4_BINARY_DIR}/docs/parameters.json + COMMAND ${PYTHON_EXECUTABLE} ${PX4_SOURCE_DIR}/src/lib/parameters/px_process_params.py --src-path `find ${PX4_SOURCE_DIR}/src -maxdepth 4 -type d` --inject-xml ${PX4_SOURCE_DIR}/src/lib/parameters/parameters_injected.xml --xml ${PX4_BINARY_DIR}/docs/parameters.xml - COMMENT "Generating full parameter metadata (markdown and xml)" + + COMMENT "Generating full parameter metadata (markdown, xml, and json)" USES_TERMINAL ) diff --git a/src/lib/parameters/CMakeLists.txt b/src/lib/parameters/CMakeLists.txt index 3adb625c2b..f53f431206 100644 --- a/src/lib/parameters/CMakeLists.txt +++ b/src/lib/parameters/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################ # -# Copyright (c) 2017 PX4 Development Team. All rights reserved. +# Copyright (c) 2017 - 2020 PX4 Development Team. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -87,11 +87,14 @@ add_custom_command(OUTPUT ${generated_serial_params_file} ) set(parameters_xml ${PX4_BINARY_DIR}/parameters.xml) +set(parameters_json ${PX4_BINARY_DIR}/parameters.json) file(GLOB_RECURSE param_src_files ${PX4_SOURCE_DIR}/src/*params.c) -add_custom_command(OUTPUT ${parameters_xml} +add_custom_command(OUTPUT ${parameters_xml} ${parameters_json} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/px_process_params.py --src-path ${module_list} ${generated_params_dir} --xml ${parameters_xml} + --json ${parameters_json} + --compress --inject-xml ${CMAKE_CURRENT_SOURCE_DIR}/parameters_injected.xml --overrides ${PARAM_DEFAULT_OVERRIDES} --board ${PX4_BOARD} @@ -102,6 +105,7 @@ add_custom_command(OUTPUT ${parameters_xml} parameters_injected.xml px4params/srcparser.py px4params/srcscanner.py + px4params/jsonout.py px4params/xmlout.py px_process_params.py parameters_injected.xml diff --git a/src/lib/parameters/px4params/jsonout.py b/src/lib/parameters/px4params/jsonout.py new file mode 100644 index 0000000000..c1e91c8b77 --- /dev/null +++ b/src/lib/parameters/px4params/jsonout.py @@ -0,0 +1,112 @@ +from xml.sax.saxutils import escape +import codecs +import json +import sys + + +class JsonOutput(): + def __init__(self, groups, board, inject_xml_file_name): + all_json=dict() + all_json['version']=1 + all_json['uid']=1 #COMPONENT_INFORMATION.comp_metadata_type + all_json['scope']="Firmware" + all_params=[] + all_json['parameters']=all_params + + #xml_parameters = ET.Element("parameters") + #xml_version = ET.SubElement(xml_parameters, "version") + #xml_version.text = "3" + #xml_version = ET.SubElement(xml_parameters, "parameter_version_major") + #xml_version.text = "1" + #xml_version = ET.SubElement(xml_parameters, "parameter_version_minor") + #xml_version.text = "15" + + schema_map = { + "short_desc": "shortDescription", + "long_desc": "longDescription", + "unit": "units", + "decimal": "decimalPlaces", + "min": "min", + "max": "max", + "increment": "increment", + "reboot_required": "rebootRequired" + } + allowed_types = { "Uint8", "Int8", "Uint16", "Int16", "Uint32", "Int32", "Float"} + + last_param_name = "" + board_specific_param_set = False + for group in groups: + group_name=group.GetName() + + for param in group.GetParams(): + if (last_param_name == param.GetName() and not board_specific_param_set) or last_param_name != param.GetName(): + curr_param=dict() + curr_param['name'] = param.GetName() + curr_param['defaultValue'] = param.GetDefault() + curr_param['type'] = param.GetType().capitalize() + if not curr_param['type'] in allowed_types: + print("Error: %s type not supported: curr_param['type']" % (curr_param['name'],curr_param['type']) ) + sys.Exit(1) + + curr_param['group'] = group_name + if (param.GetCategory()): + curr_param['category'] = param.GetCategory() + + if (param.GetVolatile() == "true"): + curr_param['volatile'] = param.GetVolatile() + + last_param_name = param.GetName() + for code in param.GetFieldCodes(): + value = param.GetFieldValue(code) + if code == "board": + if value == board: + board_specific_param_set = True + # JSON schema has no field for board_specific schema. Ignore. + else: + #xml_group.remove(xml_param) + continue + else: + #map PX4 param field names to schema names + if code in schema_map: + curr_param[schema_map[code]] = value + else: + print('ERROR: Field not in json schema: %s' % code) + sys.exit(1) + + + if last_param_name != param.GetName(): + board_specific_param_set = False + + enum_codes=param.GetEnumCodes() or '' # Gets numerical values for parameter. + if enum_codes: + enum_codes=sorted(enum_codes,key=float) + codes_list=list() + for item in enum_codes: + code_dict=dict() + code_dict['value']=item + code_dict['description']=param.GetEnumValue(item) + codes_list.append(code_dict) + curr_param['values'] = codes_list + + + if len(param.GetBitmaskList()) > 0: + bitmasks_list=list() + for index in param.GetBitmaskList(): + bitmask_dict=dict() + bitmask_dict['index']=index + bitmask_dict['description']=param.GetBitmaskBit(index) + bitmasks_list.append(bitmask_dict) + curr_param['bitmask'] = bitmasks_list + + + all_params.append(curr_param) + + + #Json string output. + self.output = json.dumps(all_json,indent=2) + + + def Save(self, filename): + with codecs.open(filename, 'w', 'utf-8') as f: + f.write(self.output) + diff --git a/src/lib/parameters/px_process_params.py b/src/lib/parameters/px_process_params.py index 243efe286a..a52b4d286c 100755 --- a/src/lib/parameters/px_process_params.py +++ b/src/lib/parameters/px_process_params.py @@ -33,7 +33,7 @@ ############################################################################ # -# PX4 paramers processor (main executable file) +# PX4 paramaters processor (main executable file) # # This tool scans the PX4 source code for declarations of tunable parameters # and outputs the list in various formats. @@ -47,12 +47,22 @@ from __future__ import print_function import sys import os import argparse -from px4params import srcscanner, srcparser, injectxmlparams, xmlout, markdownout +from px4params import srcscanner, srcparser, injectxmlparams, xmlout, markdownout, jsonout +import gzip #to create .gz file import re import json import codecs +def SaveCompressed(filename): + #create gz compressed version + gz_filename=filename+'.gz' + with gzip.open(gz_filename, 'wt') as f: + with open(filename, 'r') as content_file: + f.write(content_file.read()) + + + def main(): # Parse command line arguments parser = argparse.ArgumentParser(description="Process parameter documentation.") @@ -84,9 +94,18 @@ def main(): metavar="FILENAME", help="Create Markdown file" " (default FILENAME: parameters.md)") + parser.add_argument("-j", "--json", + nargs='?', + const="parameters.json", + metavar="FILENAME", + help="Create Json file" + " (default FILENAME: parameters.json)") parser.add_argument('-v', '--verbose', action='store_true', help="verbose output") + parser.add_argument('-c', '--compress', + action='store_true', + help="compress parameter file") parser.add_argument("-o", "--overrides", default="{}", metavar="OVERRIDES", @@ -95,7 +114,7 @@ def main(): args = parser.parse_args() # Check for valid command - if not (args.xml or args.markdown): + if not (args.xml or args.markdown or args.json): print("Error: You need to specify at least one output method!\n") parser.print_usage() sys.exit(1) @@ -134,22 +153,40 @@ def main(): param.default = val print("OVERRIDING {:s} to {:s}!!!!!".format(name, val)) + output_files = [] + # Output to XML file if args.xml: if args.verbose: print("Creating XML file " + args.xml) out = xmlout.XMLOutput(param_groups, args.board) out.Save(args.xml) + output_files.append(args.xml) # Output to Markdown/HTML tables if args.markdown: - out = markdownout.MarkdownTablesOutput(param_groups) - if args.markdown: + if args.verbose: print("Creating markdown file " + args.markdown) - out.Save(args.markdown) + out = markdownout.MarkdownTablesOutput(param_groups) + out.Save(args.markdown) + output_files.append(args.markdown) - #print("All done!") + # Output to JSON file + if args.json: + if args.verbose: + print("Creating Json file " + args.json) + cur_dir = os.path.dirname(os.path.realpath(__file__)) + out = jsonout.JsonOutput(param_groups, args.board, + os.path.join(cur_dir, args.inject_xml)) + out.Save(args.json) + output_files.append(args.json) + if args.compress: + for f in output_files: + if args.verbose: + print("Compressing file " + f) + SaveCompressed(f) + if __name__ == "__main__": main()