[37]. GNU Radio 系列教程(三七)—— GR C++ OOT 高级用法 —— 回调与动态调节 视频 GitHub 码云 | 2026-03-13 10:57 | 阅读: 0 ### 一、技术背景 在使用 gr-modtool 创建 Python 或 C++ OOT 模块时,我们发现一个问题:当尝试通过如 QT GUI Check Box 这样的控件动态改变 OOT 块的 True/False 参数时,流图并不会实时响应。用户必须停止运行、更改参数,然后再次运行才能生效。**为了在 OOT 块中实现参数的实时更新和动态控制,我们需要引入 GNU Radio 的高级特性——回调(Callback)。** </br> ### 二、技术实现 我们直接在《使用 gr-modtool 创建 C++ OOT》基础上实现: #### 1)`grc/customModule_multDivSelect.block.yml` 增加回调描述 ``` templates: imports: from gnuradio import customModule make: customModule.multDivSelect(${selector}) callbacks: - set_selector(${selector}) ``` </br> #### 2)`lib/multDivSelect_impl.h` 增加函数声明 ``` public: multDivSelect_impl(bool selector); ~multDivSelect_impl(); // Where all the action really happens int work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); // 新增函数声明 void set_selector(bool selector); ``` </br> #### 3)`lib/multDivSelect_impl.cc` 增加函数实现(在 work 函数之后) ``` void multDivSelect_impl::set_selector(bool selector) { _selector = selector; } ``` </br> #### 4)公共头文件声明函数 **上面几步只在 C++ 的 实现 文件中(`_impl.h/.cc`)添加了 `set_selector` 方法,但没有在 C++ 的 公共 API 头文件(`include/gnuradio/customModule/multDivSelect.h`)中声明它。** GNU Radio 的 OOT 结构区分了**公共 API 和私有实现**: 1. **公共 API (`include/gnuradio/customModule/multDivSelect.h`)**: * 这是模块的“门面”,是 GNU Radio 框架和 Python 绑定(通过 SWIG)“看得到”的接口。 * 这个文件里的类(`multDivSelect`)通常只包含纯虚函数(`virtual ... = 0;`)和 `make` 静态方法。 * **SWIG 只会处理这个文件**,为这里声明的 *每一个* public 方法生成对应的 Python 绑定。 2. **私有实现 (`lib/multDivSelect_impl.h` / `lib/multDivSelect_impl.cc`)**: * 这是模块的“内部”,包含实际的工作代码和成员变量。 * `multDivSelect_impl` 类继承自公共 API 类 `multDivSelect`,并 *实现* 了那些纯虚函数。 **因此**,需要在 `include/gnuradio/customModule/multDivSelect.h` 文件的 `make` 函数声明下面声明 `set_selector` 函数: ``` virtual void set_selector(bool selector) = 0; ``` 这行代码告诉 SWIG:“嘿,这个 C++ 类有一个叫做 set_selector 的公有方法,请为它创建一个 Python 绑定。” </br> #### 5)公共头文件声明函数 在 GNU Radio 3.8+ (默认使用 pybind11) 中,我们需要做两件事才能将 C++ 函数暴露给 Python: 1. 在**公共 API 头文件** (`.h`) 中声明 `virtual ... = 0;`。(**第 4 步经完成了**) 2. 在**Python 绑定定义文件** (`.cc`) 中添加 `.def(...)` 来告诉 pybind11 如何暴露这个函数。(**这是这一步需要做的**) 编辑 `python/customModule/bindings/multDivSelect_python.cc`: ``` void bind_multDivSelect(py::module& m) { using multDivSelect = gr::customModule::multDivSelect; py::class_<multDivSelect, gr::sync_block, gr::block, gr::basic_block, std::shared_ptr<multDivSelect>>(m, "multDivSelect", D(multDivSelect)) .def(py::init(&multDivSelect::make), D(multDivSelect,make) ) .def("set_selector", // Python中调用的函数名 &multDivSelect::set_selector, // C++函数指针 py::arg("selector") // Python参数名 //,D(multDivSelect,set_selector) // 文档字符串宏 ) ; } ``` **PS:** 这里的 `D(multDivSelect,set_selector)` 是 GNU Radio 用来自动查找你在 `docs/doxygen/doxygen.h` 中为这个函数编写的文档字符串的宏。如果你没有编写这个文档字符串,也可以注释掉,但最好使用完整的 `D()` 宏。 **极其重要:** 我们会发现 `multDivSelect_python.cc` 文件头上有几行说明: ``` /***********************************************************************************/ /* This file is automatically generated using bindtool and can be manually edited */ /* The following lines can be configured to regenerate this file during cmake */ /* If manual edits are made, the following tags should be modified accordingly. */ /* BINDTOOL_GEN_AUTOMATIC(0) */ /* BINDTOOL_USE_PYGCCXML(0) */ /* BINDTOOL_HEADER_FILE(multDivSelect.h) */ /* BINDTOOL_HEADER_FILE_HASH(891957d8987d2b3e84b99eebaa175498) */ /***********************************************************************************/ ``` 意思是一旦我们修改了 `multDivSelect.h` 需要更新下 `BINDTOOL_HEADER_FILE_HASH`,否则 cmake 就会认为头文件和绑定是不同步的,进而抛出错误。 此时如果我们配置 `BINDTOOL_GEN_AUTOMATIC(1)` 让其自动更新,发现编译时会报一堆头文件等错误;于是我们采用手动计算手动更新的方式:(然后将手动计算的 hash 值替换原来的即可) ``` ➜ gr-customModule git:(master) ✗ md5sum include/gnuradio/customModule/multDivSelect.h 8715bf197d2644c0d2217e42cb5d7e14 include/gnuradio/customModule/multDivSelect.h ``` </br> ### 三、效果演示 重新编译、安装: ``` rm -rf build mkdir build cd build cmake .. make sudo make install sudo ldconfig ``` 然后在原来的流程图中增加一个 bool 类型的 QT GUI Check Box 来控制 multDivSelect 做乘法还是除法: ![][p4] [p4]:https://tuchuang.beautifulzzzz.com:3000/?path=202510/oot_multDivBlock_with_callback_show.gif