├── .gitignore ├── LICENSE ├── README.md ├── SConscript ├── adapter ├── cmsis │ ├── reb_mutex.c │ ├── reb_queue.c │ ├── reb_sem.c │ └── reb_task.c └── rtthread │ ├── reb_mutex.c │ ├── reb_queue.c │ ├── reb_sem.c │ └── reb_task.c ├── example └── reb_rtt_example.c ├── include ├── reb_broker.h ├── reb_cfg.h ├── reb_def.h ├── reb_observer.h └── reb_publisher.h ├── pic ├── flow.png └── result.png └── src ├── reb_broker.c ├── reb_observer.c └── reb_publisher.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # REB 2 | REB(Rice Event Broker)全称事件代理,REB框架采用设计模式中的观察者模式,它可以使我们的代码能够高度解耦,可扩展。 3 | 4 | ## 观察者模式 5 | 6 | 聊REB之前,我们聊聊观察者模式带给我们特性,他能对我们框架设计提供什么好处。 7 | 8 | ##### 什么是观察者模式 9 | 10 | - 观察者模式(Observer Pattern)是一种行为设计模式,用于定义对象之间的一对多依赖关系,使得一个对象的状态变化会通知其所有依赖者并自动更新它们的状态。这个模式涉及两种主要类型的对象: 11 | 12 | 1. 被观察者:也称为主题或可观察者,是一个对象,它维护一组观察者(或依赖者)并提供方法来添加、删除和通知这些观察者。当被观察者的状态发生变化时,它会通知所有已注册的观察者。 13 | 2. 观察者:观察者是依赖于被观察者的对象,它们实现一个接口或抽象类,包含一个更新方法(通常称为update),用于接收并处理被观察者的状态变化通知。 14 | 15 | ##### 观察者模式工作流程 16 | - 被观察者注册观察者:被观察者维护一个观察者列表,并提供注册(添加)和注销(删除)观察者的方法。 17 | - 被观察者状态变化:当被观察者的状态发生变化,它会遍历其观察者列表,调用每个观察者的更新方法,将状态变化通知给它们。 18 | - 观察者响应:每个观察者在接收到通知后会执行自己的更新逻辑,以响应被观察者的状态变化。 19 | 20 | ##### 观察者模式优势 21 | - 解耦性:观察者模式可以帮助降低对象之间的耦合度。被观察者和观察者之间的关系是松散的,它们可以独立演化,而不会影响彼此的具体实现。 22 | - 可扩展性:你可以轻松地添加新的观察者,而不需要修改被观察者的代码。这种扩展性使你能够动态地增加或删除观察者,以满足不同的需求。 23 | - 通知机制:观察者模式允许被观察者通知观察者,从而使观察者能够在适当的时候进行响应。这可以帮助确保数据的一致性,因为观察者会立即知道被观察者的状态变化。 24 | - 分布式事件处理:观察者模式常用于实现分布式事件处理系统,其中多个观察者可以远程订阅和接收事件通知。 25 | - 可重用性:观察者模式可以在不同的应用中重复使用,因为它是一个通用的设计模式,不受特定应用领域的限制。 26 | - 灵活性:观察者模式可以用于许多不同的场景,如用户界面更新、事件处理、数据同步等,使得代码更加灵活和可维护。 27 | - 支持一对多关系:观察者模式支持一对多的依赖关系,这意味着一个被观察者可以同时通知多个观察者,从而实现多个对象之间的协同工作。 28 | 29 | ##### 观察者模式例子 30 | 31 | - 物联网协议MQTT:MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议。 32 | - Android的EventBus:EventBus是一个基于发布者/订阅者模式的事件总线框架。 33 | 34 | ## REB框架设计 35 | 36 | ##### REB框架图 37 | 38 | ![](./pic/flow.png) 39 | 40 | ##### REB框架说明 41 | 42 | 1. REB框架分为3层:osal(OS抽象层),REB核心层(包含发布者,观察者,中间人),应用层(调用REB的模块或应用)。 43 | 2. osal(OS抽象层):为了能让此框架应用于不同的操作系统,且不用修改框架本省,所以提供os适配层。 44 | 3. REB核心层(包含发布者,观察者,中间人):框架的三大角色,它们三者互相依赖。 45 | - publisher(发布者):REB框架的发布者支持4种接口:默认发送接口,默认发送完释放数据内存释放接口,紧急发送接口,紧急发送完数据内存释放接口。 46 | - observer(观察者):REB框架的观察者支持3种接口:信号接收接口,回调接收接口,线程接收接口。 47 | - broker(中间人): REB框架的中间人支持两种接口:观察者只观察一次接口,观察者观察多次接口。 48 | 4. 应用层(调用REB的模块或应用):上层应用或者模块,相互独立,互不依赖。 49 | 5. REB是以事件为导向,事件类型由主事件类型和次事件类型组成,事件类型占用32个位,主事件类型占高16位,次事件类型占低16位。一般:以网络为例:主事件类型为:net_type,次事件类型为:link_up,link_down等。 50 | 51 | ##### REB目录结构 52 | 53 | ```C 54 | ├─adapter 55 | │ ├─cmsis 56 | │ | ├─reb_mutex.c // cmsis mutex适配层 57 | │ | ├─reb_queue.c // cmsis queue适配层 58 | │ | ├─reb_sem.c // cmsis sem适配层 59 | │ | └─reb_task.c // cmsis task适配层 60 | │ └─rtthread 61 | │ ├─reb_mutex.c // rtthread mutex适配层 62 | │ ├─reb_queue.c // rtthread queue适配层 63 | │ ├─reb_sem.c // rtthread sem适配层 64 | │ └─reb_task.c // rtthread task适配层 65 | ├─example 66 | │ └─reb_rtt_example.c // rtthread 平台实例 67 | ├─include 68 | │ ├─reb_broker.h // reb 中间人的头文件 69 | │ ├─reb_cfg.h // reb 参数配置文件 70 | │ ├─reb_def.h // reb 框架通用接口定义 71 | │ ├─reb_observer.h // reb 观察者的头文件 72 | │ └─reb_publisher.h // reb 发布者的头文件 73 | └─src 74 | ├─reb_broker.c // reb 中间人的源文件 75 | ├─reb_publisher.c // reb 观察者的源文件 76 | └─reb_observer.c // reb 发布者的源文件 77 | ``` 78 | 79 | ## REB接口说明 80 | ##### broker接口 81 | 82 | | 接口 | 说明 | 83 | |------|------| 84 | | broker_create | 创建broker | 85 | | broker_delete | 删除broker | 86 | | broker_observer_attach_once | 关联观察者到broker中,并只观察一次 | 87 | | broker_observer_attach | 关联观察者到broker中,并只观察多次 | 88 | | broker_observer_detach | 从broker中脱离观察者 | 89 | 90 | - 创建broker 91 | - 在使用该框架时,必须要通过此接口创建broker,它是发布者和观察的者的中间人。 92 | 93 | ``` C 94 | reb_status broker_create(void); 95 | ``` 96 | 97 | |**参数**|**描述**| 98 | |------|------| 99 | | -- | -- | 100 | |**返回**| —— | 101 | | REB_OK | broker创建成功 | 102 | | REB_ERROR | broker创建失败 | 103 | 104 | - 删除broker 105 | - 当不在使用该框架时,可以调用此接口删除broker。 106 | 107 | ``` C 108 | reb_status broker_delete(void); 109 | ``` 110 | 111 | |**参数**|**描述**| 112 | |------|------| 113 | | -- | -- | 114 | |**返回**| —— | 115 | | REB_OK | broker删除成功 | 116 | | REB_ERROR | broker删除失败 | 117 | 118 | - 关联观察者到broker中,并只观察一次 119 | - 我创建的观察者之后,需要通过此接口将观察者关联到broker中。当发布者发布事件,可以通过broker找到对用的观察者。使用该接口观察者只观察一次事件。 120 | ``` C 121 | reb_status broker_observer_attach_once(observer_base *obs); 122 | ``` 123 | 124 | |**参数**|**描述**| 125 | |------|------| 126 | | obs | 观察者对象 | 127 | |**返回**| —— | 128 | | REB_OK | 关联观察者到broker中,成功 | 129 | | REB_ERROR | 关联观察者到broker中,失败 | 130 | 131 | - 关联观察者到broker中,并只观察多次 132 | - 我创建的观察者之后,需要通过此接口将观察者关联到broker中。当发布者发布事件,可以通过broker找到对用的观察者。使用该接口观察者只观察多次事件。 133 | ``` C 134 | reb_status broker_observer_attach(observer_base *obs); 135 | ``` 136 | 137 | |**参数**|**描述**| 138 | |------|------| 139 | | obs | 观察者对象 | 140 | |**返回**| —— | 141 | | REB_OK | 关联观察者到broker中,成功 | 142 | | REB_ERROR | 关联观察者到broker中,失败 | 143 | 144 | - 从broker中脱离观察者 145 | 146 | ``` C 147 | reb_status broker_observer_detach(observer_base *obs); 148 | ``` 149 | 150 | |**参数**|**描述**| 151 | |------|------| 152 | | obs | 观察者对象 | 153 | |**返回**| —— | 154 | | REB_OK | 观察者从broker中脱离,成功 | 155 | | REB_ERROR | 观察者从broker中脱离,失败 | 156 | 157 | ##### observer接口 158 | 159 | | 接口 | 说明 | 160 | |------|------| 161 | | observer_signal_create | 创建信号模式的观察者,只接收事件信号,不传输数据的观察者 | 162 | | observer_signal_wait | 信号模式的观察者,等待同步信号 | 163 | | observer_callback_create | 创建回调模式的观察者 | 164 | | observer_task_create | 创建任务模式的观察者 | 165 | | observer_delete | 删除观察者 | 166 | 167 | - 创建信号模式的观察者 168 | - 该接口是创建信号模式的观察者,它只接收事件信号,不传输数据的。 169 | 170 | ``` C 171 | observer_base *observer_signal_create(uint16_t type, uint16_t sub_type); 172 | ``` 173 | 174 | |**参数**|**描述**| 175 | |------|------| 176 | | type | 观察者观察的主事件类型 | 177 | | sub_type | 观察者观察的次事件类型 | 178 | |**返回**| —— | 179 | | obs | 观察者创建成功 | 180 | | NULL | 观察者创建失败 | 181 | 182 | - 信号模式的观察者,等待同步信号 183 | - 该接口是信号模式的观察者,用户层需要通过一个任务监听观察事件的同步信号接口。 184 | 185 | ``` C 186 | reb_status observer_signal_wait(observer_base *base, reb_time_t timeout); 187 | ``` 188 | 189 | |**参数**|**描述**| 190 | |------|------| 191 | | base | 观察者对象 | 192 | | timeout | 观察事件的超时事件 | 193 | |**返回**| —— | 194 | | REB_OK | 观察到对应事件 | 195 | | OTHER | 观察失败 | 196 | 197 | - 创建回调模式的观察者 198 | - 该接口是创建回调模式的观察者,当事件产生时,broker会通过回调的方式通知观察者事件的到来。 199 | ``` C 200 | observer_base *observer_callback_create(uint16_t type, 201 | uint16_t sub_type, 202 | obs_callback_cb cb, 203 | void *arg); 204 | ``` 205 | 206 | |**参数**|**描述**| 207 | |------|------| 208 | | type | 观察者观察的主事件类型 | 209 | | sub_type | 观察者观察的次事件类型 | 210 | | cb | 事件产生时,回调的接口函数 | 211 | | arg | 回调函数的用户数据 | 212 | |**返回**| —— | 213 | | obs | 观察者创建成功 | 214 | | NULL | 观察者创建失败 | 215 | 216 | - 创建任务模式的观察者 217 | - 该接口是创建任务模式的观察者,当事件产生时,broker会通过创建一个线程,然后由独立的线程将事件通知给观察者。 218 | ``` C 219 | observer_base *observer_task_create(uint16_t type, 220 | uint16_t sub_type, 221 | obs_task_cb run, 222 | void *arg, 223 | uint32_t stack_size, 224 | uint32_t prio); 225 | ``` 226 | 227 | |**参数**|**描述**| 228 | |------|------| 229 | | type | 观察者观察的主事件类型 | 230 | | sub_type | 观察者观察的次事件类型 | 231 | | run | 事件产生时,线程的处理函数 | 232 | | arg | 线程处理函数的用户数据 | 233 | | stack_size | 线程的栈空间大小 | 234 | | prio | 线程的优先级 | 235 | |**返回**| —— | 236 | | obs | 观察者创建成功 | 237 | | NULL | 观察者创建失败 | 238 | 239 | - 从broker中脱离观察者 240 | 241 | ``` C 242 | reb_status observer_delete(observer_base *base); 243 | ``` 244 | 245 | |**参数**|**描述**| 246 | |------|------| 247 | | base | 观察者对象 | 248 | |**返回**| —— | 249 | | REB_OK | 观察者删除成功 | 250 | | REB_ERROR | 观察者删除失败 | 251 | 252 | ##### publisher接口 253 | 254 | | 接口 | 说明 | 255 | |------|------| 256 | | publisher_factory_create | 创建发布者工厂 | 257 | | publisher_send | 发布者默认发送消息 | 258 | | publisher_send_with_free | 发布者默认发送消息,发送完成之后把消息缓冲删除 | 259 | | publisher_urgent_send | 发布者发送紧急消息 | 260 | | publisher_urgent_send_with_free | 发布者发送紧急消息,发送完成之后把消息缓冲删除 | 261 | 262 | - 创建发布者工厂 263 | - 该接口是创建发布者工厂,提供事件队列,使发布消息处于非阻塞式发送 264 | 265 | ``` C 266 | reb_status publisher_factory_create(pub_notify notify); 267 | ``` 268 | 269 | |**参数**|**描述**| 270 | |------|------| 271 | | notify | 事件通知回调,当发布者发布消息之后,通过回调通知broker | 272 | |**返回**| —— | 273 | | REB_OK | 发布者工厂创建成功 | 274 | | REB_ERROR | 发布者工厂创建失败 | 275 | 276 | - 发布者默认发送消息 277 | - 该接口是发布者发布事件接口,它是采用先进先出的方式发送消息 278 | 279 | ``` C 280 | reb_status publisher_send(uint16_t type, uint16_t sub_type, 281 | uint32_t data, reb_time_t timeout); 282 | ``` 283 | 284 | |**参数**|**描述**| 285 | |------|------| 286 | | type | 发布消息的主事件类型 | 287 | | sub_type | 发布消息的次事件类型 | 288 | | data | 发布消息的数据 | 289 | | timeout | 发布消息的超时时间 | 290 | |**返回**| —— | 291 | | REB_OK | 发布消息成功 | 292 | | OTHER | 发布消息失败 | 293 | 294 | - 发布者默认发送消息,发送完成之后把消息缓冲删除 295 | - 该接口是发布者发布事件接口,它是采用先进先出的方式发送消息,并且将消息发送给所有观察者之后,数据的内存会执行释放。 296 | 297 | ``` C 298 | reb_status publisher_send_with_free(uint16_t type, uint16_t sub_type, 299 | uint32_t data, reb_time_t timeout); 300 | ``` 301 | 302 | |**参数**|**描述**| 303 | |------|------| 304 | | type | 发布消息的主事件类型 | 305 | | sub_type | 发布消息的次事件类型 | 306 | | data | 发布消息的数据 | 307 | | timeout | 发布消息的超时时间 | 308 | |**返回**| —— | 309 | | REB_OK | 发布消息成功 | 310 | | OTHER | 发布消息失败 | 311 | 312 | - 发布者发送紧急消息 313 | - 该接口是发布者发布事件接口,它是采用插队的方式发送消息,它会将发布的消息插入消息队列的头部。 314 | ``` C 315 | reb_status publisher_urgent_send(uint16_t type, uint16_t sub_type, 316 | uint32_t data, reb_time_t timeout); 317 | ``` 318 | 319 | |**参数**|**描述**| 320 | |------|------| 321 | | type | 发布消息的主事件类型 | 322 | | sub_type | 发布消息的次事件类型 | 323 | | data | 发布消息的数据 | 324 | | timeout | 发布消息的超时时间 | 325 | |**返回**| —— | 326 | | REB_OK | 发布消息成功 | 327 | | OTHER | 发布消息失败 | 328 | 329 | - 发布者发送紧急消息,发送完成之后把消息缓冲删除 330 | - 该接口是发布者发布事件接口,它它是采用插队的方式发送消息,它会将发布的消息插入消息队列的头部。并且将消息发送给所有观察者之后,数据的内存会执行释放。 331 | 332 | ``` C 333 | reb_status publisher_urgent_send_with_free(uint16_t type, uint16_t sub_type, 334 | uint32_t data, reb_time_t timeout); 335 | ``` 336 | 337 | |**参数**|**描述**| 338 | |------|------| 339 | | type | 发布消息的主事件类型 | 340 | | sub_type | 发布消息的次事件类型 | 341 | | data | 发布消息的数据 | 342 | | timeout | 发布消息的超时时间 | 343 | |**返回**| —— | 344 | | REB_OK | 发布消息成功 | 345 | | OTHER | 发布消息失败 | 346 | 347 | ## REB验证 348 | 1. 创建三个不同模式的观察者,并关联到broker中。 349 | 2. 通过多次不发布事件,查看观察者是否能接收到事件。 350 | 351 | ``` 352 | #include "rtthread.h" 353 | #include "reb_broker.h" 354 | #include "reb_observer.h" 355 | #include "reb_publisher.h" 356 | 357 | observer_base *obs_signal; 358 | observer_base *obs_call; 359 | observer_base *obs_task; 360 | 361 | void sig_thread_handle(void *arg) // 信号模式观察者监听同步信号 362 | { 363 | while(1) { 364 | if(observer_signal_wait(obs_signal, RT_WAITING_FOREVER) == REB_OK) { 365 | rt_kprintf("signal: recv success\r\n"); 366 | } 367 | } 368 | } 369 | 370 | void obs_callback(uint32_t event, uint32_t data, void *arg) // 回调模式观察者处理函数 371 | { 372 | rt_kprintf("call: event: 0x%08x, data: %s\r\n", event, (char *)data); 373 | } 374 | 375 | void obs_task_fun(uint32_t event, uint32_t data, void *arg) // 任务模式观察者任务处理函数 376 | { 377 | rt_kprintf("task: event: 0x%08x, data: %s\r\n", event, (char *)data); 378 | } 379 | 380 | int reb_init(void) 381 | { 382 | rt_thread_t signal_thread = NULL; 383 | 384 | broker_create(); // broker创建 385 | 386 | obs_signal = observer_signal_create(1, REB_ALL_MINOR_TYPE); // 创建信号模式观察者 387 | 388 | signal_thread = rt_thread_create("sig_thread", sig_thread_handle, NULL, 1024, 10, 20); // 创建线程,等待信号模式下的事件 389 | rt_thread_startup(signal_thread); 390 | 391 | obs_call = observer_callback_create(1, REB_ALL_MINOR_TYPE, obs_callback, NULL); // 创建回调模式观察者 392 | 393 | obs_task = observer_task_create(1, REB_ALL_MINOR_TYPE, obs_task_fun, NULL, 1024, 15); // 创建任务模式观察者 394 | 395 | broker_observer_attach(obs_signal); // 关联信号模式观察者 396 | broker_observer_attach(obs_call); // 关联回调模式观察者 397 | broker_observer_attach_once(obs_task); // 关联任务模式观察者 398 | 399 | return RT_EOK; 400 | } 401 | INIT_COMPONENT_EXPORT(reb_init); 402 | 403 | int reb_test(void) 404 | { 405 | char *data = "RiceChen"; 406 | publisher_send(1, 1, (int)data, 1000); // 发布事件 407 | publisher_send(1, 2, (int)data, 1000); // 发布事件 408 | publisher_send(1, 3, (int)data, 1000); // 发布事件 409 | } 410 | MSH_CMD_EXPORT(reb_test, Rice Event broker test); 411 | ``` 412 | 413 | ![](./pic/result.png) -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | import os 3 | 4 | cwd = GetCurrentDir() 5 | 6 | src = Split(''' 7 | src/reb_broker.c 8 | src/reb_observer.c 9 | src/reb_publisher.c 10 | adapter/rtthread/reb_mutex.c 11 | adapter/rtthread/reb_sem.c 12 | adapter/rtthread/reb_task.c 13 | adapter/rtthread/reb_queue.c 14 | ''') 15 | 16 | CPPPATH = [cwd + '/include'] 17 | 18 | if GetDepend(['PKG_USING_REB_EXAMPLE']): 19 | src += ['example/reb_rtt_example.c'] 20 | 21 | group = DefineGroup('reb', src, depend = [''], CPPPATH = CPPPATH) 22 | Return('group') 23 | -------------------------------------------------------------------------------- /adapter/cmsis/reb_mutex.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "cmsis_os2.h" 3 | 4 | reb_mutex_id reb_mutex_create(void) 5 | { 6 | osMutexId_t mutex = NULL; 7 | mutex = osMutexNew(NULL); 8 | 9 | return (reb_mutex_id)mutex; 10 | } 11 | 12 | reb_status reb_mutex_lock(reb_mutex_id mutex) 13 | { 14 | if (mutex == NULL) { 15 | return REB_INVAL; 16 | } 17 | if(osMutexAcquire((osMutexId_t)mutex, osWaitForever) == osOK) { 18 | return REB_OK; 19 | } 20 | return REB_ERROR; 21 | } 22 | 23 | reb_status reb_mutex_unlock(reb_mutex_id mutex) 24 | { 25 | if (mutex == NULL) { 26 | return REB_INVAL; 27 | } 28 | if(osMutexRelease((osMutexId_t)mutex) == osOK) { 29 | return REB_OK; 30 | } 31 | return REB_ERROR; 32 | } 33 | 34 | void reb_mutex_delete(reb_mutex_id mutex) 35 | { 36 | if (mutex == NULL) { 37 | return; 38 | } 39 | osMutexDelete(mutex); 40 | } 41 | -------------------------------------------------------------------------------- /adapter/cmsis/reb_queue.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "cmsis_os2.h" 3 | 4 | reb_queue_id reb_queue_create(int size, int count) 5 | { 6 | osMessageQueueId_t queue = NULL; 7 | osMessageQueueAttr_t queue_attr = { 8 | .name = "reb", 9 | .attr_bits = 0, 10 | .cb_mem = NULL, 11 | .cb_size = 0, 12 | .mq_mem = NULL, 13 | .mq_size = 0}; 14 | 15 | queue = osMessageQueueNew(size, count, &queue_attr); 16 | return (reb_queue_id)queue; 17 | } 18 | 19 | reb_status reb_queue_send(reb_queue_id queue, const void *msg, 20 | uint32_t size, reb_time_t timeout) 21 | { 22 | osStatus_t ret = osMessageQueuePut((osMessageQueueId_t)queue, msg, 0, timeout); 23 | if (ret != osOK) { 24 | return REB_ERROR; 25 | } 26 | return REB_OK; 27 | } 28 | 29 | reb_status reb_queue_urgent_send(reb_queue_id queue, const void *msg, 30 | uint32_t size, reb_time_t timeout) 31 | { 32 | osStatus_t ret = osMessageQueueGet((osMessageQueueId_t)queue, msg, 1, 0); 33 | if (ret != osOK) { 34 | return REB_ERROR; 35 | } 36 | return REB_OK; 37 | } 38 | 39 | reb_status reb_queue_recv(reb_queue_id queue, void *msg, uint32_t size) 40 | { 41 | osStatus_t ret = osMessageQueueGet((osMessageQueueId_t)queue, msg, 0, osWaitForever); 42 | if(ret != osOK) { 43 | return REB_ERROR; 44 | } 45 | return REB_OK; 46 | } 47 | 48 | void reb_queue_delete(reb_queue_id queue) 49 | { 50 | if(queue != NULL) { 51 | osMessageQueueDelete((osMessageQueueId_t)queue); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /adapter/cmsis/reb_sem.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "cmsis_os2.h" 3 | 4 | reb_sem_id reb_sem_create(uint32_t value) 5 | { 6 | osSemaphoreId_t sem = NULL; 7 | sem = osSemaphoreNew(1, value, NULL); 8 | 9 | return (reb_sem_id)sem; 10 | } 11 | 12 | reb_status reb_sem_lock(reb_sem_id sem, reb_time_t timeout) 13 | { 14 | if (sem == NULL) { 15 | return REB_INVAL; 16 | } 17 | if(osSemaphoreAcquire((osSemaphoreId_t)sem, timeout) == osOK) { 18 | return REB_OK; 19 | } 20 | return REB_ERROR; 21 | } 22 | 23 | reb_status reb_sem_unlock(reb_sem_id sem) 24 | { 25 | if (sem == NULL) { 26 | return REB_INVAL; 27 | } 28 | if(osSemaphoreRelease((osSemaphoreId_t)sem) == osOK) { 29 | return REB_OK; 30 | } 31 | return REB_ERROR; 32 | } 33 | 34 | void reb_sem_delete(reb_sem_id sem) 35 | { 36 | if (sem == NULL) { 37 | return; 38 | } 39 | osSemaphoreDelete((osSemaphoreId_t)sem); 40 | } 41 | -------------------------------------------------------------------------------- /adapter/cmsis/reb_task.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "cmsis_os2.h" 3 | 4 | reb_task_id reb_task_create(reb_task_func func, void *arg, reb_task_attr *attr) 5 | { 6 | osThreadId_t thread = NULL; 7 | osThreadAttr_t task_attr = { 8 | .name = attr->name, 9 | .attr_bits = 0, 10 | .cb_mem = NULL, 11 | .cb_size = 0, 12 | .stack_mem = NULL, 13 | .stack_size = attr->stack_size, 14 | .priority = (osPriority_t)attr->priority, 15 | .tz_module = 0, 16 | .reserved = 0, 17 | }; 18 | 19 | thread = osThreadNew((osThreadFunc_t)func, arg, &task_attr); 20 | return (reb_task_id)thread; 21 | } 22 | 23 | reb_status reb_task_suspend(reb_task_id task) 24 | { 25 | osThreadSuspend((osThreadId_t)task); 26 | return REB_OK; 27 | } 28 | 29 | reb_status reb_task_resume(reb_task_id task) 30 | { 31 | osThreadResume((osThreadId_t)task); 32 | return REB_OK; 33 | } 34 | 35 | void reb_task_delete(reb_task_id task) 36 | { 37 | if(task != NULL) { 38 | osThreadTerminate((osThreadId_t)task); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /adapter/rtthread/reb_mutex.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "rtthread.h" 3 | 4 | reb_mutex_id reb_mutex_create(void) 5 | { 6 | rt_mutex_t mutex = NULL; 7 | 8 | mutex = rt_mutex_create("reb", RT_IPC_FLAG_FIFO); 9 | return (reb_mutex_id)mutex; 10 | } 11 | 12 | reb_status reb_mutex_lock(reb_mutex_id mutex) 13 | { 14 | if (mutex == NULL) { 15 | return REB_INVAL; 16 | } 17 | rt_mutex_take((rt_mutex_t)mutex, RT_WAITING_FOREVER); 18 | return REB_ERROR; 19 | } 20 | 21 | reb_status reb_mutex_unlock(reb_mutex_id mutex) 22 | { 23 | if (mutex == NULL) { 24 | return REB_INVAL; 25 | } 26 | rt_mutex_release((rt_mutex_t)mutex); 27 | return REB_ERROR; 28 | } 29 | 30 | void reb_mutex_delete(reb_mutex_id mutex) 31 | { 32 | rt_mutex_delete((rt_mutex_t)mutex); 33 | } 34 | -------------------------------------------------------------------------------- /adapter/rtthread/reb_queue.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "rtthread.h" 3 | 4 | reb_queue_id reb_queue_create(int size, int count) 5 | { 6 | rt_mq_t queue = NULL; 7 | 8 | queue = rt_mq_create("reb", size, count, RT_IPC_FLAG_FIFO); 9 | return (reb_queue_id)queue; 10 | } 11 | 12 | reb_status reb_queue_send(reb_queue_id queue, const void *msg, 13 | uint32_t size, reb_time_t timeout) 14 | { 15 | if(rt_mq_send_wait((rt_mq_t)queue, msg, size, timeout) == RT_EOK) { 16 | return REB_OK; 17 | } 18 | return REB_ERROR; 19 | } 20 | 21 | reb_status reb_queue_urgent_send(reb_queue_id queue, const void *msg, 22 | uint32_t size, reb_time_t timeout) 23 | { 24 | if(rt_mq_urgent((rt_mq_t)queue, msg, size) == RT_EOK) { 25 | return REB_OK; 26 | } 27 | return REB_ERROR; 28 | } 29 | 30 | reb_status reb_queue_recv(reb_queue_id queue, void *msg, uint32_t size) 31 | { 32 | #if RTTHREAD_VERSION >= 50000 33 | if(rt_mq_recv((rt_mq_t)queue, msg, size, RT_WAITING_FOREVER) > 0) { 34 | return REB_OK; 35 | } 36 | #else 37 | if(rt_mq_recv((rt_mq_t)queue, msg, size, RT_WAITING_FOREVER) == RT_EOK) { 38 | return REB_OK; 39 | } 40 | #endif 41 | return REB_ERROR; 42 | } 43 | 44 | void reb_queue_delete(reb_queue_id queue) 45 | { 46 | if(queue != NULL) { 47 | rt_mq_delete((rt_mq_t)queue); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /adapter/rtthread/reb_sem.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "rtthread.h" 3 | 4 | reb_sem_id reb_sem_create(uint32_t value) 5 | { 6 | rt_sem_t sem = NULL; 7 | 8 | sem = rt_sem_create("reb", value, RT_IPC_FLAG_FIFO); 9 | return (reb_sem_id)sem; 10 | } 11 | 12 | reb_status reb_sem_lock(reb_sem_id sem, reb_time_t timeout) 13 | { 14 | if (sem == NULL) { 15 | return REB_INVAL; 16 | } 17 | rt_sem_take((rt_sem_t)sem, timeout); 18 | return REB_OK; 19 | } 20 | 21 | reb_status reb_sem_unlock(reb_sem_id sem) 22 | { 23 | if (sem == NULL) { 24 | return REB_INVAL; 25 | } 26 | rt_sem_release((rt_sem_t)sem); 27 | return REB_OK; 28 | } 29 | 30 | void reb_sem_delete(reb_sem_id sem) 31 | { 32 | rt_sem_delete((rt_sem_t)sem); 33 | } 34 | -------------------------------------------------------------------------------- /adapter/rtthread/reb_task.c: -------------------------------------------------------------------------------- 1 | #include "reb_def.h" 2 | #include "rtthread.h" 3 | 4 | reb_task_id reb_task_create(reb_task_func func, void *arg, reb_task_attr *attr) 5 | { 6 | rt_thread_t thread = NULL; 7 | 8 | thread = rt_thread_create(attr->name, func, arg, attr->stack_size, attr->priority, 20); 9 | rt_thread_startup(thread); 10 | 11 | return (reb_task_id)thread; 12 | } 13 | 14 | reb_status reb_task_suspend(reb_task_id task) 15 | { 16 | rt_thread_suspend((rt_thread_t)task); 17 | return REB_OK; 18 | } 19 | 20 | reb_status reb_task_resume(reb_task_id task) 21 | { 22 | rt_thread_resume((rt_thread_t)task); 23 | return REB_OK; 24 | } 25 | 26 | void reb_task_delete(reb_task_id task) 27 | { 28 | rt_thread_delete((rt_thread_t)task); 29 | } 30 | -------------------------------------------------------------------------------- /example/reb_rtt_example.c: -------------------------------------------------------------------------------- 1 | #include "rtthread.h" 2 | #include "reb_broker.h" 3 | #include "reb_observer.h" 4 | #include "reb_publisher.h" 5 | 6 | observer_base *obs_signal; 7 | observer_base *obs_call; 8 | observer_base *obs_task; 9 | 10 | void sig_thread_handle(void *arg) 11 | { 12 | while(1) { 13 | if(observer_signal_wait(obs_signal, (reb_time_t)RT_WAITING_FOREVER) == REB_OK) { 14 | rt_kprintf("signal: recv success\r\n"); 15 | } 16 | } 17 | } 18 | 19 | void obs_callback(uint32_t event, uint32_t data, void *arg) 20 | { 21 | rt_kprintf("call: event: 0x%08x, data: %s\r\n", event, (char *)data); 22 | } 23 | 24 | void obs_task_fun(uint32_t event, uint32_t data, void *arg) 25 | { 26 | rt_kprintf("task: event: 0x%08x, data: %s\r\n", event, (char *)data); 27 | } 28 | 29 | int reb_init(void) 30 | { 31 | rt_thread_t signal_thread = NULL; 32 | 33 | broker_create(); 34 | 35 | obs_signal = observer_signal_create(1, REB_ALL_MINOR_TYPE); 36 | 37 | signal_thread = rt_thread_create("sig_thread", sig_thread_handle, NULL, 1024, 10, 20); 38 | rt_thread_startup(signal_thread); 39 | 40 | obs_call = observer_callback_create(1, REB_ALL_MINOR_TYPE, obs_callback, NULL); 41 | 42 | obs_task = observer_task_create(1, REB_ALL_MINOR_TYPE, obs_task_fun, NULL, 1024, 15); 43 | 44 | broker_observer_attach(obs_signal); 45 | broker_observer_attach(obs_call); 46 | broker_observer_attach_once(obs_task); 47 | 48 | return RT_EOK; 49 | } 50 | INIT_COMPONENT_EXPORT(reb_init); 51 | 52 | int reb_test(void) 53 | { 54 | char *data = "RiceChen"; 55 | publisher_send(1, 1, (int)data, 1000); 56 | publisher_send(1, 2, (int)data, 1000); 57 | publisher_send(1, 3, (int)data, 1000); 58 | return RT_EOK; 59 | } 60 | MSH_CMD_EXPORT(reb_test, Rice Event broker test); 61 | 62 | -------------------------------------------------------------------------------- /include/reb_broker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #ifndef __REB_BROKER_H__ 8 | #define __REB_BROKER_H__ 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include "reb_observer.h" 15 | 16 | typedef struct { 17 | reb_list_t obs_head; 18 | reb_mutex_id lock; 19 | } broker_base; 20 | 21 | reb_status broker_create(void); 22 | 23 | reb_status broker_delete(void); 24 | 25 | reb_status broker_observer_attach_once(observer_base *obs); 26 | 27 | reb_status broker_observer_attach(observer_base *obs); 28 | 29 | reb_status broker_observer_detach(observer_base *obs); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/reb_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #ifndef __REB_CFG_H__ 8 | #define __REB_CFG_H__ 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | /** 15 | * @brief The stack size for the publisher to handle event tasks. 16 | */ 17 | #define REB_PUBLISHER_TASK_STACK_SIZE (2 * 1024) 18 | 19 | /** 20 | * @brief The priority for the publisher to handle event tasks. 21 | */ 22 | #define REB_PUBLISHER_TASK_PRIO (15) 23 | 24 | /** 25 | * @brief Number of message buffers processed by the publisher for events. 26 | */ 27 | #define REB_PUBLISHER_QUEUE_MSG_COUNT (10) 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/reb_def.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #ifndef __REB_DEF_H__ 8 | #define __REB_DEF_H__ 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | typedef enum { 21 | REB_OK = 0, /**< There is no error */ 22 | REB_ERROR, /**< A generic error happens */ 23 | REB_FULL, /**< The resource is full */ 24 | REB_EMPTY, /**< The resource is empty */ 25 | REB_NOMEM, /**< No memory */ 26 | REB_INVAL, /**< Invalid argument */ 27 | } reb_status; 28 | 29 | #define REB_INLINE static __inline 30 | 31 | /** 32 | * memory API 33 | */ 34 | #ifndef REB_MALLOC 35 | #define REB_MALLOC malloc 36 | #endif 37 | 38 | #ifndef REB_FREE 39 | #define REB_FREE free 40 | #endif 41 | 42 | /** 43 | * debug API 44 | */ 45 | #define REB_LOGE_EN 1 46 | #define REB_LOGD_EN 0 47 | #define REB_LOGI_EN 0 48 | 49 | #ifndef REB_PRINT 50 | #ifdef __RTTHREAD__ 51 | #include 52 | #define REB_PRINT rt_kprintf 53 | #else 54 | #define REB_PRINT printf 55 | #endif 56 | #endif 57 | 58 | #ifndef REB_PRINT_TAG 59 | #define REB_PRINT_TAG "REB" 60 | #endif 61 | 62 | #if REB_LOGE_EN 63 | #define REB_LOGE(...) REB_PRINT("\033[31;22m[E/%s](%s:%d) ", REB_PRINT_TAG, __FUNCTION__, __LINE__); \ 64 | REB_PRINT(__VA_ARGS__); \ 65 | REB_PRINT("\033[0m\n") 66 | #else 67 | #define REB_LOGE(...) 68 | #endif 69 | 70 | #if REB_LOGI_EN 71 | #define REB_LOGI(...) REB_PRINT("\033[32;22m[I/%s](%s:%d) ", REB_PRINT_TAG, __FUNCTION__, __LINE__); \ 72 | REB_PRINT(__VA_ARGS__); \ 73 | REB_PRINT("\033[0m\n") 74 | #else 75 | #define REB_LOGI(...) 76 | #endif 77 | 78 | #if REB_LOGD_EN 79 | #define REB_LOGD(...) REB_PRINT("[D/%s](%s:%d) ", REB_PRINT_TAG, __FUNCTION__, __LINE__); \ 80 | REB_PRINT(__VA_ARGS__); \ 81 | REB_PRINT("\n"); 82 | #else 83 | #define REB_LOGD(...) 84 | #endif 85 | 86 | #define REB_ALL_MINOR_TYPE (0xFFFF) 87 | 88 | #define REB_MK_EVENT_TYPE(mojor, minor) \ 89 | (((uint32_t)(mojor) << 16) | ((uint32_t)(minor) & 0xFFFF)) 90 | #define REB_EVENT_MOJOR_TYPE(event) ((uint16_t)((event) >> 16)) 91 | #define REB_EVENT_MINOR_TYPE(event) ((uint32_t)(event) & 0xFFFF) 92 | #define REB_EVENT_TYPE_MOJOR_CMP(pub_type, obs_type) (!((pub_type ^ obs_type) & 0xFFFF0000)) 93 | 94 | typedef uint32_t reb_time_t; 95 | 96 | /** 97 | * Task API 98 | */ 99 | typedef void *reb_task_id; 100 | 101 | typedef struct reb_task_attr{ 102 | char *name; // name of the task 103 | uint32_t stack_size; // size of stack 104 | uint8_t priority; // task priority 105 | } reb_task_attr; 106 | 107 | typedef void(*reb_task_func)(void *arg); 108 | 109 | reb_task_id reb_task_create(reb_task_func func, void *arg, reb_task_attr *attr); 110 | void reb_task_delete(reb_task_id task); 111 | 112 | /** 113 | * Mutex API 114 | */ 115 | typedef void *reb_mutex_id; 116 | 117 | reb_mutex_id reb_mutex_create(void); 118 | reb_status reb_mutex_lock(reb_mutex_id mutex); 119 | reb_status reb_mutex_unlock(reb_mutex_id mutex); 120 | void reb_mutex_delete(reb_mutex_id mutex); 121 | 122 | /** 123 | * Sem API 124 | */ 125 | typedef void *reb_sem_id; 126 | 127 | reb_sem_id reb_sem_create(uint32_t value); 128 | reb_status reb_sem_lock(reb_sem_id sem, reb_time_t time); 129 | reb_status reb_sem_unlock(reb_sem_id sem); 130 | void reb_sem_delete(reb_sem_id sem); 131 | 132 | /** 133 | * Queue API 134 | */ 135 | typedef void *reb_queue_id; 136 | 137 | reb_queue_id reb_queue_create(int size, int count); 138 | reb_status reb_queue_send(reb_queue_id queue, const void *msg, 139 | uint32_t size, reb_time_t timeout); 140 | reb_status reb_queue_urgent_send(reb_queue_id queue, const void *msg, 141 | uint32_t size, reb_time_t timeout); 142 | reb_status reb_queue_recv(reb_queue_id queue, void *msg, uint32_t size); 143 | void reb_queue_delete(reb_queue_id queue); 144 | 145 | /** 146 | * List Api 147 | */ 148 | struct reb_list_node { 149 | struct reb_list_node *next; 150 | struct reb_list_node *prev; 151 | }; 152 | typedef struct reb_list_node reb_list_t; 153 | 154 | REB_INLINE void reb_list_init(reb_list_t *l) 155 | { 156 | l->next = l->prev = l; 157 | } 158 | 159 | REB_INLINE void reb_list_insert_after(reb_list_t *l, reb_list_t *n) 160 | { 161 | l->next->prev = n; 162 | n->next = l->next; 163 | l->next = n; 164 | n->prev = l; 165 | } 166 | 167 | REB_INLINE void reb_list_insert_before(reb_list_t *l, reb_list_t *n) 168 | { 169 | l->prev->next = n; 170 | n->prev = l->prev; 171 | l->prev = n; 172 | n->next = l; 173 | } 174 | 175 | REB_INLINE void reb_list_remove(reb_list_t *n) 176 | { 177 | n->next->prev = n->prev; 178 | n->prev->next = n->next; 179 | n->next = n->prev = n; 180 | } 181 | 182 | REB_INLINE int reb_list_is_empty(const reb_list_t *l) 183 | { 184 | return l->next == l; 185 | } 186 | 187 | REB_INLINE int reb_list_len(const reb_list_t *l) 188 | { 189 | int len = 0; 190 | const reb_list_t *p = l; 191 | while (p->next != l) { 192 | p = p->next; 193 | len ++; 194 | } 195 | return len; 196 | } 197 | 198 | #define reb_container_of(ptr, type, member) \ 199 | ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) 200 | 201 | #define reb_list_obj_init(obj) {&(obj), &(obj)} 202 | 203 | #define reb_list_entry(node, type, member) \ 204 | reb_container_of(node, type, member) 205 | 206 | #define reb_list_for_each(pos, head) \ 207 | for (pos = (head)->next; pos != (head); pos = pos->next) 208 | 209 | #ifdef __cplusplus 210 | } 211 | #endif 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /include/reb_observer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #ifndef __REB_OBSERVER_H__ 8 | #define __REB_OBSERVER_H__ 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include "reb_def.h" 15 | 16 | typedef enum { 17 | OBS_MODE_SIGNAL, 18 | OBS_MODE_CALLBACK, 19 | OBS_MODE_TASK, 20 | } observer_mode; 21 | 22 | typedef enum { 23 | OBS_STATE_IDLE, 24 | OBS_STATE_ATTACH, 25 | OBS_STATE_ATTACH_ONCE, 26 | OBS_STATE_DETACH, 27 | } observer_state; 28 | 29 | typedef struct observer_base observer_base; 30 | 31 | typedef void (*obs_trigger_cb)(observer_base *base, uint32_t event, uint32_t data); 32 | 33 | struct observer_base{ 34 | reb_list_t node; 35 | uint32_t event; 36 | int state; 37 | int mode; 38 | obs_trigger_cb trigger; 39 | void *arg; 40 | }; 41 | 42 | /** 43 | * Observer signal mode 44 | */ 45 | 46 | typedef struct { 47 | observer_base base; 48 | reb_sem_id signal; 49 | } observer_signal; 50 | 51 | observer_base *observer_signal_create(uint16_t type, uint16_t sub_type); 52 | reb_status observer_signal_wait(observer_base *base, reb_time_t timeout); 53 | 54 | /** 55 | * Observer callback mode 56 | */ 57 | 58 | typedef void (*obs_callback_cb)(uint32_t event, uint32_t data, void *arg); 59 | 60 | typedef struct { 61 | observer_base base; 62 | obs_callback_cb cb; 63 | } observer_callback; 64 | 65 | observer_base *observer_callback_create(uint16_t type, 66 | uint16_t sub_type, 67 | obs_callback_cb cb, 68 | void *arg); 69 | 70 | /** 71 | * Observer task mode 72 | */ 73 | 74 | typedef void (*obs_task_cb)(uint32_t event, uint32_t data, void *arg); 75 | 76 | typedef struct { 77 | observer_base base; 78 | reb_task_id task; 79 | obs_task_cb run; 80 | uint32_t stack_size; 81 | uint32_t prio; 82 | uint32_t event; 83 | uint32_t data; 84 | } observer_task; 85 | 86 | observer_base *observer_task_create(uint16_t type, 87 | uint16_t sub_type, 88 | obs_task_cb run, 89 | void *arg, 90 | uint32_t stack_size, 91 | uint32_t prio); 92 | 93 | reb_status observer_delete(observer_base *base); 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /include/reb_publisher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #ifndef __REB_PUBLISHER_H__ 8 | #define __REB_PUBLISHER_H__ 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include "reb_def.h" 15 | 16 | typedef void (*pub_notify)(uint32_t event, uint32_t data, bool need_free); 17 | 18 | reb_status publisher_factory_create(pub_notify notify); 19 | 20 | reb_status publisher_send(uint16_t type, uint16_t sub_type, 21 | uint32_t data, reb_time_t timeout); 22 | 23 | reb_status publisher_send_with_free(uint16_t type, uint16_t sub_type, 24 | uint32_t data, reb_time_t timeout); 25 | 26 | reb_status publisher_urgent_send(uint16_t type, uint16_t sub_type, 27 | uint32_t data, reb_time_t timeout); 28 | 29 | reb_status publisher_urgent_send_with_free(uint16_t type, uint16_t sub_type, 30 | uint32_t data, reb_time_t timeout); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /pic/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiceChen0/reb/9bab3db816bdf04e582ec876846062ff00aca50a/pic/flow.png -------------------------------------------------------------------------------- /pic/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiceChen0/reb/9bab3db816bdf04e582ec876846062ff00aca50a/pic/result.png -------------------------------------------------------------------------------- /src/reb_broker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #include "reb_broker.h" 8 | #include "reb_publisher.h" 9 | #include "reb_def.h" 10 | 11 | static broker_base base; 12 | 13 | static bool brober_event_type_cmp(uint32_t pub_event, uint32_t obs_event) 14 | { 15 | if (REB_EVENT_TYPE_MOJOR_CMP(pub_event, obs_event) && 16 | (REB_EVENT_MINOR_TYPE(obs_event) == REB_ALL_MINOR_TYPE || pub_event == obs_event)) 17 | { 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | static reb_status _broker_observer_attach(observer_base *obs, observer_state state) 24 | { 25 | obs->state = state; 26 | reb_mutex_lock(base.lock); 27 | reb_list_insert_after(&base.obs_head, &obs->node); 28 | reb_mutex_unlock(base.lock); 29 | 30 | REB_LOGD("Broker: attach observer event, event type: 0x%08x", obs->event); 31 | return REB_OK; 32 | } 33 | 34 | reb_status broker_observer_attach_once(observer_base *obs) 35 | { 36 | return _broker_observer_attach(obs, OBS_STATE_ATTACH_ONCE); 37 | } 38 | 39 | reb_status broker_observer_attach(observer_base *obs) 40 | { 41 | return _broker_observer_attach(obs, OBS_STATE_ATTACH); 42 | } 43 | 44 | reb_status broker_observer_detach(observer_base *obs) 45 | { 46 | reb_mutex_lock(base.lock); 47 | obs->state = OBS_STATE_DETACH; 48 | reb_list_remove(&obs->node); 49 | reb_mutex_unlock(base.lock); 50 | 51 | REB_LOGD("Broker: detach observer event, event type: 0x%08x", obs->event); 52 | return REB_OK; 53 | } 54 | 55 | static void broker_publisher_notify(uint32_t event, uint32_t data, bool need_free) 56 | { 57 | observer_base *obs = NULL; 58 | reb_list_t *node = NULL; 59 | 60 | reb_mutex_lock(base.lock); 61 | reb_list_for_each(node, &base.obs_head) { 62 | obs = reb_list_entry(node, observer_base, node); 63 | if(obs == NULL) { 64 | REB_LOGE("Broker: find observer node failed"); 65 | continue; 66 | } 67 | 68 | if(brober_event_type_cmp(event, obs->event) && 69 | (obs->state == OBS_STATE_ATTACH || obs->state == OBS_STATE_ATTACH_ONCE)) { 70 | if(obs->trigger) { 71 | obs->trigger(obs, event, data); 72 | } 73 | if(obs->state == OBS_STATE_ATTACH_ONCE) { 74 | obs->state = OBS_STATE_IDLE; 75 | } 76 | } 77 | } 78 | 79 | reb_mutex_unlock(base.lock); 80 | 81 | if(need_free) { 82 | REB_FREE((void *)data); 83 | } 84 | } 85 | 86 | reb_status broker_create(void) 87 | { 88 | reb_status status = REB_OK; 89 | base.lock = reb_mutex_create(); 90 | if(base.lock == NULL) { 91 | REB_LOGE("Broker: create queue failed"); 92 | return REB_ERROR; 93 | } 94 | 95 | reb_list_init(&base.obs_head); 96 | status = publisher_factory_create(broker_publisher_notify); 97 | if(status != REB_OK) { 98 | REB_LOGE("Broker: Create puvlisher factory failed"); 99 | return status; 100 | } 101 | 102 | REB_LOGD("Briker: init success"); 103 | return status; 104 | } 105 | 106 | reb_status broker_delete(void) 107 | { 108 | reb_status status = REB_OK; 109 | 110 | reb_list_remove(&base.obs_head); 111 | 112 | if(base.lock) { 113 | reb_mutex_delete(base.lock); 114 | } 115 | 116 | return status; 117 | } 118 | -------------------------------------------------------------------------------- /src/reb_observer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #include "reb_observer.h" 8 | 9 | static int observer_create(observer_base *base, uint32_t event, 10 | obs_trigger_cb trigger, void *arg) 11 | { 12 | reb_list_init(&base->node); 13 | base->event = event; 14 | base->trigger = trigger; 15 | base->arg = arg; 16 | return REB_OK; 17 | } 18 | 19 | static void observer_signal_trigger(observer_base *base, uint32_t event, uint32_t data) 20 | { 21 | observer_signal *obs = reb_container_of(base, observer_signal, base); 22 | reb_sem_unlock(obs->signal); 23 | } 24 | 25 | observer_base *observer_signal_create(uint16_t type, uint16_t sub_type) 26 | { 27 | observer_signal *obs = NULL; 28 | 29 | obs = REB_MALLOC(sizeof(observer_signal)); 30 | if(obs == NULL) { 31 | REB_LOGE("Observer: Failed to create observer for signal mode, event type: 0x%08x", REB_MK_EVENT_TYPE(type, sub_type)); 32 | return NULL; 33 | } 34 | memset(obs, 0, sizeof(observer_signal)); 35 | 36 | observer_create(&obs->base, 37 | REB_MK_EVENT_TYPE(type, sub_type), 38 | observer_signal_trigger, NULL); 39 | obs->base.mode = OBS_MODE_SIGNAL; 40 | obs->signal = reb_sem_create(0); 41 | if(obs->signal == NULL) { 42 | REB_LOGE("Observer: create sem failed"); 43 | REB_FREE(obs); 44 | obs = NULL; 45 | return NULL; 46 | } 47 | 48 | REB_LOGD("Observer: create signal mode success, event type: 0x%08x", REB_MK_EVENT_TYPE(type, sub_type)); 49 | 50 | return &obs->base; 51 | } 52 | 53 | reb_status observer_signal_wait(observer_base *base, reb_time_t timeout) 54 | { 55 | observer_signal *obs = reb_container_of(base, observer_signal, base); 56 | return reb_sem_lock(obs->signal, timeout); 57 | } 58 | 59 | static void observer_callback_trigger(observer_base *base, uint32_t event, uint32_t data) 60 | { 61 | observer_callback *obs = reb_container_of(base, observer_callback, base); 62 | 63 | if(obs->cb) { 64 | obs->cb(event, data, obs->base.arg); 65 | } 66 | } 67 | 68 | observer_base *observer_callback_create(uint16_t type, 69 | uint16_t sub_type, 70 | obs_callback_cb cb, 71 | void *arg) 72 | { 73 | observer_callback *obs = NULL; 74 | 75 | obs = REB_MALLOC(sizeof(observer_callback)); 76 | if(obs == NULL) { 77 | REB_LOGE("Observer: Failed to create observer for callback mode, event type: 0x%08x", REB_MK_EVENT_TYPE(type, sub_type)); 78 | return NULL; 79 | } 80 | memset(obs, 0, sizeof(observer_callback)); 81 | 82 | observer_create(&obs->base, 83 | REB_MK_EVENT_TYPE(type, sub_type), 84 | observer_callback_trigger, arg); 85 | obs->base.mode = OBS_MODE_CALLBACK; 86 | obs->cb = cb; 87 | 88 | REB_LOGD("Observer: create callback mode success, event type: 0x%08x", REB_MK_EVENT_TYPE(type, sub_type)); 89 | 90 | return &obs->base; 91 | } 92 | 93 | void task_trigger_handle(void *arg) 94 | { 95 | observer_task *obs = (observer_task *)arg; 96 | 97 | obs->run(obs->event, obs->data, obs->base.arg); 98 | } 99 | 100 | static void observer_task_trigger(observer_base *base, uint32_t event, uint32_t data) 101 | { 102 | observer_task *obs = reb_container_of(base, observer_task, base); 103 | reb_task_attr task_attr = { 104 | .name = "obs_task", 105 | .priority = obs->prio, 106 | .stack_size = obs->stack_size, 107 | }; 108 | 109 | if(obs->task != NULL) { 110 | return; 111 | } 112 | 113 | obs->event = event; 114 | obs->data = data; 115 | 116 | if(obs->task) { 117 | REB_LOGE("Observer: Task still running"); 118 | return; 119 | } 120 | 121 | obs->task = reb_task_create(task_trigger_handle, obs, &task_attr); 122 | if(obs->task == NULL) { 123 | REB_LOGE("Observer: create task failed"); 124 | return; 125 | } 126 | } 127 | 128 | observer_base *observer_task_create(uint16_t type, 129 | uint16_t sub_type, 130 | obs_task_cb run, 131 | void *arg, 132 | uint32_t stack_size, 133 | uint32_t prio) 134 | { 135 | observer_task *obs = NULL; 136 | 137 | obs = REB_MALLOC(sizeof(observer_task)); 138 | if(obs == NULL) { 139 | REB_LOGE("Observer: Failed to create observer for task mode, event type: 0x%08x", REB_MK_EVENT_TYPE(type, sub_type)); 140 | return NULL; 141 | } 142 | memset(obs, 0, sizeof(observer_task)); 143 | 144 | observer_create(&obs->base, 145 | REB_MK_EVENT_TYPE(type, sub_type), 146 | observer_task_trigger, arg); 147 | obs->base.mode = OBS_MODE_TASK; 148 | obs->run = run; 149 | obs->stack_size = stack_size; 150 | obs->prio = prio; 151 | 152 | REB_LOGD("Observer: create task mode success, event type: 0x08x", REB_MK_EVENT_TYPE(type, sub_type)); 153 | 154 | return &obs->base; 155 | } 156 | 157 | reb_status observer_delete(observer_base *base) 158 | { 159 | if(base == NULL) { 160 | return REB_INVAL; 161 | } 162 | if(base->state != OBS_STATE_IDLE) { 163 | return REB_ERROR; 164 | } 165 | REB_FREE(base); 166 | return REB_OK; 167 | } 168 | -------------------------------------------------------------------------------- /src/reb_publisher.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Change Logs: 3 | * Date Author Notes 4 | * 2023-10-10 RiceChen the first version 5 | */ 6 | 7 | #include "reb_publisher.h" 8 | #include "reb_cfg.h" 9 | 10 | typedef struct { 11 | reb_task_id task; 12 | reb_queue_id queue; 13 | pub_notify notify; 14 | } publisher_base; 15 | 16 | typedef struct { 17 | uint32_t event; 18 | uint32_t data; 19 | bool free; 20 | } publisher_msg; 21 | 22 | static publisher_base pub; 23 | 24 | static void publisher_event_handle(void *arg) 25 | { 26 | reb_status status; 27 | publisher_base *pub = (publisher_base *)arg; 28 | publisher_msg msg = {0}; 29 | 30 | while(1) { 31 | status = reb_queue_recv(pub->queue, &msg, sizeof(publisher_msg)); 32 | if(status != REB_OK) { 33 | REB_LOGE("Publisher: queue recv failed %d", status); 34 | continue; 35 | } 36 | 37 | if(pub->notify) { 38 | pub->notify(msg.event, msg.data, msg.free); 39 | } 40 | else { 41 | if(msg.free == true) { 42 | REB_FREE((void *)msg.data); 43 | } 44 | } 45 | }; 46 | } 47 | 48 | reb_status publisher_factory_create(pub_notify notify) 49 | { 50 | reb_task_attr task_attr = { 51 | .name = "reb_pub", 52 | .stack_size = REB_PUBLISHER_TASK_STACK_SIZE, 53 | .priority = REB_PUBLISHER_TASK_PRIO, 54 | }; 55 | 56 | pub.queue = reb_queue_create(sizeof(publisher_msg), REB_PUBLISHER_QUEUE_MSG_COUNT); 57 | if(pub.queue == NULL) { 58 | REB_LOGE("Publisher: create queue failed"); 59 | return REB_ERROR; 60 | } 61 | 62 | pub.task = reb_task_create(publisher_event_handle, &pub, &task_attr); 63 | if(pub.task == NULL) { 64 | REB_LOGE("Publisher: create task failed"); 65 | reb_queue_delete(pub.queue); 66 | return REB_ERROR; 67 | } 68 | 69 | pub.notify = notify; 70 | 71 | return REB_OK; 72 | } 73 | 74 | static reb_status _publisher_send(uint16_t type, uint16_t sub_type, uint32_t data, 75 | reb_time_t timeout, bool free) 76 | { 77 | publisher_msg msg = {0}; 78 | uint32_t event = REB_MK_EVENT_TYPE(type, sub_type); 79 | 80 | msg.event = event; 81 | msg.data = data; 82 | msg.free = free; 83 | 84 | REB_LOGD("Publisher: send event, event type: 0x%08x", REB_MK_EVENT_TYPE(type, sub_type)); 85 | 86 | return reb_queue_send(pub.queue, &msg, sizeof(publisher_msg), timeout); 87 | } 88 | 89 | reb_status publisher_send(uint16_t type, uint16_t sub_type, 90 | uint32_t data, reb_time_t timeout) 91 | { 92 | return _publisher_send(type, sub_type, data, timeout, false); 93 | } 94 | 95 | reb_status publisher_send_with_free(uint16_t type, uint16_t sub_type, 96 | uint32_t data, reb_time_t timeout) 97 | { 98 | return _publisher_send(type, sub_type, data, timeout, true); 99 | } 100 | 101 | static reb_status _publisher_urgent_send(uint16_t type, uint16_t sub_type, uint32_t data, 102 | reb_time_t timeout, bool free) 103 | { 104 | publisher_msg msg = {0}; 105 | uint32_t event = REB_MK_EVENT_TYPE(type, sub_type); 106 | 107 | msg.event = event; 108 | msg.data = data; 109 | msg.free = free; 110 | 111 | return reb_queue_urgent_send(pub.queue, &msg, sizeof(publisher_msg), timeout); 112 | } 113 | 114 | reb_status publisher_urgent_send(uint16_t type, uint16_t sub_type, 115 | uint32_t data, reb_time_t timeout) 116 | { 117 | return _publisher_urgent_send(type, sub_type, data, timeout, false); 118 | } 119 | 120 | reb_status publisher_urgent_send_with_free(uint16_t type, uint16_t sub_type, 121 | uint32_t data, reb_time_t timeout) 122 | { 123 | return _publisher_urgent_send(type, sub_type, data, timeout, true); 124 | } 125 | --------------------------------------------------------------------------------