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