View on GitHub

newsched

The GNU Radio 4.0 Runtime Proof Of Concept

Block Design Workflow

Creating a custom block in newsched is designed to be as easy as possible and get the developer right to the “insert signal processing here” part

gr_modtool Substitute

Partly out of “getting it done quickly” and partly out of leveraging the simplicity of the new block design, there are some simple scripts to create modules and blocks rather than any gr_modtool integration at this point

Integration into a new gr_modtool would be a highly desirable feature for newsched

Create a new module

Let’s assume the newsched source tree lives at $NEWSCHED_SRC, which is likely $PREFIX/src/newsched, and we want to create an out of tree module named myoot

cd $PREFIX/src
python3 $NEWSCHED_SRC/utils/modtool/create_mod.py myoot

This has now created a skeleton module structure at $NEWSCHED_SRC/ns-myoot/

Now, we can create a block that we will use to do our signal processing

cd ns-myoot
python3 $NEWSCHED_SRC/utils/modtool/create_block.py foo --cpu

The create_block.py script will generate the block with the desired reference implementation (--cpu and/or --cuda)

usage: create_block.py [-h] [--cpu] [--cuda] [--templated] block_name

Also, with the --templated flag, a block that will be templated across a variety of possible datatypes (complex, float, etc.) will be generated and can be modified accordingly

Now, let’s look at the components of the block that was generated

The YAML File

The files for each block lives in it’s own directory, and the main file driving much of the underlying code generation is the yaml file - in this case foo.yml

At the top of the yaml file, we have some basic information

module: myoot # <-- the module to which this block belongs
block: foo    # <-- the name of the block - needs to match the dir
label: foo    # <-- the label as it would show up in GRC
blocktype: sync_block  # <-- the type of the block as in c++ class names {sync_block, block }

If the block is templated, we have a section for how the templated code will be generated

typekeys:
  - id: T # <-- an id for the template key
    type: class # <-- the type of template parameter
    options:    
      - value: int16_t # <-- the c++ datatype to be explicitly instantiated
        suffix: ss     # <-- suffix given for typedef, e.g. add_ss
      - value: int32_t 
        suffix: ii 
      - value: float
        suffix: ff   
      - value: gr_complex 
        suffix: cc 

Next, we have parameters, which define how the block will be instantiated and accessed. Unless told otherwise, all parameters become constructor arguments. Set cotr: false to not have a parameter as a constructor argument. It can then have only setter and/or getter

parameters:
-   id: k            # <-- the name of the parameter
    label: Constant  # <-- for GRC purposes
    dtype: T         # <-- the datatype - can be any c++ datatype, or one of the typekeys
    settable: true   # <-- if true, will create set_k() and k() methods
-   id: vlen
    label: Vec. Length
    dtype: size_t
    settable: false
    default: 1       # <-- default value, must go last in list (no non-default value parameters after a default)

## additionally, can set
#   cotr: false      #< -- this will make the parameter not appear in the constructor, but can be set or queried via accessors

The ports reference how blocks will be connected together and with what corresponding types

ports:
-   domain: stream  # <-- {stream, message}
    id: in          # <-- give the port a name
    direction: input  #<-- {input, output}
    type: typekeys/T  # <-- lookup in the typekeys section, type T
    dims: parameters/vlen  # <-- lookup in the parameters section, value of vlen

-   domain: stream
    id: out
    direction: output
    type: typekeys/T
    dims: parameters/vlen

The implementations section is super-important. This will determine which implementations you will be specifying in the c++ files that live with the yaml file

In the example below, we will be including a foo_cpu.cc file, but have decided to not compile a foo_cuda.cc

In the top level meson.build, it is important that for each implementation, an IMPLEMENT_IMPL variable is set. In this case, we would need IMPLEMENT_CPU=true set somewhere in that meson.build

implementations:
-   id: cpu
# -   id: cuda

Next: Implementing the Block