Subsections
This section gives an overview of the module-creation and the use
of it. Even though gives an example of how
to create a new module, it is a good idea to read at least this introduction,
so that you know what it is about.
Before a module can be used, it usually has to go through the following
steps:
- Registration with the CDB, usually in module_init, this happens
when loading the module into memory
- Instantiation, which means setting up the needed memory and calling
init
- A call to reconfig to assure that everything is OK
The points 2 and 3 are done automatically when calling swr_sdb_instantiate_*
and may happen more than once, where a new memory-block is allocated
for each instantiation, in order to make sure that all copies of the
module work in an independent way.
Once this has been done, a module can be asked to do one of the following
tasks:
- [pdata]Process an incoming data-block and eventually produce some
output-data
- [reconfig]Reconfigure itself because one of the configuration variables
have been changed
- [resize]Re-calculate its input- and output-sizes
- [custom-msg]React to a user-message
- [finalize]Clean up allocated values
The names to the left are the internal names used in the module-definition.
You will never call these functions directly, but rather ask the MSR
to do something that will then call one of these functions. So if
you reconfigure one module using swr_sdb_set_configure_int
you ask the MSR to set the configuration of this module-instance to
a certain value and to call the appropriate reconfig function.
Data Structures
A module has three different data-structures:
- [config]Where other modules may ask for a change in the behaviour
- [stats]Results from the signal-processing
- [private]Internal structure that is not available to the outside
While the first two have already been discussed a bit, the third is
new. It may be used for internal tables built depending on the configuration,
it may contain a copy of important config-parameters or anything else
needed for a module to function correctly. An important point: the
private-structure is personal to each copy of the module, so it is
not suited to keep 'global' options.
The config and stats structures are protected by mutexes, as they
are open to all other modules to use. So in order to use a config-structure,
one has first to call
-
- swr_sdb_get_config_struct( context->id, (void**)&config );
before being able to use config->something. To
free the structure, use
-
- swr_sdb_free_config_struct( context->id, (void**)&config );
after which other modules can alos access this structure. The same
goes for the stats-structure. You don't have to make this extra effort
with the private-structure, as they are local to each instance anyway.
Data Types
Blocks
Blocks are a defined in the following way:
-
- typedef struct {
void *data;
int size;
swr_signal_type_t type;
} block_t;
They can be used to give a window into an internal vector. The matched-filter
module for example has a block that points to the matched-filter used,
so the user can see the matched-filter in real-time, using the visualisation
tool.
The data pointer has to point to the vectory you want to display,
size is the size in units of type, which is one of the
Data-Types described in here (w/o Block, of course).
-
- typedef struct {
short int real;
short int imag;
} SYMBOL_COMPLEX;
-
- typedef struct {
int real;
int imag;
} SYMBOL_COMPLEX;
Describes one complex symbol in a special format. It is done like
this:
The utility of this is that if we want to do a complex multiplication,
we can arrange the second complex number in the following way:
And then a special MMX-operation on these two complex numbers yields
directly the result, separated into real and imaginary part. This
is very useful for convolutions that need to be optimised.
- [U8]Unsigned 8-bit
- [S8]Signed 8-bit
- [U32]Unsigned 32-bit
- [S32]Signed 32-bit
- [SAMPLE_S12]Signed 12-bit, where the 12 upper bits are used. For
the available hardware, the lower 4 bits signal RX/TX
- [SYMBOL_S16]Signed 16-bit real symbol
Macros
Each function that is defined in a module takes at least one argument:
swr_sdb_t *context In there all necessary information to
distinguish one instance of another is stored. As this information
may be a bit difficult to access, a lot of macros allow easy access
to this information. These macros are defined in spc.h which
is already included in the templates.
This function is a bit special in that it only registers the module
with the CDB and doesn't do any actual signal-processing. So these
are the macros you can use:
- [UM_CONFIG_INT]adds an int-parameter to the configuration
- [UM_CONFIG_DOUBLE]adds a double-parameter to the configuration
- [UM_CONFIG_STR128]adds a char[128] parameter to the configuration
- [UM_CONFIG_POINTER]adds a void* parameter to the configuration
- [UM_STATS_INT]adds an int-parameter to the statistics
- [UM_STATS_DOUBLE]adds a double-parameter to the statistics
- [UM_STATS_STR128]adds a char[128] parameter to the statistics
- [UM_STATS_POINTER]adds a void* parameter to the statistics
- [UM_STATS_BLOCK]adds a block_t parameter to the statistics, see
17.4.3.1
- [UM_INPUT]adds an input-port, for the types see ,
and allows to define a flag
- [UM_OUTPUT]adds an output-port, for the types see ,
and allows to define a flag
- [private]allows access to this modules private-structure
- [size_in(n)]returns the input-size of the port n. This may
also be used to assign a size to a port, so size_in(0)=256;
is valid.
- [size_out(n)]returns the output-size of the port n. Allocating
sizes is possible as with size_in.
- [data_available(n)]returns true if the input-port n has some
new data
- [buffer_in(n)]returns a pointer to the input-buffer n and
clears the data-flag on this input-port
- [buffer_out(n)]returns a pointer to the output-buffer n and
sets the data-flag on this output-port
Linus Gasser
2004-04-14