├── .clang-format ├── .clangd ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── om ├── .clang-format ├── .clangd ├── .github │ └── workflows │ │ └── cmake.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake │ └── FindCheck.cmake ├── config │ └── om_config_template.h ├── doc │ ├── config.md │ ├── dev.md │ └── user.md ├── img │ └── log.png ├── src │ ├── CMakeLists.txt │ ├── app │ │ ├── om_afl.c │ │ ├── om_afl.h │ │ ├── om_com.c │ │ ├── om_com.h │ │ ├── om_evt.c │ │ ├── om_evt.h │ │ ├── om_fmt.c │ │ ├── om_fmt.h │ │ ├── om_log.c │ │ ├── om_log.h │ │ ├── om_msg.c │ │ └── om_msg.h │ ├── comp │ │ ├── om_color.c │ │ ├── om_color.h │ │ ├── om_crc.c │ │ ├── om_crc.h │ │ ├── om_fifo.c │ │ ├── om_fifo.h │ │ ├── om_list.c │ │ ├── om_list.h │ │ ├── om_rbt.c │ │ └── om_rbt.h │ ├── core │ │ ├── om_core.c │ │ ├── om_core.h │ │ ├── om_def.h │ │ └── om_lib.h │ ├── om.c │ └── om.h └── test │ ├── CMakeLists.txt │ ├── om_test.h │ ├── om_test_base.c │ ├── om_test_main.c │ └── om_test_module.c └── src ├── om.cpp └── om.hpp /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BasedOnStyle: Google 3 | IncludeBlocks: Regroup 4 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | Diagnostics: 2 | ClangTidy: 3 | Add: [readability-braces-around-statements, 4 | readability-identifier-naming, 5 | misc*,google*, 6 | clang-analyzer-nullability*, 7 | clang-analyzer-*, cert-*, 8 | bugprone-*, 9 | cppcoreguidelines-*, 10 | modernize-deprecated-headers, 11 | modernize-loop-convert, 12 | modernize-avoid-c-arrays, 13 | concurrency-*, 14 | performance-*] 15 | Remove: [google-build-using-namespace, 16 | bugprone-undefined-memory-manipulation, 17 | cppcoreguidelines-pro-type-member-init, 18 | cppcoreguidelines-pro-type-union-access, 19 | misc-no-recursion, 20 | cert-env33-c, 21 | cert-err58-cpp, 22 | cert-msc*, 23 | concurrency-mt-unsafe, 24 | cppcoreguidelines-no-malloc, 25 | cppcoreguidelines-owning-memory, 26 | cppcoreguidelines-special-member-functions, 27 | google-readability-todo, 28 | bugprone-easily-swappable-parameters, 29 | cppcoreguidelines-pro-bounds-constant-array-index, 30 | cppcoreguidelines-explicit-virtual-functions, 31 | cppcoreguidelines-virtual-class-destructor, 32 | cppcoreguidelines-pro-type-reinterpret-cast, 33 | google-explicit-constructor, 34 | cppcoreguidelines-pro-bounds-array-to-pointer-decay, 35 | cppcoreguidelines-pro-bounds-pointer-arithmetic, 36 | cppcoreguidelines-pro-type-vararg, 37 | cppcoreguidelines-avoid-magic-numbers, 38 | cppcoreguidelines-avoid-c-arrays, 39 | cppcoreguidelines-avoid-non-const-global-variables, 40 | cppcoreguidelines-non-private-member-variables-in-classes] 41 | CheckOptions: 42 | misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: 1 43 | modernize-loop-convert.MinConfidence: risky 44 | readability-identifier-naming.VariableCase: lower_case 45 | readability-identifier-naming.GlobalVariableCase: lower_case 46 | readability-identifier-naming.ClassMemberCase: lower_case 47 | readability-identifier-naming.ClassMemberSuffix: _ 48 | readability-identifier-naming.PrivateMemberCase: lower_case 49 | readability-identifier-naming.PrivateMemberSuffix: _ 50 | readability-identifier-naming.ProtectedMemberCase: lower_case 51 | readability-identifier-naming.ProtectedMemberSuffix: _ 52 | readability-identifier-naming.EnumCase: UPPER_CASE 53 | readability-identifier-naming.EnumConstantCase: UPPER_CASE 54 | readability-identifier-naming.MacroDefinitionCase: UPPER_CASE 55 | readability-identifier-naming.ConstantCase: UPPER_CASE 56 | readability-identifier-naming.ClassCase: CamelCase 57 | readability-identifier-naming.StructCase : CamelCase 58 | readability-identifier-naming.FunctionCase: lower_case 59 | readability-identifier-naming.ClassMethodCase: CamelCase 60 | readability-identifier-naming.MethodCase: CamelCase 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | .vscode/* 3 | config/om_config.h 4 | utils/*.csv 5 | .cache/** 6 | .history/** 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/om/src) 4 | 5 | file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") 6 | 7 | target_sources(OneMessage PUBLIC ${${PROJECT_NAME}_SOURCES}) 8 | 9 | target_include_directories( 10 | OneMessage 11 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) 12 | 13 | project(OneMessageCPP) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OneMessageCPP 2 | 3 | 本仓库为[OneMessage](https://github.com/Jiu-xiao/OneMessage.git)的C++封装,多数API在初始化时会动态申请内存。使用时请对照[OneMessage](https://github.com/Jiu-xiao/OneMessage.git)文档。 4 | 5 | --- 6 | 7 | ## USAGE 8 | 9 | 请参照[OneMessage](https://github.com/Jiu-xiao/OneMessage.git)中的 [Readme.md](https://github.com/Jiu-xiao/OneMessage/blob/master/README.md) 编写om_config.h文件。 10 | 11 | ## om_config.h 12 | 13 | om_config.h中需要另外声明一个函数,如果在中断中调用此函数,应当返回true,否则返回false。在linux等平台可以直接返回false。 14 | 15 | ```c++ 16 | #include 17 | static inline bool om_in_isr() { 18 | ... 19 | } 20 | ``` 21 | 22 | ## CMake 23 | 24 | 作为CMake子模块编译 25 | 26 | CMakeList.txt 27 | 28 | ```CMake 29 | # OneMessageCPP_directory 为OneMessageCPP所在目录 30 | # om_config_file_directory 为om_config.h所在目录 31 | 32 | add_subdirectory(OneMessageCPP_directory) 33 | 34 | target_include_directories( 35 | OneMessage 36 | PUBLIC om_config_file_directory 37 | ... 38 | ) 39 | ``` 40 | 41 | ## API 42 | 43 | > `template class Topic` 44 | 45 | 构造函数: 46 | 47 | Topic可以直接隐式类型转换为om_topic_t* 48 | 49 | 新创建一个Topic,cached为false代表不拷贝数据,只传递指针 50 | 51 | ```c++ 52 | Topic(const char *name, bool cached = false); 53 | ``` 54 | 55 | 拷贝一个已有的topic,不允许重复创建同名topic。 56 | 57 | ```c++ 58 | Topic(om_topic_t *topic); 59 | ``` 60 | 61 | 队列: 62 | 63 | ```c++ 64 | template 65 | class Queue{ 66 | Queue(topic_t* topic); 67 | 68 | uint32_t Size(); 69 | 70 | bool Read(Data& buff); 71 | 72 | bool Reads(Data* buff, uint32_t len); 73 | 74 | bool Pop(); 75 | 76 | void Reset(); 77 | } 78 | ``` 79 | 80 | 链接: 81 | 82 | ```c++ 83 | bool Link(Topic &source); 84 | 85 | bool Link(om_topic_t *source); 86 | 87 | bool Link(const char *source_name); 88 | ``` 89 | 90 | 查找topic: 91 | 92 | ```c++ 93 | om_topic_t *Find(const char *name); 94 | ``` 95 | 96 | 加锁: 97 | 98 | ```c++ 99 | bool Lock(); 100 | 101 | void Unlock(); 102 | ``` 103 | 104 | 高级过滤器: 105 | 106 | ```c++ 107 | void RangeDivide(Topic &topic, uint32_t length, uint32_t offset, uint32_t scope, uint32_t start, uint32_t num); 108 | 109 | void ListDivide(Topic &topic, uint32_t length, uint32_t offset, uint32_t scope, void *temp); 110 | 111 | void DecomposeDivide(Topic &topic, uint32_t length, uint32_t offset, uint32_t scope); 112 | ``` 113 | 114 | 注册回调: 115 | 116 | ```c++ 117 | //Fun的类型应当为bool (*)(Data &, Arg) 118 | 119 | template 120 | void RegisterFilter(Fun fun, Arg arg); 121 | 122 | 123 | template 124 | void RegisterCallback(Fun fun, Arg arg); 125 | ``` 126 | 127 | 发布: 128 | 129 | ```c++ 130 | bool Publish(Data &data, bool in_isr = om_in_isr()); 131 | ``` 132 | 133 | 打包数据: 134 | 135 | ```c++ 136 | bool PackData(RemoteData &data); 137 | ``` 138 | 139 | > `template class Subscriber` 140 | 141 | 构造: 142 | 143 | 构造时需要传入订阅的话题名,如果目标话题未创建,会等待timeout时间后返回。 144 | 145 | ```c++ 146 | Subscriber(const char *name uint32_t timeout = UINT32_MAX); 147 | ``` 148 | 149 | 如果能够获取到对应话题,可以使用以下构造函数: 150 | 151 | ```c++ 152 | Subscriber(om_topic_t *topic); 153 | 154 | Subscriber(Topic &topic); 155 | ``` 156 | 157 | 是否创建成功: 158 | 159 | ```c++ 160 | bool Ready(); 161 | ``` 162 | 163 | 是否有新数据: 164 | 165 | ```c++ 166 | bool Available(); 167 | ``` 168 | 169 | 导出数据到绑定的变量: 170 | 171 | ```c++ 172 | bool DumpData(Data& buff, bool in_isr = om_in_isr()); 173 | ``` 174 | 175 | > `class Remote` 176 | 177 | 能够解析打包的话题数据。 178 | 179 | 构造函数: 180 | 181 | ```c++ 182 | Remote(uint32_t buff_size, uint32_t topic_num); 183 | ``` 184 | 185 | 添加可解析的话题: 186 | 187 | ```c++ 188 | void AddTopic(const char *topic_name); 189 | 190 | void AddTopic(om_topic_t *topic); 191 | ``` 192 | 193 | 解析数据: 194 | 195 | ```c++ 196 | bool PraseData(uint8_t *data, uint32_t size,, bool in_isr = om_in_isr()); 197 | ``` 198 | 199 | > `class Event` 200 | 201 | 构造函数: 202 | 203 | ```c++ 204 | Event(const char *name); 205 | 206 | Event(om_event_group_t *group); 207 | ``` 208 | 209 | 查找事件组: 210 | 211 | ```c++ 212 | om_event_group_t *FindEvent(const char *name); 213 | ``` 214 | 215 | 注册事件: 216 | 217 | ```c++ 218 | bool Register(uint32_t event, Status status, void (*callback)(uint32_t event, void *arg), void *arg); 219 | ``` 220 | 221 | 激活事件: 222 | 223 | ```c++ 224 | bool Active(uint32_t event, bool in_isr = om_in_isr()); 225 | ``` 226 | -------------------------------------------------------------------------------- /om/.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BasedOnStyle: Google 3 | IncludeBlocks: Regroup 4 | -------------------------------------------------------------------------------- /om/.clangd: -------------------------------------------------------------------------------- 1 | Diagnostics: 2 | ClangTidy: 3 | Add: [readability-braces-around-statements, 4 | readability-identifier-naming, 5 | misc*,google*, 6 | clang-analyzer-nullability*, 7 | clang-analyzer-*, cert-*, 8 | bugprone-*, 9 | cppcoreguidelines-*, 10 | modernize-deprecated-headers, 11 | modernize-loop-convert, 12 | modernize-avoid-c-arrays, 13 | concurrency-*, 14 | performance-*] 15 | Remove: [google-build-using-namespace, 16 | bugprone-undefined-memory-manipulation, 17 | cppcoreguidelines-pro-type-member-init, 18 | cppcoreguidelines-pro-type-union-access, 19 | misc-no-recursion, 20 | cert-env33-c, 21 | cert-err58-cpp, 22 | cert-msc*, 23 | concurrency-mt-unsafe, 24 | cppcoreguidelines-no-malloc, 25 | cppcoreguidelines-owning-memory, 26 | cppcoreguidelines-special-member-functions, 27 | google-readability-todo, 28 | bugprone-easily-swappable-parameters, 29 | cppcoreguidelines-pro-bounds-constant-array-index, 30 | cppcoreguidelines-explicit-virtual-functions, 31 | cppcoreguidelines-virtual-class-destructor, 32 | cppcoreguidelines-pro-type-reinterpret-cast, 33 | google-explicit-constructor, 34 | cppcoreguidelines-pro-bounds-array-to-pointer-decay, 35 | cppcoreguidelines-pro-bounds-pointer-arithmetic, 36 | cppcoreguidelines-pro-type-vararg, 37 | cppcoreguidelines-avoid-magic-numbers, 38 | cppcoreguidelines-avoid-c-arrays, 39 | cppcoreguidelines-avoid-non-const-global-variables, 40 | cppcoreguidelines-non-private-member-variables-in-classes] 41 | CheckOptions: 42 | misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: 1 43 | modernize-loop-convert.MinConfidence: risky 44 | readability-identifier-naming.VariableCase: lower_case 45 | readability-identifier-naming.GlobalVariableCase: lower_case 46 | readability-identifier-naming.ClassMemberCase: lower_case 47 | readability-identifier-naming.ClassMemberSuffix: _ 48 | readability-identifier-naming.PrivateMemberCase: lower_case 49 | readability-identifier-naming.PrivateMemberSuffix: _ 50 | readability-identifier-naming.ProtectedMemberCase: lower_case 51 | readability-identifier-naming.ProtectedMemberSuffix: _ 52 | readability-identifier-naming.EnumCase: UPPER_CASE 53 | readability-identifier-naming.EnumConstantCase: UPPER_CASE 54 | readability-identifier-naming.MacroDefinitionCase: UPPER_CASE 55 | readability-identifier-naming.ConstantCase: UPPER_CASE 56 | readability-identifier-naming.ClassCase: CamelCase 57 | readability-identifier-naming.StructCase : CamelCase 58 | readability-identifier-naming.FunctionCase: lower_case 59 | readability-identifier-naming.ClassMethodCase: CamelCase 60 | readability-identifier-naming.MethodCase: CamelCase 61 | -------------------------------------------------------------------------------- /om/.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | 2 | name: CMake 3 | 4 | on: 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | 10 | env: 11 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 12 | BUILD_TYPE: Release 13 | 14 | jobs: 15 | build: 16 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 17 | # You can convert this to a matrix build if you need cross-platform coverage. 18 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - name: Set env 25 | # Build your program with the given configuration 26 | run: sudo apt install check -y 27 | 28 | - name: Configure CMake 29 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 30 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 31 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 32 | 33 | - name: Build 34 | # Build your program with the given configuration 35 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 36 | 37 | - name: Test 38 | working-directory: ${{github.workspace}}/build 39 | # Execute tests defined by the CMake configuration. 40 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 41 | run: ${{github.workspace}}/build/test/om_test 42 | -------------------------------------------------------------------------------- /om/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | .vscode/* 3 | config/om_config.h 4 | utils/*.csv 5 | .cache/** 6 | .history/** 7 | -------------------------------------------------------------------------------- /om/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | project(OM_Unit_Test) 4 | 5 | message(STATUS "CMAKE_PROJECT_NAME = ${CMAKE_PROJECT_NAME}") 6 | message(STATUS "PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}") 7 | 8 | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 9 | 10 | # set(CHECK_INSTALL_DIR "/usr/local/include/") 11 | 12 | set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb") 13 | set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") 14 | 15 | include(CheckCSourceCompiles) 16 | include(CheckCSourceRuns) 17 | include(CheckFunctionExists) 18 | include(CheckIncludeFile) 19 | include(CheckIncludeFiles) 20 | include(CheckLibraryExists) 21 | include(CheckSymbolExists) 22 | include(CheckTypeSize) 23 | 24 | # Check headers 25 | set(INCLUDES "") 26 | macro(ck_check_include_file header var) 27 | check_include_files("${INCLUDES};${header}" ${var}) 28 | if(${var}) 29 | set(INCLUDES ${INCLUDES} ${header}) 30 | endif(${var}) 31 | endmacro(ck_check_include_file) 32 | 33 | ck_check_include_file("stdlib.h" HAVE_STDLIB_H) 34 | check_type_size(intmax_t INTMAX_T) 35 | check_type_size(uintmax_t UINTMAX_T) 36 | 37 | # Generate "config.h" from "cmake/config.h.cmake" 38 | add_definitions(-DOM_TEST) 39 | 40 | # Subdirectories 41 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src) 42 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) 43 | 44 | # Unit tests 45 | enable_testing() 46 | add_test(NAME om_test COMMAND om_test) 47 | -------------------------------------------------------------------------------- /om/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /om/README.md: -------------------------------------------------------------------------------- 1 | # OneMessage 2 | 3 | 一个基于 `发布-订阅`模型的跨平台消息框架,纯C语言编写,性能和灵活性极高 4 | 5 | ------------------------------------------------------------------------ 6 | 7 | ## 什么是OneMessage 8 | 9 | OneMessage核心为订阅发布的消息框架,包含了红黑树,链表,队列,crc校验和终端文本格式控制五个基本组件的完整实现。在此基础上完成了如下六个功能模块: 10 | 11 | * MSG 消息/话题控制: 控制消息的订阅与发布,话题和订阅者的创建与管理 12 | * FMT 格式化配置:为用户提供格式化字符串的方式来快速配置话题/订阅/过滤器 13 | * EVT 事件机制:基于topic实现的事件触发机制 14 | * LOG 日志系统:多等级的日志打印 15 | * AFL 高级过滤器:为topic提供灵活的筛选方式 16 | * COM 通信解析:用于跨进程/跨设备共享topic 17 | 18 | 本项目旨在为跨线程和跨设备通信提供一个通用解决方案,以较小的性能代价换取数倍的开发效率。 19 | 20 | 在STM32F103上使用-Og优化选项下的GCC编译本框架,FLASH占用增加4.2k. 21 | 22 | ## 相关概念 23 | 24 | 在OneMessage里只有两种主体,话题(topic)和订阅者(sub/suber/subscriber)。一个消息一定是先被发送到一个话题上,经过筛选/回调/转发等方式发送到另一个话题或订阅者。 25 | 26 | 话题可以配置filter_function,简单筛选可以发布到此话题的消息,也可以配置高级过滤器(AFL),通过一些较为复杂的规则,将此话题的数据筛选并发布到其他的话题。话题可以通过开关缓冲区来实现无拷贝发布,通过对话题加锁保证线程安全。 27 | 28 | 订阅者分为以下几种:1.用于检测话题数据更新,并导出话题数据(export)2.用于将话题数据放在队列中,防止消息丢失(queue/fifo)3.存放用户注册的回调函数,在对应话题发布消息时调用(同步方式获取数据/suber_callback)4.用于连接两个话题,源话题发布消息时转发到目标话题上(link) 29 | 30 | 几乎所有API都提供动态/静态内存分配两种接口,静态需要用户手动创建数据结构体,并保证变量一直存活,而且无法对其使用删除相关的API。 31 | 32 | PS:不定长消息为实验功能,强烈建议每个话题的消息长度为定长。 33 | 34 | ## 文档 35 | 36 | > [配置文件](https://github.com/Jiu-xiao/OneMessage/blob/master/doc/config.md) 37 | 38 | > [使用说明](https://github.com/Jiu-xiao/OneMessage/blob/master/doc/user.md) 39 | 40 | > [开发文档](https://github.com/Jiu-xiao/OneMessage/blob/master/doc/dev.md) 41 | 42 | ## 系统支持 43 | 44 | 已在Linux,FreeRTOS,ThreadX上成功运行,欢迎适配到其他平台。 45 | 46 | * 简单示例 47 | * [example for linux(use cmake)](https://gitee.com/jiu-xiao/msg-example.git) 48 | * [example for stm32f103(use makefile)](https://gitee.com/jiu-xiao/om-example-mcu.git) 49 | * 使用本框架的开源项目 50 | * [XRobot](https://github.com/xrobot-org/XRobot):FreeRTOS/Linux/裸机 51 | * [Shenzhen-innoX-2024wc-referembedded](https://github.com/RM-camp-for-high-school-students/Shenzhen-innoX-2024wc-referembedded):ThreadX 52 | 53 | ## 特性 54 | 55 | * 发布-订阅 56 | 57 | * 底层由红黑树+链表实现,查找与遍历都有良好的性能表现 58 | * 话题为操作的主体,匿名发布且不限制订阅者数量 59 | * 支持零拷贝发布 60 | * 订阅者可开启内置队列,防止消息丢失 61 | 62 | * 安全性 63 | * 保证线程安全 64 | * 允许在中断中使用 65 | * 提供静态API,可以实现无动态内存分配 66 | * 单元测试覆盖所有功能 67 | 68 | * 消息过滤器 69 | 70 | * 支持为每个话题和订阅者注册过滤器,只接受符合条件的消息 71 | 72 | * 订阅回调 73 | 74 | * 订阅者可在接收时调用用户回调函数,暂存数据或者转发到另一个话题。 75 | 76 | * 快速配置 77 | 78 | * 使用格式化输入的方式配置话题,极少的代码量就能实现整个消息网络的搭建 79 | 80 | * 事件触发 81 | 82 | * 以订阅为核心的事件触发器,在保证执行效率的同时,一个触发条件可以对应多个处理函数。 83 | 84 | * 批量筛选 85 | 86 | * 对于条件简单且分支较多的话题,可开启高级过滤器而不需要注册大量函数,现已支持 `列表`、`范围`、`分解`模式。例如针对id筛选CAN总线数据,或者将结构体拆分后发布。 87 | 88 | * 话题共享 89 | 90 | * 提供topic数据打包与解析api,可通过任意协议共享多个topic数据,实现跨进程和跨设备通信。通过fifo与crc校验保证数据完成性,在拆包/组包/错位和夹杂无效数据的情况下也能确保正确解析。 91 | 92 | * 日志框架 93 | 94 | * 使用示例程序打印的日志:![效果](img/log.png) 95 | 96 | ## 获取源码 97 | 98 | 克隆这个仓库 99 | 100 | [Gitee](https://gitee.com/jiu-xiao/one-message.git) 101 | 102 | [Github](https://github.com/Jiu-xiao/OneMessage.git) 103 | 104 | ```shell 105 | git clone https://github.com/Jiu-xiao/OneMessage.git 106 | ``` 107 | 108 | 或者使用 `git submodule`将其包含在你的仓库中 109 | 110 | ```shell 111 | git submodule add https://github.com/Jiu-xiao/OneMessage.git 112 | ``` 113 | 114 | ## 代码结构 115 | 116 | ```c 117 | OneMessage 118 | ├─config 119 | ├─src 120 | │ ├─app 121 | │ ├─comp 122 | │ └─core 123 | └─test 124 | ``` 125 | 126 | | 文件夹 | 功能 | 127 | | -------- | ------------ | 128 | | config | 配置文件模板 | 129 | | doc | 文档 | 130 | | src/app | 应用 | 131 | | src/comp | 组件 | 132 | | src/core | 核心api | 133 | | src | 用户接口 | 134 | | test | 单元测试 | 135 | | example | 例程 | 136 | 137 | ## C++ 138 | 139 | C++兼容层[OneMessageCPP](https://github.com/Jiu-xiao/OneMessageCPP) 140 | -------------------------------------------------------------------------------- /om/cmake/FindCheck.cmake: -------------------------------------------------------------------------------- 1 | # * Try to find the CHECK libraries Once done this will define 2 | # 3 | # CHECK_FOUND - system has check CHECK_INCLUDE_DIR - the check include directory 4 | # CHECK_LIBRARIES - check library 5 | # 6 | # This configuration file for finding libcheck is originally from the opensync 7 | # project. The originally was downloaded from here: 8 | # opensync.org/browser/branches/3rd-party-cmake-modules/modules/FindCheck.cmake 9 | # 10 | # Copyright (c) 2007 Daniel Gollub Copyright (c) 2007 Bjoern 11 | # Ricks 12 | # 13 | # Redistribution and use is allowed according to the terms of the New BSD 14 | # license. For details see the accompanying COPYING-CMAKE-SCRIPTS file. 15 | 16 | include(FindPkgConfig) 17 | 18 | # Take care about check.pc settings 19 | pkg_search_module(check Check) 20 | 21 | # Look for CHECK include dir and libraries 22 | if(NOT CHECK_FOUND) 23 | if(CHECK_INSTALL_DIR) 24 | message(STATUS "Using override CHECK_INSTALL_DIR to find Check") 25 | set(CHECK_INCLUDE_DIR "${CHECK_INSTALL_DIR}/include") 26 | set(CHECK_INCLUDE_DIRS "${CHECK_INCLUDE_DIR}") 27 | find_library( 28 | CHECK_LIBRARY 29 | NAMES check 30 | PATHS "${CHECK_INSTALL_DIR}/lib") 31 | find_library( 32 | COMPAT_LIBRARY 33 | NAMES compat 34 | PATHS "${CHECK_INSTALL_DIR}/lib") 35 | set(CHECK_LIBRARIES "${CHECK_LIBRARY}" "${COMPAT_LIBRARY}") 36 | else(CHECK_INSTALL_DIR) 37 | find_path(CHECK_INCLUDE_DIR check.h) 38 | find_library(CHECK_LIBRARIES NAMES check) 39 | endif(CHECK_INSTALL_DIR) 40 | 41 | if(CHECK_INCLUDE_DIR AND CHECK_LIBRARIES) 42 | set(CHECK_FOUND 1) 43 | if(NOT Check_FIND_QUIETLY) 44 | message(STATUS "Found CHECK: ${CHECK_LIBRARIES}") 45 | endif(NOT Check_FIND_QUIETLY) 46 | else(CHECK_INCLUDE_DIR AND CHECK_LIBRARIES) 47 | if(Check_FIND_REQUIRED) 48 | message(FATAL_ERROR "Could NOT find CHECK") 49 | else(Check_FIND_REQUIRED) 50 | if(NOT Check_FIND_QUIETLY) 51 | message(STATUS "Could NOT find CHECK") 52 | endif(NOT Check_FIND_QUIETLY) 53 | endif(Check_FIND_REQUIRED) 54 | endif(CHECK_INCLUDE_DIR AND CHECK_LIBRARIES) 55 | endif(NOT CHECK_FOUND) 56 | 57 | # Hide advanced variables from CMake GUIs 58 | mark_as_advanced(CHECK_INCLUDE_DIR CHECK_LIBRARIES) 59 | -------------------------------------------------------------------------------- /om/config/om_config_template.h: -------------------------------------------------------------------------------- 1 | /* Debug */ 2 | #define OM_DEBUG (1) 3 | 4 | /* 使用用户自定义的内存分配 */ 5 | #define OM_USE_USER_MALLOC (0) 6 | 7 | /* 用户内存分配函数 */ 8 | #if OM_USE_USER_MALLOC 9 | #define om_malloc user_malloc 10 | #define om_free user_free 11 | #endif 12 | 13 | /* 非阻塞延时函数 */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #define om_delay_ms(arg) \ 19 | struct timeval tv; \ 20 | tv.tv_sec = arg / 1000; \ 21 | tv.tv_usec = (arg % 1000) * 1000; \ 22 | int err; \ 23 | do { \ 24 | err = select(0, NULL, NULL, NULL, &tv); \ 25 | } while (err < 0 && errno == EINTR); 26 | 27 | /* OS层互斥锁api */ 28 | #include 29 | #define om_mutex_t pthread_mutex_t 30 | #define om_mutex_init(arg) pthread_mutex_init(arg, NULL) 31 | #define om_mutex_lock(arg) pthread_mutex_lock(arg) 32 | #define om_mutex_trylock(arg) pthread_mutex_trylock(arg) == 0 ? OM_OK : OM_ERROR 33 | #define om_mutex_unlock(arg) pthread_mutex_unlock(arg) 34 | 35 | #define om_mutex_lock_isr(arg) pthread_mutex_lock(arg) 36 | #define om_mutex_unlock_isr(arg) pthread_mutex_unlock(arg) 37 | 38 | #define om_mutex_delete(arg) pthread_mutex_destroy(arg) 39 | 40 | /* 将运行时间作为消息发出的时间 */ 41 | #define OM_TIME (1) 42 | 43 | #if OM_TIME 44 | #include 45 | #define om_time_t time_t 46 | #define om_time_get(_time) time(_time) 47 | #endif 48 | 49 | /* 开启"om_log"话题作为OneMessage的日志输出 */ 50 | #define OM_LOG_OUTPUT (1) 51 | 52 | #if OM_LOG_OUTPUT 53 | /* 按照日志等级以不同颜色输出 */ 54 | #define OM_LOG_COLORFUL (1) 55 | /* 日志最大长度 */ 56 | #define OM_LOG_MAX_LEN (60) 57 | /* 日志等级 1:default 2:notice 3:pass 4:warning 5:error */ 58 | #define OM_LOG_LEVEL (1) 59 | #endif 60 | 61 | /* 话题名称最大长度 */ 62 | #define OM_TOPIC_MAX_NAME_LEN (15) 63 | 64 | /* for OneMessageCPP:https://github.com/Jiu-xiao/OneMessageCPP */ 65 | 66 | /* 67 | #include 68 | static inline bool om_in_isr() { return false; } 69 | */ 70 | -------------------------------------------------------------------------------- /om/doc/config.md: -------------------------------------------------------------------------------- 1 | # 配置文件 2 | 3 | ------ 4 | 5 | ## OM_DEBUG 6 | 7 | >使能这个宏将会开启OM_ASSENT和OM_CHECK,对空指针等异常情况进行检测,定位异常发生位置。 8 | 9 | ## OM_USE_USER_MALLOC 10 | 11 | >使用用户的内存分配函数,使能时需要自定义om_malloc和om_free。 12 | > 13 | >> 14 | >>FreeRTOS示例 15 | >> 16 | >>>#include "FreeRTOS.h" 17 | >>> 18 | >>>#define om_malloc pvPortMalloc 19 | >>> 20 | >>>#define om_free vPortFree 21 | 22 | ## OM_DELAY 23 | 24 | >非阻塞延时函数 25 | >>om_delay_ms 等待一毫秒 26 | 27 | ## OM_MUTEX_* 28 | 29 | ### OS层提供的互斥锁API 30 | 31 | >Linux示例 32 | >>#include 33 | >> 34 | >>#define om_mutex_t pthread_mutex_t 35 | >> 36 | >>#define om_mutex_init(arg) pthread_mutex_init(arg, NULL) 37 | >> 38 | >>#define om_mutex_lock(arg) pthread_mutex_lock(arg) 39 | >> 40 | >>#define om_mutex_trylock(arg) pthread_mutex_trylock(arg) == 0 ? OM_OK:OM_ERROR 41 | >> 42 | >>#define om_mutex_unlock(arg) pthread_mutex_unlock(arg) 43 | >> 44 | >>#define om_mutex_lock_isr(arg) pthread_mutex_lock(arg) 45 | >> 46 | >>#define om_mutex_unlock_isr(arg) pthread_mutex_unlock(arg) 47 | >> 48 | >>#define om_mutex_delete(arg) pthread_mutex_destroy(arg) 49 | >> 50 | > 51 | >FreeRTOS示例 52 | >>#include "semphr.h" 53 | >> 54 | >>#define om_mutex_t SemaphoreHandle_t 55 | >> 56 | >>#define om_mutex_init(arg) *arg = xSemaphoreCreateBinary(); 57 | >>xSemaphoreGive(*arg) 58 | >> 59 | >>#define om_mutex_lock(arg) xSemaphoreTake(*arg,portMAX_DELAY) 60 | >> 61 | >>#define om_mutex_trylock(arg) xSemaphoreTake(*arg,0) == pdTRUE ? OM_OK:OM_ERROR 62 | >> 63 | >>#define om_mutex_unlock(arg) xSemaphoreGive(*arg) 64 | >> 65 | >>#define om_mutex_lock_isr(arg) xSemaphoreTakeFromISR(*arg, NULL) == pdTRUE ? OM_OK:OM_ERROR 66 | >> 67 | >>#define om_mutex_unlock_isr(arg) xSemaphoreGiveFromISR(*arg, NULL) 68 | >> 69 | >>#define om_mutex_delete(arg) vSemaphoreDelete(*arg) 70 | > 71 | >ThreadX示例 72 | >>#include "tx_api.h" 73 | >> 74 | >>#define om_mutex_t TX_MUTEX 75 | >> 76 | >>#define om_mutex_init(arg) tx_mutex_create(arg, NULL, TX_NO_INHERIT) 77 | >> 78 | >>#define om_mutex_lock(arg) tx_mutex_get(arg, TX_WAIT_FOREVER) 79 | >> 80 | >>#define om_mutex_trylock(arg) tx_mutex_get(arg, TX_NO_WAIT) == TX_SUCCESS ? OM_OK:OM_ERROR 81 | >> 82 | >>#define om_mutex_unlock(arg) tx_mutex_put(arg) 83 | >> 84 | >>#define om_mutex_lock_isr(arg) tx_mutex_get(arg, TX_NO_WAIT) == TX_SUCCESS ? OM_OK:OM_ERROR 85 | >> 86 | >>#define om_mutex_unlock_isr(arg) tx_mutex_put(arg) 87 | >> 88 | >>#define om_mutex_delete(arg) tx_mutex_delete(arg) 89 | 90 | ## OM_TIME 91 | 92 | >发布消息和log时记录时间 93 | >>om_time_t 存放时间数据的类型 94 | >> 95 | >>om_time_t om_time_get() 返回时间 96 | 97 | ## OM_LOG_OUTPUT 98 | 99 | >开启日志,输出到`om_log`话题。 100 | 101 | ## OM_LOG_COLORFUL 102 | 103 | >按照日志等级以不同颜色输出。 104 | 105 | ## OM_TOPIC_MAX_NAME_LEN 106 | 107 | >话题名称最大长度 108 | 109 | ## OM_LOG_MAX_LEN 110 | 111 | >日志最大长度 112 | 113 | ## OM_LOG_LEVEL 114 | 115 | >日志最小打印等级 1:default 2:notice 3:pass 4:warning 5:error 116 | -------------------------------------------------------------------------------- /om/doc/dev.md: -------------------------------------------------------------------------------- 1 | # 开发 2 | 3 | ----- 4 | 5 | ## 工具 6 | 7 | 使用check作为单元测试工具,cmake+ninja编译,推荐使用VS Code开发。 8 | -------------------------------------------------------------------------------- /om/doc/user.md: -------------------------------------------------------------------------------- 1 | # 使用方法 2 | 3 | ## 创建om_config.h配置文件 4 | 5 | 参照`config/om_config_template.h`和[配置文件介绍](config.md),编写`om_config.h`。 6 | 7 | ## 添加源文件和头文件到工程 8 | 9 | ### CMake 10 | 11 | 直接将src文件夹作为子目录加入 12 | 13 | add_subdirectory(user_dir/one-message/src om.out) 14 | 15 | 将om_config.h配置文件所在目录加入到OneMessage目标 16 | 17 | target_include_directories(OneMessage PUBLIC config_file_dir) 18 | 19 | ### Makefile 20 | 21 | 将src下的所有目录和源文件,以及om_config.h配置文件所在目录加入到编译目标当中。 22 | 23 | ## 引用头文件 24 | 25 | `include "om.h"` 26 | 27 | ## 初始化 28 | 29 | om_status_t om_init(); 30 | 31 | ## 创建话题/订阅者/链接 32 | 33 | 动态分配内存 34 | 35 | om_topic_t* om_create_topic(const char* name,size_t buff_len) 36 | om_suber_t* om_create_suber(om_topic_t* link) 37 | om_status_t om_topic_link(om_topic_t* source, om_topic_t* target); 38 | 39 | 静态内存 40 | 41 | om_topic_t* om_create_topic_static(om_topic_t* topic, const char* name,size_t buff_len) 42 | om_suber_t* om_create_suber_static(om_suber_t* suber, om_topic_t* link) 43 | om_status_t om_topic_link_static(om_suber_t* suber, om_link_t* link, 44 | om_topic_t* source, om_topic_t* target); 45 | 46 | ## 发布消息 47 | 48 | om_status_t om_publish(om_topic_t* topic, void* buff, uint32_t size, bool block, bool in_isr) 49 | 50 | block参数决定同时有其他线程发布这个话题时是否等待,in_isr取决于是否在中断中调用 51 | 52 | ## 异步订阅话题 53 | 54 | om_suber_t* om_subscribe(om_topic_t* topic); 55 | 56 | om_suber_t* om_subscribe_static(om_topic_t* topic, om_suber_t* sub); 57 | 58 | om_status_t om_suber_export(om_suber_t* suber, void* buff, bool in_isr); 59 | 60 | bool om_suber_available(om_suber_t* suber); 61 | 62 | * om_subscribe会返回一个可导出话题数据的订阅者 63 | * 当订阅者接收到新数据时,调用om_suber_export会将数据写入buff,并返回OM_OK. 64 | * om_suber_available判断是否有新数据 65 | 66 | ## 为话题添加订阅队列 67 | 68 | 与普通订阅者不同,使用队列可以存储一个topic上的多个消息,但是无法使用回调函数。 69 | 70 | 动态分配内存 71 | 72 | om_fifo_t* om_queue_add(om_topic_t* topic, uint32_t len); 73 | 74 | example: 75 | 76 | /* 创建topic */ 77 | om_topic_t* topic = om_create_topic("topic", 1u); 78 | /* 添加队列 */ 79 | om_fifo_t* queue = om_queue_add(topic, 10); 80 | /* 发布消息 */ 81 | //om_publish(...) 82 | 83 | /* 加锁 */ 84 | OM_TOPIC_LOCK(topic); 85 | 86 | /* 获取消息数量 */ 87 | uint32_t count = om_fifo_readable_item_count(queue); 88 | 89 | /* 弹出数据 */ 90 | for(int i=0;i10kb)时,解析性能可能较低。 518 | 2. 为了提高带宽利用率和打包速度,使用crc32作为topic的id,存在重复的可能性,出现此情况时请给topic更名。后续考虑使用分布更均匀的生成算法。 519 | -------------------------------------------------------------------------------- /om/img/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiu-xiao/OneMessageCPP/1990ab504065fa198ca3724224a96226dd3b1e0e/om/img/log.png -------------------------------------------------------------------------------- /om/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | project(OneMessage) 3 | 4 | file( 5 | GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.c" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/app/*.c" "${CMAKE_CURRENT_SOURCE_DIR}/core/*.c" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/comp/*.c") 8 | 9 | add_library(${PROJECT_NAME} STATIC) 10 | 11 | target_sources(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_SOURCES}) 12 | 13 | target_include_directories( 14 | ${PROJECT_NAME} 15 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} 16 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/app 17 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/core 18 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/comp 19 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../config) 20 | -------------------------------------------------------------------------------- /om/src/app/om_afl.c: -------------------------------------------------------------------------------- 1 | #include "om_afl.h" 2 | 3 | #include "om_fmt.h" 4 | #include "om_log.h" 5 | #include "om_msg.h" 6 | 7 | om_afl_t* om_afl_create(om_topic_t* source) { 8 | om_afl_t* afl = om_malloc(sizeof(om_afl_t)); 9 | 10 | return om_afl_create_static(afl, source); 11 | } 12 | 13 | om_afl_filter_t* om_afl_filter_create(om_topic_t* target) { 14 | om_afl_filter_t* filter = om_malloc(sizeof(om_afl_filter_t)); 15 | 16 | return om_afl_filter_create_static(filter, target); 17 | } 18 | 19 | om_afl_t* om_afl_create_static(om_afl_t* afl, om_topic_t* source) { 20 | OM_ASSERT(afl); 21 | memset(afl, 0, sizeof(om_afl_t)); 22 | 23 | OM_INIT_LIST_HEAD(&afl->filter); 24 | afl->source_topic = source; 25 | source->afl = afl; 26 | 27 | return afl; 28 | } 29 | 30 | om_afl_filter_t* om_afl_filter_create_static(om_afl_filter_t* filter, 31 | om_topic_t* target) { 32 | OM_ASSERT(filter); 33 | memset(filter, 0, sizeof(om_afl_filter_t)); 34 | 35 | filter->target = target; 36 | 37 | return filter; 38 | } 39 | 40 | om_status_t om_afl_add_filter(om_afl_t* afl, om_afl_filter_t* filter) { 41 | OM_ASSERT(afl); 42 | OM_ASSERT(filter); 43 | 44 | om_list_add(&filter->self, &afl->filter); 45 | 46 | return OM_OK; 47 | } 48 | 49 | om_status_t om_afl_set_filter(om_afl_filter_t* filter, uint8_t mode, 50 | uint32_t offset, uint32_t length, uint32_t scope, 51 | uint32_t arg, void* fl_template) { 52 | OM_ASSERT(filter); 53 | 54 | filter->mode = mode; 55 | filter->length = length; 56 | 57 | switch (mode) { 58 | case OM_AFL_MODE_LIST: 59 | filter->data.list.scope = scope; 60 | filter->data.list.offset = offset; 61 | filter->data.list.fl_template = fl_template; 62 | break; 63 | case OM_AFL_MODE_RANGE: 64 | filter->data.range.offset = offset; 65 | filter->data.range.start = scope; 66 | filter->data.range.range = arg; 67 | break; 68 | 69 | case OM_AFL_MODE_DECOMPOSE: 70 | filter->data.decomp.offset = offset; 71 | filter->data.decomp.size = scope; 72 | break; 73 | default: 74 | OM_ASSERT(false); 75 | return OM_ERROR; 76 | } 77 | 78 | return OM_OK; 79 | } 80 | 81 | om_status_t _om_afl_filter_check(om_afl_filter_t* filter, om_msg_t* msg) { 82 | if (filter->length && msg->size != filter->length) return OM_ERROR; 83 | 84 | uint8_t* buff = msg->buff; 85 | 86 | switch (filter->mode) { 87 | case OM_AFL_MODE_LIST: 88 | if (msg->size < filter->data.list.scope + filter->data.list.offset) 89 | return OM_ERROR; 90 | buff += filter->data.list.offset; 91 | if (!memcmp(buff, filter->data.list.fl_template, filter->data.list.scope)) 92 | return OM_OK; 93 | break; 94 | case OM_AFL_MODE_RANGE: 95 | if (msg->size < filter->data.range.offset + sizeof(uint32_t)) { 96 | OM_ASSERT(false); 97 | return OM_ERROR; 98 | } 99 | buff += filter->data.range.offset; 100 | if (*((uint32_t*)buff) - filter->data.range.start < 101 | filter->data.range.range) 102 | return OM_OK; 103 | break; 104 | case OM_AFL_MODE_DECOMPOSE: 105 | if (msg->size < filter->data.decomp.offset + filter->data.decomp.size) 106 | return OM_ERROR; 107 | return OM_OK; 108 | 109 | default: 110 | return OM_ERROR; 111 | } 112 | 113 | return OM_ERROR; 114 | } 115 | 116 | om_status_t _om_afl_filter_apply(om_afl_filter_t* filter, om_msg_t* msg, 117 | bool block, bool in_isr) { 118 | switch (filter->mode) { 119 | case OM_AFL_MODE_LIST: 120 | case OM_AFL_MODE_RANGE: 121 | om_publish(filter->target, msg->buff, msg->size, block, in_isr); 122 | break; 123 | case OM_AFL_MODE_DECOMPOSE: 124 | om_publish(filter->target, msg->buff + filter->data.decomp.offset, 125 | filter->data.decomp.size, block, in_isr); 126 | break; 127 | default: 128 | OM_ASSERT(false); 129 | return OM_ERROR; 130 | } 131 | 132 | return OM_OK; 133 | } 134 | 135 | om_status_t om_afl_apply(om_msg_t* msg, om_afl_t* afl, bool block, 136 | bool in_isr) { 137 | OM_ASSERT(msg); 138 | OM_ASSERT(afl); 139 | 140 | om_list_head_t* pos; 141 | om_list_for_each(pos, &afl->filter) { 142 | om_afl_filter_t* filter = om_list_entry(pos, om_afl_filter_t, self); 143 | if (_om_afl_filter_check(filter, msg) == OM_OK) 144 | _om_afl_filter_apply(filter, msg, block, in_isr); 145 | } 146 | 147 | return OM_OK; 148 | } 149 | 150 | om_status_t om_afl_filter_del(om_list_head_t* filter) { 151 | om_list_del(filter); 152 | 153 | om_afl_filter_t* t = om_list_entry(filter, om_afl_filter_t, self); 154 | 155 | om_free(t); 156 | 157 | return OM_OK; 158 | } 159 | 160 | uint32_t om_afl_get_num(om_afl_t* afl) { return om_list_get_num(&afl->filter); } 161 | 162 | om_status_t om_afl_del(om_afl_t* afl) { 163 | om_del_all(&afl->filter, om_afl_filter_del); 164 | 165 | om_free(afl); 166 | 167 | return OM_OK; 168 | } 169 | -------------------------------------------------------------------------------- /om/src/app/om_afl.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_AFL_H__ 2 | #define __OM_AFL_H__ 3 | 4 | #include "om_core.h" 5 | 6 | typedef enum { 7 | OM_AFL_MODE_LIST, 8 | OM_AFL_MODE_RANGE, 9 | OM_AFL_MODE_DECOMPOSE, 10 | OM_AFL_MODE_NUMBER 11 | } om_afl_mode_t; 12 | 13 | typedef struct { 14 | om_topic_t* source_topic; 15 | om_list_head_t filter; 16 | } om_afl_t; 17 | 18 | typedef struct { 19 | uint32_t offset; 20 | uint32_t scope; 21 | void* fl_template; 22 | } _om_afl_filter_list_t; 23 | 24 | typedef struct { 25 | uint32_t offset; 26 | uint32_t start; 27 | uint32_t range; 28 | } _om_afl_filter_range_t; 29 | 30 | typedef struct { 31 | uint32_t offset; 32 | uint32_t size; 33 | } _om_afl_filter_decompose_t; 34 | 35 | typedef struct { 36 | uint32_t length; 37 | om_afl_mode_t mode; 38 | union { 39 | _om_afl_filter_list_t list; 40 | _om_afl_filter_range_t range; 41 | _om_afl_filter_decompose_t decomp; 42 | } data; 43 | om_list_head_t self; 44 | om_topic_t* target; 45 | } om_afl_filter_t; 46 | 47 | om_afl_t* om_afl_create(om_topic_t* source); 48 | 49 | om_afl_filter_t* om_afl_filter_create(om_topic_t* target); 50 | 51 | om_afl_t* om_afl_create_static(om_afl_t* afl, om_topic_t* source); 52 | 53 | om_afl_filter_t* om_afl_filter_create_static(om_afl_filter_t* filter, 54 | om_topic_t* target); 55 | 56 | om_status_t om_afl_add_filter(om_afl_t* afl, om_afl_filter_t* filter); 57 | 58 | om_status_t om_afl_set_filter(om_afl_filter_t* filter, uint8_t mode, 59 | uint32_t offset, uint32_t length, uint32_t scope, 60 | uint32_t arg, void* fl_template); 61 | 62 | om_status_t _om_afl_filter_check(om_afl_filter_t* filter, om_msg_t* msg); 63 | 64 | om_status_t _om_afl_filter_apply(om_afl_filter_t* filter, om_msg_t* msg, 65 | bool block, bool in_isr); 66 | 67 | om_status_t om_afl_apply(om_msg_t* msg, om_afl_t* afl, bool block, bool in_isr); 68 | 69 | om_status_t om_afl_filter_del(om_list_head_t* filter); 70 | 71 | uint32_t om_afl_get_num(om_afl_t* afl); 72 | 73 | om_status_t om_afl_del(om_afl_t* afl); 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /om/src/app/om_com.c: -------------------------------------------------------------------------------- 1 | #include "om_com.h" 2 | 3 | #include "om_crc.h" 4 | #include "om_def.h" 5 | #include "om_fifo.h" 6 | #include "om_msg.h" 7 | 8 | om_status_t om_com_create_static(om_com_t* com, void* fifo_buff, 9 | uint32_t buffer_size, om_com_map_item_t* map, 10 | uint16_t map_len, uint8_t* prase_buff, 11 | uint32_t prase_buff_len) { 12 | OM_ASSERT(com); 13 | OM_ASSERT(fifo_buff); 14 | OM_ASSERT(map); 15 | OM_ASSERT(prase_buff); 16 | OM_ASSERT(buffer_size >= OM_COM_TYPE_SIZE(void)); 17 | OM_ASSERT(map_len); 18 | OM_ASSERT(prase_buff_len >= OM_COM_TYPE_SIZE(void)); 19 | 20 | memset(com, 0, sizeof(*com)); 21 | 22 | om_fifo_create(&com->recv_fifo, fifo_buff, buffer_size, sizeof(uint8_t)); 23 | com->map = map; 24 | com->map_len = map_len; 25 | com->map_index = 0; 26 | com->prase_buff = prase_buff; 27 | com->prase_buff_len = prase_buff_len; 28 | memset(map, 0, sizeof(om_com_map_item_t) * map_len); 29 | 30 | return OM_OK; 31 | } 32 | 33 | om_status_t om_com_create(om_com_t* com, uint32_t buffer_size, uint16_t map_len, 34 | uint32_t prase_buff_len) { 35 | OM_ASSERT(com); 36 | OM_ASSERT(buffer_size >= OM_COM_TYPE_SIZE(void)); 37 | OM_ASSERT(map_len); 38 | OM_ASSERT(prase_buff_len >= OM_COM_TYPE_SIZE(void)); 39 | 40 | return om_com_create_static(com, om_malloc(buffer_size), buffer_size, 41 | om_malloc(sizeof(om_com_map_item_t) * map_len), 42 | map_len, om_malloc(prase_buff_len), 43 | prase_buff_len); 44 | } 45 | 46 | om_status_t om_com_add_topic(om_com_t* com, om_topic_t* topic){ 47 | OM_ASSERT(com); 48 | OM_ASSERT(topic); 49 | 50 | if (com->map_index >= com->map_len) { 51 | OM_ASSERT(false); 52 | return OM_ERROR_FULL; 53 | } 54 | 55 | topic->crc32 = om_crc32_calc((const uint8_t*)topic->name, 56 | strnlen(topic->name, OM_TOPIC_MAX_NAME_LEN)); 57 | 58 | /* The result of crc32 should not be 0, please change the topic name */ 59 | OM_ASSERT(topic->crc32 != 0); 60 | com->map[com->map_index].topic = topic; 61 | com->map[com->map_index].crc32 = topic->crc32; 62 | com->map_index++; 63 | 64 | return OM_OK; 65 | } 66 | 67 | 68 | om_status_t om_com_add_topic_with_name(om_com_t* com, const char* topic_name) { 69 | OM_ASSERT(com); 70 | OM_ASSERT(topic_name); 71 | 72 | if (com->map_index >= com->map_len) { 73 | OM_ASSERT(false); 74 | return OM_ERROR_FULL; 75 | } 76 | 77 | om_topic_t* topic = om_core_find_topic(topic_name, 0); 78 | OM_ASSERT(topic); 79 | 80 | topic->crc32 = om_crc32_calc((const uint8_t*)topic->name, 81 | strnlen(topic->name, OM_TOPIC_MAX_NAME_LEN)); 82 | 83 | /* The result of crc32 should not be 0, please change the topic name */ 84 | OM_ASSERT(topic->crc32 != 0); 85 | com->map[com->map_index].topic = topic; 86 | com->map[com->map_index].crc32 = topic->crc32; 87 | com->map_index++; 88 | 89 | return OM_OK; 90 | } 91 | 92 | om_status_t om_com_generate_pack(om_topic_t* topic, void* buff) { 93 | OM_ASSERT(topic); 94 | OM_ASSERT(buff); 95 | 96 | if (topic->msg.buff == 0) { 97 | return OM_ERROR_NULL; 98 | } 99 | 100 | if (topic->crc32 == 0) { 101 | topic->crc32 = om_crc32_calc((const uint8_t*)topic->name, 102 | strnlen(topic->name, OM_TOPIC_MAX_NAME_LEN)); 103 | } 104 | 105 | om_com_raw_type_t* raw_buff = buff; 106 | raw_buff->prefix = OM_COM_PACK_PREFIX; 107 | raw_buff->topic_name_crc32 = topic->crc32; 108 | raw_buff->data_len = topic->buff_len; 109 | memcpy(&raw_buff->pack_crc8, topic->msg.buff, topic->msg.size); 110 | 111 | raw_buff->pack_header_crc8 = 112 | om_crc8_calc(buff, om_offset_of(om_com_raw_type_t, pack_header_crc8)); 113 | 114 | uint8_t* data_buff = (uint8_t*)buff; 115 | data_buff[sizeof(om_com_raw_type_t) + topic->buff_len - 1] = 116 | om_crc8_calc(buff, sizeof(om_com_raw_type_t) + topic->buff_len - 1); 117 | 118 | return OM_OK; 119 | } 120 | 121 | om_com_recv_ans_t om_com_prase_recv(om_com_t* com, uint8_t* buff, uint32_t size, 122 | bool block, bool in_isr) { 123 | OM_ASSERT(com); 124 | OM_ASSERT(buff); 125 | 126 | om_com_recv_ans_t ans = OM_COM_RECV_NOT_FOUND; 127 | 128 | om_fifo_writes(&com->recv_fifo, buff, size); 129 | 130 | while (om_fifo_readable(&com->recv_fifo)) { 131 | switch (com->status) { 132 | case OM_COM_STATUS_WAIT_START: 133 | om_fifo_peek(&com->recv_fifo, com->prase_buff); 134 | 135 | if (com->prase_buff[0] == OM_COM_PACK_PREFIX) { 136 | com->status = OM_COM_STATUS_WAIT_TOPIC; 137 | } else { 138 | om_fifo_pop(&com->recv_fifo); 139 | } 140 | 141 | continue; 142 | 143 | case OM_COM_STATUS_WAIT_TOPIC: 144 | if (om_fifo_readable_item_count(&com->recv_fifo) < 145 | om_offset_of(om_com_raw_type_t, pack_crc8)) { 146 | return ans; 147 | } 148 | 149 | om_fifo_peek_batch(&com->recv_fifo, com->prase_buff, 150 | om_offset_of(om_com_raw_type_t, pack_crc8)); 151 | 152 | if (om_crc8_verify(com->prase_buff, 153 | om_offset_of(om_com_raw_type_t, pack_crc8))) { 154 | om_fifo_pop_batch(&com->recv_fifo, 155 | om_offset_of(om_com_raw_type_t, pack_crc8)); 156 | 157 | om_com_raw_type_t* pack = (om_com_raw_type_t*)com->prase_buff; 158 | 159 | for (int i = 0; i < com->map_index; i++) { 160 | if (pack->topic_name_crc32 == com->map[i].crc32) { 161 | if (pack->data_len + sizeof(om_com_raw_type_t) > 162 | com->prase_buff_len || 163 | pack->data_len + sizeof(om_com_raw_type_t) > 164 | com->recv_fifo.item_sum) { 165 | /* ERR: Buff is too small */ 166 | OM_ASSERT(false); 167 | } 168 | 169 | com->topic = com->map[i].topic; 170 | com->data_len = pack->data_len; 171 | /* ERR: diff buff size in same topic */ 172 | OM_ASSERT(com->data_len == com->topic->buff_len); 173 | com->status = OM_COM_STATUS_WAIT_DATA_CRC; 174 | continue; 175 | } 176 | } 177 | } else { 178 | om_fifo_pop(&com->recv_fifo); 179 | } 180 | 181 | continue; 182 | case OM_COM_STATUS_WAIT_DATA_CRC: 183 | if (om_fifo_readable_item_count(&com->recv_fifo) < 184 | com->data_len + sizeof(uint8_t)) { 185 | return ans; 186 | } 187 | 188 | om_fifo_reads( 189 | &com->recv_fifo, 190 | com->prase_buff + om_offset_of(om_com_raw_type_t, pack_crc8), 191 | com->data_len + sizeof(uint8_t)); 192 | 193 | if (om_crc8_verify(com->prase_buff, 194 | sizeof(om_com_raw_type_t) + com->data_len)) { 195 | om_publish( 196 | com->topic, 197 | com->prase_buff + om_offset_of(om_com_raw_type_t, pack_crc8), 198 | com->data_len, block, in_isr); 199 | com->status = OM_COM_STATUS_WAIT_START; 200 | ans = OM_COM_RECV_SUCESS; 201 | 202 | } else { 203 | com->status = OM_COM_STATUS_WAIT_START; 204 | ans = OM_COM_RECV_FAILED; 205 | } 206 | 207 | continue; 208 | } 209 | } 210 | 211 | return ans; 212 | } 213 | -------------------------------------------------------------------------------- /om/src/app/om_com.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_COM_H__ 2 | #define __OM_COM_H__ 3 | 4 | #include "om_core.h" 5 | 6 | #define OM_COM_PACK_PREFIX 0x5C 7 | 8 | #define OM_COM_TYPE(_data_type) \ 9 | struct __attribute__((packed)) { \ 10 | uint8_t prefix; \ 11 | uint32_t topic_name_crc32; \ 12 | uint32_t data_len : 24; \ 13 | uint8_t pack_header_crc8; \ 14 | uint8_t data[sizeof(_data_type)]; \ 15 | uint8_t pack_crc8; \ 16 | } 17 | 18 | #define OM_COM_TYPE_SIZE(_data_type) sizeof(OM_COM_TYPE(_data_type)) 19 | 20 | typedef struct __attribute__((packed)) { 21 | uint8_t prefix; 22 | uint32_t topic_name_crc32; 23 | uint32_t data_len : 24; 24 | uint8_t pack_header_crc8; 25 | uint8_t pack_crc8; 26 | } om_com_raw_type_t; 27 | 28 | typedef enum { 29 | OM_COM_STATUS_WAIT_START, 30 | OM_COM_STATUS_WAIT_TOPIC, 31 | OM_COM_STATUS_WAIT_DATA_CRC 32 | } om_com_recv_status_t; 33 | 34 | typedef enum { 35 | OM_COM_RECV_SUCESS, 36 | OM_COM_RECV_NOT_FOUND, 37 | OM_COM_RECV_FAILED, 38 | } om_com_recv_ans_t; 39 | 40 | typedef struct { 41 | uint32_t crc32; 42 | om_topic_t* topic; 43 | } om_com_map_item_t; 44 | 45 | typedef struct { 46 | om_fifo_t recv_fifo; 47 | om_com_map_item_t* map; 48 | uint16_t map_len; 49 | uint16_t map_index; 50 | uint8_t* prase_buff; 51 | uint32_t prase_buff_len; 52 | om_com_recv_status_t status; 53 | uint32_t data_len; 54 | om_topic_t* topic; 55 | } om_com_t; 56 | 57 | om_status_t om_com_create_static(om_com_t* com, void* fifo_buff, 58 | uint32_t buffer_size, om_com_map_item_t* map, 59 | uint16_t map_len, uint8_t* prase_buff, 60 | uint32_t prase_buff_len); 61 | 62 | om_status_t om_com_create(om_com_t* com, uint32_t buffer_size, uint16_t map_len, 63 | uint32_t prase_buff_len); 64 | 65 | om_status_t om_com_add_topic(om_com_t* com, om_topic_t* topic); 66 | 67 | om_status_t om_com_add_topic_with_name(om_com_t* com, const char* topic_name); 68 | 69 | om_status_t om_com_generate_pack(om_topic_t* topic, void* buff); 70 | 71 | om_com_recv_ans_t om_com_prase_recv(om_com_t* com, uint8_t* buff, uint32_t size, 72 | bool block, bool in_isr); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /om/src/app/om_evt.c: -------------------------------------------------------------------------------- 1 | #include "om_evt.h" 2 | 3 | #include "om_afl.h" 4 | #include "om_fmt.h" 5 | #include "om_log.h" 6 | #include "om_msg.h" 7 | 8 | static om_status_t om_event_check(om_msg_t* msg, void* arg) { 9 | om_event_t* evt = (om_event_t*)arg; 10 | 11 | bool active = *((uint32_t*)msg->buff) == evt->event; 12 | 13 | switch (evt->status) { 14 | case OM_EVENT_START: 15 | if (!evt->last && active) evt->callback(evt->event, evt->arg); 16 | break; 17 | case OM_EVENT_PROGRESS: 18 | if (active) evt->callback(evt->event, evt->arg); 19 | break; 20 | case OM_EVENT_END: 21 | if (evt->last && !active) evt->callback(evt->event, evt->arg); 22 | break; 23 | } 24 | 25 | evt->last = active; 26 | 27 | return OM_OK; 28 | } 29 | 30 | om_event_group_t* om_event_create_group(const char* name) { 31 | om_event_group_t* group = om_config_topic(NULL, "A", name, sizeof(uint32_t)); 32 | return group; 33 | } 34 | 35 | om_event_group_t* om_event_create_group_static(om_event_group_t* group, 36 | const char* name) { 37 | om_create_topic_static(group, name, sizeof(uint32_t)); 38 | om_config_topic(group, "A"); 39 | return group; 40 | } 41 | 42 | om_event_group_t* om_event_find_group(const char* name, uint32_t timeout) { 43 | return om_find_topic(name, timeout); 44 | } 45 | 46 | om_status_t om_event_register(om_event_group_t* group, uint32_t event, 47 | om_event_status_t status, 48 | void (*callback)(uint32_t event, void* arg), 49 | void* arg) { 50 | om_event_t* handle = (om_event_t*)om_malloc(sizeof(om_event_t)); 51 | 52 | handle->event = event; 53 | handle->callback = callback; 54 | handle->arg = arg; 55 | handle->status = status; 56 | 57 | om_config_topic(group, "D", om_event_check, handle); 58 | return OM_OK; 59 | } 60 | 61 | om_status_t om_event_register_static( 62 | om_event_t* handle, om_event_group_t* group, uint32_t event, 63 | om_event_status_t status, void (*callback)(uint32_t event, void* arg), 64 | void* arg) { 65 | handle->event = event; 66 | handle->callback = callback; 67 | handle->arg = arg; 68 | handle->status = status; 69 | 70 | om_config_topic(group, "D", om_event_check, handle); 71 | return OM_OK; 72 | } 73 | 74 | om_status_t om_event_active(om_event_group_t* group, uint32_t event, bool block, 75 | bool in_isr) { 76 | return om_publish(group, &event, sizeof(event), block, in_isr); 77 | } 78 | -------------------------------------------------------------------------------- /om/src/app/om_evt.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_EVT_H__ 2 | #define __OM_EVT_H__ 3 | 4 | #include "om_core.h" 5 | 6 | typedef om_topic_t om_event_group_t; 7 | 8 | typedef enum { 9 | OM_EVENT_START, 10 | OM_EVENT_PROGRESS, 11 | OM_EVENT_END, 12 | } om_event_status_t; 13 | 14 | typedef struct { 15 | void (*callback)(uint32_t event, void* arg); 16 | void* arg; 17 | uint32_t event; 18 | bool last; 19 | om_event_status_t status; 20 | } om_event_t; 21 | 22 | om_event_group_t* om_event_create_group(const char* name); 23 | 24 | om_event_group_t* om_event_create_group_static(om_event_group_t* group, 25 | const char* name); 26 | 27 | om_event_group_t* om_event_find_group(const char* name, uint32_t timeout); 28 | 29 | om_status_t om_event_register(om_event_group_t* group, uint32_t event, 30 | om_event_status_t status, 31 | void (*callback)(uint32_t event, void* arg), 32 | void* arg); 33 | 34 | om_status_t om_event_register_static( 35 | om_event_t* handle, om_event_group_t* group, uint32_t event, 36 | om_event_status_t status, void (*callback)(uint32_t event, void* arg), 37 | void* arg); 38 | 39 | om_status_t om_event_active(om_event_group_t* group, uint32_t event, bool block, 40 | bool in_isr); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /om/src/app/om_fmt.c: -------------------------------------------------------------------------------- 1 | #include "om_fmt.h" 2 | 3 | #include "om_afl.h" 4 | #include "om_log.h" 5 | #include "om_msg.h" 6 | 7 | #define GET_CAPITAL(_c) (isupper(_c) ? _c : toupper(_c)) 8 | /* MSG */ 9 | #define ADD2LIST ('A') 10 | #define FILTER_FLAG ('F') 11 | #define SUBER_CB_FLAG ('D') 12 | #define LINK_FLAG ('L') 13 | #define STATIC_LINK_FLAG ('K') 14 | #define SUBER_FLAG ('S') 15 | #define TOPIC_FLAG ('T') 16 | #define STATIC_TOPIC_FLAG ('E') 17 | #define CACHE_FLAG ('C') 18 | #define STATIC_CACHE_FLAG ('X') 19 | 20 | /* AFL */ 21 | #define DECOMPOSE_FLAG ('D') 22 | #define LIST_FLAG ('L') 23 | #define RANGE_FLAG ('R') 24 | 25 | om_topic_t* om_config_topic(om_topic_t* topic, const char* format, ...) { 26 | va_list valist; 27 | va_start(valist, format); 28 | 29 | if (!topic) { 30 | const char* name = va_arg(valist, const char*); 31 | uint32_t len = va_arg(valist, uint32_t); 32 | topic = om_core_topic_create(name, len); 33 | } 34 | 35 | if (format == NULL) { 36 | va_end(valist); 37 | return topic; 38 | } 39 | 40 | for (const uint8_t* index = (const uint8_t*)format; *index != '\0'; index++) { 41 | OM_ASSERT(isalpha(*index)); 42 | 43 | switch (GET_CAPITAL(*index)) { 44 | case FILTER_FLAG: 45 | topic->user_fun.filter = va_arg(valist, om_user_fun_t); 46 | topic->user_fun.filter_arg = va_arg(valist, void*); 47 | 48 | OM_ASSERT(topic->user_fun.filter); 49 | break; 50 | case LINK_FLAG: 51 | om_core_link(topic, va_arg(valist, om_topic_t*)); 52 | break; 53 | case STATIC_LINK_FLAG: { 54 | om_suber_t* suber = va_arg(valist, om_suber_t*); 55 | om_link_t* link = va_arg(valist, om_link_t*); 56 | om_topic_t* target = va_arg(valist, om_topic_t*); 57 | 58 | om_core_link_static(suber, link, topic, target); 59 | break; 60 | } 61 | case SUBER_FLAG: 62 | om_core_add_suber(topic, va_arg(valist, om_suber_t*)); 63 | break; 64 | case TOPIC_FLAG: 65 | om_core_link(va_arg(valist, om_topic_t*), topic); 66 | break; 67 | case STATIC_TOPIC_FLAG: { 68 | om_suber_t* suber = va_arg(valist, om_suber_t*); 69 | om_link_t* link = va_arg(valist, om_link_t*); 70 | om_topic_t* source = va_arg(valist, om_topic_t*); 71 | om_core_link_static(suber, link, source, topic); 72 | break; 73 | } 74 | case CACHE_FLAG: 75 | topic->msg.buff = om_malloc(topic->buff_len); 76 | topic->virtual_mode = false; 77 | break; 78 | case STATIC_CACHE_FLAG: 79 | topic->msg.buff = va_arg(valist, void*); 80 | topic->virtual_mode = false; 81 | break; 82 | case ADD2LIST: { 83 | om_add_topic(topic); 84 | break; 85 | } 86 | case SUBER_CB_FLAG: { 87 | om_user_fun_t fun = va_arg(valist, om_user_fun_t); 88 | void* arg = va_arg(valist, void*); 89 | om_config_suber(NULL, "DT", fun, arg, topic); 90 | } break; 91 | default: 92 | OM_ASSERT(false); 93 | va_end(valist); 94 | return NULL; 95 | } 96 | } 97 | va_end(valist); 98 | 99 | return topic; 100 | } 101 | 102 | om_suber_t* om_config_suber(om_suber_t* suber, const char* format, ...) { 103 | if (!suber) 104 | suber = om_core_suber_create(NULL); 105 | else 106 | om_create_suber_static(suber, NULL); 107 | if (format == NULL) return suber; 108 | 109 | va_list valist; 110 | va_start(valist, format); 111 | 112 | for (const uint8_t* index = (const uint8_t*)format; *index != '\0'; index++) { 113 | OM_ASSERT(isalpha(*index)); 114 | switch (GET_CAPITAL(*index)) { 115 | case SUBER_CB_FLAG: 116 | suber->mode = OM_SUBER_MODE_DEFAULT; 117 | 118 | suber->data.as_suber.sub_callback = va_arg(valist, om_user_fun_t); 119 | suber->data.as_suber.sub_cb_arg = va_arg(valist, void*); 120 | 121 | OM_ASSERT(suber->data.as_suber.sub_callback); 122 | break; 123 | case TOPIC_FLAG: 124 | om_core_add_suber(va_arg(valist, om_topic_t*), suber); 125 | break; 126 | default: 127 | OM_ASSERT(false); 128 | va_end(valist); 129 | return NULL; 130 | } 131 | } 132 | va_end(valist); 133 | 134 | return suber; 135 | } 136 | 137 | om_status_t om_config_filter(om_topic_t* topic, const char* format, ...) { 138 | OM_ASSERT(topic); 139 | OM_ASSERT(format); 140 | 141 | va_list valist; 142 | va_start(valist, format); 143 | 144 | if (topic->afl == NULL) { 145 | om_afl_create(topic); 146 | } 147 | 148 | for (const uint8_t* index = (const uint8_t*)format; *index != '\0'; index++) { 149 | OM_ASSERT(isalpha(*index)); 150 | switch (GET_CAPITAL(*index)) { 151 | case LIST_FLAG: { 152 | om_afl_filter_t* filter = 153 | om_afl_filter_create(va_arg(valist, om_topic_t*)); 154 | uint32_t length = va_arg(valist, uint32_t); 155 | uint32_t offset = va_arg(valist, uint32_t); 156 | uint32_t scope = va_arg(valist, uint32_t); 157 | void* fl_template = va_arg(valist, void*); 158 | om_afl_set_filter(filter, OM_AFL_MODE_LIST, offset, length, scope, 0, 159 | fl_template); 160 | om_afl_add_filter(topic->afl, filter); 161 | break; 162 | } 163 | case DECOMPOSE_FLAG: { 164 | om_afl_filter_t* filter = 165 | om_afl_filter_create(va_arg(valist, om_topic_t*)); 166 | uint32_t length = va_arg(valist, uint32_t); 167 | uint32_t offset = va_arg(valist, uint32_t); 168 | uint32_t scope = va_arg(valist, uint32_t); 169 | om_afl_set_filter(filter, OM_AFL_MODE_DECOMPOSE, offset, length, scope, 170 | 0, NULL); 171 | om_afl_add_filter(topic->afl, filter); 172 | break; 173 | } 174 | case RANGE_FLAG: { 175 | om_afl_filter_t* filter = 176 | om_afl_filter_create(va_arg(valist, om_topic_t*)); 177 | uint32_t length = va_arg(valist, uint32_t); 178 | uint32_t offset = va_arg(valist, uint32_t); 179 | uint32_t scope = va_arg(valist, uint32_t); 180 | uint32_t start = va_arg(valist, uint32_t); 181 | uint32_t arg = va_arg(valist, uint32_t); 182 | 183 | OM_UNUSED(scope); 184 | 185 | om_afl_set_filter(filter, OM_AFL_MODE_RANGE, offset, length, start, arg, 186 | NULL); 187 | om_afl_add_filter(topic->afl, filter); 188 | break; 189 | } 190 | 191 | default: 192 | OM_ASSERT(false); 193 | return OM_ERROR; 194 | } 195 | } 196 | 197 | va_end(valist); 198 | 199 | return OM_OK; 200 | } 201 | 202 | om_status_t om_config_filter_static(om_topic_t* topic, const char* format, 203 | ...) { 204 | OM_ASSERT(topic); 205 | OM_ASSERT(format); 206 | 207 | va_list valist; 208 | va_start(valist, format); 209 | 210 | if (topic->afl == NULL) { 211 | om_afl_create_static(va_arg(valist, om_afl_t*), topic); 212 | } 213 | 214 | for (const uint8_t* index = (const uint8_t*)format; *index != '\0'; index++) { 215 | OM_ASSERT(isalpha(*index)); 216 | switch (GET_CAPITAL(*index)) { 217 | case LIST_FLAG: { 218 | om_afl_filter_t* filter = va_arg(valist, om_afl_filter_t*); 219 | om_topic_t* master = va_arg(valist, om_topic_t*); 220 | om_afl_filter_create_static(filter, master); 221 | uint32_t length = va_arg(valist, uint32_t); 222 | uint32_t offset = va_arg(valist, uint32_t); 223 | uint32_t scope = va_arg(valist, uint32_t); 224 | void* fl_template = va_arg(valist, void*); 225 | om_afl_set_filter(filter, OM_AFL_MODE_LIST, offset, length, scope, 0, 226 | fl_template); 227 | om_afl_add_filter(topic->afl, filter); 228 | break; 229 | } 230 | case DECOMPOSE_FLAG: { 231 | om_afl_filter_t* filter = va_arg(valist, om_afl_filter_t*); 232 | om_topic_t* master = va_arg(valist, om_topic_t*); 233 | om_afl_filter_create_static(filter, master); 234 | uint32_t length = va_arg(valist, uint32_t); 235 | uint32_t offset = va_arg(valist, uint32_t); 236 | uint32_t scope = va_arg(valist, uint32_t); 237 | om_afl_set_filter(filter, OM_AFL_MODE_DECOMPOSE, offset, length, scope, 238 | 0, NULL); 239 | om_afl_add_filter(topic->afl, filter); 240 | break; 241 | } 242 | case RANGE_FLAG: { 243 | om_afl_filter_t* filter = va_arg(valist, om_afl_filter_t*); 244 | om_topic_t* master = va_arg(valist, om_topic_t*); 245 | om_afl_filter_create_static(filter, master); 246 | uint32_t length = va_arg(valist, uint32_t); 247 | uint32_t offset = va_arg(valist, uint32_t); 248 | uint32_t scope = va_arg(valist, uint32_t); 249 | uint32_t start = va_arg(valist, uint32_t); 250 | uint32_t arg = va_arg(valist, uint32_t); 251 | 252 | OM_UNUSED(scope); 253 | 254 | om_afl_set_filter(filter, OM_AFL_MODE_RANGE, offset, length, start, arg, 255 | NULL); 256 | om_afl_add_filter(topic->afl, filter); 257 | break; 258 | } 259 | 260 | default: 261 | OM_ASSERT(false); 262 | return OM_ERROR; 263 | } 264 | } 265 | 266 | va_end(valist); 267 | 268 | return OM_OK; 269 | } 270 | -------------------------------------------------------------------------------- /om/src/app/om_fmt.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_FMT_H__ 2 | #define __OM_FMT_H__ 3 | 4 | #include "om_core.h" 5 | 6 | om_topic_t* om_config_topic(om_topic_t* topic, const char* format, ...); 7 | 8 | om_suber_t* om_config_suber(om_suber_t* suber, const char* format, ...); 9 | 10 | om_status_t om_config_filter(om_topic_t* topic, const char* format, ...); 11 | 12 | om_status_t om_config_filter_static(om_topic_t* topic, const char* format, ...); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /om/src/app/om_log.c: -------------------------------------------------------------------------------- 1 | #include "om_log.h" 2 | 3 | #include "om_afl.h" 4 | #include "om_fmt.h" 5 | #include "om_msg.h" 6 | 7 | #if OM_LOG_OUTPUT 8 | 9 | #if OM_LOG_COLORFUL 10 | static const om_log_format_t LOG_FORMAT[OM_LOG_COLOR_NUMBER] = { 11 | { 12 | .bg_color = OM_COLOR_BACKGROUND_NONE, 13 | .ft_color = OM_COLOR_FONT_RED, 14 | .fm_color = OM_COLOR_FORMAT_NONE, 15 | }, 16 | { 17 | .bg_color = OM_COLOR_BACKGROUND_NONE, 18 | .ft_color = OM_COLOR_FONT_GREEN, 19 | .fm_color = OM_COLOR_FORMAT_NONE, 20 | }, 21 | { 22 | .bg_color = OM_COLOR_BACKGROUND_NONE, 23 | .ft_color = OM_COLOR_FONT_BLUE, 24 | .fm_color = OM_COLOR_FORMAT_NONE, 25 | }, 26 | { 27 | .bg_color = OM_COLOR_BACKGROUND_NONE, 28 | .ft_color = OM_COLOR_FONT_YELLOW, 29 | .fm_color = OM_COLOR_FORMAT_NONE, 30 | }, 31 | { 32 | .bg_color = OM_COLOR_BACKGROUND_NONE, 33 | .ft_color = OM_COLOR_FONT_NONE, 34 | .fm_color = OM_COLOR_FORMAT_NONE, 35 | }, 36 | }; 37 | #endif 38 | 39 | static bool om_log_initd = false; 40 | static om_mutex_t om_log_mutex; 41 | static om_topic_t om_log_topic; 42 | 43 | om_status_t om_log_init() { 44 | om_core_topic_create_static(&om_log_topic, "om_log", sizeof(om_log_t)); 45 | om_mutex_init(&om_log_mutex); 46 | om_mutex_unlock(&om_log_mutex); 47 | om_log_initd = true; 48 | 49 | return OM_OK; 50 | } 51 | 52 | inline om_topic_t* om_get_log_handle() { return &om_log_topic; } 53 | 54 | static om_log_t log_buf; 55 | static char fm_buf[OM_LOG_MAX_LEN]; 56 | 57 | om_status_t om_print_log(const char* name, om_log_level_t level, bool block, 58 | bool in_isr, const char* format, ...) { 59 | if (!om_log_initd) return OM_ERROR_NOT_INIT; 60 | 61 | om_mutex_lock(&om_log_mutex); 62 | 63 | log_buf.level = level; 64 | 65 | #if OM_TIME 66 | om_time_get(&log_buf.time); 67 | #endif 68 | 69 | #if OM_LOG_COLORFUL 70 | snprintf(fm_buf, OM_LOG_MAX_LEN, "%s%s%s[%s]%s%s\r\n", 71 | OM_COLOR_BG[LOG_FORMAT[level].bg_color], 72 | OM_COLOR_FONT[LOG_FORMAT[level].ft_color], 73 | OM_COLOR_FORMAT[LOG_FORMAT[level].fm_color], name, 74 | OM_COLOR_FORMAT[OM_COLOR_FORMAT_RESET], format); 75 | #else 76 | snprintf(fm_buf, OM_LOG_MAX_LEN, "[%s]%s\r\n", name, format); 77 | #endif 78 | va_list vArgList; 79 | va_start(vArgList, format); 80 | vsnprintf(log_buf.data, OM_LOG_MAX_LEN, fm_buf, vArgList); 81 | va_end(vArgList); 82 | om_status_t res = 83 | om_publish(&om_log_topic, &log_buf, sizeof(om_log_t), block, in_isr); 84 | 85 | om_mutex_unlock(&om_log_mutex); 86 | 87 | return res; 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /om/src/app/om_log.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_LOG_H__ 2 | #define __OM_LOG_H__ 3 | 4 | #include "om_core.h" 5 | 6 | #if OM_LOG_OUTPUT 7 | 8 | #if OM_LOG_LEVEL <= 1 9 | #define OMLOG_DEFAULT(...) \ 10 | om_print_log("Default", OM_LOG_LEVEL_DEFAULT, true, false, __VA_ARGS__) 11 | #define OMLOG_DEFAULT_ISR(...) \ 12 | om_print_log("Default", OM_LOG_LEVEL_DEFAULT, false, true, __VA_ARGS__) 13 | #else 14 | #define OMLOG_DEFAULT(...) 15 | #define OMLOG_DEFAULT_ISR(...) 16 | #endif 17 | 18 | #if OM_LOG_LEVEL <= 2 19 | #define OMLOG_NOTICE(...) \ 20 | om_print_log("Notice", OM_LOG_LEVEL_NOTICE, true, false, __VA_ARGS__) 21 | #define OMLOG_NOTICE_ISR(...) \ 22 | om_print_log("Notice", OM_LOG_LEVEL_NOTICE, false, true, __VA_ARGS__) 23 | #else 24 | #define OMLOG_NOTICE(...) 25 | #define OMLOG_NOTICE_ISR(...) 26 | #endif 27 | 28 | #if OM_LOG_LEVEL <= 3 29 | #define OMLOG_PASS(...) \ 30 | om_print_log("Pass", OM_LOG_LEVEL_PASS, true, false, __VA_ARGS__) 31 | #define OMLOG_PASS_ISR(...) \ 32 | om_print_log("Pass", OM_LOG_LEVEL_PASS, false, true, __VA_ARGS__) 33 | #else 34 | #define OMLOG_PASS(...) 35 | #define OMLOG_PASS_ISR(...) 36 | #endif 37 | 38 | #if OM_LOG_LEVEL <= 4 39 | #define OMLOG_WARNING(...) \ 40 | om_print_log("Warning", OM_LOG_LEVEL_WARNING, true, false, __VA_ARGS__) 41 | #define OMLOG_WARNING_ISR(...) \ 42 | om_print_log("Warning", OM_LOG_LEVEL_WARNING, false, true, __VA_ARGS__) 43 | #else 44 | #define OMLOG_WARNING(...) 45 | #define OMLOG_WARNING_ISR(...) 46 | #endif 47 | 48 | #if OM_LOG_LEVEL <= 5 49 | #define OMLOG_ERROR(...) \ 50 | om_print_log("Error", OM_LOG_LEVEL_ERROR, true, false, __VA_ARGS__) 51 | #define OMLOG_ERROR_ISR(...) \ 52 | om_print_log("Error", OM_LOG_LEVEL_ERROR, false, true, __VA_ARGS__) 53 | #else 54 | #define OMLOG_ERROR(...) 55 | #define OMLOG_ERROR_ISR(...) 56 | #endif 57 | 58 | typedef enum { 59 | OM_LOG_COLOR_RED, 60 | OM_LOG_COLOR_GREEN, 61 | OM_LOG_COLOR_BLUE, 62 | OM_LOG_COLOR_YELLOW, 63 | OM_LOG_COLOR_DEFAULT, 64 | OM_LOG_COLOR_NUMBER 65 | } om_log_color_t; 66 | 67 | typedef enum { 68 | OM_LOG_LEVEL_DEFAULT = OM_LOG_COLOR_DEFAULT, 69 | OM_LOG_LEVEL_WARNING = OM_LOG_COLOR_YELLOW, 70 | OM_LOG_LEVEL_ERROR = OM_LOG_COLOR_RED, 71 | OM_LOG_LEVEL_PASS = OM_LOG_COLOR_GREEN, 72 | OM_LOG_LEVEL_NOTICE = OM_LOG_COLOR_BLUE 73 | } om_log_level_t; 74 | 75 | typedef struct { 76 | char data[OM_LOG_MAX_LEN]; 77 | #if OM_TIME 78 | om_time_t time; 79 | #endif 80 | om_log_level_t level; 81 | } om_log_t; 82 | 83 | typedef struct { 84 | om_color_background_t bg_color; 85 | om_color_font_t ft_color; 86 | om_color_format_t fm_color; 87 | } om_log_format_t; 88 | 89 | om_status_t om_log_init(); 90 | 91 | om_topic_t* om_get_log_handle(); 92 | 93 | om_status_t om_print_log(const char* name, om_log_level_t level, bool block, 94 | bool in_isr, const char* format, ...); 95 | 96 | #endif 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /om/src/app/om_msg.c: -------------------------------------------------------------------------------- 1 | #include "om_msg.h" 2 | 3 | #include "om_afl.h" 4 | #include "om_fmt.h" 5 | #include "om_log.h" 6 | 7 | extern om_rbt_root_t _topic_list; 8 | 9 | inline om_status_t _om_publish_to_suber(om_suber_t* sub, om_topic_t* topic, 10 | bool block, bool in_isr) { 11 | OM_ASSERT(sub); 12 | OM_ASSERT(topic); 13 | 14 | switch (sub->mode) { 15 | case OM_SUBER_MODE_DEFAULT: 16 | sub->data.as_suber.sub_callback(&topic->msg, 17 | sub->data.as_suber.sub_cb_arg); 18 | break; 19 | case OM_SUBER_MODE_LINK: 20 | if (!in_isr) { 21 | if (block) 22 | om_mutex_lock(&sub->data.as_link.target->mutex); 23 | else { 24 | if (om_mutex_trylock(&sub->data.as_link.target->mutex) != OM_OK) 25 | break; 26 | } 27 | 28 | _om_publish(sub->data.as_link.target, &topic->msg, block, in_isr); 29 | 30 | om_mutex_unlock(&sub->data.as_link.target->mutex); 31 | } else { 32 | if (om_mutex_lock_isr(&sub->data.as_link.target->mutex) != OM_OK) 33 | return OM_ERROR_BUSY; 34 | _om_publish(sub->data.as_link.target, &topic->msg, block, in_isr); 35 | om_mutex_unlock_isr(&sub->data.as_link.target->mutex); 36 | } 37 | break; 38 | case OM_SUBER_MODE_EXPORT: 39 | sub->data.as_export.new_data = true; 40 | break; 41 | case OM_SUBER_MODE_FIFO: 42 | om_fifo_write(sub->data.as_queue.fifo, topic->msg.buff); 43 | break; 44 | case OM_SUBER_MODE_UNKNOW: 45 | break; 46 | default: 47 | OM_ASSERT(false); 48 | return OM_ERROR; 49 | } 50 | 51 | return OM_OK; 52 | } 53 | 54 | inline om_status_t _om_publish_to_topic(om_topic_t* topic, om_msg_t* msg, 55 | bool block, bool in_isr) { 56 | OM_ASSERT(topic); 57 | OM_ASSERT(msg); 58 | 59 | OM_UNUSED(in_isr); 60 | OM_UNUSED(block); 61 | 62 | if (msg->size > topic->buff_len) { 63 | OM_ASSERT(false); 64 | return OM_ERROR; 65 | } 66 | 67 | #if OM_TIME 68 | om_time_get(&msg->time); 69 | #endif 70 | 71 | if (topic->user_fun.filter != NULL && 72 | topic->user_fun.filter(msg, topic->user_fun.filter_arg) != OM_OK) 73 | return OM_ERROR; 74 | 75 | if (topic->virtual_mode) 76 | memcpy(&topic->msg, msg, sizeof(*msg)); 77 | else { 78 | OM_ASSERT(topic->msg.buff); 79 | memcpy(topic->msg.buff, msg->buff, msg->size); 80 | topic->msg.size = msg->size; 81 | #if OM_TIME 82 | topic->msg.time = msg->time; 83 | #endif 84 | } 85 | 86 | return OM_OK; 87 | } 88 | 89 | om_status_t _om_publish(om_topic_t* topic, om_msg_t* msg, bool block, 90 | bool in_isr) { 91 | OM_ASSERT(topic); 92 | OM_ASSERT(msg); 93 | 94 | if (_om_publish_to_topic(topic, msg, block, in_isr) != OM_OK) return OM_ERROR; 95 | 96 | if (topic->afl) om_afl_apply(&(topic->msg), topic->afl, block, in_isr); 97 | 98 | om_list_head_t* pos; 99 | om_list_for_each(pos, &topic->suber) { 100 | om_suber_t* sub = om_list_entry(pos, om_suber_t, self); 101 | 102 | _om_publish_to_suber(sub, topic, block, in_isr); 103 | } 104 | 105 | return OM_OK; 106 | } 107 | 108 | om_status_t om_publish(om_topic_t* topic, void* buff, uint32_t size, bool block, 109 | bool in_isr) { 110 | OM_ASSERT(topic); 111 | OM_ASSERT(buff); 112 | 113 | if (!in_isr) { 114 | if (block) 115 | om_mutex_lock(&topic->mutex); 116 | else if (om_mutex_trylock(&topic->mutex) != OM_OK) 117 | return OM_ERROR_BUSY; 118 | } else { 119 | if (om_mutex_lock_isr(&topic->mutex) != OM_OK) { 120 | return OM_ERROR_BUSY; 121 | } 122 | } 123 | 124 | om_msg_t msg = {.buff = buff, .size = size}; 125 | 126 | om_status_t res = _om_publish(topic, &msg, block, in_isr); 127 | 128 | if (!in_isr) { 129 | om_mutex_unlock(&topic->mutex); 130 | } else { 131 | om_mutex_unlock_isr(&topic->mutex); 132 | } 133 | 134 | return res; 135 | } 136 | 137 | om_suber_t* om_subscribe(om_topic_t* topic) { 138 | OM_ASSERT(topic); 139 | 140 | om_suber_t* sub = om_core_suber_create(NULL); 141 | om_core_set_export_target(sub); 142 | om_core_add_suber(topic, sub); 143 | 144 | return sub; 145 | } 146 | 147 | om_suber_t* om_subscribe_static(om_topic_t* topic, om_suber_t* sub) { 148 | OM_ASSERT(topic); 149 | OM_ASSERT(sub); 150 | 151 | om_core_set_export_target(sub); 152 | om_core_add_suber(topic, sub); 153 | 154 | return sub; 155 | } 156 | 157 | inline bool om_suber_available(om_suber_t* suber) { 158 | return suber->data.as_export.new_data; 159 | } 160 | 161 | om_status_t om_suber_export(om_suber_t* suber, void* buff, bool in_isr) { 162 | OM_ASSERT(suber); 163 | OM_ASSERT(suber->mode == OM_SUBER_MODE_EXPORT); 164 | 165 | if (suber->data.as_export.new_data) { 166 | if (!in_isr) 167 | om_mutex_lock(&suber->master->mutex); 168 | else { 169 | if (om_mutex_lock_isr(&suber->master->mutex) != OM_OK) 170 | return OM_ERROR_BUSY; 171 | } 172 | 173 | suber->data.as_export.new_data = false; 174 | 175 | memcpy(buff, suber->master->msg.buff, suber->master->msg.size); 176 | 177 | if (!in_isr) 178 | om_mutex_unlock(&suber->master->mutex); 179 | else 180 | om_mutex_unlock_isr(&suber->master->mutex); 181 | 182 | return OM_OK; 183 | } else { 184 | return OM_ERROR; 185 | } 186 | } 187 | 188 | om_status_t om_msg_del_topic(om_topic_t* topic) { 189 | OM_ASSERT(topic); 190 | 191 | return om_core_del_topic(&topic->self); 192 | } 193 | 194 | om_status_t om_msg_del_suber(om_suber_t* suber) { 195 | OM_ASSERT(suber); 196 | 197 | return om_core_del_suber(&suber->self); 198 | } 199 | 200 | typedef struct { 201 | bool (*fun)(om_topic_t* topic, void* arg); 202 | void* arg; 203 | } om_msg_cb_block; 204 | 205 | static bool _om_msg_foreach_topic(om_rbt_node_t* node, void* arg) { 206 | om_msg_cb_block* block = (om_msg_cb_block*)arg; 207 | om_topic_t* topic = om_container_of(node, om_topic_t, self); 208 | 209 | return block->fun(topic, block->arg); 210 | } 211 | 212 | om_status_t om_msg_foreach_topic(bool (*fun)(om_topic_t* topic, void* arg), 213 | void* arg) { 214 | om_msg_cb_block block = {fun, arg}; 215 | 216 | om_rbtree_foreach(&_topic_list, _om_msg_foreach_topic, &block); 217 | 218 | return OM_OK; 219 | } 220 | 221 | uint32_t om_msg_get_topic_num() { return om_rbtree_get_num(&_topic_list); } 222 | 223 | uint32_t om_msg_get_suber_num(om_topic_t* topic) { 224 | return om_list_get_num(&topic->suber); 225 | } 226 | 227 | uint32_t om_msg_get_link_num(om_topic_t* topic) { 228 | return om_list_get_num(&topic->link); 229 | } 230 | 231 | #if OM_TIME 232 | om_time_t om_msg_get_last_time(om_topic_t* topic) { return topic->msg.time; } 233 | #endif 234 | -------------------------------------------------------------------------------- /om/src/app/om_msg.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_MSG_H__ 2 | #define __OM_MSG_H__ 3 | 4 | #include "om_core.h" 5 | 6 | #define om_topic_add_suber om_core_add_suber 7 | #define om_add_topic om_core_add_topic 8 | #define om_topic_link om_core_link 9 | #define om_topic_link_static om_core_link_static 10 | #define om_find_topic om_core_find_topic 11 | #define om_create_topic om_core_topic_create 12 | #define om_create_topic_static om_core_topic_create_static 13 | #define om_create_suber om_core_suber_create 14 | #define om_create_suber_static om_core_suber_create_static 15 | #define om_create_link om_core_link_create 16 | #define om_create_link_static om_core_link_create_static 17 | #define om_queue_add om_core_queue_add 18 | #define om_queue_add_static om_core_queue_add_static 19 | #define om_queue_init_fifo_static om_core_queue_init_fifo_static 20 | 21 | om_status_t _om_publish_to_suber(om_suber_t* sub, om_topic_t* topic, bool block, 22 | bool in_isr); 23 | 24 | om_status_t _om_publish_to_topic(om_topic_t* topic, om_msg_t* msg, bool block, 25 | bool in_isr); 26 | 27 | om_status_t _om_publish(om_topic_t* topic, om_msg_t* msg, bool block, 28 | bool in_isr); 29 | 30 | om_status_t om_publish(om_topic_t* topic, void* buff, uint32_t size, bool block, 31 | bool in_isr); 32 | 33 | om_status_t om_sync(bool in_isr); 34 | 35 | om_suber_t* om_subscribe(om_topic_t* topic); 36 | 37 | om_suber_t* om_subscribe_static(om_topic_t* topic, om_suber_t* sub); 38 | 39 | bool om_suber_available(om_suber_t* suber); 40 | 41 | om_status_t om_suber_export(om_suber_t* suber, void* buff, bool in_isr); 42 | 43 | om_status_t om_msg_del_topic(om_topic_t* topic); 44 | 45 | om_status_t om_msg_del_suber(om_suber_t* suber); 46 | 47 | om_status_t om_msg_foreach_topic(bool (*fun)(om_topic_t* topic, void* arg), 48 | void* arg); 49 | 50 | uint32_t om_msg_get_topic_num(); 51 | 52 | uint32_t om_msg_get_suber_num(om_topic_t* topic); 53 | 54 | uint32_t om_msg_get_link_num(om_topic_t* topic); 55 | 56 | #if OM_TIME 57 | om_time_t om_msg_get_last_time(om_topic_t* topic); 58 | #endif 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /om/src/comp/om_color.c: -------------------------------------------------------------------------------- 1 | #include "om_color.h" 2 | 3 | const char* OM_COLOR_FORMAT[] = { 4 | "", "\033[m", "\033[1m", "\033[2m", "\033[4m", 5 | "\033[5m", "\033[7m", "\033[8m", "\033[K", 6 | }; 7 | 8 | const char* OM_COLOR_FONT[] = { 9 | "", "\033[30m", "\033[31m", "\033[32m", "\033[33m", 10 | "\033[34m", "\033[35m", "\033[36m", "\033[37m", 11 | }; 12 | 13 | const char* OM_COLOR_BG[] = { 14 | "", "\033[40m", "\033[41m", "\033[42m", "\033[43m", 15 | "\033[44m", "\033[45m", "\033[46m", "\033[47m", 16 | }; 17 | 18 | const char* OM_COLOR_BOLD[] = { 19 | "", 20 | "\033[33m\033[1m", 21 | "\033[31m\033[1m", 22 | "\033[1m\033[41m", 23 | }; 24 | -------------------------------------------------------------------------------- /om/src/comp/om_color.h: -------------------------------------------------------------------------------- 1 | typedef enum { 2 | OM_COLOR_FORMAT_NONE = 0, 3 | OM_COLOR_FORMAT_RESET, 4 | OM_COLOR_FORMAT_BOLD, 5 | OM_COLOR_FORMAT_DARK, 6 | OM_COLOR_FORMAT_UNDERLINE, 7 | OM_COLOR_FORMAT_BLINK, 8 | OM_COLOR_FORMAT_REVERSE, 9 | OM_COLOR_FORMAT_CONCEALED, 10 | OM_COLOR_FORMAT_CLEAR_LINE, 11 | OM_COLOR_FORMAT_NUM 12 | } om_color_format_t; 13 | 14 | typedef enum { 15 | OM_COLOR_FONT_NONE = 0, 16 | OM_COLOR_FONT_BLACK, 17 | OM_COLOR_FONT_RED, 18 | OM_COLOR_FONT_GREEN, 19 | OM_COLOR_FONT_YELLOW, 20 | OM_COLOR_FONT_BLUE, 21 | OM_COLOR_FONT_MAGENTA, 22 | OM_COLOR_FONT_CYAN, 23 | OM_COLOR_FONT_WHITE, 24 | OM_COLOR_FONT_NUM 25 | } om_color_font_t; 26 | 27 | typedef enum { 28 | OM_COLOR_BACKGROUND_NONE = 0, 29 | OM_COLOR_BACKGROUND_BLACK, 30 | OM_COLOR_BACKGROUND_RED, 31 | OM_COLOR_BACKGROUND_GREEN, 32 | OM_COLOR_BACKGROUND_YELLOW, 33 | OM_COLOR_BACKGROUND_BLUE, 34 | OM_COLOR_BACKGROUND_MAGENTA, 35 | OM_COLOR_BACKGROUND_CYAN, 36 | OM_COLOR_BACKGROUND_WHITE, 37 | OM_COLOR_BACKGROUND_NUM 38 | } om_color_background_t; 39 | 40 | typedef enum { 41 | OM_COLOR_BOLD_NONE = 0, 42 | OM_COLOR_BOLD_YELLOW, 43 | OM_COLOR_BOLD_RED, 44 | OM_COLOR_BOLD_ON_RED, 45 | OM_COLOR_BOLD_NUM 46 | } om_color_bold_t; 47 | 48 | extern const char* OM_COLOR_FORMAT[]; 49 | extern const char* OM_COLOR_FONT[]; 50 | extern const char* OM_COLOR_BG[]; 51 | extern const char* OM_COLOR_BOLD[]; -------------------------------------------------------------------------------- /om/src/comp/om_crc.c: -------------------------------------------------------------------------------- 1 | #include "om_crc.h" 2 | 3 | #define CRC8_INIT 0xFF 4 | #define CRC32_INIT 0xFFFFFFFF 5 | 6 | uint8_t om_crc8_tab[256]; 7 | 8 | uint32_t om_crc32_tab[256]; 9 | 10 | void om_generate_crc8_table() { 11 | uint8_t crc = 0; 12 | 13 | for (int i = 0; i < 256; i++) { 14 | om_crc8_tab[i] = i; 15 | } 16 | 17 | for (int i = 0; i < 256; i++) { 18 | for (int j = 7; j >= 0; j--) { 19 | crc = om_crc8_tab[i] & 0x01; 20 | 21 | if (crc) { 22 | om_crc8_tab[i] = om_crc8_tab[i] >> 1; 23 | om_crc8_tab[i] ^= 0x8c; 24 | } else { 25 | om_crc8_tab[i] = om_crc8_tab[i] >> 1; 26 | } 27 | } 28 | } 29 | } 30 | 31 | void om_generate_crc32_table() { 32 | uint32_t crc = 0; 33 | for (int i = 0; i < 256; ++i) { 34 | crc = i; 35 | for (int j = 0; j < 8; ++j) { 36 | if (crc & 1) { 37 | crc = (crc >> 1) ^ 0xEDB88320; 38 | } else { 39 | crc >>= 1; 40 | } 41 | } 42 | om_crc32_tab[i] = crc; 43 | } 44 | } 45 | 46 | uint8_t om_crc8_calc(const uint8_t* buf, size_t len) { 47 | uint8_t crc = CRC8_INIT; 48 | 49 | /* loop over the buffer data */ 50 | while (len-- > 0) { 51 | crc = om_crc8_tab[(crc ^ *buf++) & 0xff]; 52 | } 53 | 54 | return crc; 55 | } 56 | 57 | bool om_crc8_verify(const uint8_t* buf, size_t len) { 58 | if (len < 2) { 59 | return false; 60 | } 61 | uint8_t expected = om_crc8_calc(buf, len - sizeof(uint8_t)); 62 | return expected == buf[len - sizeof(uint8_t)]; 63 | } 64 | 65 | static inline uint32_t crc32_byte(uint32_t crc, const uint8_t data) { 66 | return om_crc32_tab[(crc ^ data) & 0xff] ^ (crc >> 8); 67 | } 68 | 69 | uint32_t om_crc32_calc(const uint8_t* buf, size_t len) { 70 | uint32_t crc = CRC32_INIT; 71 | while (len--) { 72 | crc = crc32_byte(crc, *buf++); 73 | } 74 | return crc; 75 | } 76 | 77 | bool om_crc32_verify(const uint8_t* buf, size_t len) { 78 | if (len < 2) return false; 79 | 80 | uint32_t expected = om_crc32_calc(buf, len - sizeof(uint32_t)); 81 | return expected == ((const uint32_t*)((const uint8_t*)buf + 82 | (len % 4)))[len / sizeof(uint32_t) - 1]; 83 | } 84 | -------------------------------------------------------------------------------- /om/src/comp/om_crc.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_CRC_H__ 2 | #define __OM_CRC_H__ 3 | 4 | #include "om_def.h" 5 | 6 | void om_generate_crc8_table(); 7 | 8 | void om_generate_crc32_table(); 9 | 10 | uint8_t om_crc8_calc(const uint8_t* buf, size_t len); 11 | 12 | bool om_crc8_verify(const uint8_t* buf, size_t len); 13 | 14 | uint32_t om_crc32_calc(const uint8_t* buf, size_t len); 15 | 16 | bool om_crc32_verify(const uint8_t* buf, size_t len); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /om/src/comp/om_fifo.c: -------------------------------------------------------------------------------- 1 | #include "om_fifo.h" 2 | 3 | #include 4 | 5 | #include "om_def.h" 6 | 7 | inline void om_fifo_create(om_fifo_t* fifo, void* fifo_ptr, uint32_t item_sum, 8 | uint32_t item_size) { 9 | fifo->item_sum = item_sum; 10 | fifo->item_size = item_size; 11 | fifo->ptr_write = 0; 12 | fifo->ptr_read = 0; 13 | fifo->is_full = false; 14 | fifo->fifo_ptr = fifo_ptr; 15 | } 16 | 17 | inline bool om_fifo_writeable(om_fifo_t* fifo) { return !fifo->is_full; } 18 | 19 | inline om_status_t om_fifo_write(om_fifo_t* fifo, const void* data) { 20 | if (fifo->is_full) { 21 | return OM_ERROR_FULL; 22 | } 23 | 24 | memcpy((uint8_t*)(fifo->fifo_ptr) + fifo->ptr_write * fifo->item_size, data, 25 | fifo->item_size); 26 | 27 | fifo->ptr_write++; 28 | 29 | if (fifo->ptr_write >= fifo->item_sum) { 30 | fifo->ptr_write = 0; 31 | } 32 | 33 | if (fifo->ptr_write == fifo->ptr_read) { 34 | fifo->is_full = true; 35 | } 36 | 37 | return OM_OK; 38 | } 39 | 40 | inline om_status_t om_fifo_writes(om_fifo_t* fifo, const void* data, 41 | uint32_t item_num) { 42 | if (om_fifo_writeable_item_count(fifo) < item_num) { 43 | return OM_ERROR_FULL; 44 | } 45 | 46 | if (fifo->ptr_write + item_num < fifo->item_sum) { 47 | memcpy((uint8_t*)(fifo->fifo_ptr) + fifo->ptr_write * fifo->item_size, data, 48 | fifo->item_size * item_num); 49 | } else { 50 | memcpy((uint8_t*)(fifo->fifo_ptr) + fifo->ptr_write * fifo->item_size, data, 51 | fifo->item_size * (fifo->item_sum - fifo->ptr_write)); 52 | 53 | memcpy( 54 | (uint8_t*)(fifo->fifo_ptr), 55 | (uint8_t*)(data) + fifo->item_size * (fifo->item_sum - fifo->ptr_write), 56 | fifo->item_size * (item_num - fifo->item_sum + fifo->ptr_write)); 57 | } 58 | 59 | fifo->ptr_write += item_num; 60 | 61 | if (fifo->ptr_write >= fifo->item_sum) { 62 | fifo->ptr_write -= fifo->item_sum; 63 | } 64 | 65 | if (fifo->ptr_write == fifo->ptr_read) { 66 | fifo->is_full = true; 67 | } 68 | 69 | return OM_OK; 70 | } 71 | 72 | inline bool om_fifo_readable(om_fifo_t* fifo) { 73 | if (fifo->ptr_write == fifo->ptr_read && !fifo->is_full) { 74 | return false; 75 | } 76 | return true; 77 | } 78 | 79 | inline om_status_t om_fifo_read(om_fifo_t* fifo, void* data) { 80 | if (fifo->ptr_write == fifo->ptr_read && !fifo->is_full) { 81 | return OM_ERROR_EMPTY; 82 | } 83 | 84 | memcpy(data, (uint8_t*)(fifo->fifo_ptr) + fifo->ptr_read * fifo->item_size, 85 | fifo->item_size); 86 | fifo->ptr_read++; 87 | if (fifo->ptr_read >= fifo->item_sum) { 88 | fifo->ptr_read = 0; 89 | } 90 | fifo->is_full = false; 91 | return OM_OK; 92 | } 93 | 94 | om_status_t om_fifo_pop(om_fifo_t* fifo) { 95 | if (fifo->ptr_write == fifo->ptr_read && !fifo->is_full) { 96 | return OM_ERROR_EMPTY; 97 | } 98 | 99 | fifo->ptr_read++; 100 | if (fifo->ptr_read >= fifo->item_sum) { 101 | fifo->ptr_read = 0; 102 | } 103 | 104 | fifo->is_full = false; 105 | return OM_OK; 106 | } 107 | 108 | om_status_t om_fifo_pop_batch(om_fifo_t* fifo, uint32_t item_num) { 109 | if (om_fifo_readable_item_count(fifo) < item_num) { 110 | return OM_ERROR_EMPTY; 111 | } 112 | 113 | fifo->ptr_read += item_num; 114 | 115 | if (fifo->ptr_read >= fifo->item_sum) { 116 | fifo->ptr_read -= fifo->item_sum; 117 | } 118 | 119 | fifo->is_full = false; 120 | return OM_OK; 121 | } 122 | 123 | om_status_t om_fifo_push(om_fifo_t* fifo, const void* data) { 124 | return om_fifo_write(fifo, data); 125 | } 126 | 127 | inline om_status_t om_fifo_peek(om_fifo_t* fifo, void* data) { 128 | if (fifo->ptr_write == fifo->ptr_read && !fifo->is_full) { 129 | return OM_ERROR_EMPTY; 130 | } 131 | 132 | memcpy(data, (uint8_t*)(fifo->fifo_ptr) + fifo->ptr_read * fifo->item_size, 133 | fifo->item_size); 134 | return OM_OK; 135 | } 136 | 137 | inline om_status_t om_fifo_jump_peek(om_fifo_t* fifo, uint32_t num, 138 | void* data) { 139 | if (om_fifo_readable_item_count(fifo) < num) { 140 | return OM_ERROR_EMPTY; 141 | } 142 | 143 | uint32_t index = fifo->ptr_read + num; 144 | 145 | if (index >= fifo->item_sum) { 146 | index -= fifo->item_sum; 147 | } 148 | 149 | memcpy(data, (uint8_t*)(fifo->fifo_ptr) + index * fifo->item_size, 150 | fifo->item_size); 151 | return OM_OK; 152 | } 153 | 154 | inline om_status_t om_fifo_peek_batch(om_fifo_t* fifo, void* data, 155 | uint32_t item_num) { 156 | if (om_fifo_readable_item_count(fifo) < item_num) { 157 | return OM_ERROR_EMPTY; 158 | } 159 | 160 | if (fifo->ptr_read + item_num < fifo->item_sum) { 161 | memcpy(data, (uint8_t*)(fifo->fifo_ptr) + fifo->ptr_read * fifo->item_size, 162 | fifo->item_size * item_num); 163 | } else { 164 | memcpy(data, (uint8_t*)(fifo->fifo_ptr) + fifo->ptr_read * fifo->item_size, 165 | fifo->item_size * (fifo->item_sum - fifo->ptr_read)); 166 | 167 | memcpy( 168 | (uint8_t*)(data) + fifo->item_size * (fifo->item_sum - fifo->ptr_read), 169 | (uint8_t*)(fifo->fifo_ptr), 170 | fifo->item_size * (item_num - fifo->item_sum + fifo->ptr_read)); 171 | } 172 | 173 | return OM_OK; 174 | } 175 | 176 | inline om_status_t om_fifo_reads(om_fifo_t* fifo, void* data, 177 | uint32_t item_num) { 178 | if (om_fifo_readable_item_count(fifo) < item_num) { 179 | return OM_ERROR_EMPTY; 180 | } 181 | 182 | if (fifo->ptr_read + item_num < fifo->item_sum) { 183 | memcpy(data, (uint8_t*)(fifo->fifo_ptr) + fifo->ptr_read * fifo->item_size, 184 | fifo->item_size * item_num); 185 | } else { 186 | memcpy(data, (uint8_t*)(fifo->fifo_ptr) + fifo->ptr_read * fifo->item_size, 187 | fifo->item_size * (fifo->item_sum - fifo->ptr_read)); 188 | 189 | memcpy( 190 | (uint8_t*)(data) + fifo->item_size * (fifo->item_sum - fifo->ptr_read), 191 | (uint8_t*)(fifo->fifo_ptr), 192 | fifo->item_size * (item_num - fifo->item_sum + fifo->ptr_read)); 193 | } 194 | 195 | fifo->ptr_read += item_num; 196 | if (fifo->ptr_read >= fifo->item_sum) { 197 | fifo->ptr_read -= fifo->item_sum; 198 | } 199 | fifo->is_full = false; 200 | return OM_OK; 201 | } 202 | 203 | inline uint32_t om_fifo_readable_item_count(om_fifo_t* fifo) { 204 | if (fifo->is_full) { 205 | return fifo->item_sum; 206 | } else { 207 | return (fifo->item_sum + fifo->ptr_write - fifo->ptr_read) % fifo->item_sum; 208 | } 209 | } 210 | 211 | inline uint32_t om_fifo_writeable_item_count(om_fifo_t* fifo) { 212 | if (fifo->is_full) { 213 | return 0; 214 | } else { 215 | if (fifo->ptr_write == fifo->ptr_read) { 216 | return fifo->item_sum; 217 | } else { 218 | return (fifo->item_sum + fifo->ptr_read - fifo->ptr_write) % 219 | fifo->item_sum; 220 | } 221 | } 222 | } 223 | 224 | inline om_status_t om_fifo_reset(om_fifo_t* fifo) { 225 | fifo->ptr_read = fifo->ptr_write; 226 | fifo->is_full = false; 227 | 228 | return OM_OK; 229 | } 230 | 231 | inline om_status_t om_fifo_overwrite(om_fifo_t* fifo, const void* data) { 232 | om_fifo_reset(fifo); 233 | 234 | return om_fifo_write(fifo, data); 235 | } 236 | 237 | void om_fifo_foreach(om_fifo_t* fifo, bool (*fun)(void* data, void* arg), 238 | void* arg) { 239 | uint32_t index = fifo->ptr_read, num = om_fifo_readable_item_count(fifo); 240 | 241 | for (uint32_t i = 0; i < num; i++) { 242 | if (!fun((uint8_t*)(fifo->fifo_ptr) + fifo->item_size * index, arg)) { 243 | return; 244 | } 245 | index++; 246 | if (index >= fifo->item_sum) { 247 | index -= fifo->item_sum; 248 | } 249 | } 250 | } 251 | 252 | void* om_fifo_foreach_dist(om_fifo_t* fifo, void* data) { 253 | uint32_t index = fifo->ptr_read, num = om_fifo_readable_item_count(fifo); 254 | 255 | if (num == 0) { 256 | return NULL; 257 | } 258 | 259 | if (data == NULL) { 260 | return (uint8_t*)(fifo->fifo_ptr) + fifo->item_size * fifo->ptr_read; 261 | } 262 | 263 | index = ((data - fifo->fifo_ptr) / fifo->item_size + 1) % fifo->item_sum; 264 | 265 | if (index == fifo->ptr_write) { 266 | return NULL; 267 | } else { 268 | return (uint8_t*)(fifo->fifo_ptr) + fifo->item_size * index; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /om/src/comp/om_fifo.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_FIFO_H_ 2 | #define __OM_FIFO_H_ 3 | 4 | #include "om_def.h" 5 | 6 | typedef struct { 7 | uint32_t ptr_write; 8 | uint32_t ptr_read; 9 | bool is_full; 10 | 11 | uint32_t item_sum; 12 | uint32_t item_size; 13 | void* fifo_ptr; 14 | } om_fifo_t; 15 | 16 | void om_fifo_create(om_fifo_t* fifo, void* fifo_ptr, uint32_t item_sum, 17 | uint32_t item_size); 18 | 19 | bool om_fifo_writeable(om_fifo_t* fifo); 20 | 21 | om_status_t om_fifo_write(om_fifo_t* fifo, const void* data); 22 | 23 | om_status_t om_fifo_writes(om_fifo_t* fifo, const void* data, 24 | uint32_t item_num); 25 | 26 | bool om_fifo_readable(om_fifo_t* fifo); 27 | 28 | om_status_t om_fifo_read(om_fifo_t* fifo, void* data); 29 | 30 | om_status_t om_fifo_pop(om_fifo_t* fifo); 31 | 32 | om_status_t om_fifo_pop_batch(om_fifo_t* fifo, uint32_t item_num); 33 | 34 | om_status_t om_fifo_push(om_fifo_t* fifo, const void* data); 35 | 36 | om_status_t om_fifo_jump_peek(om_fifo_t* fifo, uint32_t num, void* data); 37 | 38 | om_status_t om_fifo_peek(om_fifo_t* fifo, void* data); 39 | 40 | om_status_t om_fifo_peek_batch(om_fifo_t* fifo, void* data, uint32_t item_num); 41 | 42 | om_status_t om_fifo_reads(om_fifo_t* fifo, void* data, uint32_t item_num); 43 | 44 | uint32_t om_fifo_readable_item_count(om_fifo_t* fifo); 45 | 46 | uint32_t om_fifo_writeable_item_count(om_fifo_t* fifo); 47 | 48 | om_status_t om_fifo_reset(om_fifo_t* fifo); 49 | 50 | om_status_t om_fifo_overwrite(om_fifo_t* fifo, const void* data); 51 | 52 | void om_fifo_foreach(om_fifo_t* fifo, bool (*fun)(void* data, void* arg), 53 | void* arg); 54 | 55 | void* om_fifo_foreach_dist(om_fifo_t* fifo, void* data); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /om/src/comp/om_list.c: -------------------------------------------------------------------------------- 1 | #include "om_list.h" 2 | 3 | void _OM_INIT_LIST_HEAD(om_list_head_t* list) { list->next = list; } 4 | 5 | static void __list_add(om_list_head_t* new_data, om_list_head_t* prev, 6 | om_list_head_t* next) { 7 | new_data->next = next; 8 | prev->next = new_data; 9 | } 10 | 11 | void om_list_add(om_list_head_t* new_data, om_list_head_t* head) { 12 | __list_add(new_data, head, head->next); 13 | } 14 | 15 | static void __list_del(om_list_head_t* prev, om_list_head_t* next) { 16 | prev->next = next; 17 | } 18 | 19 | static om_list_head_t* __list_get_prev(om_list_head_t* entry) { 20 | om_list_head_t* prev = entry; 21 | while (prev->next != entry) { 22 | prev = prev->next; 23 | } 24 | return prev; 25 | } 26 | 27 | void om_list_del(om_list_head_t* entry) { 28 | __list_del(__list_get_prev(entry), entry->next); 29 | } 30 | 31 | void om_list_replace(om_list_head_t* old, om_list_head_t* new_data) { 32 | new_data->next = old->next; 33 | __list_get_prev(old)->next = new_data; 34 | } 35 | 36 | int om_list_empty(const om_list_head_t* head) { return head->next == head; } 37 | 38 | size_t om_list_get_num(const om_list_head_t* head) { 39 | uint32_t num = 0; 40 | 41 | om_list_head_t* pos; 42 | om_list_for_each(pos, head) { num++; } 43 | 44 | return num; 45 | } 46 | -------------------------------------------------------------------------------- /om/src/comp/om_list.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_LIST_H__ 2 | #define __OM_LIST_H__ 3 | 4 | #include "om_def.h" 5 | 6 | typedef struct _om_list_head { 7 | struct _om_list_head* next; 8 | } om_list_head_t; 9 | 10 | #define OM_LIST_HEAD_INIT(name) \ 11 | { &(name), &(name) } 12 | 13 | #define OM_LIST_HEAD(name) om_list_head_t name = OM_LIST_HEAD_INIT(name) 14 | 15 | #define om_list_for_each(pos, head) \ 16 | for (pos = (head)->next; pos != (head); pos = pos->next) 17 | 18 | #define om_list_for_each_safe(pos, n, head) \ 19 | for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next) 20 | 21 | #define om_list_entry(ptr, type, member) om_container_of(ptr, type, member) 22 | 23 | void _OM_INIT_LIST_HEAD(om_list_head_t* list); 24 | 25 | #define OM_INIT_LIST_HEAD(arg) _OM_INIT_LIST_HEAD(arg) 26 | 27 | #define om_del_all(source, del_fun) \ 28 | do { \ 29 | om_list_head_t *pos, *tmp; \ 30 | for (pos = (source)->next; pos != (source);) { \ 31 | tmp = pos; \ 32 | pos = pos->next; \ 33 | del_fun(tmp); \ 34 | } \ 35 | } while (0) 36 | 37 | #define OM_PRASE_STRUCT(container, member) \ 38 | sizeof(container), om_offset_of(container, member), \ 39 | om_member_size_of(container, member) 40 | 41 | #define OM_PRASE_VAR(_arg) (&_arg), (sizeof(_arg)) 42 | 43 | void om_list_add(om_list_head_t* new_data, om_list_head_t* head); 44 | 45 | void om_list_del(om_list_head_t* entry); 46 | 47 | void om_list_replace(om_list_head_t* old, om_list_head_t* new_data); 48 | 49 | int om_list_empty(const om_list_head_t* head); 50 | 51 | size_t om_list_get_num(const om_list_head_t* head); 52 | #endif 53 | -------------------------------------------------------------------------------- /om/src/comp/om_rbt.c: -------------------------------------------------------------------------------- 1 | #include "om_rbt.h" 2 | 3 | #define GET_PARENT(r) ((r)->parent) 4 | #define GET_COLOR(r) ((r)->color) 5 | #define IS_RED(r) ((r)->color == RBT_COLOR_RED) 6 | #define IS_BLACK(r) ((r)->color == RBT_COLOR_BLACK) 7 | 8 | #define SET_BLACK(r) \ 9 | do { \ 10 | (r)->color = RBT_COLOR_BLACK; \ 11 | } while (0) 12 | 13 | #define SET_RED(r) \ 14 | do { \ 15 | (r)->color = RBT_COLOR_RED; \ 16 | } while (0) 17 | 18 | #define SET_PARENT(r, p) \ 19 | do { \ 20 | (r)->parent = (p); \ 21 | } while (0) 22 | 23 | #define SET_COLOR(r, c) \ 24 | do { \ 25 | (r)->color = (c); \ 26 | } while (0) 27 | 28 | static om_rbt_node_t *_search(om_rbt_t x, const char *key) { 29 | if (x == NULL) return NULL; 30 | 31 | int ans = strcmp(key, x->key); 32 | 33 | if (ans == 0) 34 | return x; 35 | else if (ans < 0) 36 | return _search(x->left, key); 37 | else 38 | return _search(x->right, key); 39 | } 40 | 41 | om_rbt_node_t *om_rbtree_search(om_rbt_root_t *root, const char *key) { 42 | return _search(root->node, key); 43 | } 44 | 45 | static void rbtree_left_rotate(om_rbt_root_t *root, om_rbt_node_t *x) { 46 | om_rbt_node_t *y = x->right; 47 | 48 | x->right = y->left; 49 | if (y->left != NULL) y->left->parent = x; 50 | 51 | y->parent = x->parent; 52 | 53 | if (x->parent == NULL) { 54 | root->node = y; 55 | } else { 56 | if (x->parent->left == x) 57 | x->parent->left = y; 58 | else 59 | x->parent->right = y; 60 | } 61 | 62 | y->left = x; 63 | x->parent = y; 64 | } 65 | 66 | static void rbtree_right_rotate(om_rbt_root_t *root, om_rbt_node_t *y) { 67 | om_rbt_node_t *x = y->left; 68 | 69 | y->left = x->right; 70 | if (x->right != NULL) x->right->parent = y; 71 | 72 | x->parent = y->parent; 73 | 74 | if (y->parent == NULL) { 75 | root->node = x; 76 | } else { 77 | if (y == y->parent->right) 78 | y->parent->right = x; 79 | else 80 | y->parent->left = x; 81 | } 82 | 83 | x->right = y; 84 | 85 | y->parent = x; 86 | } 87 | 88 | static void rbtree_insert_fixup(om_rbt_root_t *root, om_rbt_node_t *node) { 89 | om_rbt_node_t *parent, *gparent; 90 | 91 | while ((parent = GET_PARENT(node)) && IS_RED(parent)) { 92 | gparent = GET_PARENT(parent); 93 | 94 | if (parent == gparent->left) { 95 | { 96 | om_rbt_node_t *uncle = gparent->right; 97 | if (uncle && IS_RED(uncle)) { 98 | SET_BLACK(uncle); 99 | SET_BLACK(parent); 100 | SET_RED(gparent); 101 | node = gparent; 102 | continue; 103 | } 104 | } 105 | 106 | if (parent->right == node) { 107 | om_rbt_node_t *tmp; 108 | rbtree_left_rotate(root, parent); 109 | tmp = parent; 110 | parent = node; 111 | node = tmp; 112 | } 113 | 114 | SET_BLACK(parent); 115 | SET_RED(gparent); 116 | rbtree_right_rotate(root, gparent); 117 | } else { 118 | { 119 | om_rbt_node_t *uncle = gparent->left; 120 | if (uncle && IS_RED(uncle)) { 121 | SET_BLACK(uncle); 122 | SET_BLACK(parent); 123 | SET_RED(gparent); 124 | node = gparent; 125 | continue; 126 | } 127 | } 128 | 129 | if (parent->left == node) { 130 | om_rbt_node_t *tmp; 131 | rbtree_right_rotate(root, parent); 132 | tmp = parent; 133 | parent = node; 134 | node = tmp; 135 | } 136 | 137 | SET_BLACK(parent); 138 | SET_RED(gparent); 139 | rbtree_left_rotate(root, gparent); 140 | } 141 | } 142 | 143 | SET_BLACK(root->node); 144 | } 145 | 146 | static void rbtree_insert(om_rbt_root_t *root, om_rbt_node_t *node) { 147 | om_rbt_node_t *y = NULL; 148 | om_rbt_node_t *x = root->node; 149 | 150 | while (x != NULL) { 151 | y = x; 152 | if (strcmp(node->key, x->key) < 0) 153 | x = x->left; 154 | else 155 | x = x->right; 156 | } 157 | GET_PARENT(node) = y; 158 | 159 | if (y != NULL) { 160 | if (strcmp(node->key, y->key) < 0) 161 | y->left = node; 162 | else 163 | y->right = node; 164 | } else { 165 | root->node = node; 166 | } 167 | 168 | node->color = RBT_COLOR_RED; 169 | 170 | rbtree_insert_fixup(root, node); 171 | } 172 | 173 | bool om_rbtree_insert(om_rbt_root_t *root, om_rbt_node_t *node) { 174 | node->left = NULL; 175 | node->right = NULL; 176 | node->parent = NULL; 177 | node->color = RBT_COLOR_BLACK; 178 | 179 | rbtree_insert(root, node); 180 | 181 | return true; 182 | } 183 | 184 | static void rbtree_delete_fixup(om_rbt_root_t *root, om_rbt_node_t *node, 185 | om_rbt_node_t *parent) { 186 | om_rbt_node_t *other; 187 | 188 | while ((!node || IS_BLACK(node)) && node != root->node) { 189 | if (parent->left == node) { 190 | other = parent->right; 191 | if (IS_RED(other)) { 192 | SET_BLACK(other); 193 | SET_RED(parent); 194 | rbtree_left_rotate(root, parent); 195 | other = parent->right; 196 | } 197 | if ((!other->left || IS_BLACK(other->left)) && 198 | (!other->right || IS_BLACK(other->right))) { 199 | SET_RED(other); 200 | node = parent; 201 | parent = GET_PARENT(node); 202 | } else { 203 | if (!other->right || IS_BLACK(other->right)) { 204 | SET_BLACK(other->left); 205 | SET_RED(other); 206 | rbtree_right_rotate(root, other); 207 | other = parent->right; 208 | } 209 | SET_COLOR(other, GET_COLOR(parent)); 210 | SET_BLACK(parent); 211 | SET_BLACK(other->right); 212 | rbtree_left_rotate(root, parent); 213 | node = root->node; 214 | break; 215 | } 216 | } else { 217 | other = parent->left; 218 | if (IS_RED(other)) { 219 | SET_BLACK(other); 220 | SET_RED(parent); 221 | rbtree_right_rotate(root, parent); 222 | other = parent->left; 223 | } 224 | if ((!other->left || IS_BLACK(other->left)) && 225 | (!other->right || IS_BLACK(other->right))) { 226 | SET_RED(other); 227 | node = parent; 228 | parent = GET_PARENT(node); 229 | } else { 230 | if (!other->left || IS_BLACK(other->left)) { 231 | SET_BLACK(other->right); 232 | SET_RED(other); 233 | rbtree_left_rotate(root, other); 234 | other = parent->left; 235 | } 236 | SET_COLOR(other, GET_COLOR(parent)); 237 | SET_BLACK(parent); 238 | SET_BLACK(other->left); 239 | rbtree_right_rotate(root, parent); 240 | node = root->node; 241 | break; 242 | } 243 | } 244 | } 245 | if (node) SET_BLACK(node); 246 | } 247 | 248 | void om_rbtree_delete(om_rbt_root_t *root, om_rbt_node_t *node) { 249 | om_rbt_node_t *child, *parent; 250 | int color; 251 | 252 | if ((node->left != NULL) && (node->right != NULL)) { 253 | om_rbt_node_t *replace = node; 254 | 255 | replace = replace->right; 256 | while (replace->left != NULL) replace = replace->left; 257 | 258 | if (GET_PARENT(node)) { 259 | if (GET_PARENT(node)->left == node) 260 | GET_PARENT(node)->left = replace; 261 | else 262 | GET_PARENT(node)->right = replace; 263 | } else 264 | root->node = replace; 265 | 266 | child = replace->right; 267 | parent = GET_PARENT(replace); 268 | color = GET_COLOR(replace); 269 | 270 | if (parent == node) { 271 | parent = replace; 272 | } else { 273 | if (child) SET_PARENT(child, parent); 274 | parent->left = child; 275 | 276 | replace->right = node->right; 277 | SET_PARENT(node->right, replace); 278 | } 279 | 280 | replace->parent = node->parent; 281 | replace->color = node->color; 282 | replace->left = node->left; 283 | node->left->parent = replace; 284 | 285 | if (color == RBT_COLOR_BLACK) rbtree_delete_fixup(root, child, parent); 286 | 287 | return; 288 | } 289 | 290 | if (node->left != NULL) 291 | child = node->left; 292 | else 293 | child = node->right; 294 | 295 | parent = node->parent; 296 | color = node->color; 297 | 298 | if (child) child->parent = parent; 299 | 300 | if (parent) { 301 | if (parent->left == node) 302 | parent->left = child; 303 | else 304 | parent->right = child; 305 | } else 306 | root->node = child; 307 | 308 | if (color == RBT_COLOR_BLACK) rbtree_delete_fixup(root, child, parent); 309 | } 310 | 311 | void _rbtree_get_num(om_rbt_node_t *node, uint32_t *num) { 312 | if (node == NULL) return; 313 | 314 | (*num)++; 315 | 316 | _rbtree_get_num(node->left, num); 317 | _rbtree_get_num(node->right, num); 318 | } 319 | 320 | uint32_t om_rbtree_get_num(om_rbt_root_t *root) { 321 | uint32_t num; 322 | num = 0; 323 | _rbtree_get_num(root->node, &num); 324 | return num; 325 | } 326 | 327 | static bool _om_rbtree_foreach(om_rbt_node_t *node, 328 | bool (*fun)(om_rbt_node_t *node, void *arg), 329 | void *arg) { 330 | if (node == NULL) { 331 | return false; 332 | } 333 | 334 | if (_om_rbtree_foreach(node->left, fun, arg) && fun(node, arg)) { 335 | return _om_rbtree_foreach(node->right, fun, arg); 336 | } 337 | 338 | return false; 339 | } 340 | 341 | void om_rbtree_foreach(om_rbt_root_t *root, 342 | bool (*fun)(om_rbt_node_t *node, void *arg), void *arg) { 343 | _om_rbtree_foreach(root->node, fun, arg); 344 | } 345 | 346 | om_rbt_node_t *om_rbtree_foreach_disc(om_rbt_root_t *rbt, om_rbt_node_t *node) { 347 | if (node == NULL) { 348 | node = rbt->node; 349 | while (node->left != NULL) { 350 | node = node->left; 351 | } 352 | return node; 353 | } 354 | 355 | if (node->right != NULL) { 356 | node = node->right; 357 | while (node->left != NULL) { 358 | node = node->left; 359 | } 360 | return node; 361 | } 362 | 363 | if (node->parent != NULL) { 364 | if (node == node->parent->left) { 365 | return node->parent; 366 | } else { 367 | while (node->parent != NULL && node == node->parent->right) { 368 | node = node->parent; 369 | } 370 | return node->parent; 371 | } 372 | } 373 | 374 | return NULL; 375 | } 376 | -------------------------------------------------------------------------------- /om/src/comp/om_rbt.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_RBT_H__ 2 | #define __OM_RBT_H__ 3 | 4 | #include "om_def.h" 5 | 6 | #define RBT_ROOT(name) om_rbt_root_t name = {NULL} 7 | 8 | typedef enum { 9 | RBT_COLOR_RED, 10 | RBT_COLOR_BLACK, 11 | } om_rbt_color_t; 12 | 13 | typedef struct rbt_node { 14 | om_rbt_color_t color; 15 | const char *key; 16 | struct rbt_node *left; 17 | struct rbt_node *right; 18 | struct rbt_node *parent; 19 | } om_rbt_node_t, *om_rbt_t; 20 | 21 | typedef struct rb_root { 22 | om_rbt_node_t *node; 23 | } om_rbt_root_t; 24 | 25 | bool om_rbtree_insert(om_rbt_root_t *root, om_rbt_node_t *node); 26 | 27 | void om_rbtree_delete(om_rbt_root_t *root, om_rbt_node_t *node); 28 | 29 | om_rbt_node_t *om_rbtree_search(om_rbt_root_t *root, const char *key); 30 | 31 | uint32_t om_rbtree_get_num(om_rbt_root_t *root); 32 | 33 | void om_rbtree_foreach(om_rbt_root_t *root, 34 | bool (*fun)(om_rbt_node_t *node, void *arg), void *arg); 35 | 36 | om_rbt_node_t *om_rbtree_foreach_disc(om_rbt_root_t *rbt, om_rbt_node_t *node); 37 | #endif -------------------------------------------------------------------------------- /om/src/core/om_core.c: -------------------------------------------------------------------------------- 1 | #include "om_core.h" 2 | #include "om_crc.h" 3 | 4 | RBT_ROOT(_topic_list); 5 | 6 | static om_mutex_t core_lock; 7 | 8 | om_status_t om_core_init() { 9 | om_mutex_init(&core_lock); 10 | om_mutex_unlock(&core_lock); 11 | om_generate_crc32_table(); 12 | om_generate_crc8_table(); 13 | return OM_OK; 14 | } 15 | 16 | om_topic_t* om_core_topic_create(const char* name, uint32_t buff_len) { 17 | om_topic_t* topic = om_malloc(sizeof(om_topic_t)); 18 | 19 | return om_core_topic_create_static(topic, name, buff_len); 20 | } 21 | 22 | om_topic_t* om_core_topic_create_static(om_topic_t* topic, const char* name, 23 | uint32_t buff_len) { 24 | OM_ASSERT(topic); 25 | 26 | memset(topic, 0, sizeof(*topic)); 27 | strncpy(topic->name, name, OM_TOPIC_MAX_NAME_LEN); 28 | 29 | topic->self.key = topic->name; 30 | topic->virtual_mode = true; 31 | topic->buff_len = buff_len; 32 | 33 | OM_INIT_LIST_HEAD(&topic->suber); 34 | OM_INIT_LIST_HEAD(&topic->link); 35 | 36 | om_mutex_init(&topic->mutex); 37 | om_mutex_unlock(&topic->mutex); 38 | 39 | return topic; 40 | } 41 | 42 | om_status_t om_core_add_topic(om_topic_t* topic) { 43 | OM_ASSERT(topic); 44 | 45 | if (om_core_find_topic(topic->name, 0) != NULL) { 46 | OM_ASSERT(false); 47 | return OM_ERROR; 48 | } 49 | 50 | om_mutex_lock(&core_lock); 51 | 52 | om_rbtree_insert(&_topic_list, &topic->self); 53 | 54 | om_mutex_unlock(&core_lock); 55 | 56 | return OM_OK; 57 | } 58 | 59 | om_suber_t* om_core_suber_create(om_topic_t* link) { 60 | om_suber_t* suber = om_malloc(sizeof(*suber)); 61 | 62 | return om_core_suber_create_static(suber, link); 63 | } 64 | 65 | om_suber_t* om_core_suber_create_static(om_suber_t* suber, om_topic_t* link) { 66 | OM_ASSERT(suber); 67 | memset(suber, 0, sizeof(*suber)); 68 | if (link) { 69 | suber->mode = OM_SUBER_MODE_LINK; 70 | suber->data.as_link.target = link; 71 | } 72 | return suber; 73 | } 74 | 75 | om_status_t om_core_add_suber(om_topic_t* topic, om_suber_t* sub) { 76 | OM_ASSERT(topic); 77 | OM_ASSERT(sub); 78 | 79 | sub->master = topic; 80 | 81 | om_mutex_lock(&core_lock); 82 | 83 | om_list_add(&sub->self, &(topic->suber)); 84 | 85 | om_mutex_unlock(&core_lock); 86 | 87 | return OM_OK; 88 | } 89 | 90 | om_link_t* om_core_link_create(om_suber_t* sub, om_topic_t* topic) { 91 | om_link_t* link = om_malloc(sizeof(*link)); 92 | 93 | return om_core_link_create_static(link, sub, topic); 94 | } 95 | 96 | om_link_t* om_core_link_create_static(om_link_t* link, om_suber_t* sub, 97 | om_topic_t* topic) { 98 | OM_ASSERT(link); 99 | link->source.suber = sub; 100 | link->source.topic = topic; 101 | 102 | return link; 103 | } 104 | 105 | om_status_t om_core_add_link(om_topic_t* topic, om_link_t* link) { 106 | OM_ASSERT(topic); 107 | OM_ASSERT(link); 108 | 109 | om_mutex_lock(&core_lock); 110 | 111 | om_list_add(&link->self, &(topic->link)); 112 | 113 | om_mutex_unlock(&core_lock); 114 | 115 | return OM_OK; 116 | } 117 | 118 | om_status_t om_core_queue_init_fifo_static(om_topic_t* topic, om_fifo_t* fifo, 119 | void* buff, uint32_t len) { 120 | OM_ASSERT(topic); 121 | OM_ASSERT(fifo); 122 | OM_ASSERT(buff); 123 | OM_ASSERT(len); 124 | 125 | om_fifo_create(fifo, buff, len, topic->buff_len); 126 | 127 | return OM_OK; 128 | } 129 | 130 | om_fifo_t* om_core_queue_add(om_topic_t* topic, uint32_t len) { 131 | om_fifo_t* fifo = om_malloc(sizeof(om_fifo_t)); 132 | om_suber_t* suber = om_malloc(sizeof(om_suber_t)); 133 | om_core_queue_init_fifo_static(topic, fifo, om_malloc(topic->buff_len * len), 134 | len); 135 | om_core_queue_add_static(topic, suber, fifo); 136 | 137 | return fifo; 138 | } 139 | 140 | om_fifo_t* om_core_queue_add_static(om_topic_t* topic, om_suber_t* sub, 141 | om_fifo_t* fifo) { 142 | om_core_suber_create_static(sub, NULL); 143 | sub->mode = OM_SUBER_MODE_FIFO; 144 | sub->data.as_queue.fifo = fifo; 145 | 146 | om_core_add_suber(topic, sub); 147 | 148 | return fifo; 149 | } 150 | 151 | om_status_t om_core_link(om_topic_t* source, om_topic_t* target) { 152 | OM_ASSERT(source); 153 | OM_ASSERT(target); 154 | 155 | om_suber_t* sub = om_core_suber_create(target); 156 | om_core_add_suber(source, sub); 157 | om_link_t* link = om_core_link_create(sub, source); 158 | om_core_add_link(target, link); 159 | 160 | return OM_OK; 161 | } 162 | 163 | om_status_t om_core_link_static(om_suber_t* suber, om_link_t* link, 164 | om_topic_t* source, om_topic_t* target) { 165 | OM_ASSERT(source); 166 | OM_ASSERT(target); 167 | 168 | om_core_suber_create_static(suber, target); 169 | om_core_add_suber(source, suber); 170 | om_core_link_create_static(link, suber, source); 171 | om_core_add_link(target, link); 172 | 173 | return OM_OK; 174 | } 175 | 176 | om_status_t om_core_delink(om_list_head_t* head) { 177 | OM_ASSERT(head); 178 | om_link_t* link = om_list_entry(head, om_link_t, self); 179 | 180 | om_list_del(&link->self); 181 | om_list_del(&link->source.suber->self); 182 | 183 | om_free(link->source.suber); 184 | om_free(link); 185 | 186 | return OM_OK; 187 | } 188 | 189 | om_status_t om_core_del_suber(om_list_head_t* head) { 190 | OM_ASSERT(head); 191 | om_suber_t* sub = om_list_entry(head, om_suber_t, self); 192 | 193 | om_mutex_lock(&core_lock); 194 | om_list_del(&sub->self); 195 | om_mutex_unlock(&core_lock); 196 | 197 | if (sub->mode == OM_SUBER_MODE_LINK) { 198 | OM_ASSERT(sub->master); 199 | om_list_head_t* pos; 200 | om_list_for_each(pos, &sub->data.as_link.target->link) { 201 | om_link_t* link = om_list_entry(pos, om_link_t, self); 202 | if (link->source.suber == sub) { 203 | om_mutex_lock(&core_lock); 204 | om_list_del(&link->self); 205 | om_mutex_unlock(&core_lock); 206 | om_free(link); 207 | break; 208 | } 209 | } 210 | } else if (sub->mode == OM_SUBER_MODE_FIFO) { 211 | om_free(sub->data.as_queue.fifo); 212 | } 213 | 214 | om_free(sub); 215 | 216 | return OM_OK; 217 | } 218 | 219 | om_status_t om_core_del_topic(om_rbt_node_t* node) { 220 | OM_ASSERT(node); 221 | om_topic_t* topic = om_container_of(node, om_topic_t, self); 222 | 223 | om_mutex_lock(&core_lock); 224 | om_rbtree_delete(&_topic_list, &topic->self); 225 | om_mutex_unlock(&core_lock); 226 | 227 | om_del_all(&topic->link, om_core_delink); 228 | om_del_all(&topic->suber, om_core_del_suber); 229 | if (!topic->virtual_mode && topic->msg.buff) om_free(topic->msg.buff); 230 | om_mutex_delete(&topic->mutex); 231 | om_free(topic); 232 | 233 | return OM_OK; 234 | } 235 | 236 | om_topic_t* om_core_find_topic(const char* name, uint32_t timeout) { 237 | om_rbt_node_t* node; 238 | do { 239 | om_mutex_lock(&core_lock); 240 | node = om_rbtree_search(&_topic_list, name); 241 | if (node != NULL) { 242 | om_mutex_unlock(&core_lock); 243 | return om_container_of(node, om_topic_t, self); 244 | } 245 | om_mutex_unlock(&core_lock); 246 | if (timeout) { 247 | om_delay_ms(1); 248 | timeout--; 249 | } 250 | } while (timeout); 251 | return NULL; 252 | } 253 | 254 | om_status_t om_core_set_export_target(om_suber_t* suber) { 255 | OM_ASSERT(suber); 256 | 257 | suber->mode = OM_SUBER_MODE_EXPORT; 258 | suber->data.as_export.new_data = false; 259 | return OM_OK; 260 | } 261 | 262 | void om_error(const char* file, uint32_t line) { 263 | (void)(file); 264 | (void)(line); 265 | while (1) { 266 | }; 267 | } 268 | -------------------------------------------------------------------------------- /om/src/core/om_core.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_CORE_H__ 2 | #define __OM_CORE_H__ 3 | 4 | #include "om_color.h" 5 | #include "om_crc.h" 6 | #include "om_def.h" 7 | #include "om_fifo.h" 8 | #include "om_lib.h" 9 | #include "om_list.h" 10 | #include "om_rbt.h" 11 | 12 | #define OM_TOPIC_LOCK(_topic) om_mutex_lock(&((_topic)->mutex)) 13 | #define OM_TOPIC_UNLOCK(_topic) om_mutex_unlock(&((_topic)->mutex)) 14 | 15 | typedef struct { 16 | bool virtual_mode; 17 | uint32_t buff_len; 18 | om_mutex_t mutex; 19 | om_msg_t msg; 20 | char name[OM_TOPIC_MAX_NAME_LEN]; 21 | uint32_t crc32; 22 | om_rbt_node_t self; 23 | om_list_head_t suber; 24 | om_list_head_t link; /* 指向本话题的订阅者 */ 25 | struct { 26 | om_user_fun_t filter; 27 | void* filter_arg; 28 | } user_fun; 29 | void* afl; 30 | } om_topic_t; 31 | 32 | typedef enum { 33 | OM_SUBER_MODE_UNKNOW, 34 | OM_SUBER_MODE_LINK, 35 | OM_SUBER_MODE_EXPORT, 36 | OM_SUBER_MODE_FIFO, 37 | OM_SUBER_MODE_DEFAULT, 38 | } om_suber_mode_t; 39 | 40 | typedef struct { 41 | om_suber_mode_t mode; 42 | 43 | om_list_head_t self; 44 | om_topic_t* master; 45 | 46 | union { 47 | struct { 48 | om_user_fun_t sub_callback; 49 | void* sub_cb_arg; 50 | } as_suber; 51 | 52 | struct { 53 | om_topic_t* target; 54 | } as_link; 55 | 56 | struct { 57 | bool new_data; 58 | } as_export; 59 | 60 | struct { 61 | om_fifo_t* fifo; 62 | } as_queue; 63 | } data; 64 | } om_suber_t; 65 | 66 | typedef struct { 67 | om_list_head_t self; 68 | struct { 69 | om_suber_t* suber; 70 | om_topic_t* topic; 71 | } source; 72 | } om_link_t; 73 | 74 | om_status_t om_core_init(); 75 | 76 | om_topic_t* om_core_topic_create(const char* name, uint32_t buff_len); 77 | 78 | om_topic_t* om_core_topic_create_static(om_topic_t* topic, const char* name, 79 | uint32_t buff_len); 80 | 81 | om_status_t om_core_add_topic(om_topic_t* topic); 82 | 83 | om_suber_t* om_core_suber_create(om_topic_t* link); 84 | 85 | om_suber_t* om_core_suber_create_static(om_suber_t* suber, om_topic_t* link); 86 | 87 | om_status_t om_core_add_suber(om_topic_t* topic, om_suber_t* sub); 88 | 89 | om_link_t* om_core_link_create(om_suber_t* sub, om_topic_t* topic); 90 | 91 | om_link_t* om_core_link_create_static(om_link_t* link, om_suber_t* sub, 92 | om_topic_t* topic); 93 | 94 | om_status_t om_core_add_link(om_topic_t* topic, om_link_t* link); 95 | 96 | om_status_t om_core_queue_init_fifo_static(om_topic_t* topic, om_fifo_t* fifo, 97 | void* buff, uint32_t len); 98 | 99 | om_fifo_t* om_core_queue_add(om_topic_t* topic, uint32_t len); 100 | 101 | om_fifo_t* om_core_queue_add_static(om_topic_t* topic, om_suber_t* sub, 102 | om_fifo_t* fifo); 103 | 104 | om_status_t om_core_link(om_topic_t* source, om_topic_t* target); 105 | 106 | om_status_t om_core_link_static(om_suber_t* suber, om_link_t* link, 107 | om_topic_t* source, om_topic_t* target); 108 | 109 | om_status_t om_core_delink(om_list_head_t* head); 110 | 111 | om_status_t om_core_del_suber(om_list_head_t* head); 112 | 113 | om_status_t om_core_del_topic(om_rbt_node_t* node); 114 | 115 | om_status_t om_core_set_export_target(om_suber_t* suber); 116 | 117 | om_topic_t* om_core_find_topic(const char* name, uint32_t timeout); 118 | 119 | void om_error(const char* file, uint32_t line); 120 | #endif 121 | -------------------------------------------------------------------------------- /om/src/core/om_def.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_DEF_H_ 2 | #define __OM_DEF_H_ 3 | 4 | #include "om_lib.h" 5 | 6 | #ifdef OM_TEST 7 | #include "om_config_template.h" 8 | #else 9 | #include "om_config.h" 10 | #endif 11 | 12 | #if !OM_USE_USER_MALLOC 13 | #define om_malloc malloc 14 | #define om_free free 15 | #endif 16 | 17 | #if OM_LOG_OUTPUT 18 | #if (OM_LOG_LEVEL < 1 || OM_LOG_LEVEL > 6) 19 | #error "OM_LOG_LEVEL must be between 1 and 6." 20 | #endif 21 | #endif 22 | 23 | typedef enum { 24 | OM_OK = 0, 25 | OM_ERROR = 1, 26 | OM_ERROR_NULL, 27 | OM_ERROR_BUSY, 28 | OM_ERROR_TIMEOUT, 29 | OM_ERROR_FULL, 30 | OM_ERROR_EMPTY, 31 | OM_ERROR_NOT_INIT 32 | } om_status_t; 33 | 34 | typedef struct { 35 | uint32_t size; 36 | void* buff; 37 | #if OM_TIME 38 | om_time_t time; 39 | #endif 40 | } om_msg_t; 41 | 42 | typedef om_status_t (*om_user_fun_t)(om_msg_t* msg, void* arg); 43 | 44 | #if OM_DEBUG 45 | #define OM_ASSERT(arg) \ 46 | if (!(arg)) om_error(__FILE__, __LINE__); 47 | #define OM_CHECK(arg) \ 48 | if (!(arg)) om_error(__FILE__, __LINE__); 49 | 50 | #else 51 | #define OM_ASSERT(arg) (void)0; 52 | #define OM_CHECK(arg) (void)0; 53 | #endif 54 | 55 | #define OM_UNUSED(X) ((void)X) 56 | 57 | #define om_offset_of(type, member) ((size_t) & ((type*)0)->member) 58 | 59 | #define om_member_size_of(type, member) (sizeof(typeof(((type*)0)->member))) 60 | 61 | #define om_container_of(ptr, type, member) \ 62 | ({ \ 63 | const typeof(((type*)0)->member)* __mptr = (ptr); \ 64 | (type*)((char*)__mptr - om_offset_of(type, member)); \ 65 | }) 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /om/src/core/om_lib.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include -------------------------------------------------------------------------------- /om/src/om.c: -------------------------------------------------------------------------------- 1 | #include "om.h" 2 | 3 | om_status_t om_init() { 4 | om_status_t res = OM_OK; 5 | 6 | res += om_core_init(); 7 | 8 | #if OM_LOG_OUTPUT 9 | res += om_log_init(); 10 | #endif 11 | return res; 12 | } 13 | -------------------------------------------------------------------------------- /om/src/om.h: -------------------------------------------------------------------------------- 1 | #ifndef __OM_H__ 2 | #define __OM_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "om_afl.h" 9 | #include "om_com.h" 10 | #include "om_evt.h" 11 | #include "om_fmt.h" 12 | #include "om_log.h" 13 | #include "om_msg.h" 14 | 15 | om_status_t om_init(); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif -------------------------------------------------------------------------------- /om/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | project(Test) 3 | 4 | find_package(Check REQUIRED) 5 | include_directories(${CHECK_INCLUDE_DIRS}) 6 | link_directories(${CHECK_LIBRARY_DIRS}) 7 | 8 | file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.c") 9 | add_library(${PROJECT_NAME} STATIC) 10 | target_sources(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_SOURCES}) 11 | 12 | target_include_directories( 13 | ${PROJECT_NAME} 14 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} 15 | PUBLIC $) 16 | 17 | set(TEST_SOURCES om_test_main.c) 18 | 19 | add_executable(om_test ${TEST_SOURCES}) 20 | 21 | target_link_libraries( 22 | om_test 23 | PRIVATE ${PROJECT_NAME} 24 | PRIVATE OneMessage 25 | PRIVATE ${CHECK_LIBRARIES} 26 | PRIVATE subunit 27 | PRIVATE pthread 28 | PRIVATE rt 29 | PRIVATE m) 30 | -------------------------------------------------------------------------------- /om/test/om_test.h: -------------------------------------------------------------------------------- 1 | #include "check.h" 2 | #include "om.h" 3 | 4 | Suite *make_om_base_suite(void); 5 | Suite *make_om_module_suite(void); -------------------------------------------------------------------------------- /om/test/om_test_base.c: -------------------------------------------------------------------------------- 1 | #include "om.h" 2 | #include "om_test.h" 3 | 4 | START_TEST(_MALLOC) { 5 | void* ptr = NULL; 6 | 7 | ptr = om_malloc(sizeof(int)); 8 | ck_assert_msg(ptr, "内存分配失败"); 9 | om_free(ptr); 10 | } 11 | END_TEST 12 | 13 | START_TEST(_MUTEX) { 14 | om_mutex_t ptr; 15 | 16 | om_mutex_init(&ptr); 17 | 18 | om_mutex_lock(&ptr); 19 | om_mutex_unlock(&ptr); 20 | 21 | if ((om_mutex_trylock(&ptr)) == OM_OK) { 22 | om_mutex_unlock(&ptr); 23 | } else { 24 | ck_assert_msg(false, "解锁失败"); 25 | } 26 | 27 | om_mutex_lock(&ptr); 28 | 29 | if (om_mutex_trylock(&ptr) != OM_OK) { 30 | om_mutex_unlock(&ptr); 31 | } else { 32 | ck_assert_msg(false, "加锁失败"); 33 | } 34 | 35 | om_mutex_delete(&ptr); 36 | } 37 | END_TEST 38 | 39 | START_TEST(_FIFO) { 40 | om_fifo_t fifo; 41 | char data[10], buff[10]; 42 | 43 | om_fifo_create(&fifo, data, 10, sizeof(char)); 44 | 45 | for (int i = 0; i < 8; i++) { 46 | om_fifo_write(&fifo, &i); 47 | om_fifo_pop(&fifo); 48 | } 49 | 50 | for (int i = 0; i < 4; i++) { 51 | om_fifo_write(&fifo, &i); 52 | } 53 | 54 | for (int i = 0; i < 4; i++) { 55 | char tmp = 0; 56 | om_fifo_jump_peek(&fifo, i, &tmp); 57 | ck_assert_msg(tmp == i, "数据损坏,应为%d,实际为%d", i, tmp); 58 | } 59 | 60 | void* tmp = NULL; 61 | for (int i = 0; i < 100; i++) { 62 | tmp = om_fifo_foreach_dist(&fifo, tmp); 63 | if (tmp == NULL) { 64 | break; 65 | } 66 | ck_assert_msg(*((char*)tmp) == i, "数据损坏,应为%d,实际为%d", i, 67 | *((char*)tmp)); 68 | } 69 | 70 | for (int i = 0; i < 4; i++) { 71 | om_fifo_read(&fifo, buff); 72 | } 73 | 74 | for (int i = 0; i < 10; i++) { 75 | char data = '0' + i; 76 | om_fifo_write(&fifo, &data); 77 | } 78 | 79 | for (int i = 0; i < 10; i++) { 80 | char data = '0' + i, tmp = 0; 81 | om_fifo_read(&fifo, &tmp); 82 | ck_assert_msg(data == tmp, "队列数据损坏。应为:%d 实际:%d", data, tmp); 83 | } 84 | 85 | for (int i = 0; i < 10; i++) { 86 | buff[i] = '0' + i; 87 | } 88 | 89 | om_fifo_writes(&fifo, buff, 10); 90 | 91 | for (int i = 0; i < 10; i++) { 92 | buff[i] = 0; 93 | } 94 | 95 | ck_assert_msg(fifo.is_full, "队列未满"); 96 | 97 | ck_assert_msg(om_fifo_write(&fifo, "0") == OM_ERROR_FULL, "队列未满"); 98 | 99 | om_fifo_reads(&fifo, buff, 10); 100 | 101 | for (int i = 0; i < 10; i++) { 102 | char data = '0' + i; 103 | ck_assert_msg(data == buff[i], "批量读写第%d个数据损坏。应为:%d 实际:%d", 104 | i, data, buff[i]); 105 | } 106 | } 107 | END_TEST 108 | 109 | START_TEST(_RBT) { 110 | RBT_ROOT(rbt); 111 | om_rbt_node_t node[50] = {}; 112 | for (int i = 0; i < 50; i++) { 113 | char* tmp = malloc(50); 114 | memset(tmp, 0, 50); 115 | tmp[0] = i + 'A'; 116 | node[i].key = tmp; 117 | om_rbtree_insert(&rbt, &node[i]); 118 | } 119 | 120 | om_rbt_node_t* tmp = NULL; 121 | 122 | for (int i = 0; i < 50; i++) { 123 | tmp = om_rbtree_foreach_disc(&rbt, tmp); 124 | ck_assert_msg(tmp->key[0] == 'A' + i, "遍历第%d个数据错误,为%d", i, 125 | tmp->key[0] - 'A'); 126 | } 127 | } 128 | END_TEST 129 | 130 | Suite* make_om_base_suite(void) { 131 | Suite* om_base = suite_create("底层API测试"); 132 | 133 | TCase* tc_malloc = tcase_create("内存分配测试"); 134 | suite_add_tcase(om_base, tc_malloc); 135 | tcase_add_test(tc_malloc, _MALLOC); 136 | 137 | TCase* tc_mutex = tcase_create("互斥锁测试"); 138 | suite_add_tcase(om_base, tc_mutex); 139 | tcase_add_test(tc_mutex, _MUTEX); 140 | 141 | TCase* tc_fifo = tcase_create("队列测试"); 142 | suite_add_tcase(om_base, tc_fifo); 143 | tcase_add_test(tc_fifo, _FIFO); 144 | 145 | TCase* tc_rbt = tcase_create("红黑树测试"); 146 | suite_add_tcase(om_base, tc_rbt); 147 | tcase_add_test(tc_rbt, _RBT); 148 | 149 | return om_base; 150 | } 151 | -------------------------------------------------------------------------------- /om/test/om_test_main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "om_test.h" 4 | 5 | int main(void) { 6 | int n = 0; 7 | 8 | SRunner* base = srunner_create(make_om_base_suite()); 9 | srunner_set_fork_status(base, CK_FORK); 10 | srunner_run_all(base, CK_VERBOSE); 11 | n += srunner_ntests_failed(base); 12 | srunner_free(base); 13 | 14 | SRunner* module = srunner_create(make_om_module_suite()); 15 | srunner_set_fork_status(module, CK_FORK); 16 | srunner_run_all(module, CK_VERBOSE); 17 | n += srunner_ntests_failed(module); 18 | srunner_free(module); 19 | 20 | return (n == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 21 | } -------------------------------------------------------------------------------- /om/test/om_test_module.c: -------------------------------------------------------------------------------- 1 | #include "om.h" 2 | #include "om_test.h" 3 | 4 | static char str1[] = "This is str1"; 5 | static char str2[] = "This is str2"; 6 | static char str3[] = "This is str3"; 7 | 8 | static bool filter = false, sub_callback = false; 9 | 10 | static char str_tmp[20]; 11 | 12 | static om_status_t deploy_fun(om_msg_t* msg, void* arg) { 13 | OM_UNUSED(arg); 14 | 15 | sub_callback = true; 16 | strncpy(str_tmp, msg->buff, 20); 17 | 18 | return OM_OK; 19 | } 20 | 21 | static om_status_t filter_fun(om_msg_t* msg, void* arg) { 22 | OM_UNUSED(arg); 23 | 24 | filter = true; 25 | if (!strncmp(str1, msg->buff, 20) || !strncmp(str2, msg->buff, 20)) 26 | return OM_OK; 27 | else 28 | return OM_ERROR; 29 | } 30 | 31 | static float pub_freq = 12.5; 32 | 33 | START_TEST(_PUBLISH) { 34 | om_init(); 35 | om_status_t res = OM_OK; 36 | 37 | om_topic_t* topic = om_config_topic(NULL, "fdac", "topic", 100u, filter_fun, 38 | NULL, deploy_fun, NULL); 39 | om_topic_t* topic2 = om_config_topic(NULL, "la", "topic2", 100, topic); 40 | ck_assert_msg(topic, "topic 指针为 NULL."); 41 | ck_assert_msg(topic2, "topic2 指针为 NULL."); 42 | 43 | ck_assert_msg(om_find_topic("topic", 0) == topic, "无法根据名称寻找话题。"); 44 | 45 | om_publish(om_find_topic("topic2", 0), str2, sizeof(str2), true, false); 46 | ck_assert_msg(!strncmp(str_tmp, str2, 20), "publish数据损坏。"); 47 | 48 | om_publish(om_find_topic("topic2", 0), str3, sizeof(str3), true, false); 49 | ck_assert_msg(strncmp(str_tmp, str3, 20), "filter函数未生效。"); 50 | 51 | fail_if(res); 52 | } 53 | END_TEST 54 | 55 | START_TEST(_PUBLISH_STATIC) { 56 | om_init(); 57 | om_status_t res = OM_OK; 58 | 59 | om_topic_t _topic, _topic2; 60 | 61 | om_create_topic_static(&_topic, "static_topic", 100u); 62 | om_create_topic_static(&_topic2, "static_topic2", 100); 63 | 64 | om_suber_t suber; 65 | om_link_t link; 66 | 67 | uint8_t topic_buff[100]; 68 | 69 | om_topic_t* topic = om_config_topic(&_topic, "fdax", filter_fun, NULL, 70 | deploy_fun, NULL, topic_buff); 71 | om_topic_t* topic2 = om_config_topic(&_topic2, "ka", &suber, &link, topic); 72 | 73 | ck_assert_msg(topic, "topic 指针为 NULL."); 74 | ck_assert_msg(topic2, "topic2 指针为 NULL."); 75 | 76 | ck_assert_msg(om_find_topic("static_topic", 0) == topic, 77 | "无法根据名称寻找话题。"); 78 | 79 | om_publish(om_find_topic("static_topic2", 0), str2, sizeof(str2), true, 80 | false); 81 | ck_assert_msg(!strncmp(str_tmp, str2, 20), "publish数据损坏:%s", str_tmp); 82 | 83 | om_publish(om_find_topic("static_topic2", 0), str3, sizeof(str3), true, 84 | false); 85 | ck_assert_msg(strncmp(str_tmp, str3, 20), "filter函数未生效。"); 86 | 87 | fail_if(res); 88 | } 89 | END_TEST 90 | 91 | START_TEST(_QUEUE) { 92 | om_topic_t* topic = om_config_topic(NULL, "a", "topic", 1u); 93 | om_fifo_t* queue = om_queue_add(topic, 10); 94 | for (uint8_t i = 0; i < 5; i++) { 95 | om_publish(topic, &i, sizeof(i), true, false); 96 | } 97 | OM_TOPIC_LOCK(topic); 98 | ck_assert_msg(om_fifo_readable_item_count(queue) == 5, "队列元素数量错误"); 99 | 100 | for (uint8_t i = 0; i < 5; i++) { 101 | uint8_t tmp; 102 | 103 | om_fifo_read(queue, &tmp); 104 | ck_assert_msg(tmp == i, "队列元素数据损坏"); 105 | } 106 | OM_TOPIC_UNLOCK(topic); 107 | } 108 | END_TEST 109 | 110 | START_TEST(_QUEUE_STATIC) { 111 | om_topic_t topic; 112 | om_fifo_t queue; 113 | om_suber_t suber; 114 | uint8_t buff[10]; 115 | om_create_topic_static(&topic, "static_topic", 1u); 116 | om_queue_init_fifo_static(&topic, &queue, buff, 10); 117 | om_queue_add_static(&topic, &suber, &queue); 118 | for (uint8_t i = 0; i < 5; i++) { 119 | om_publish(&topic, &i, sizeof(i), true, false); 120 | } 121 | OM_TOPIC_LOCK(&topic); 122 | ck_assert_msg(om_fifo_readable_item_count(&queue) == 5, "队列元素数量错误"); 123 | 124 | for (uint8_t i = 0; i < 5; i++) { 125 | uint8_t tmp; 126 | 127 | om_fifo_read(&queue, &tmp); 128 | ck_assert_msg(tmp == i, "队列元素数据损坏"); 129 | } 130 | OM_TOPIC_UNLOCK(&topic); 131 | } 132 | END_TEST 133 | 134 | START_TEST(_LOG) { 135 | char str_log[] = {"Log test."}; 136 | om_init(); 137 | char buff[100] = {0}; 138 | om_topic_t* topic_log = om_get_log_handle(); 139 | 140 | om_suber_t* sub = om_subscribe(topic_log); 141 | 142 | ck_assert_msg(topic_log, "获取不到log话题。"); 143 | om_print_log("init", OM_LOG_LEVEL_DEFAULT, true, false, "%s", str_log); 144 | om_suber_export(sub, buff, false); 145 | ck_assert_msg(!strcmp(buff, "[init]\033[mLog test.\r\n"), "LOG数据错误:%s", 146 | buff); 147 | } 148 | END_TEST 149 | 150 | typedef enum { EVENT_1 = 0x21, EVENT_2 = 0x01 } test_event_t; 151 | 152 | uint32_t last_event = 0, event_counter = 0; 153 | 154 | void event_callback(uint32_t event, void* arg) { 155 | OM_UNUSED(arg); 156 | 157 | last_event = event; 158 | event_counter++; 159 | } 160 | 161 | START_TEST(_EVENT) { 162 | om_init(); 163 | 164 | om_event_group_t* evt_group = om_event_create_group("test_group"); 165 | 166 | om_event_register(evt_group, EVENT_1, OM_EVENT_END, event_callback, NULL); 167 | om_event_register(evt_group, EVENT_2, OM_EVENT_START, event_callback, NULL); 168 | 169 | om_event_active(evt_group, EVENT_1, true, false); 170 | 171 | ck_assert_msg(event_counter == 0, "事件误触发"); 172 | ck_assert_msg(last_event == 0, "事件误触发"); 173 | 174 | om_event_active(evt_group, EVENT_2, true, false); 175 | 176 | ck_assert_msg(event_counter == 2, "事件触发失败"); 177 | ck_assert_msg(last_event == EVENT_1, "触发了错误的事件,应为%d,实际为%d", 178 | EVENT_1, last_event); 179 | } 180 | END_TEST 181 | 182 | START_TEST(_EVENT_STATIC) { 183 | om_init(); 184 | 185 | om_event_group_t group; 186 | 187 | om_event_create_group_static(&group, "test_group"); 188 | 189 | om_event_t event1, event2; 190 | 191 | om_event_register_static(&event1, &group, EVENT_1, OM_EVENT_END, 192 | event_callback, NULL); 193 | om_event_register_static(&event2, &group, EVENT_2, OM_EVENT_START, 194 | event_callback, NULL); 195 | 196 | om_event_active(&group, EVENT_1, true, false); 197 | 198 | ck_assert_msg(event_counter == 0, "事件误触发"); 199 | ck_assert_msg(last_event == 0, "事件误触发"); 200 | 201 | om_event_active(&group, EVENT_2, true, false); 202 | 203 | ck_assert_msg(event_counter == 2, "事件触发失败"); 204 | ck_assert_msg(last_event == EVENT_1, "触发了错误的事件,应为%d,实际为%d", 205 | EVENT_1, last_event); 206 | } 207 | END_TEST 208 | 209 | typedef struct { 210 | uint32_t range; 211 | uint8_t list[10]; 212 | float decompose; 213 | } om_afl_test_t; 214 | 215 | START_TEST(_FILTER) { 216 | om_init(); 217 | 218 | om_afl_test_t test = {0}, ans1 = {0}, ans2 = {0}, ans3 = {0}; 219 | uint8_t fl_template[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 220 | 221 | om_topic_t* source = 222 | om_config_topic(NULL, NULL, "source", sizeof(om_afl_test_t)); 223 | om_topic_t* list = om_config_topic(NULL, NULL, "list", sizeof(om_afl_test_t)); 224 | om_topic_t* range = 225 | om_config_topic(NULL, NULL, "range", sizeof(om_afl_test_t)); 226 | om_topic_t* decompose = 227 | om_config_topic(NULL, NULL, "decompose", sizeof(om_afl_test_t)); 228 | 229 | om_suber_t* list_sub = om_subscribe(list); 230 | om_suber_t* range_sub = om_subscribe(range); 231 | om_suber_t* decompose_sub = om_subscribe(decompose); 232 | 233 | om_config_filter(source, "LDR", list, OM_PRASE_STRUCT(om_afl_test_t, list), 234 | fl_template, decompose, 235 | OM_PRASE_STRUCT(om_afl_test_t, decompose), range, 236 | OM_PRASE_STRUCT(om_afl_test_t, range), 213, 100); 237 | 238 | memcpy(&test.list, fl_template, sizeof(fl_template)); 239 | om_publish(source, &test, sizeof(test), true, false); 240 | om_suber_export(list_sub, &ans1, false); 241 | ck_assert_msg(!memcmp(&test.list, &ans1.list, sizeof(ans1.list)), 242 | "过滤器list模式数据错误"); 243 | test.list[1] = 0; 244 | om_publish(source, &test, sizeof(test), true, false); 245 | ck_assert_msg(memcmp(&test.list, &ans1.list, sizeof(ans1.list)), 246 | "过滤器list模式失效"); 247 | 248 | for (uint32_t i = 0; i < 100; i++) { 249 | test.range = 213 + i; 250 | om_publish(source, &test, sizeof(test), true, false); 251 | om_suber_export(range_sub, &ans2, false); 252 | ck_assert_msg(test.range == ans2.range, 253 | "过滤器range模式数据错误在%d,应为%d,实际为%d", i, test.range, 254 | ans2.range); 255 | } 256 | 257 | for (uint32_t i = 1000; i < 2000; i++) { 258 | test.range = 213 + i; 259 | om_publish(source, &test, sizeof(test), true, false); 260 | om_suber_export(range_sub, &ans2, false); 261 | ck_assert_msg(test.range != ans2.range, 262 | "过滤器range模式失效在%d,应为%d,实际为%d", i, test.range, 263 | ans2.range); 264 | } 265 | 266 | test.decompose = 5.63f; 267 | om_publish(source, &test, sizeof(test), true, false); 268 | om_suber_export(decompose_sub, &ans3.decompose, false); 269 | ck_assert_msg(test.decompose == ans3.decompose, 270 | "过滤器decompose模式数据错误"); 271 | } 272 | END_TEST 273 | 274 | START_TEST(_FILTER_STATIC) { 275 | om_init(); 276 | 277 | om_afl_test_t test = {0}, ans1 = {0}, ans2 = {0}, ans3 = {0}; 278 | uint8_t fl_template[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 279 | 280 | om_topic_t source, list, range, decompose; 281 | 282 | om_create_topic_static(&source, "source", sizeof(om_afl_test_t)); 283 | om_create_topic_static(&list, "list", sizeof(om_afl_test_t)); 284 | om_create_topic_static(&range, "range", sizeof(om_afl_test_t)); 285 | om_create_topic_static(&decompose, "decompose", sizeof(om_afl_test_t)); 286 | 287 | om_suber_t* list_sub = om_subscribe(&list); 288 | om_suber_t* range_sub = om_subscribe(&range); 289 | om_suber_t* decompose_sub = om_subscribe(&decompose); 290 | 291 | om_afl_t afl; 292 | om_afl_filter_t f_list, f_range, f_decompose; 293 | 294 | om_config_filter_static( 295 | &source, "LDR", &afl, &f_list, &list, 296 | OM_PRASE_STRUCT(om_afl_test_t, list), fl_template, &f_decompose, 297 | &decompose, OM_PRASE_STRUCT(om_afl_test_t, decompose), &f_range, &range, 298 | OM_PRASE_STRUCT(om_afl_test_t, range), 213, 100); 299 | 300 | memcpy(&test.list, fl_template, sizeof(fl_template)); 301 | om_publish(&source, &test, sizeof(test), true, false); 302 | om_suber_export(list_sub, &ans1, false); 303 | ck_assert_msg(!memcmp(&test.list, &ans1.list, sizeof(ans1.list)), 304 | "过滤器list模式数据错误"); 305 | test.list[1] = 0; 306 | om_publish(&source, &test, sizeof(test), true, false); 307 | om_suber_export(list_sub, &ans1, false); 308 | ck_assert_msg(memcmp(&test.list, &ans1.list, sizeof(ans1.list)), 309 | "过滤器list模式失效"); 310 | 311 | for (uint32_t i = 0; i < 100; i++) { 312 | test.range = 213 + i; 313 | om_publish(&source, &test, sizeof(test), true, false); 314 | om_suber_export(range_sub, &ans2, false); 315 | ck_assert_msg(test.range == ans2.range, 316 | "过滤器range模式数据错误在%d,应为%d,实际为%d", i, test.range, 317 | ans2.range); 318 | } 319 | 320 | for (uint32_t i = 1000; i < 2000; i++) { 321 | test.range = 213 + i; 322 | om_publish(&source, &test, sizeof(test), true, false); 323 | om_suber_export(range_sub, &ans2, false); 324 | ck_assert_msg(test.range != ans2.range, 325 | "过滤器range模式失效在%d,应为%d,实际为%d", i, test.range, 326 | ans2.range); 327 | } 328 | 329 | test.decompose = 5.63f; 330 | om_publish(&source, &test, sizeof(test), true, false); 331 | om_suber_export(decompose_sub, &ans3.decompose, false); 332 | ck_assert_msg(test.decompose == ans3.decompose, 333 | "过滤器decompose模式数据错误"); 334 | } 335 | END_TEST 336 | 337 | typedef struct { 338 | uint32_t test; 339 | char str[10]; 340 | } om_com_test_t; 341 | 342 | static uint32_t com_pub_count = 0; 343 | 344 | static om_status_t com_cb(om_msg_t* msg, void* arg) { 345 | OM_UNUSED(arg); 346 | 347 | com_pub_count++; 348 | 349 | return OM_OK; 350 | } 351 | 352 | START_TEST(_COM) { 353 | om_init(); 354 | 355 | om_topic_t* source = om_config_topic(NULL, "cad", "source", 356 | sizeof(om_com_test_t), com_cb, NULL); 357 | 358 | om_topic_t* source1 = 359 | om_config_topic(NULL, "ca", "source1", sizeof(om_com_test_t)); 360 | 361 | om_com_t com; 362 | 363 | om_com_test_t test_data = {.str = "test data1", .test = 0x12345678}; 364 | 365 | om_com_create(&com, 128, 5, 128); 366 | 367 | om_com_add_topic_with_name(&com, "source1"); 368 | 369 | om_com_add_topic(&com, source); 370 | 371 | OM_COM_TYPE(om_com_test_t) trans_buffer; 372 | 373 | om_publish(source, &test_data, sizeof(om_com_test_t), true, false); 374 | 375 | ck_assert(com_pub_count == 1); 376 | 377 | om_com_generate_pack(source, &trans_buffer); 378 | 379 | test_data = (om_com_test_t){.str = "test data2", .test = 0x12785634}; 380 | 381 | om_publish(source, &test_data, sizeof(om_com_test_t), true, false); 382 | 383 | ck_assert(com_pub_count == 2); 384 | 385 | /* prase an entire packet of data */ 386 | for (int i = 0; i < 100; i++) { 387 | com_pub_count = 0; 388 | om_com_prase_recv(&com, (uint8_t*)&trans_buffer, 389 | OM_COM_TYPE_SIZE(om_com_test_t), true, false); 390 | 391 | ck_assert(com_pub_count == 1); 392 | } 393 | 394 | om_com_test_t* test_ans = (om_com_test_t*)source->msg.buff; 395 | 396 | ck_assert_msg(strncmp(test_ans->str, "test data1", 10) == 0, "数据损坏"); 397 | ck_assert_msg(test_ans->test == 0x12345678, "数据损坏"); 398 | 399 | /* prase packet by byte */ 400 | for (int j = 0; j < 100; j++) { 401 | com_pub_count = 0; 402 | for (int i = 0; i < sizeof(trans_buffer); i++) { 403 | ck_assert(com_pub_count == 0); 404 | uint8_t* data_buff = (uint8_t*)&trans_buffer; 405 | om_com_prase_recv(&com, data_buff + i, 1, true, false); 406 | } 407 | ck_assert(com_pub_count == 1); 408 | } 409 | 410 | /* prase packet with invalid data */ 411 | for (uint8_t j = 0; j <= 254; j++) { 412 | com_pub_count = 0; 413 | for (int t = 0; t < j; t++) { 414 | om_com_prase_recv(&com, &j, 1, true, false); 415 | } 416 | for (int i = 0; i < sizeof(trans_buffer); i++) { 417 | ck_assert(com_pub_count == 0); 418 | uint8_t* data_buff = (uint8_t*)&trans_buffer; 419 | om_com_prase_recv(&com, data_buff + i, 1, true, false); 420 | } 421 | ck_assert(com_pub_count == 1); 422 | } 423 | } 424 | 425 | Suite* make_om_module_suite(void) { 426 | Suite* om_module = suite_create("模块测试"); 427 | 428 | TCase* tc_log = tcase_create("日志测试"); 429 | suite_add_tcase(om_module, tc_log); 430 | tcase_add_test(tc_log, _LOG); 431 | 432 | TCase* tc_public = tcase_create("订阅发布测试"); 433 | suite_add_tcase(om_module, tc_public); 434 | tcase_add_test(tc_public, _PUBLISH); 435 | 436 | TCase* tc_public_static = tcase_create("静态订阅发布测试"); 437 | suite_add_tcase(om_module, tc_public_static); 438 | tcase_add_test(tc_public_static, _PUBLISH_STATIC); 439 | 440 | TCase* tc_queue = tcase_create("队列测试"); 441 | suite_add_tcase(om_module, tc_queue); 442 | tcase_add_test(tc_queue, _QUEUE); 443 | 444 | TCase* tc_queue_static = tcase_create("静态队列测试"); 445 | suite_add_tcase(om_module, tc_queue_static); 446 | tcase_add_test(tc_queue_static, _QUEUE); 447 | 448 | TCase* tc_event = tcase_create("事件触发测试"); 449 | suite_add_tcase(om_module, tc_event); 450 | tcase_add_test(tc_event, _EVENT); 451 | 452 | TCase* tc_event_static = tcase_create("静态事件触发测试"); 453 | suite_add_tcase(om_module, tc_event_static); 454 | tcase_add_test(tc_event_static, _EVENT_STATIC); 455 | 456 | TCase* tc_filter = tcase_create("高级过滤器测试"); 457 | suite_add_tcase(om_module, tc_filter); 458 | tcase_add_test(tc_filter, _FILTER); 459 | 460 | TCase* tc_filter_static = tcase_create("静态高级过滤器测试"); 461 | suite_add_tcase(om_module, tc_filter_static); 462 | tcase_add_test(tc_filter_static, _FILTER_STATIC); 463 | 464 | TCase* tc_com = tcase_create("通信收发器测试"); 465 | suite_add_tcase(om_module, tc_com); 466 | tcase_add_test(tc_com, _COM); 467 | 468 | return om_module; 469 | } 470 | -------------------------------------------------------------------------------- /src/om.cpp: -------------------------------------------------------------------------------- 1 | #include "om.hpp" 2 | -------------------------------------------------------------------------------- /src/om.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __OM_H_CPP__ 2 | #define __OM_H_CPP__ 3 | 4 | #include "om.h" 5 | #include "om_core.h" 6 | 7 | class Message { 8 | public: 9 | Message() { om_init(); } 10 | 11 | template 12 | class Callback { 13 | public: 14 | Callback(bool (*fun)(Data& data, Arg arg), Arg arg) 15 | : fun_(fun), arg_(arg) {} 16 | 17 | static om_status_t Call(om_msg_t* msg, void* arg) { 18 | Callback* self = static_cast(arg); 19 | auto data = static_cast(msg->buff); 20 | 21 | return self->fun_(*data, self->arg_) ? OM_OK : OM_ERROR; 22 | } 23 | 24 | bool (*fun_)(Data& data, Arg arg); 25 | Arg arg_; 26 | }; 27 | 28 | template 29 | class Topic { 30 | public: 31 | Topic(const char* name, bool cached = false) { 32 | if (!cached) { 33 | this->om_topic_ = om_config_topic(NULL, "A", name, sizeof(Data)); 34 | } else { 35 | this->om_topic_ = om_config_topic(NULL, "CA", name, sizeof(Data)); 36 | } 37 | } 38 | 39 | Topic(om_topic_t* topic) { this->om_topic_ = topic; } 40 | 41 | bool Lock() { return OM_TOPIC_LOCK(om_topic_); } 42 | 43 | void Unlock() { OM_TOPIC_UNLOCK(om_topic_); } 44 | 45 | bool Link(Topic& source) { 46 | return om_core_link(source, this->om_topic_) == OM_OK; 47 | } 48 | 49 | bool Link(om_topic_t* source) { 50 | return om_core_link(source, this->om_topic_) == OM_OK; 51 | } 52 | 53 | bool Link(const char* source_name) { 54 | return om_core_link(om_find_topic(source_name, UINT32_MAX), 55 | this->om_topic_) == OM_OK; 56 | } 57 | 58 | static om_topic_t* Find(const char* name) { return om_find_topic(name, 0); } 59 | 60 | template 61 | void RegisterFilter(Fun fun, Arg arg) { 62 | static_cast(fun); 63 | 64 | Callback* cb = static_cast*>( 65 | om_malloc(sizeof(Callback))); 66 | 67 | new (cb) Callback(fun, arg); 68 | 69 | om_config_topic(this->om_topic_, "F", Callback::Call, cb); 70 | } 71 | 72 | template 73 | void RegisterCallback(Fun fun, Arg arg) { 74 | (void)static_cast(fun); 75 | 76 | Callback* cb = static_cast*>( 77 | om_malloc(sizeof(Callback))); 78 | 79 | *cb = Callback(fun, arg); 80 | 81 | om_config_topic(this->om_topic_, "D", Callback::Call, cb); 82 | } 83 | 84 | void RangeDivide(Topic& topic, uint32_t length, uint32_t offset, 85 | uint32_t scope, uint32_t start, uint32_t num) { 86 | om_config_filter(this->om_topic_, "R", topic, length, offset, scope, 87 | start, num); 88 | } 89 | 90 | void ListDivide(Topic& topic, uint32_t length, uint32_t offset, 91 | uint32_t scope, void* temp) { 92 | om_config_filter(this->om_topic_, "L", topic, length, offset, scope, 93 | temp); 94 | } 95 | 96 | void DecomposeDivide(Topic& topic, uint32_t length, uint32_t offset, 97 | uint32_t scope) { 98 | om_config_filter(this->om_topic_, topic, "D", this->om_topic_, length, 99 | offset, scope); 100 | } 101 | 102 | bool Publish(Data& data, bool in_isr = om_in_isr()) { 103 | return om_publish(this->om_topic_, &data, sizeof(Data), true, in_isr) == 104 | OM_OK; 105 | }; 106 | 107 | typedef OM_COM_TYPE(Data) RemoteData; 108 | 109 | bool PackData(RemoteData& data) { 110 | return om_com_generate_pack(om_topic_, &data) == OM_OK; 111 | }; 112 | 113 | template 114 | class Queue { 115 | Queue(om_topic_t* topic) : topic_(topic) { 116 | OM_ASSERT(topic); 117 | om_queue_init_fifo_static(topic, &fifo_, buff_, Len); 118 | om_queue_add_static(topic, &sub_, &fifo_); 119 | } 120 | 121 | uint32_t Size() { return om_fifo_readable_item_count(&fifo_); } 122 | 123 | bool Read(Data& buff) { 124 | OM_TOPIC_LOCK(topic_); 125 | auto ans = om_fifo_read(&fifo_, &buff); 126 | OM_TOPIC_UNLOCK(topic_); 127 | return ans == OM_OK; 128 | } 129 | 130 | bool Reads(Data* buff, uint32_t len) { 131 | OM_TOPIC_LOCK(topic_); 132 | auto ans = om_fifo_reads(&fifo_, buff, len); 133 | OM_TOPIC_UNLOCK(topic_); 134 | return ans == OM_OK; 135 | } 136 | 137 | bool Pop() { 138 | OM_TOPIC_LOCK(topic_); 139 | auto ans = om_fifo_pop(&fifo_); 140 | OM_TOPIC_UNLOCK(topic_); 141 | return ans == OM_OK; 142 | } 143 | 144 | void Reset() { 145 | OM_TOPIC_LOCK(topic_); 146 | om_fifo_reset(&fifo_); 147 | OM_TOPIC_UNLOCK(topic_); 148 | } 149 | 150 | om_fifo_t fifo_; 151 | om_suber_t sub_; 152 | uint8_t buff_[sizeof(Data) * Len]; 153 | om_topic_t* topic_; 154 | }; 155 | 156 | operator om_topic_t*() { return this->om_topic_; }; 157 | 158 | om_topic_t* om_topic_; 159 | }; 160 | 161 | template 162 | class Subscriber { 163 | public: 164 | Subscriber(const char* name, uint32_t timeout = UINT32_MAX) { 165 | om_topic_t* topic = om_find_topic(name, timeout); 166 | if (topic != NULL) { 167 | this->om_suber_ = om_subscribe(topic); 168 | } else { 169 | this->om_suber_ = NULL; 170 | } 171 | } 172 | 173 | Subscriber(om_topic_t* topic) { this->om_suber_ = om_subscribe(topic); } 174 | 175 | Subscriber(Topic& topic) { this->om_suber_ = om_subscribe(topic); } 176 | 177 | bool Ready() { return this->om_suber_ != NULL; } 178 | 179 | bool Available() { 180 | if (this->Ready()) { 181 | return om_suber_available(this->om_suber_); 182 | } else { 183 | return false; 184 | } 185 | } 186 | 187 | bool DumpData(Data& buff, bool in_isr = om_in_isr()) { 188 | if (this->Ready()) { 189 | return om_suber_export(this->om_suber_, &buff, in_isr) == OM_OK; 190 | } else { 191 | return false; 192 | } 193 | } 194 | 195 | om_suber_t* om_suber_; 196 | }; 197 | 198 | class Remote { 199 | public: 200 | om_com_t com_; 201 | 202 | Remote(uint32_t buff_size, uint32_t topic_num) { 203 | om_com_create(&com_, buff_size, topic_num, buff_size); 204 | } 205 | 206 | void AddTopic(const char* topic_name) { 207 | om_com_add_topic_with_name(&com_, topic_name); 208 | } 209 | 210 | void AddTopic(om_topic_t* topic) { om_com_add_topic(&com_, topic); } 211 | 212 | bool PraseData(uint8_t* data, uint32_t size, bool in_isr = om_in_isr()) { 213 | return om_com_prase_recv(&com_, data, size, true, in_isr) == 214 | OM_COM_RECV_SUCESS; 215 | } 216 | }; 217 | 218 | class Event { 219 | public: 220 | typedef enum { 221 | EVENT_START = OM_EVENT_START, 222 | EVENT_PROGRESS = OM_EVENT_PROGRESS, 223 | EVENT_END = OM_EVENT_END 224 | } Status; 225 | 226 | Event(const char* name) : group_(om_event_create_group(name)) {} 227 | 228 | Event(om_event_group_t* group) : group_(group) {} 229 | 230 | static om_event_group_t* FindEvent(const char* name) { 231 | return om_event_find_group(name, UINT32_MAX); 232 | } 233 | 234 | bool Register(uint32_t event, Status status, 235 | void (*callback)(uint32_t event, void* arg), void* arg) { 236 | return om_event_register(this->group_, event, 237 | static_cast(status), callback, 238 | arg); 239 | } 240 | 241 | bool Active(uint32_t event, bool in_isr = om_in_isr()) { 242 | return om_event_active(this->group_, event, true, in_isr); 243 | } 244 | 245 | om_event_group_t* group_; 246 | }; 247 | }; 248 | 249 | #endif 250 | --------------------------------------------------------------------------------