Scetion 1: The Flowgraph
The flowgraph moves data from sources into sinks.
一个流图由多个模块组成,其中一般包括信源(Source)模块和信宿(Sink)模块,然后通过连线将他们连接在一起并形成一个顶层模块(top_block类),最后通过调用顶层模块下的start()成员函数启动GNU Radio平台下的软件运行。在运行过程中,每一个模块都相当于是一个线程,通过GNU Radio平台下的调度机制将信源模块产生的数据经过一系列的处理模块,最后传输到信宿模块。这样一个运行过程包括了硬件驱动、数据buffer管理以及线程调度等工作。其中数据buffer的管理机制是零拷贝循环缓存(Section 4 会讲到),这样能够保证来自源的数据流高效在各个模块之间传输。
Example of data moving with rate changes.
GNU Radio 中的block根据输入输出样点的关系分为: 任意比例、1: 1,N: 1,1: N (Section 2会讲到),其中 sync 是1: 1的关系,即输出样点数等于输入样点数,decim是N: 1的关系,即输入: 输出 = N: 1。通过decim(抽取器)实现降速率传输。
The flowgraph must check the bounds to satify input/output requirements.
All input streams and output streams must satify the constraints.
Flowgraph 运行时会检查每个模块(block)是否满足输入输出的要求。每个模块的输出端口都绑定一个循环缓冲区(buffer),通过一个写指针 r_ptr 输出数据。它的下游模块通过一个读指针w_ptr 读取数据。每一个模块在满足输出缓冲区空间足够,并且输入缓冲区可读数据足够,该模块才能正常运行。对于上图 sync 模块来说,需要满足n_out >= 2048 && n_in >= 2048 该模块才能正常运行。
The boundary conditions can change with rate changing blocks.
Decimators need enough input to calculate the decimated output.
The conditions are independently established with each block.
This block is asking for less than it can on the input.
Scetion 2: The general_work and work functions
The input and output buffers
general_work / work have two vectors passed to it.
int
block::general_work(int output_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
int
block::work(int output_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
- intput_items is a vector of pointers to input buffers.
- output_items is a vector of pointers to output buffers.
前面提到,每一个模块(block)都是一个线程,general_work() / work()是该线程的入口函数。通过两个 vector: intput_items 和 output_items 分别控制输入输出缓冲区的读写。对于上图的sync 模块来说,它有两个输入端口,一个输出端口,那么input_items[0],input_items[1]分别是两个输入端口的读指针,output_items[0]是输出端口的写指针。
general_work has not input/output relationship
It's told the number of output and input items:
int
block::general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
- noutput_items: minimum number of output available on all output buffers.
- ninput_items: vector of items available on all input buffers.
general_work函数对应的模块的输入输出关系是任意的,通过noutput_items 和 nintput_items来控制输入和输出之间的关系。其中我们注意到:noutput_items是一个变量,而nintout_items 是vector。这是因为GNU Radio要求模块的每个输出端口产生的样点数都必须相同,而对于输入则没有这个要求。对于上图的 sync 模块来说,nintput_items[0],nintput_items[1]分别表示两个端口输入的样点数,noutput_items表示所有输出端口的样点数。
Number of input and output items?
noutput_items: how many output items work can produce
- general_work: no guaranteed relationship between inputs and outputs.
-
work: knowing noutput_items tells us ninput_items based on the established relationship
- gr::sync_block: ninput_items[i] = noutput_items
- gr::sync_decimator: ninput_items[i] = noutput_items*decimation()
- gr::sync_interpolator: ninput_items[i] = noutput_items/interpolation()
- Because of the input/output relationship of a sync block, only need to know one side
work函数对应的模块输入输出关系是确定的,分为3种:gr::sync_block,gr::sync_decimator,gr::sync_interpolator,输入输出的关系分别为1: 1,N: 1,1: N。并且在work()函数中没有nintput_items这个变量,因为可以根据上述关系,通过noutput_items计算出nintput_items。
work operates off just noutput items
From this number, we infer how many input items we have:
int
block::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
- noutput_items: minimum number of output available on all output buffers.
- ninput_items: calculated from noutput_items and type of sync block.
Scetion 3: Scheduler's job
Overview
The scheduler handles the buffer states, block requirements, messages, and stream tags.
"A stream of samples is much more interesting when there is parsable metadata connected to that stream, such as the time of reception, center frequency, subframe index or even protocol-specific information. So there must be a way to identify PDU boundaries, pass control data between blocks. GNU Radio supports two ways to do this: Message passing and stream tag."
GNU Radio采用两种机制: Message passing and stream tag,在block 之间传输信息,例如接收时间,中心频率,子帧号或者特定的协议信息。其中Stream tag是同步标签,只能单向传输。Message是异步消息,可以向任何方向传输。在GNU Radio中,Stream tag中实线表示,Message用虚线表示。注意:Stream tag与数据流是并行传输模式,不是插入到原始数据流,也不会改变原始数据流,而是绑定到数据流的某一个样点,只能在block之间传递消息,不能通过天线发送出去!
Message Passing Layer
Send commands, metadata, and packets between blocks.
Asynchronous messages from and to any block:
tb.msg_connect(Blk1, "out port", Blk0, "in port")
tb.msg_connect(Blk2, "out port", Sink, "in port")
Scheduler Handles the Asynchronous Message Passing
Asynchronous Message Passing:
- When a message is posted, it is placed in each subscribers queue.
- Messages are handled before general_work is called.
-
The scheduler dispatches the messages:
- Checks if there is a handler for the message type.
- If there is no handler, a queue of max_nmsgs is held.
- Oldest message is dropped if more than max_nmsgs in queue.
- max_nmsgs is set in preferences le in [DEFAULT]:max_messages.
- Pops the message off the queue.
- Dispatches the message by calling the block's handler.
- Checks if there is a handler for the message type.
Stream tag layer
Adds a Control, Logic, and Metadata layer to data flow
Tags carry key/value data associated with a specic sample.
Tags are propagated downstream through each block.
Tags are updated by data rate changes.
1 #ifndef INCLUDED_GR_TAGS_H 2 #define INCLUDED_GR_TAGS_H 3 4 #include <gnuradio/api.h> 5 #include <pmt/pmt.h> 6 7 namespace gr { 8 9 struct GR_RUNTIME_API tag_t 10 { 11 //! the item \p tag occurred at (as a uint64_t) 12 uint64_t offset; 13 14 //! the key of \p tag (as a PMT symbol) 15 pmt::pmt_t key; 16 17 //! the value of \p tag (as a PMT) 18 pmt::pmt_t value; 19 20 //! the source ID of \p tag (as a PMT) 21 pmt::pmt_t srcid; 22 23 //! Used by gr_buffer to mark a tagged as deleted by a specific block. You can usually ignore this. 24 std::vector<long> marked_deleted; 25 26 /*! 27 * Comparison function to test which tag, \p x or \p y, came 28 * first in time 29 */ 30 static inline bool offset_compare(const tag_t &x, 31 const tag_t &y) 32 { 33 return x.offset < y.offset; 34 } 35 36 inline bool operator == (const tag_t &t) const 37 { 38 return (t.key == key) && (t.value == value) && \ 39 (t.srcid == srcid) && (t.offset == offset); 40 } 41 42 tag_t() 43 : offset(0), 44 key(pmt::PMT_NIL), 45 value(pmt::PMT_NIL), 46 srcid(pmt::PMT_F) // consistent with default srcid value in block::add_item_tag 47 { 48 } 49 50 ~tag_t() 51 { 52 } 53 }; 54 55 } /* namespace gr */ 56 57 #endif /*INCLUDED_GR_TAGS_H*/