init
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
// Copyright 2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef CMD_OFFSETS_H
|
||||
#define CMD_OFFSETS_H
|
||||
|
||||
#include <stages/adsp_module.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "cmds.h"
|
||||
%for name in cmd_map:
|
||||
#include "${name}_config.h"
|
||||
%endfor
|
||||
|
||||
typedef struct {
|
||||
uint32_t cmd_id; // CmdID
|
||||
uint32_t offset; // offset
|
||||
uint32_t size; //size
|
||||
}module_config_offsets_t;
|
||||
|
||||
%for name, data in cmd_map.items():
|
||||
// Offset and size of fields in the ${name}_config_t structure
|
||||
static module_config_offsets_t ${name}_config_offsets[] = {
|
||||
%for field_name, field_data in data.items():
|
||||
<% field_data["size"] = field_data["size"] if "size" in field_data else 1 %>\
|
||||
{.cmd_id=CMD_${name.upper()}_${field_name.upper()}, .offset=offsetof(${name}_config_t, ${field_name}), .size=sizeof(${field_data["type"]}) * ${field_data["size"]}},
|
||||
%endfor
|
||||
};
|
||||
%endfor
|
||||
|
||||
static module_config_offsets_t *ptr_module_offsets[] = {
|
||||
%for name, data in cmd_map.items():
|
||||
${name}_config_offsets,
|
||||
%endfor
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
%for name in cmd_map:
|
||||
e_dsp_stage_${name},
|
||||
%endfor
|
||||
num_dsp_stages
|
||||
}all_dsp_stages_t;
|
||||
|
||||
#endif
|
||||
17
lib_audio_dsp/python/audio_dsp/design/templates/cmds_h.mako
Normal file
17
lib_audio_dsp/python/audio_dsp/design/templates/cmds_h.mako
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef CMDS_H
|
||||
#define CMDS_H
|
||||
|
||||
%for name, data in cmd_map.items():
|
||||
// ${name} module commands
|
||||
<% cmd_id = 1 %>\
|
||||
%for field_name, field_data in data.items():
|
||||
#define CMD_${name.upper()}_${field_name.upper()} ${cmd_id}
|
||||
<% cmd_id = cmd_id + 1 %>\
|
||||
%endfor
|
||||
#define NUM_CMDS_${name.upper()} ${len(data)} // Number of commands in the ${name} module
|
||||
|
||||
%endfor
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
%for name in cmd_map:
|
||||
#include "${name}_config.h"
|
||||
%endfor
|
||||
|
||||
#if OFFSET_GEN
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
FILE *fp;
|
||||
printf("argc = %d\n", argc);
|
||||
if(argc == 2)
|
||||
{
|
||||
printf("argv = %s\n", argv[1]);
|
||||
fp = fopen(argv[1], "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
fp = fopen("cmd_offset_size.h", "w");
|
||||
}
|
||||
fprintf(fp, "#ifndef CMD_NUM_VALUES_H\n");
|
||||
fprintf(fp, "#define CMD_NUM_VALUES_H\n\n");
|
||||
|
||||
// Number of values read or written as part of the command. Used in the host cmd_map.c file. Needs to be generated by running
|
||||
// an application since the config yaml files might specified size in terms of #defines (for eg. FILTERS * NUM_COEFFS_PER_BIQUAD)
|
||||
%for name, data in cmd_map.items():
|
||||
%for field_name, field_data in data.items():
|
||||
<%
|
||||
if "size" in field_data:
|
||||
size = field_data["size"]
|
||||
elif field_data["type"] == "float_s32_t":
|
||||
size = 2
|
||||
else:
|
||||
size = 1
|
||||
%>\
|
||||
fprintf(fp, "#define NUM_VALUES_${name.upper()}_${field_name.upper()} %u\n", ${size});
|
||||
fprintf(fp, "\n");
|
||||
%endfor
|
||||
%endfor
|
||||
fprintf(fp, "#endif\n");
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "cmd_num_values.h"
|
||||
#include "cmds.h"
|
||||
|
||||
static cmd_t commands[] =
|
||||
{
|
||||
%for name, data in cmd_map.items():
|
||||
%for field_name, field_data in data.items():
|
||||
<%
|
||||
field_data["size"] = field_data["size"] if "size" in field_data else 1
|
||||
cmd_type = {'int32_t': 'TYPE_INT32', 'int16_t': 'TYPE_INT16', 'int8_t': 'TYPE_CHAR', 'uint8_t': 'TYPE_UINT8', 'float': 'TYPE_FLOAT', 'int': 'TYPE_INT32', 'uint32_t': 'TYPE_UINT32', 'float_s32_t': 'TYPE_INT32', 'int32_t*': 'TYPE_INT32'}
|
||||
%>\
|
||||
{0xff, "${name.upper()}_${field_name.upper()}", ${cmd_type[field_data["type"]]}, CMD_${name.upper()}_${field_name.upper()}, CMD_READ_WRITE, NUM_VALUES_${name.upper()}_${field_name.upper()}, "${field_data["help"].strip()}", false},
|
||||
%endfor
|
||||
|
||||
%endfor
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
.. _${title}_stages:
|
||||
|
||||
${"#"*(len(title) + 7)}
|
||||
${title} Stages
|
||||
${"#"*(len(title) + 7)}
|
||||
|
||||
${docstring}
|
||||
|
||||
% for cl in classes:
|
||||
.. _${cl}_stage:
|
||||
|
||||
${"="*len(cl)}
|
||||
${cl}
|
||||
${"="*len(cl)}
|
||||
|
||||
.. autoclass:: audio_dsp.stages.${cl}
|
||||
:noindex:
|
||||
:members:
|
||||
:inherited-members: Stage
|
||||
<%
|
||||
|
||||
## Get the parameter type from the stage.set_parameters method
|
||||
import importlib
|
||||
import inspect
|
||||
from typing import get_type_hints
|
||||
import types
|
||||
import audio_dsp
|
||||
# Import the stage class
|
||||
stages_mod = importlib.import_module('audio_dsp.stages')
|
||||
stage_cls = getattr(stages_mod, cl)
|
||||
# Get the set_parameters method
|
||||
set_params = getattr(stage_cls, 'set_parameters')
|
||||
# Get the type hints for the method
|
||||
hints = get_type_hints(set_params)
|
||||
# Assume the first argument after 'self' is the model class
|
||||
params = inspect.signature(set_params).parameters
|
||||
param_names = list(params.keys())
|
||||
# Skip 'self', get the next parameter
|
||||
param_name = param_names[1]
|
||||
model_cls = hints.get(param_name)
|
||||
|
||||
if model_cls == audio_dsp.design.stage.StageParameterType:
|
||||
# generic StageParameterType, so no specific model class
|
||||
model_cls = []
|
||||
elif type(model_cls) == types.UnionType:
|
||||
# If it's a Union, there's multiple types
|
||||
model_cls = list(model_cls.__args__)
|
||||
else:
|
||||
model_cls = [model_cls]
|
||||
|
||||
for i, cls in enumerate(model_cls):
|
||||
# get the full class path
|
||||
model_cls[i] = f"{cls.__module__}.{cls.__name__}"
|
||||
|
||||
%>
|
||||
% for param_cls in model_cls:
|
||||
.. autopydantic_model:: ${param_cls}
|
||||
:noindex:
|
||||
:members:
|
||||
:inherited-members: StageParameters
|
||||
% endfor ## for cls in model_cls
|
||||
|
||||
|
||||
${cl} Control
|
||||
${"="*len(cl)}========
|
||||
|
||||
% if class_data[cl]:
|
||||
The following runtime command ids are available for the ${cl} Stage. For
|
||||
details on reading and writing these commands, see the Run-Time Control User Guide.
|
||||
|
||||
<%
|
||||
row_list = []
|
||||
max_cmd = len("Command ID macro") + 2 # add 2 so the title doesn't ever get split in the PDF
|
||||
max_pay = len("Payload length")
|
||||
max_help = len("Description")
|
||||
for field_name, field_data in class_data[cl].items():
|
||||
import re
|
||||
size_str = "*[" + str(field_data['size']) + "]" if "size" in field_data else ""
|
||||
help_str = f'{field_data["help"].strip()}' if "help" in field_data else ""
|
||||
if "rw_type" in field_data and field_data["rw_type"] == "CMD_READ_ONLY":
|
||||
help_str += " This command is read only. When sending a write control command, it will be ignored."
|
||||
safe_name = cl.replace("RMS", "Rms")
|
||||
snake_name = re.sub(r'(?<!^)(?=[A-Z])', '_', safe_name).upper()
|
||||
cmd_str = f"CMD_{snake_name}_{field_name.upper()}"
|
||||
payload_str = f"``sizeof({field_data['type']}){size_str}``"
|
||||
this_row = [cmd_str, payload_str, help_str]
|
||||
row_list.append(this_row)
|
||||
|
||||
if len(cmd_str) > max_cmd:
|
||||
max_cmd = len(cmd_str)
|
||||
if len(payload_str) > max_pay:
|
||||
max_pay = len(payload_str)
|
||||
if len(help_str) > max_help:
|
||||
max_help = len(help_str)
|
||||
|
||||
page_width = 74 # this is a guesstimate of number of chars in a page
|
||||
cmd_width = int((max_cmd/page_width)*100)
|
||||
pay_width = int(((max_pay - 5)/page_width)*100) # subtract ` chars and compensate for font (ish)
|
||||
help_width = 100 - pay_width
|
||||
|
||||
%>
|
||||
## do the printing, use ljust to pad to max size
|
||||
.. table::
|
||||
:widths: ${help_width}, ${pay_width}
|
||||
% if len(row_list) > 6:
|
||||
:class: longtable
|
||||
%endif
|
||||
|
||||
${"="*max_help} ${"="*max_pay}
|
||||
${"Control parameter".ljust(max_help)} ${"Payload length".ljust(max_pay)}
|
||||
${"="*max_help} ${"="*max_pay}
|
||||
% for row in row_list:
|
||||
${row[0].ljust(max_help)} ${row[1].ljust(max_pay)}
|
||||
% if "²" in row[2]: ## ljust in Mako ignores ², no idea why
|
||||
${row[2].ljust(max_help + 1)} ${'\\'.ljust(max_pay)}
|
||||
% else:
|
||||
${row[2].ljust(max_help)} ${'\\'.ljust(max_pay)}
|
||||
%endif ## "²" in row[2]:
|
||||
% if row_list.index(row) < len(row_list) - 1:
|
||||
## don't print a blank row at the end
|
||||
|
|
||||
${"-"*max_help}--${"-"*max_pay}
|
||||
% endif ## row_list.index(row) < len(row_list) - 1
|
||||
% endfor ## row in row_list
|
||||
${"="*max_help} ${"="*max_pay}
|
||||
|
||||
% else: ## class_data[cl]
|
||||
|
||||
The ${cl} Stage has no runtime controllable parameters.
|
||||
|
||||
% endif ## class_data[cl]
|
||||
|
||||
% endfor ## cl in classes
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2024 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef ${name.upper()}_CONFIG_H
|
||||
#define ${name.upper()}_CONFIG_H
|
||||
|
||||
%for i in includes:
|
||||
#include <${i}>
|
||||
%endfor
|
||||
|
||||
%for d in defines:
|
||||
#define ${d} ${defines[d]}
|
||||
%endfor
|
||||
|
||||
/**
|
||||
* This structure allows for real time control of the ${name} stage.
|
||||
* It should be passed to the ${name}_control function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
%for field_name, field_data in data.items():
|
||||
<%
|
||||
attrib_str = f'{field_data["attribute"]} ' if "attribute" in field_data else ""
|
||||
size_str = "[" + str(field_data['size']) + "]" if "size" in field_data else ""
|
||||
help_str = f'{field_data["help"]} ' if "help" in field_data else ""
|
||||
%>\
|
||||
<%block filter="wrap_helpstr">
|
||||
${help_str}
|
||||
</%block>
|
||||
${field_data["type"]} ${attrib_str}${field_name}${size_str};
|
||||
|
||||
%endfor
|
||||
}${name}_config_t;
|
||||
|
||||
#endif
|
||||
|
||||
<%!
|
||||
# This is a function to wrap long help descriptions
|
||||
import textwrap
|
||||
def wrap_helpstr(text):
|
||||
line_len = 80
|
||||
max_len = line_len - 4 - 4 - 3
|
||||
if len(text) > line_len:
|
||||
return " /**\n * " + '\n'.join(textwrap.wrap(text.strip(), line_len, subsequent_indent=' * ')).strip() + "\n */"
|
||||
else:
|
||||
return f" /** {text.strip()} */"
|
||||
%>
|
||||
Reference in New Issue
Block a user