Message Passing
- Introduction(介紹)
- Message Passing API(訊息傳遞埠)
- Message Handler Functions(訊息處理函式)
- Connecting Messages through the Flowgraph(通過流圖連接訊息)
- Posting from External Sources(從外部來源傳輸)
- Using Messages as Commands(使用訊息作為命令)
- Code Examples(代碼樣例)
- C++
- Python
- Flowgraph Example(流圖示例)
- PDUs
- Flowgraph Example: Chat Application(流圖樣例:聊天應用)
Introduction(介紹)
GNU Radio was originally a streaming system with no other mechanism to pass data between blocks. Streams of data are a model that work well for samples, bits, etc., but are not really the right mechanism for control data, metadata, or packet structures (at least at some point in the processing chain).
GNU Radio最初是一個流系統,沒有其他機制可以在塊之間傳遞資料,資料流是一種適用于樣本,位等等的一個模型,但是對于控制資料,元資料或者資料包結構來說并不是一個真正正確的機制(至少在傳輸鏈上的一些點來說是這樣)
We solved part of this problem by introducing the tag stream (see Stream Tags). This is a parallel stream to the data streaming. The difference is that tags are designed to hold metadata and control information. Tags are specifically associated with a particular sample in the data stream and flow downstream alongside the data. This model allows other blocks to identify that an event or action has occurred or should occur on a particular item. The major limitation is that the tag stream is really only accessible inside a work function and only flows in one direction. Its benefit is that it is isosynchronous with the data.
我們通過引入標簽流來解決這一部分問題(參考標簽流),這是一個資料流的平行流,不同之處是標簽是被設計用來存放元資料和控制資訊,標簽專門與資料流中的一個特定樣本相關聯并且與資料一起向下流動,這個模型允許其他的塊去識別在一個特定的專案上的一個事件或者動作已經發生或者應該發生,主要的限制是標簽流只能在作業函式的內部被訪問并且只能往一個方向流動,這樣做的好處是它能夠與資料同步,
We want a more general message passing system for a couple of reasons. The first is to allow blocks downstream to communicate back to blocks upstream. The second is to allow an easier way for us to communicate back and forth between external applications and GNU Radio. GNU Radio’s message passing interface handles these cases, although it does so on an asynchronous basis.
出于一些原因,我們想要一個更通用的訊息傳遞系統,首先是要允許下游塊與上游塊通信,其次是允許我們以一種更簡單的方式在外部應用與GNU Radio之間來回通信,GNU Radio的訊息傳遞介面處理這些情況,盡管它是在異步基礎上進行的,
The message passing interface heavily relies on Polymorphic Types (PMTs) in GNU Radio. For further information about these data structures, see the page Polymorphic Types (PMTs).
訊息傳遞介面非常依賴GNU Radio中的多型型別(PMTs),關于這些資料型別的更多介紹可以參考多型型別頁面,

Message Passing API(訊息傳遞埠)
The message passing interface is designed into the gr::basic_block, which is the parent class for all blocks in GNU Radio. Each block has a set of message queues to hold incoming messages and can post messages to the message queues of other blocks. The blocks also distinguish between input and output ports.
訊息傳遞的介面設計在gr::basic_block中,這是GNU Radio中所有塊的父類,每一個塊都有一個訊息佇列來存放輸入的訊息同時還可以傳遞訊息給其他塊的訊息佇列,這些塊還區分輸入和輸出埠,
A block has to declare its input and output message ports in its constructor. The message ports are described by a name, which is in practice a PMT symbol (i.e., an interned string). The API calls to register a new port are:
一個塊需要在它的建構式中宣告它的訊息輸入和輸出埠,訊息埠通過一個名字來描述,這個名字其實是一個PMT符號(例如一個內部字串),注冊新埠的API呼叫如下所示:
void message_port_register_in(pmt::pmt_t port_id)
void message_port_register_out(pmt::pmt_t port_id)
In Python:
self.message_port_register_in(pmt.intern("port name"))
self.message_port_register_out(pmt.intern("port name"))
The ports are now identifiable by that port name. Other blocks who may want to post or receive messages on a port must subscribe to it. When a block has a message to send, they are published on a particular port using the following API:
現在可以通過埠的名字來區分埠,一個塊想在一個埠上傳輸或者接收資訊就必須得先訂閱它,當一個塊有一個訊息要傳遞,它們將會使用下面的API來發送到一個特定的埠:
void message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg);
In Python:(python實作方式)
self.message_port_pub(pmt.intern("port name"), <pmt message>)
Subscribing is usually done in the form of connecting message ports as part of the flowgraph, as discussed later. Internally, when message ports are connected, the gr::basic_block::message_port_sub method is called.
訂閱通常以連接訊息埠的形式作為流圖的一部分,稍后在討論,在內部,當訊息埠被連接時,gr::basic_block::message_port_sub方法將被呼叫,
Any block that has a subscription to another block’s output message port will receive the message when it is published. Internally, when a block publishes a message, it simply iterates through all blocks that have subscribed and uses the gr::basic_block::_post method to send the message to that block’s message queue.
任何塊在訂閱了其他塊訊息輸出埠后都將收到它發布的訊息,在內部,當一個塊發布了一個訊息,它只是簡單的遍歷所有訂閱過它的塊并使用gr::basic_block::_post方法來傳遞訊息到那些塊的訊息佇列,
Message Handler Functions(訊息處理函式)
A subscriber block must declare a message handler function to process the messages that are posted to it. After using the gr::basic_block::message_port_register_in to declare a subscriber port, we must then bind this port to the message handler.
訂閱者必須宣告一個訊息處理函式來處理發布給它的訊息,在使用gr::basic_block::message_port_register_in宣告一個訂閱埠后,我們必須將這個埠系結到訊息處理程式上,
Starting in GNU Radio 3.81 using C++11 we do that using a lambda function:
從使用c++11的GNU Radio3.8開始我們開始使用下面的lambda函式
set_msg_handler(pmt::pmt_t port_id,
[this](const pmt::pmt_t& msg) { message_handler_function(msg); });
In Python:
self.set_msg_handler(pmt.intern("port name"), <msg handler function>)
When a new message is pushed onto a port’s message queue, it is this function that is used to process the message. The ‘port_id’ is the same PMT as used when registering the input port. The ‘block_class::message_handler_function’ is the member function of the class designated to handle messages to this port.
當一個新的訊息被放到一個埠的訊息佇列中后,就是用這個函式來處理訊息的,‘port_id’與注冊輸入埠時使用的PMT相同,‘block_class::message_handler_function’是被指定用來處理埠訊息的類的成員函式,
The prototype for all message handling functions is:
所有訊息處理函式的原型是:
void block_class::message_handler_function(const pmt::pmt_t& msg);
In Python the equivalent function would be:
python中的函式型別如下:
def handle_msg(self, msg):
We give examples of using this below.
我們在下面給出了使用它的實體,
Connecting Messages through the Flowgraph(通過流圖連接訊息)
From the flowgraph level, we have instrumented a gr::hier_block2::msg_connect method to make it easy to subscribe blocks to other blocks’ messages. Assume that the block src has an output message port named pdus and the block dbg has an input port named print. The message connection in the flowgraph (in Python) looks like the following:
從流圖層面,我們檢測到一個gr::hier_block2::msg_connect方法使得更容易讓一個塊訂閱其他塊的訊息,假設塊src有一個輸出訊息埠叫做pdus另一個塊dbg有一個輸入埠叫做print,在python中流圖中訊息的傳遞像如下這樣:
self.tb.msg_connect(src, "pdus", dbg, "print")
All messages published by the src block on port pdus will be received by dbg on port print. Note here how we are just using strings to define the ports, not PMT symbols. This is a convenience to the user to be able to more easily type in the port names (for reference, you can create a PMT symbol in Python using the pmt::intern function as pmt.intern(“string”)).
所有由src塊在pdus埠產生的訊息都會被dbg塊在print埠接收,注意這里我們是如何僅僅通過字串來定義埠,而不是PMT符號,這跟方便用戶更簡單的輸入埠名(提示下,你可以在python中你可以像c++中使用pmt::intern函式一樣使用pmt.inter(”string“)函式來創建一個PMT標簽),
Users can also query blocks for the names of their input and output ports using the following API calls:
用戶 還可以使用以下的API來查詢塊的輸入輸出埠名稱,
pmt::pmt_t message_ports_in();
pmt::pmt_t message_ports_out();
The return value for these are a PMT vector filled with PMT symbols, so PMT operators must be used to manipulate them.
它們的回傳值是一個內容為PMT符號的向量組,因此必須使用PMT運算子來操作它們,
Each block has internal methods to handle posting and receiving of messages. The gr::basic_block::_post method takes in a message and places it into its queue. The publishing model uses the gr::basic_block::_post method of the blocks as the way to access the message queue. So the message queue of the right name will have a new message. Posting messages also has the benefit of waking up the block’s thread if it is in a wait state. So if idle, as soon as a message is posted, it will wake up and call the message handler.
每個塊都有一個內部方法來處理發送和接收到的訊息,gr::basic_block::post方法接收一個訊息并把它放入自己訊息佇列中,所以相應的訊息佇列中將會有一個新的訊息,發送訊息同樣有喚醒一個在等待狀態的塊的執行緒,因此,如果在空閑狀態,同時發布一個訊息,那么它將喚醒并調動訊息處理程式,
Posting from External Sources(從外部來源傳輸)
An important feature of the message passing architecture is how it can be used to take in messages from an external source. We can call a block’s gr::basic_block::_post method directly and pass it a message. So any block with an input message port can receive messages from the outside in this way.
訊息傳遞架構的一個重要特點是如何使用它從一個外部的資源中接收訊息,我們可以直接使用塊的gr::basic_block::post方法傳遞訊息,所以任何有訊息輸入埠的塊可以通過這個方法從外部接收到訊息,
The following example uses a gr::blocks::pdu_to_tagged_stream block as the source block to a flowgraph. Its purpose is to wait for messages as PDUs posted to it and convert them to a normal stream. The payload will be sent on as a normal stream while the meta data will be decoded into tags and sent on the tagged stream.
以下示例使用gr::blocks::pdu_to_tagged_stream塊作為流程圖的源塊,它的目的是等待一個訊息作為PDUs發送給它并將它們轉化為普通流,有效載荷將作為一個普通流發送,而元資料將被解碼為標簽并被標記在流上發送,
So if we have created a src block as a PDU to stream, it has a pdus input port, which is how we will inject PDU messages into the flowgraph. These PDUs could come from another block or flowgraph, but here, we will create and insert them by hand.
所以如果我們創建了一個src塊作為流式傳輸的PDU,它有一個pdus輸入埠,這就是我們將PDU訊息注入流程圖的方式,這些PDU可以來自其他塊或者流圖,但是在這里,我們將手動創建并插入它們,
port = pmt.intern("pdus")
msg = pmt.cons(pmt.PMT_NIL, pmt.make_u8vector(16, 0xFF))
src.to_basic_block()._post(port, msg)
The PDU’s metadata section is empty, hence the pmt::PMT_NIL object. The payload is now just a simple vector of 16 bytes of all 1’s. To post the message, we have to access the block’s gr::basic_block class, which we do using the gr::basic_block::to_basic_block method and then call the gr::basic_block::_post method to pass the PDU to the right port.
PDU的元資料部分都是空的,因此是pmt::PMT_NIL物件,有效載荷現在只是一個16位元組的全1向量,要傳遞訊息,我們必須訪問塊的gr::basic_block類,我們使用gr::basic_block::to_basic_block方法同時使用gr::basic_block::_post方法將PDU傳輸到正確的埠,
All of these mechanisms are explored and tested in the QA code of the file qa_pdu.py.
所有的這些機制都在qa_pdu.py檔案中的QA代碼中進行了探索和檢測,
There are some examples of using the message passing infrastructure through GRC in:
這里有一些通過GRC使用訊息傳輸基礎設施的例子:
gr-blocks/examples/msg_passing
Using Messages as Commands(使用訊息作為命令)
One important use of messages is to send commands to blocks. Examples for this include:
一個非常重要的用處是使用訊息向塊傳遞命令,這方面的例子包括:
gr::qtgui::freq_sink_c: The scaling of the frequency axis can be changed by messages(可以通過訊息來改變頻率軸的間隔)
gr::uhd::usrp_source and gr::uhd::usrp_sink: Many transceiver-related settings can be manipulated through command messages, such as frequency, gain and LO offset(許多收發器相關的設定可以通過命令訊息來修改,比如頻率,增益和LO偏移)
gr::digital::header_payload_demux, which receives an acknowledgement from a header parser block on how many payload items there are to process(它從頭決議器接收有多少負載專案要處理的確認)
There is no special PMT type to encode commands, however, it is strongly recommended to use one of the following formats:
沒有特殊的PMT型別來編碼命令,然而,非常建議使用下面的格式:
pmt::cons(KEY, VALUE): This format is useful for commands that take a single value. Think of KEY and VALUE as the argument name and value, respectively. For the case of the QT GUI Frequency Sink, KEY would be “freq” and VALUE would be the new center frequency in Hz.(這個格式非常適用于使用單個值的命令,KEY和VALUE分別為引數名和值,對于QT GUI Frequency Sink案例,KEY將是”freq“而VALUE為新的中心頻率(單位為Hz))
pmt::dict((KEY1: VALUE1), (KEY2: VALUE2), …): This is basically the same as the previous format, but you can provide multiple key/value pairs. This is particularly useful when a single command takes multiple arguments which can’t be broken into multiple command messages (e.g., the USRP blocks might have both a timestamp and a center frequency in a command message, which are closely associated).(這和前面的格式基本一樣,但是你可以使用多個鍵值對,這對一個使用多個引數而不能分解為多個命令訊息的命令非常有用(例如,USRP塊在命令訊息中有時間戳和中心頻率,它們密切相關))
In both cases, all KEYs should be pmt::symbols (i.e. strings). VALUEs can be whatever the block requires.
在這些案例中,所有的KEY都應該是pmt::symbols(即字串),VALUE可以是塊中需要的任何值,
It might be tempting to deviate from this format, e.g. the QT Frequency sink could simply take a float value as a command message, and it would still work fine. However, there are some very good reasons to stick to this format:
偏離這種格式可能很誘人,例如,QT Frequency sink可以簡單的使用浮點數值作為一個訊息命令,它仍然可以正常作業,但是堅持使用這種格式有很多的好處:
Interoperability: The more people use the standard format, the more likely it is that blocks from different sources can work together(使用標準格式的人越多,那么來自不同源的塊能一同作業的機會有越大)
Inspectability: A message debug block will display more useful information about a message if it’s containing both a value and a key(如果一個訊息調式塊包含值和鍵,那么它可以顯示一個訊息的更多的有效資訊)
Intuition: This format is pretty versatile and unlikely to create situations where it is not sufficient (especially considering that values are PMTs themselves). As a counterexample, using positional arguments (something like “the first argument is the frequency, the second the gain”) is easily forgotten, or changed in one place and not another, etc.(這種格式非常通用,不太可能造成一個不適用的情況(特別是考慮到值本身就是PMT),作為一個反例,使用位置引數(比如說”第一個引數是頻率,第二個引數是增益“)非常容易被遺忘, 或者在一個地方而不是另一個地方改變,等等),
Code Examples(代碼樣例)
C++
The following is snippets of code from blocks currently in GNU Radio that take advantage of message passing. We will be using gr::blocks::message_debug and gr::blocks::tagged_stream_to_pdu below to show setting up both input and output message passing capabilities.
以下是當前GNU Radio中利用訊息傳遞的塊的代碼片段,我們將在下面使用gr::blocks::message_debug和gr::blocks::tagged_stream_to_pdu來顯示設定輸入和輸出訊息傳遞功能,
The gr::blocks::message_debug block is used for debugging the message passing system. It describes two input message ports: print and store. The print port simply prints out all messages to standard out while the store port keeps a list of all messages posted to it. The store port works in conjunction with a gr::blocks::message_debug::get_message(size_t i) call that allows us to retrieve message i afterward.
gr::blocks::message_debug塊被用來除錯訊息傳輸系統,它描述了兩個輸入訊息埠:print和store,print埠把所有的訊息簡單的列印到標準輸出,但是store埠存放了被傳輸過來的所有訊息串列,store埠與gr::block::message_debug::get_message(size_t i)一同呼叫,允許我們后面檢索訊息i,
The constructor of this block looks like this:
這個塊的構造如下所示:
{
message_port_register_in(pmt::mp("print"));
set_msg_handler(pmt::mp("print"),
[this](const pmt::pmt_t& msg) { print(msg); });
message_port_register_in(pmt::mp("store"));
set_msg_handler(pmt::mp("store"),
[this](const pmt::pmt_t& msg) { store(msg); });
}
The three message input ports are registered by their respective names. We then use the gr::basic_block::set_msg_handler function to identify this particular port name with a callback function.
三個訊息輸入埠按照它們各自的名字來注冊,然后,我們使用gr::basic_block::set_msg_handler函式通過回呼函式來識別特定埠的名稱,
So now the functions in the block’s private implementation class, gr::blocks::message_debug_impl::print and gr::blocks::message_debug_impl::store are assigned to handle messages passed to them. Below is the print function for reference.
所以現在塊的私有實作類中的函式gr::blocks::message_debug_impl::print和gr::blocks::message_debug_impl::store函式被用來處理分配給他們的訊息,參考下面的輸出函式,
void
message_debug_impl::print(const pmt::pmt_t& msg)
{
std::cout << "***** MESSAGE DEBUG PRINT ********\n";
pmt::print(msg);
std::cout << "**********************************\n";
}
The function simply takes in the PMT message and prints it. The method pmt::print is a function in the PMT library to print the PMT in a friendly and (mostly) pretty manner.
函式只是簡單的接收了PMT訊息并輸出了他們,PMT庫中的pmt::print方法是一個更友好和漂亮的方式來輸出一個PMT,
The gr::blocks::tagged_stream_to_pdu block only defines a single output message port. In this case, its constructor contains the line:
gr::blocks::tagged_stream_to_pdu塊只是定義了單個的輸出訊息埠,這種情況下,它的建構式包括了一下行:
{
message_port_register_out(pdu_port_id);
}
So we are only creating a single output port where pdu_port_id is defined in the file pdu.h as pdus.
所以我們只是創建了一個輸出埠,同時pdu_prot_id作為pdus被定義在pdu.h頭檔案里面,
This block’s purpose is to take in a stream of samples along with stream tags and construct a predefined PDU message from it. In GNU Radio, we define a PDU as a PMT pair of (metadata, data). The metadata describes the samples found in the data portion of the pair. Specifically, the metadata can contain the length of the data segment and any other information (sample rate, etc.). The PMT vectors know their own length, so the length value is not actually necessary unless useful for purposes down the line. The metadata is a PMT dictionary while the data segment is a PMT uniform vector of either bytes, floats, or complex values.
塊的目的是接收樣本流和流標簽同時從從它們之中構建一個一個預定義PDU訊息,在GNU Radio中,我們將一個PDU定義為一個PMT對(元資料,資料),元資料描述了在該對資料部分找到的樣本,特別的是,該元資料能夠包含資料段的長度以及任何其他資訊(樣本率等等),PMT向量組知道它們自己的長度,所以長度不是必須的,除非在后面的代碼中有用,元資料是一個PMT資料字典而資料段是位元組、浮點數或者復數值的一個PMT的統一向量,
In the end, when a PDU message is ready, the block calls its gr::blocks::tagged_stream_to_pdu_impl::send_message function that is shown below.
最后,當一個PDU訊息準備好的時候,塊會呼叫它的gr::blocks::tagged_stream_to_pdu_impl::send_message函式,像下面這樣:
void
tagged_stream_to_pdu_impl::send_message()
{
if(pmt::length(d_pdu_vector) != d_pdu_length) {
throw std::runtime_error("msg length not correct");
}
pmt::pmt_t msg = pmt::cons(d_pdu_meta,
d_pdu_vector);
message_port_pub(pdu_port_id, msg);
d_pdu_meta = pmt::PMT_NIL;
d_pdu_vector = pmt::PMT_NIL;
d_pdu_length = 0;
d_pdu_remain = 0;
d_inpdu = false;
}
This function does a bit of checking to make sure the PDU is OK as well as some cleanup in the end. But it is the line where the message is published that is important to this discussion. Here, the block posts the PDU message to any subscribers by calling gr::basic_block::message_port_pub publishing method.
此函式會進行一系列的檢查來確保PDU是正確的以及最后的一些清理工作,但是發布訊息的行對于這項作業來說非常重要,在此,塊通過呼叫gr::basic_block::message_port_pub函式的發布方法來向任意它的訂閱者發布訊息,
There is similarly a gr::blocks::pdu_to_tagged_stream block that essentially does the opposite. It acts as a source to a flowgraph and waits for PDU messages to be posted to it on its input port pdus. It extracts the metadata and data and processes them. The metadata dictionary is split up into key:value pairs and stream tags are created out of them. The data is then converted into an output stream of items and passed along. The next section describes how PDUs can be passed into a flowgraph using the gr::blocks::pdu_to_tagged_stream block.
類似的還有一個gr::blocks::pdu_to_tagged_stream塊做了一些本質上相反的事情,它充當一個流圖的源,并等待發送給它的輸入埠pdus的PDU訊息,它提取元資料和資料然后處理它們,元資料字典被拆分為鍵值對并從中創建標簽,然后將資料轉換為一個專案的輸出流并隨后傳遞它們,下一節將描述如何使用gr::blocks::pdu_to_tagged_stream塊將PDUs傳遞到流圖中,
Python
A Python Block example:
一個python塊樣例:
class msg_block(gr.basic_block):
def __init__(self):
gr.basic_block.__init__(
self,
name="msg_block",
in_sig=None,
out_sig=None)
self.message_port_register_out(pmt.intern('msg_out'))
self.message_port_register_in(pmt.intern('msg_in'))
self.set_msg_handler(pmt.intern('msg_in'), self.handle_msg)
def handle_msg(self, msg):
self.message_port_pub(pmt.intern('msg_out'), pmt.intern('message received!'))
Flowgraph Example(流圖示例)
Here’s a simple example of a flow graph using both streaming and messages:
這里是一個同時使用流和訊息的流圖樣例:

There are several interesting things to point out. First, there are two source blocks, which both output items at regular intervals, one every 1000 and one every 750 milliseconds. Dotted lines denote connected message ports, as opposed to solid lines, which denote connected streaming ports. In the top half of the flow graph, we can see that it is, in fact, possible to switch between message passing and streaming ports, but only if the type of the PMTs matches the type of the streaming ports (in this example, the pink color of the streaming ports denotes bytes, which means the PMT should be a u8vector if we want to stream the same data we sent as PMT).
這里有一些有趣的事情值得被指出,首先,這里有兩個源塊,它們都在一個固定的間隔輸出專案,一個以沒1000毫秒的間隔輸入另一個則以750毫秒的間隔輸入,虛線表示連接訊息埠,而實線表示連接流埠,在流圖的上半部分我們可以看到,實際上,可以實作訊息埠和流埠之間的轉換,但是只有在PMT的型別與流埠相匹配的時候才可以實作(在本樣例中,粉色的流埠表示位元組,意味著如果我們想要以流傳輸我們以PMT形式發送的相同的資料,PMT的格式應該是u8vector的形式),
Another interesting fact is that we can connect more than one message output port to a single message input port, which is not possible with streaming ports. This is due to the asynchronous nature of messages: The receiving block will process all messages whenever it has a chance to do so, and not necessarily in any specific order. Receiving messages from multiple blocks simply means that there might be more messages to process.
另一個有趣的事情是我們可以將多個訊息輸出埠連接到一個訊息輸入埠上,但是這在流埠上是不能實作的,這是由于訊息的異步性:接收塊將在空閑的時間處理所有接收到的訊息,并且不一定要按照一定的順序,從多個塊接收到訊息只是意味著有更多的訊息需要去處理,
What happens to a message once it was posted to a block? This depends on the actual block implementation, but there are two possibilities:
當訊息被發送到一個塊時會發生什么?這取決于塊的實際操作,但是這里有兩種可能性:
- A message handler is called, which processes the message immediately.
1)一個訊息處理器被呼叫,立刻處理訊息, - The message is written to a FIFO buffer, and the block can make use of it whenever it likes, usually in the work function.
2)訊息被寫入一個FIFO緩沖區,塊可以在任何時候處理它們,這通常在作業函式內實作,
For a block that has both message ports and streaming ports, any of these two options is OK, depending on the application. However, we strongly discourage the processing of messages inside of a work function and instead recommend the use of message handlers. Using messages in the work function encourages us to block in work waiting for a message to arrive. This is bad behavior for a work function, which should never block. If a block depends upon a message to operate, use the message handler concept to receive the message, which may then be used to inform the block’s actions when the work function is called. Only on specially, well-identified occasions should we use method 2 above in a block.
對于一個同時擁有訊息埠 和流埠的塊來說,這兩種選擇都可以,取決于應用程式,當時,我們強烈反對在一個作業函式內來處理訊息,我們推薦通過使用訊息處理器來處理訊息,在作業函式內使用訊息會使得我們在等待訊息的程序中形成阻塞,這對于永遠不能被阻塞的作業函式來說是一個非常不好的行為,如果依賴一個訊息來操作,使用訊息處理程式來接收訊息,然后在呼叫作業函式時來使用訊息來告知塊的操作,只有在啊特殊明確的場合我們才應該使用上面的方法2,
With a message passing interface, we can write blocks that don’t have streaming ports, and then the work function becomes useless, since it’s a function that is designed to work on streaming items. In fact, blocks that don’t have streaming ports usually don’t even have a work function.
通過訊息傳遞介面,我們可以撰寫一個不需要流埠的塊,然后作業函式將變得沒有用,因為作業函式時被設計用來處理流專案的, 事實上,沒有流埠的塊甚至通常沒有作業函式,
PDUs
In the previous flow graph, we have a block called PDU to Tagged Stream. A PDU (protocol data unit) in GNU Radio has a special PMT type, it is a pair of a dictionary (on CAR) and a uniform vector type. So, this would yield a valid PDU, with no metadata and 10 zeros as stream data:
在之前的流圖中,我們有一個叫做PDU to Tagged Stream的塊,一個在GNU Radio中的PDU(協議資料單元)有一個特殊的資料型別,它是一對字典(在CAR上)和統一向量型別,所以我們將會生成一個有效的PDU,沒有元資料和10個0作為流資料,
pdu = pmt.cons(pmt.make_dict(), pmt.make_u8vector(10, 0))
The key/value pairs in the dictionary are then interpreted as key/value pairs of stream tags.
字典中的鍵值對將會解釋為流標簽的鍵值對,
Flowgraph Example: Chat Application(流圖樣例:聊天應用)
Let’s build an application that uses message passing. A chat program is an ideal use case, since it waits for the user to type a message, and then sends it. Because of that, no Throttle block is needed.
讓我們來創建一個傳遞訊息的應用程式,聊天程式是一個非常理想的用例,因為它等待用戶輸入一個訊息,然后發送它,因此它不需要Throttle塊,
Create the following flowgraph and save it as ‘chat_app2.grc’:
創建下面的流圖并保存命名為’chat_app2.grc’:

The ZMQ Message blocks have an Address of ‘tcp://127.0.0.1:50261’. Typing in the QT GUI Message Edit Box will send the text once the Enter key is pressed. Output is on the terminal screen where gnuradio-companion was started.
ZMQ訊息塊有一個地址為’tcp://127.0.0.1:50261’,一但按下回車鍵,QT訊息編輯框中輸入的訊息就會發送出去,輸出在運行gnuradio-companion的終端窗上,
If you want to talk to another user (instead of just yourself), you can create an additional flowgraph with a different name such as ‘chat_app3.grc’. Then change the ZMQ port numbers as follows:
如果你想與另一個用戶(或者就是你自己)交流,你可以創建一個額外的流圖命名為
另一個不同的名字比如’chat_app3.grc’,然后像下面這樣改變ZMQ的埠名:
chat_app2
ZMQ PUSH Sink: tcp://127.0.0.1:50261
ZMQ PULL Source: tcp://127.0.0.1:50262
chat_app3
ZMQ PUSH Sink: tcp://127.0.0.1:50262
ZMQ PULL Source: tcp://127.0.0.1:50261
When using GRC, doing a Generate and/or Run creates a Python file with the same name as the .grc file. You can execute the Python file without running GRC again.
當使用GRC時,執行生成同時/或者運行命令會創建一個同名.grc檔案的python檔案,你可以在不再次運行GRC的情況下執行python檔案,
For testing this system we will use two processes, so we will need two terminal windows.
我們將使用兩個行程來測驗這個系統,因此我們需要兩個終端視窗,
Terminal 1:(終端1)
since you just finished building the chat_app3 flowgraph, you can just do a Run.
因為我們剛剛完成了chat_app3流圖的構建,因此我們只需要運行即可,
Terminal 2: Open another terminal window.(終端2:打開另一個終端視窗,)
change to whatever directory you used to generate the flowgraph for chat_app2.
更改為你用于為chat_app2生成流圖的任何專案,
execute the following command:
執行以下命令:
python3 -u chat_app2.py
Typing in the Message Edit Box for chat_app2 should be displayed on the Terminal 1 screen (chat_app3) and vice versa.
在chat_app2訊息編輯框中輸入的訊息將會出現在在終端1的螢屏上(chat_app3),反之亦然,
To terminate each of the processes cleanly, click on the ‘X’ in the upper corner of the GUI rather than using Control-C.
要干凈利落的終止整個程式,應該點擊GUI視窗上的’X’關閉而不是輸入Control-C指令,
1 In old GNU Radio 3.7, we used Boost’s ‘bind’ function:
在老版本的GNU Radio 3.7中我們使用了Boost的’bind‘函式:
set_msg_handler(pmt::pmt_t port_id,
boost::bind(&block_class::message_handler_function, this, _1));}}
The ‘this’ and ‘_1’ are standard ways of using the Boost bind function to pass the ‘this’ pointer as the first argument to the class (standard OOP practice) and the _1 is an indicator that the function expects 1 additional argument.
’this‘和’_1‘是使用Boost bind函式傳遞第一個’this‘指標引數到類(標準OOP實踐)中以及_1是函式需要一個附加引數的指示符,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291943.html
標籤:其他
上一篇:MQTT(二) 實作聊天功能
