2016-03-17 02:04:03 -03:00
#!/usr/bin/env python
2016-11-08 07:06:05 -04:00
from __future__ import print_function
2016-03-17 02:04:03 -03:00
import re
2017-05-02 07:36:14 -03:00
from param import known_param_fields , known_units
2016-03-17 02:04:03 -03:00
from emit import Emit
2021-01-02 01:08:25 -04:00
try :
from cgi import escape as cescape
except Exception :
from html import escape as cescape
2016-03-17 02:04:03 -03:00
2016-07-31 07:22:06 -03:00
2016-03-17 02:04:03 -03:00
# Emit docs in a RST format
class RSTEmit ( Emit ) :
def blurb ( self ) :
2016-07-31 07:22:06 -03:00
return """ This is a complete list of the parameters which can be set (e.g. via the MAVLink protocol) to control vehicle behaviour. They are stored in persistent storage on the vehicle.
2016-03-17 02:04:03 -03:00
This list is automatically generated from the latest ardupilot source code , and so may contain parameters which are not yet in the stable released versions of the code .
2018-10-07 22:20:54 -03:00
""" # noqa
2016-07-31 07:22:06 -03:00
2016-03-17 02:04:03 -03:00
def toolname ( self ) :
return " Tools/autotest/param_metadata/param_parse.py "
2021-08-18 21:37:55 -03:00
def output_fname ( self ) :
return ' Parameters.rst '
2021-04-07 00:12:41 -03:00
def __init__ ( self , * args , * * kwargs ) :
Emit . __init__ ( self , * args , * * kwargs )
2021-08-18 21:37:55 -03:00
self . f = open ( self . output_fname ( ) , mode = ' w ' )
2016-03-17 02:04:03 -03:00
self . spacer = re . compile ( " ^ " , re . MULTILINE )
self . rstescape = re . compile ( " ([^a-zA-Z0-9 \n ]) " )
2023-01-08 23:29:38 -04:00
self . emitted_sitl_heading = False
2023-01-06 20:59:44 -04:00
parameterlisttype = " Complete Parameter List "
2021-04-07 01:52:02 -03:00
parameterlisttype + = " \n " + " = " * len ( parameterlisttype )
2016-07-31 07:22:06 -03:00
self . preamble = """ .. Dynamically generated list of documented parameters
2016-03-17 02:04:03 -03:00
. . This page was generated using { toolname }
. . DO NOT EDIT
2016-03-22 04:31:05 -03:00
. . _parameters :
2016-03-17 02:04:03 -03:00
2021-04-07 01:52:02 -03:00
{ parameterlisttype }
2016-03-17 02:04:03 -03:00
{ blurb }
2016-07-31 07:22:06 -03:00
""" .format(blurb=self.escape(self.blurb()),
2021-04-07 01:52:02 -03:00
parameterlisttype = parameterlisttype ,
2016-03-17 02:04:03 -03:00
toolname = self . escape ( self . toolname ( ) ) )
self . t = ' '
def escape ( self , s ) :
2021-08-18 21:37:55 -03:00
ret = re . sub ( self . rstescape , r " \\ \ g<1> " , s )
2016-03-17 02:04:03 -03:00
return ret
def close ( self ) :
self . f . write ( self . preamble )
self . f . write ( self . t )
self . f . close ( )
def start_libraries ( self ) :
pass
2016-04-05 21:38:38 -03:00
def tablify_row ( self , rowheading , row , widths , height ) :
joiner = " | "
2016-07-31 07:22:06 -03:00
row_lines = [ x . split ( " \n " ) for x in row ]
2016-04-05 21:38:38 -03:00
for row_line in row_lines :
2016-07-31 07:22:06 -03:00
row_line . extend ( [ " " ] * ( height - len ( row_line ) ) )
2016-04-05 21:38:38 -03:00
if rowheading is not None :
rowheading_lines = rowheading . split ( " \n " )
2016-07-31 07:22:06 -03:00
rowheading_lines . extend ( [ " " ] * ( height - len ( rowheading_lines ) ) )
2016-04-05 21:38:38 -03:00
out_lines = [ ]
2016-07-31 07:22:06 -03:00
for i in range ( 0 , height ) :
2016-04-05 21:38:38 -03:00
out_line = " "
if rowheading is not None :
rowheading_line = rowheading_lines [ i ]
2016-07-31 07:22:06 -03:00
out_line + = joiner + " " + rowheading_line + " " * ( widths [ 0 ] - len ( rowheading_line ) - 1 )
2016-04-05 21:38:38 -03:00
joiner = " # "
2016-07-31 07:22:06 -03:00
j = 0
2016-04-05 21:38:38 -03:00
for item in row_lines :
widthnum = j
if rowheading is not None :
widthnum + = 1
line = item [ i ]
2016-07-31 07:22:06 -03:00
out_line + = joiner + " " + line + " " * ( widths [ widthnum ] - len ( line ) - 1 )
2016-04-05 21:38:38 -03:00
joiner = " | "
j + = 1
out_line + = " | "
out_lines . append ( out_line )
return " \n " . join ( out_lines )
2016-07-31 07:22:06 -03:00
def tablify_longest_row_length ( self , rows , rowheadings , headings ) :
2016-04-05 21:38:38 -03:00
check_width_rows = rows [ : ]
if headings is not None :
check_width_rows . append ( headings )
longest_row_length = 0
for row in check_width_rows :
if len ( row ) > longest_row_length :
longest_row_length = len ( row )
if rowheadings is not None :
longest_row_length + = 1
return longest_row_length
def longest_line_in_string ( self , string ) :
longest = 0
for line in string . split ( " \n " ) :
if len ( line ) > longest :
longest = len ( line )
return longest
def tablify_calc_row_widths_heights ( self , rows , rowheadings , headings ) :
rows_to_check = [ ]
if headings is not None :
rows_to_check . append ( headings )
rows_to_check . extend ( rows [ : ] )
heights = [ 0 ] * len ( rows_to_check )
2016-07-31 07:22:06 -03:00
longest_row_length = self . tablify_longest_row_length ( rows , rowheadings , headings )
2016-04-05 21:38:38 -03:00
widths = [ 0 ] * longest_row_length
all_rowheadings = [ ]
if rowheadings is not None :
if headings is not None :
all_rowheadings . append ( " " )
all_rowheadings . extend ( rowheadings )
2016-07-31 07:22:06 -03:00
for rownum in range ( 0 , len ( rows_to_check ) ) :
2016-04-05 21:38:38 -03:00
row = rows_to_check [ rownum ]
values_to_check = [ ]
if rowheadings is not None :
values_to_check . append ( all_rowheadings [ rownum ] )
values_to_check . extend ( row [ : ] )
colnum = 0
for value in values_to_check :
height = len ( value . split ( " \n " ) )
if height > heights [ rownum ] :
heights [ rownum ] = height
longest_line = self . longest_line_in_string ( value )
2016-07-31 07:22:06 -03:00
width = longest_line + 2 # +2 for leading/trailing ws
2016-04-05 21:38:38 -03:00
if width > widths [ colnum ] :
widths [ colnum ] = width
colnum + = 1
2016-07-31 07:22:06 -03:00
return ( widths , heights )
2016-04-05 21:38:38 -03:00
def tablify ( self , rows , headings = None , rowheadings = None ) :
2016-07-31 07:22:06 -03:00
( widths , heights ) = self . tablify_calc_row_widths_heights ( rows , rowheadings , headings )
2016-03-17 02:04:03 -03:00
# create dividing lines
bar = " "
heading_bar = " "
for width in widths :
bar + = " + "
heading_bar + = " + "
bar + = " - " * width
heading_bar + = " = " * width
bar + = " + "
heading_bar + = " + "
# create table
ret = bar + " \n "
2016-04-05 21:38:38 -03:00
if headings is not None :
rowheading = None
if rowheadings is not None :
rowheading = " "
ret + = self . tablify_row ( rowheading , headings , widths , heights [ 0 ] ) + " \n "
ret + = heading_bar + " \n "
2016-07-31 07:22:06 -03:00
for i in range ( 0 , len ( rows ) ) :
2016-04-05 21:38:38 -03:00
rowheading = None
height = i
if rowheadings is not None :
rowheading = rowheadings [ i ]
if headings is not None :
height + = 1
ret + = self . tablify_row ( rowheading , rows [ i ] , widths , heights [ height ] ) + " \n "
2016-03-17 02:04:03 -03:00
ret + = bar + " \n "
return ret
2016-04-05 21:38:38 -03:00
def render_prog_values_field ( self , render_info , param , field ) :
values = ( param . __dict__ [ field ] ) . split ( ' , ' )
rows = [ ]
for value in values :
2016-07-31 07:22:06 -03:00
v = [ x . strip ( ) for x in value . split ( ' : ' ) ]
2016-04-05 21:38:38 -03:00
rows . append ( v )
return self . tablify ( rows , headings = render_info [ " headings " ] )
2021-08-18 21:37:55 -03:00
def render_table_headings ( self , ret , row , headings , field_table_info , field , param ) :
row . append ( self . render_prog_values_field ( field_table_info [ field ] , param , field ) )
return ' '
2018-12-06 05:07:51 -04:00
def emit ( self , g ) :
2023-01-08 23:29:38 -04:00
# make only a single group for SIM_ parameters
do_emit_heading = True
if g . reference . startswith ( " SIM_ " ) :
if self . emitted_sitl_heading :
do_emit_heading = False
self . emitted_sitl_heading = True
tag = " Simulation Parameters "
reference = " parameters_sim "
else :
tag = ' %s Parameters ' % self . escape ( g . reference )
reference = " parameters_ " + g . reference
2016-04-05 21:38:38 -03:00
field_table_info = {
" Values " : {
2016-07-31 07:22:06 -03:00
" headings " : [ ' Value ' , ' Meaning ' ] ,
2016-04-05 21:38:38 -03:00
} ,
" Bitmask " : {
2016-07-31 07:22:06 -03:00
" headings " : [ ' Bit ' , ' Meaning ' ] ,
} ,
2016-04-05 21:38:38 -03:00
}
2023-01-08 23:29:38 -04:00
ret = " "
if do_emit_heading :
ret = """
2016-03-17 02:04:03 -03:00
2016-03-21 06:56:49 -03:00
. . _ { reference } :
2016-03-17 02:04:03 -03:00
{ tag }
{ underline }
2016-07-31 07:22:06 -03:00
""" .format(tag=tag, underline= " - " * len(tag),
2016-03-21 06:56:49 -03:00
reference = reference )
2016-03-17 02:04:03 -03:00
for param in g . params :
if not hasattr ( param , ' DisplayName ' ) or not hasattr ( param , ' Description ' ) :
continue
d = param . __dict__
2018-09-24 03:02:18 -03:00
# Get param path if defined (i.e. is duplicate parameter)
param_path = getattr ( param , ' path ' , ' ' )
2021-04-06 23:48:40 -03:00
name = param . name . split ( ' : ' ) [ - 1 ]
2018-09-24 03:02:18 -03:00
tag_param_path = ' ( %s ) ' % param_path if param_path else ' '
tag = ' %s %s : %s ' % ( self . escape ( name ) , self . escape ( tag_param_path ) , self . escape ( param . DisplayName ) , )
2016-03-17 02:04:03 -03:00
tag = tag . strip ( )
reference = param . name
# remove e.g. "ArduPlane:" from start of parameter name:
2021-04-06 23:48:40 -03:00
reference = reference . split ( " : " ) [ - 1 ]
2018-09-24 03:02:18 -03:00
if param_path :
reference + = ' __ ' + param_path
2016-03-21 06:56:49 -03:00
2016-07-31 07:22:06 -03:00
ret + = """
2016-03-17 02:04:03 -03:00
. . _ { reference } :
{ tag }
{ tag_underline }
2016-07-31 07:22:06 -03:00
""" .format(tag=tag, tag_underline= ' ~ ' * len(tag), reference=reference)
2016-03-17 02:04:03 -03:00
2016-07-31 07:22:06 -03:00
if d . get ( ' User ' , None ) == ' Advanced ' :
2016-03-17 02:04:03 -03:00
ret + = ' \n | *Note: This parameter is for advanced users* '
2021-08-17 23:50:29 -03:00
if d . get ( ' RebootRequired ' , None ) == ' True ' :
ret + = ' \n | *Note: Reboot required after change* '
elif ' RebootRequired ' in d and d . get ( ' RebootRequired ' ) != ' True ' :
raise Exception ( " Bad RebootRequired metadata tag value for {} in {} " . format ( d . get ( ' name ' ) , d . get ( ' real_path ' ) ) )
2016-03-17 02:04:03 -03:00
ret + = " \n \n %s \n " % self . escape ( param . Description )
headings = [ ]
2016-04-05 21:38:38 -03:00
row = [ ]
2020-04-14 23:48:29 -03:00
for field in sorted ( param . __dict__ . keys ( ) ) :
2021-08-18 21:37:55 -03:00
if ( field not in [ ' name ' , ' DisplayName ' , ' Description ' , ' User ' , ' RebootRequired ' ] and
field in known_param_fields ) :
2016-04-05 21:38:38 -03:00
headings . append ( field )
if field in field_table_info and Emit . prog_values_field . match ( param . __dict__ [ field ] ) :
2021-08-18 21:37:55 -03:00
ret + = self . render_table_headings ( ret , row , headings , field_table_info , field , param )
2016-04-05 21:38:38 -03:00
elif field == " Range " :
2016-07-31 07:22:06 -03:00
( param_min , param_max ) = ( param . __dict__ [ field ] ) . split ( ' ' )
2022-07-08 11:14:20 -03:00
row . append ( " %s to %s " % ( param_min , param_max , ) )
2017-05-02 07:36:14 -03:00
elif field == ' Units ' :
2021-08-17 17:10:34 -03:00
abbreviated_units = param . __dict__ [ field ]
if abbreviated_units != ' ' :
2018-10-07 22:20:54 -03:00
# use the known_units dictionary to
2021-08-17 17:10:34 -03:00
# convert the abbreviated unit into a full
2018-10-07 22:20:54 -03:00
# textual one:
2021-08-17 17:10:34 -03:00
units = known_units [ abbreviated_units ]
2021-01-02 01:08:25 -04:00
row . append ( cescape ( units ) )
2016-03-17 02:04:03 -03:00
else :
2021-01-02 01:08:25 -04:00
row . append ( cescape ( param . __dict__ [ field ] ) )
2016-04-05 21:38:38 -03:00
if len ( row ) :
ret + = " \n \n " + self . tablify ( [ row ] , headings = headings ) + " \n \n "
self . t + = ret + " \n "
2016-07-31 07:22:06 -03:00
2016-04-05 21:38:38 -03:00
def table_test ( ) :
e = RSTEmit ( )
print ( " Test 1 " )
2016-07-31 07:22:06 -03:00
print ( e . tablify ( [ [ " A " , " B " ] , [ " C " , " D " ] ] ) )
2016-04-05 21:38:38 -03:00
print ( " Test 2 " )
2016-11-08 07:06:05 -04:00
print ( e . tablify ( [ [ " A " , " B " ] , [ " CD \n E " , " FG " ] ] ) )
2016-04-05 21:38:38 -03:00
print ( " Test 3 " )
2016-07-31 07:22:06 -03:00
print ( e . tablify ( [ [ " A " , " B " ] , [ " CD \n EF " , " GH " ] ] , rowheadings = [ " r1 " , " row2 " ] ) )
2016-04-05 21:38:38 -03:00
print ( " Test 4 " )
2016-07-31 07:22:06 -03:00
print ( e . tablify ( [ [ " A " , " B " ] , [ " CD \n EF " , " GH " ] ] , headings = [ " c1 " , " col2 " ] ) )
2016-04-05 21:38:38 -03:00
print ( " Test 5 " )
2016-07-31 07:22:06 -03:00
print ( e . tablify ( [ [ " A " , " B " ] , [ " CD \n EF " , " GH " ] ] , headings = [ " c1 " , " col2 " ] , rowheadings = [ " r1 " , " row2 " ] ) )
2016-03-17 02:04:03 -03:00
2016-04-05 21:38:38 -03:00
if __name__ == ' __main__ ' :
table_test ( )