├── .gitattributes ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── dev └── VisualStudio │ ├── main.c │ ├── ringbuff_dev.sln │ ├── ringbuff_dev.vcxproj │ └── ringbuff_dev.vcxproj.filters ├── docs ├── Makefile ├── api-reference │ ├── index.rst │ └── ringbuff.rst ├── conf.py ├── doxyfile.doxy ├── examples_src │ ├── example_advance_1.c │ ├── example_advance_2.c │ ├── example_dma_skip.c │ ├── example_events.c │ ├── example_index.c │ ├── example_minimal.c │ ├── example_skip_1.c │ ├── example_skip_2.c │ ├── example_tt_buff_size.c │ └── example_tt_buff_size_log.c ├── get-started │ └── index.rst ├── index.rst ├── make.bat ├── requirements.txt ├── static │ ├── css │ │ ├── common.css │ │ └── custom.css │ └── images │ │ ├── buff_cases.svg │ │ ├── buff_cases.xml │ │ ├── buff_lin_read_skip.svg │ │ ├── buff_lin_read_skip.xml │ │ ├── buff_lin_write_advance.svg │ │ ├── buff_lin_write_advance.xml │ │ ├── logo.drawio │ │ ├── logo.svg │ │ ├── logo_tm.png │ │ └── logo_tm_full.png ├── tips-tricks │ └── index.rst └── user-manual │ ├── events.rst │ ├── how-it-works.rst │ ├── hw-dma-usage.rst │ └── index.rst └── lwrb └── src ├── include └── lwrb │ └── lwrb.h └── lwrb └── lwrb.c /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Build Keil files 2 | *.rar 3 | *.o 4 | *.d 5 | *.crf 6 | *.htm 7 | *.dep 8 | *.map 9 | *.bak 10 | *.axf 11 | *.lnp 12 | *.lst 13 | *.ini 14 | *.scvd 15 | *.iex 16 | *.sct 17 | *.MajerleT 18 | *.tjuln 19 | *.tilen 20 | *.dbgconf 21 | *.uvguix 22 | *.uvoptx 23 | *.__i 24 | *.i 25 | *.txt 26 | !docs/*.txt 27 | RTE/ 28 | 29 | # IAR Settings 30 | **/settings/*.crun 31 | **/settings/*.dbgdt 32 | **/settings/*.cspy 33 | **/settings/*.cspy.* 34 | **/settings/*.xcl 35 | **/settings/*.dni 36 | **/settings/*.wsdt 37 | **/settings/*.wspos 38 | 39 | # IAR Debug Exe 40 | **/Exe/*.sim 41 | 42 | # IAR Debug Obj 43 | **/Obj/*.pbd 44 | **/Obj/*.pbd.* 45 | **/Obj/*.pbi 46 | **/Obj/*.pbi.* 47 | 48 | *.TMP 49 | /docs_src/x_Doxyfile.doxy 50 | 51 | .DS_Store 52 | 53 | ## Ignore Visual Studio temporary files, build results, and 54 | ## files generated by popular Visual Studio add-ons. 55 | ## 56 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 57 | 58 | # User-specific files 59 | *.suo 60 | *.user 61 | *.userosscache 62 | *.sln.docstates 63 | 64 | # User-specific files (MonoDevelop/Xamarin Studio) 65 | *.userprefs 66 | 67 | # Build results 68 | [Dd]ebug/ 69 | [Dd]ebugPublic/ 70 | [Rr]elease/ 71 | [Rr]eleases/ 72 | x64/ 73 | x86/ 74 | bld/ 75 | [Bb]in/ 76 | [Oo]bj/ 77 | [Ll]og/ 78 | _build/ 79 | 80 | # Visual Studio 2015/2017 cache/options directory 81 | .vs/ 82 | # Uncomment if you have tasks that create the project's static files in wwwroot 83 | #wwwroot/ 84 | 85 | # Visual Studio 2017 auto generated files 86 | Generated\ Files/ 87 | 88 | # MSTest test Results 89 | [Tt]est[Rr]esult*/ 90 | [Bb]uild[Ll]og.* 91 | 92 | # NUNIT 93 | *.VisualState.xml 94 | TestResult.xml 95 | 96 | # Build Results of an ATL Project 97 | [Dd]ebugPS/ 98 | [Rr]eleasePS/ 99 | dlldata.c 100 | 101 | # Benchmark Results 102 | BenchmarkDotNet.Artifacts/ 103 | 104 | # .NET Core 105 | project.lock.json 106 | project.fragment.lock.json 107 | artifacts/ 108 | **/Properties/launchSettings.json 109 | 110 | # StyleCop 111 | StyleCopReport.xml 112 | 113 | # Files built by Visual Studio 114 | *_i.c 115 | *_p.c 116 | *_i.h 117 | *.ilk 118 | *.meta 119 | *.obj 120 | *.pch 121 | *.pdb 122 | *.pgc 123 | *.pgd 124 | *.rsp 125 | *.sbr 126 | *.tlb 127 | *.tli 128 | *.tlh 129 | *.tmp 130 | *.tmp_proj 131 | *.log 132 | *.vspscc 133 | *.vssscc 134 | .builds 135 | *.pidb 136 | *.svclog 137 | *.scc 138 | *.out 139 | *.sim 140 | 141 | # Chutzpah Test files 142 | _Chutzpah* 143 | 144 | # Visual C++ cache files 145 | ipch/ 146 | *.aps 147 | *.ncb 148 | *.opendb 149 | *.opensdf 150 | *.sdf 151 | *.cachefile 152 | *.VC.db 153 | *.VC.VC.opendb 154 | 155 | # Visual Studio profiler 156 | *.psess 157 | *.vsp 158 | *.vspx 159 | *.sap 160 | 161 | # Visual Studio Trace Files 162 | *.e2e 163 | 164 | # TFS 2012 Local Workspace 165 | $tf/ 166 | 167 | # Guidance Automation Toolkit 168 | *.gpState 169 | 170 | # ReSharper is a .NET coding add-in 171 | _ReSharper*/ 172 | *.[Rr]e[Ss]harper 173 | *.DotSettings.user 174 | 175 | # JustCode is a .NET coding add-in 176 | .JustCode 177 | 178 | # TeamCity is a build add-in 179 | _TeamCity* 180 | 181 | # DotCover is a Code Coverage Tool 182 | *.dotCover 183 | 184 | # AxoCover is a Code Coverage Tool 185 | .axoCover/* 186 | !.axoCover/settings.json 187 | 188 | # Visual Studio code coverage results 189 | *.coverage 190 | *.coveragexml 191 | 192 | # NCrunch 193 | _NCrunch_* 194 | .*crunch*.local.xml 195 | nCrunchTemp_* 196 | 197 | # MightyMoose 198 | *.mm.* 199 | AutoTest.Net/ 200 | 201 | # Web workbench (sass) 202 | .sass-cache/ 203 | 204 | # Installshield output folder 205 | [Ee]xpress/ 206 | 207 | # DocProject is a documentation generator add-in 208 | DocProject/buildhelp/ 209 | DocProject/Help/*.HxT 210 | DocProject/Help/*.HxC 211 | DocProject/Help/*.hhc 212 | DocProject/Help/*.hhk 213 | DocProject/Help/*.hhp 214 | DocProject/Help/Html2 215 | DocProject/Help/html 216 | 217 | # Click-Once directory 218 | publish/ 219 | 220 | # Publish Web Output 221 | *.[Pp]ublish.xml 222 | *.azurePubxml 223 | # Note: Comment the next line if you want to checkin your web deploy settings, 224 | # but database connection strings (with potential passwords) will be unencrypted 225 | *.pubxml 226 | *.publishproj 227 | 228 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 229 | # checkin your Azure Web App publish settings, but sensitive information contained 230 | # in these scripts will be unencrypted 231 | PublishScripts/ 232 | 233 | # NuGet Packages 234 | *.nupkg 235 | # The packages folder can be ignored because of Package Restore 236 | **/[Pp]ackages/* 237 | # except build/, which is used as an MSBuild target. 238 | !**/[Pp]ackages/build/ 239 | # Uncomment if necessary however generally it will be regenerated when needed 240 | #!**/[Pp]ackages/repositories.config 241 | # NuGet v3's project.json files produces more ignorable files 242 | *.nuget.props 243 | *.nuget.targets 244 | 245 | # Microsoft Azure Build Output 246 | csx/ 247 | *.build.csdef 248 | 249 | # Microsoft Azure Emulator 250 | ecf/ 251 | rcf/ 252 | 253 | # Windows Store app package directories and files 254 | AppPackages/ 255 | BundleArtifacts/ 256 | Package.StoreAssociation.xml 257 | _pkginfo.txt 258 | *.appx 259 | 260 | # Visual Studio cache files 261 | # files ending in .cache can be ignored 262 | *.[Cc]ache 263 | # but keep track of directories ending in .cache 264 | !*.[Cc]ache/ 265 | 266 | # Others 267 | ClientBin/ 268 | ~$* 269 | *~ 270 | *.dbmdl 271 | *.dbproj.schemaview 272 | *.jfm 273 | *.pfx 274 | *.publishsettings 275 | orleans.codegen.cs 276 | 277 | # Including strong name files can present a security risk 278 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 279 | #*.snk 280 | 281 | # Since there are multiple workflows, uncomment next line to ignore bower_components 282 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 283 | #bower_components/ 284 | 285 | # RIA/Silverlight projects 286 | Generated_Code/ 287 | 288 | # Backup & report files from converting an old project file 289 | # to a newer Visual Studio version. Backup files are not needed, 290 | # because we have git ;-) 291 | _UpgradeReport_Files/ 292 | Backup*/ 293 | UpgradeLog*.XML 294 | UpgradeLog*.htm 295 | 296 | # SQL Server files 297 | *.mdf 298 | *.ldf 299 | *.ndf 300 | 301 | # Business Intelligence projects 302 | *.rdl.data 303 | *.bim.layout 304 | *.bim_*.settings 305 | 306 | # Microsoft Fakes 307 | FakesAssemblies/ 308 | 309 | # GhostDoc plugin setting file 310 | *.GhostDoc.xml 311 | 312 | # Node.js Tools for Visual Studio 313 | .ntvs_analysis.dat 314 | node_modules/ 315 | 316 | # TypeScript v1 declaration files 317 | typings/ 318 | 319 | # Visual Studio 6 build log 320 | *.plg 321 | 322 | # Visual Studio 6 workspace options file 323 | *.opt 324 | 325 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 326 | *.vbw 327 | 328 | # Visual Studio LightSwitch build output 329 | **/*.HTMLClient/GeneratedArtifacts 330 | **/*.DesktopClient/GeneratedArtifacts 331 | **/*.DesktopClient/ModelManifest.xml 332 | **/*.Server/GeneratedArtifacts 333 | **/*.Server/ModelManifest.xml 334 | _Pvt_Extensions 335 | 336 | # Paket dependency manager 337 | .paket/paket.exe 338 | paket-files/ 339 | 340 | # FAKE - F# Make 341 | .fake/ 342 | 343 | # JetBrains Rider 344 | .idea/ 345 | *.sln.iml 346 | 347 | # CodeRush 348 | .cr/ 349 | 350 | # Python Tools for Visual Studio (PTVS) 351 | __pycache__/ 352 | *.pyc 353 | 354 | # Cake - Uncomment if you are using it 355 | # tools/** 356 | # !tools/packages.config 357 | 358 | # Tabs Studio 359 | *.tss 360 | 361 | # Telerik's JustMock configuration file 362 | *.jmconfig 363 | 364 | # BizTalk build output 365 | *.btp.cs 366 | *.btm.cs 367 | *.odx.cs 368 | *.xsd.cs 369 | 370 | # OpenCover UI analysis results 371 | OpenCover/ 372 | 373 | # Azure Stream Analytics local run output 374 | ASALocalRun/ 375 | 376 | # MSBuild Binary and Structured Log 377 | *.binlog 378 | 379 | log_file.txt 380 | .metadata/ 381 | .mxproject 382 | .settings/ 383 | project.ioc 384 | mx.scratch 385 | *.tilen majerle 386 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuzhl2018/LwRB/3c8d3396e0c5c2cb4a63528811fa4c65f2c34f48/.gitmodules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tilen MAJERLE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generic ring buffer manager 2 | 3 | Library provides generic FIFO ring buffer implementation. 4 | 5 |

Read first: Documentation

6 | 7 | ## Features 8 | 9 | * Written in ANSI C99, compatible with ``size_t`` for size data types 10 | * Platform independent, no architecture specific code 11 | * FIFO (First In First Out) buffer implementation 12 | * No dynamic memory allocation, data is static array 13 | * Uses optimized memory copy instead of loops to read/write data from/to memory 14 | * Thread safe when used as pipe with single write and single read entries 15 | * Interrupt safe when used as pipe with single write and single read entries 16 | * Suitable for DMA transfers from and to memory with zero-copy overhead between buffer and application memory 17 | * Supports data peek, skip for read and advance for write 18 | * Implements support for event notifications 19 | * User friendly MIT license 20 | 21 | ## Contribute 22 | 23 | Fresh contributions are always welcome. Simple instructions to proceed:: 24 | 25 | 1. Fork Github repository 26 | 2. Respect [C style & coding rules](https://github.com/MaJerle/c-code-style) used by the library 27 | 3. Create a pull request to develop branch with new features or bug fixes 28 | 29 | Alternatively you may: 30 | 31 | 1. Report a bug 32 | 2. Ask for a feature request -------------------------------------------------------------------------------- /dev/VisualStudio/main.c: -------------------------------------------------------------------------------- 1 | // ringbuff_dev.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include 5 | #include 6 | #include "ringbuff/ringbuff.h" 7 | 8 | /* Create data array and buffer */ 9 | uint8_t ringbuff_data[8 + 1]; 10 | ringbuff_t buff; 11 | 12 | static void debug_buff(uint8_t cmp, size_t r_w, size_t r_r, size_t r_f, size_t r_e); 13 | 14 | uint8_t tmp[8]; 15 | 16 | void 17 | my_buff_evt_fn(ringbuff_t* buff, ringbuff_evt_type_t type, size_t len) { 18 | switch (type) { 19 | case RINGBUFF_EVT_RESET: 20 | printf("[EVT] Buffer reset event!\r\n"); 21 | break; 22 | case RINGBUFF_EVT_READ: 23 | printf("[EVT] Buffer read event: %d byte(s)!\r\n", (int)len); 24 | break; 25 | case RINGBUFF_EVT_WRITE: 26 | printf("[EVT] Buffer write event: %d byte(s)!\r\n", (int)len); 27 | break; 28 | default: break; 29 | } 30 | } 31 | 32 | int 33 | main() { 34 | size_t len; 35 | 36 | /* Init buffer */ 37 | ringbuff_init(&buff, ringbuff_data, sizeof(ringbuff_data)); 38 | ringbuff_set_evt_fn(&buff, my_buff_evt_fn); 39 | 40 | ringbuff_write(&buff, "abc", 3); 41 | ringbuff_write(&buff, "abc", 3); 42 | ringbuff_write(&buff, "abc", 3); 43 | len = ringbuff_read(&buff, tmp, 9); 44 | 45 | buff.r = 0; 46 | buff.w = 0; 47 | memset(ringbuff_get_linear_block_write_address(&buff), 'A', ringbuff_get_linear_block_write_length(&buff)); 48 | ringbuff_advance(&buff, ringbuff_get_linear_block_write_length(&buff)); 49 | 50 | buff.r = 2; 51 | buff.w = 0; 52 | memset(ringbuff_get_linear_block_write_address(&buff), 'B', ringbuff_get_linear_block_write_length(&buff)); 53 | ringbuff_advance(&buff, ringbuff_get_linear_block_write_length(&buff)); 54 | 55 | buff.r = 3; 56 | buff.w = 3; 57 | memset(ringbuff_get_linear_block_write_address(&buff), 'C', ringbuff_get_linear_block_write_length(&buff)); 58 | ringbuff_advance(&buff, ringbuff_get_linear_block_write_length(&buff)); 59 | 60 | ringbuff_reset(&buff); 61 | 62 | //for (size_t r = 0; r < sizeof(ringbuff_data); ++r) { 63 | // void* ptr; 64 | // for (size_t w = 0; w < sizeof(ringbuff_data); ++w) { 65 | // buff.r = r; 66 | // buff.w = w; 67 | // ptr = ringbuff_get_linear_block_write_address(&buff); 68 | // len = ringbuff_get_linear_block_write_length(&buff); 69 | // printf("W: %3d, R: %3d, LEN: %3d\r\n", (int)w, (int)r, (int)len); 70 | // } 71 | //} 72 | 73 | return 0; 74 | } 75 | 76 | static void 77 | debug_buff(uint8_t cmp, size_t r_w, size_t r_r, size_t r_f, size_t r_e) { 78 | /* Previous and current write, read pointers and full, empty values */ 79 | static size_t p_r, p_w, p_f, p_e; 80 | size_t r, w, f, e; 81 | 82 | r = buff.r; 83 | w = buff.w; 84 | f = ringbuff_get_full(&buff); 85 | e = ringbuff_get_free(&buff); 86 | 87 | printf("R: %3d, W: %3d, F: %3d, E: %3d\r\n", (int)r, (int)w, (int)f, (int)e); 88 | } 89 | -------------------------------------------------------------------------------- /dev/VisualStudio/ringbuff_dev.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28803.452 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ringbuff_dev", "ringbuff_dev.vcxproj", "{65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Debug|x64.ActiveCfg = Debug|Win32 17 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Debug|x64.Build.0 = Debug|Win32 18 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Debug|x86.Build.0 = Debug|Win32 20 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Release|x64.ActiveCfg = Release|x64 21 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Release|x64.Build.0 = Release|x64 22 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Release|x86.ActiveCfg = Release|Win32 23 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {BB6333C1-478F-4F2D-978B-B829AF08272D} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /dev/VisualStudio/ringbuff_dev.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {65B0BF4D-8CA6-48F2-8B0B-6BFD456AA57B} 24 | Win32Proj 25 | ringbuff_dev 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | ..\..\ringbuff\src\include\;$(IncludePath) 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | 94 | 95 | Console 96 | 97 | 98 | 99 | 100 | 101 | 102 | Level3 103 | Disabled 104 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | 106 | 107 | Console 108 | 109 | 110 | 111 | 112 | Level3 113 | 114 | 115 | MaxSpeed 116 | true 117 | true 118 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 119 | 120 | 121 | Console 122 | true 123 | true 124 | 125 | 126 | 127 | 128 | Level3 129 | 130 | 131 | MaxSpeed 132 | true 133 | true 134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | 136 | 137 | Console 138 | true 139 | true 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /dev/VisualStudio/ringbuff_dev.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/api-reference/index.rst: -------------------------------------------------------------------------------- 1 | .. _api_reference: 2 | 3 | API reference 4 | ============= 5 | 6 | List of all the modules: 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | ringbuff -------------------------------------------------------------------------------- /docs/api-reference/ringbuff.rst: -------------------------------------------------------------------------------- 1 | .. _api_ringbuff: 2 | 3 | Ring buffer 4 | =========== 5 | 6 | .. doxygengroup:: RINGBUFF -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | from sphinx.builders.html import StandaloneHTMLBuilder 17 | import subprocess, os 18 | 19 | # Run doxygen first 20 | # read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True' 21 | # if read_the_docs_build: 22 | subprocess.call('doxygen doxyfile.doxy', shell=True) 23 | # -- Project information ----------------------------------------------------- 24 | 25 | project = 'Ringbuffer' 26 | copyright = '2020, Tilen MAJERLE' 27 | author = 'Tilen MAJERLE' 28 | 29 | # The full version, including alpha/beta/rc tags 30 | version = '1.3.1' 31 | 32 | # Try to get branch at which this is running 33 | # and try to determine which version to display in sphinx 34 | git_branch = '' 35 | res = os.popen('git branch').read().strip() 36 | for line in res.split("\n"): 37 | if line[0] == '*': 38 | git_branch = line[1:].strip() 39 | 40 | # Decision for display version 41 | try: 42 | if git_branch.index('develop') >= 0: 43 | version = "latest-develop" 44 | except Exception: 45 | print("Exception for index check") 46 | 47 | # For debugging purpose 48 | print("GIT BRANCH: " + git_branch) 49 | print("VERSION: " + version) 50 | 51 | # -- General configuration --------------------------------------------------- 52 | 53 | # Add any Sphinx extension module names here, as strings. They can be 54 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 55 | # ones. 56 | extensions = [ 57 | 'sphinx.ext.autodoc', 58 | 'sphinx.ext.intersphinx', 59 | 'sphinx.ext.autosectionlabel', 60 | 'sphinx.ext.todo', 61 | 'sphinx.ext.coverage', 62 | 'sphinx.ext.mathjax', 63 | 'sphinx.ext.ifconfig', 64 | 'sphinx.ext.viewcode', 65 | 'sphinx_sitemap', 66 | 67 | 'breathe', 68 | ] 69 | 70 | # Add any paths that contain templates here, relative to this directory. 71 | templates_path = ['templates'] 72 | 73 | # List of patterns, relative to source directory, that match files and 74 | # directories to ignore when looking for source files. 75 | # This pattern also affects html_static_path and html_extra_path. 76 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 77 | 78 | highlight_language = 'c' 79 | 80 | # -- Options for HTML output ------------------------------------------------- 81 | 82 | # The theme to use for HTML and HTML Help pages. See the documentation for 83 | # a list of builtin themes. 84 | # 85 | html_theme = 'sphinx_rtd_theme' 86 | html_theme_options = { 87 | 'canonical_url': '', 88 | 'analytics_id': '', # Provided by Google in your dashboard 89 | 'display_version': True, 90 | 'prev_next_buttons_location': 'bottom', 91 | 'style_external_links': False, 92 | 93 | 'logo_only': False, 94 | 95 | # Toc options 96 | 'collapse_navigation': True, 97 | 'sticky_navigation': True, 98 | 'navigation_depth': 4, 99 | 'includehidden': True, 100 | 'titles_only': False 101 | } 102 | html_logo = 'static/images/logo.svg' 103 | github_url = 'https://github.com/MaJerle/ringbuff' 104 | html_baseurl = 'https://docs.majerle.eu/projects/ringbuff/' 105 | 106 | # Add any paths that contain custom static files (such as style sheets) here, 107 | # relative to this directory. They are copied after the builtin static files, 108 | # so a file named "default.css" will overwrite the builtin "default.css". 109 | html_static_path = ['static'] 110 | html_css_files = [ 111 | 'css/common.css', 112 | 'css/custom.css', 113 | ] 114 | html_js_files = [ 115 | 'https://kit.fontawesome.com/3102794088.js' 116 | ] 117 | 118 | master_doc = 'index' 119 | 120 | # 121 | # Breathe configuration 122 | # 123 | # 124 | # 125 | breathe_projects = { 126 | "ringbuff": "_build/xml/" 127 | } 128 | breathe_default_project = "ringbuff" 129 | breathe_default_members = ('members', 'undoc-members') -------------------------------------------------------------------------------- /docs/examples_src/example_advance_1.c: -------------------------------------------------------------------------------- 1 | /* Declare buffer variables */ 2 | ringbuff_t buff; 3 | uint8_t buff_data[8]; 4 | 5 | size_t len; 6 | uint8_t* data; 7 | 8 | /* Initialize buffer, use buff_data as data array */ 9 | ringbuff_init(&buff, buff_data, sizeof(buff_data)); 10 | 11 | /* Use write, read operations, process data */ 12 | /* ... */ 13 | 14 | /* IMAGE PART A */ 15 | 16 | /* At this stage, we have buffer as on image above */ 17 | /* R = 4, W = 4, buffer is considered empty */ 18 | 19 | /* Get length of linear memory at write pointer */ 20 | /* Function returns 4 as we can write 4 bytes to buffer in sequence */ 21 | /* When function returns 0, there is no memory available in the buffer for write anymore */ 22 | if ((len = ringbuff_get_linear_block_write_length(&buff)) > 0) { 23 | /* Get pointer to first element in linear block at write address */ 24 | /* Function returns &buff_data[4] */ 25 | data = ringbuff_get_linear_block_write_address(&buff); 26 | 27 | /* Receive data via DMA and wait to finish (for sake of example) */ 28 | /* Any other hardware may directly write to data array */ 29 | /* Data array has len bytes length */ 30 | /* Or use memcpy(data, my_array, len); */ 31 | receive_data(data, len); 32 | 33 | /* Now advance buffer for written bytes to buffer = move write pointer */ 34 | /* Write pointer is moved for len bytes */ 35 | ringbuff_advance(&buff, len); 36 | 37 | /* Now W points to top of buffer, W = 0 */ 38 | /* At this point, we are at image part B */ 39 | } 40 | 41 | /* IMAGE PART B */ 42 | 43 | /* Get length of linear memory at write pointer */ 44 | /* Function returns 3 as we can write 3 bytes to buffer in sequence */ 45 | /* When function returns 0, there is no memory available in the buffer for write anymore */ 46 | if ((len = ringbuff_get_linear_block_read_length(&buff)) > 0) { 47 | /* Get pointer to first element in linear block at write address */ 48 | /* Function returns &buff_data[0] */ 49 | data = ringbuff_get_linear_block_read_address(&buff); 50 | 51 | /* Receive data via DMA and wait to finish (for sake of example) */ 52 | /* Any other hardware may directly write to data array */ 53 | /* Data array has len bytes length */ 54 | /* Or use memcpy(data, my_array, len); */ 55 | receive_data(data, len); 56 | 57 | /* Now advance buffer for written bytes to buffer = move write pointer */ 58 | /* Write pointer is moved for len bytes */ 59 | ringbuff_advance(&buff, len); 60 | 61 | /* Now W points to 3, R points to 4, that is R == W + 1 and buffer is now full */ 62 | /* At this point, we are at image part C */ 63 | } 64 | 65 | /* IMAGE PART C */ 66 | 67 | /* Buffer is considered full as R == W + 1 */ -------------------------------------------------------------------------------- /docs/examples_src/example_advance_2.c: -------------------------------------------------------------------------------- 1 | #include "ringbuff/ringbuff.h" 2 | 3 | /* Buffer variables */ 4 | ringbuff_t buff; /* Declare ring buffer structure */ 5 | uint8_t buff_data[8]; /* Declare raw buffer data array */ 6 | 7 | /* Application variables 8 | uint8_t data[2]; /* Application working data */ 9 | 10 | /* Application code ... */ 11 | ringbuff_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */ 12 | 13 | /* Write 4 bytes of data */ 14 | ringbuff_write(&buff, "0123", 4); 15 | 16 | /* Print number of bytes in buffer */ 17 | printf("Bytes in buffer: %d\r\n", (int)ringbuff_get_full(&buff)); 18 | 19 | /* Will print "4" */ -------------------------------------------------------------------------------- /docs/examples_src/example_dma_skip.c: -------------------------------------------------------------------------------- 1 | /* Buffer */ 2 | ringbuff_t buff; 3 | uint8_t buff_data[8]; 4 | 5 | /* Working data length */ 6 | size_t len; 7 | 8 | /* Send data function */ 9 | void send_data(void); 10 | 11 | int 12 | main(void) { 13 | /* Initialize buffer */ 14 | ringbuff_init(&buff, buff_data, sizeof(buff_data)); 15 | 16 | /* Write 4 bytes of data */ 17 | ringbuff_write(&buff, "0123", 4); 18 | 19 | /* Send data over DMA */ 20 | send_data(); 21 | 22 | while (1); 23 | } 24 | 25 | /* Send data over DMA */ 26 | void 27 | send_data(void) { 28 | /* If len > 0, DMA transfer is on-going */ 29 | if (len > 0) { 30 | return; 31 | } 32 | 33 | /* Get maximal length of buffer to read data as linear memory */ 34 | len = ringbuff_get_linear_block_read_length(&buff); 35 | if (len > 0) { 36 | /* Get pointer to read memory */ 37 | uint8_t* data = ringbuff_get_linear_block_read_address(&buff); 38 | 39 | /* Start DMA transfer */ 40 | start_dma_transfer(data, len); 41 | } 42 | 43 | /* Function does not wait for transfer to finish */ 44 | } 45 | 46 | /* Interrupt handler */ 47 | /* Called on DMA transfer finish */ 48 | void 49 | DMA_Interrupt_handler(void) { 50 | /* Transfer finished */ 51 | if (len > 0) { 52 | /* Now skip the data (move read pointer) as they were successfully transferred over DMA */ 53 | ringbuff_skip(&buff, len); 54 | 55 | /* Reset length = DMA is not active */ 56 | len = 0; 57 | 58 | /* Try to send more */ 59 | send_data(); 60 | } 61 | } -------------------------------------------------------------------------------- /docs/examples_src/example_events.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Buffer event function 3 | */ 4 | void 5 | my_buff_evt_fn(ringbuff_t* buff, ringbuff_evt_type_t type, size_t len) { 6 | switch (type) { 7 | case RINGBUFF_EVT_RESET: 8 | printf("[EVT] Buffer reset event!\r\n"); 9 | break; 10 | case RINGBUFF_EVT_READ: 11 | printf("[EVT] Buffer read event: %d byte(s)!\r\n", (int)len); 12 | break; 13 | case RINGBUFF_EVT_WRITE: 14 | printf("[EVT] Buffer write event: %d byte(s)!\r\n", (int)len); 15 | break; 16 | default: break; 17 | } 18 | } 19 | 20 | /* Later in the code... */ 21 | ringbuff_t buff; 22 | uint8_t buff_data[8]; 23 | 24 | /* Init buffer and set event function */ 25 | ringbuff_init(&buff, buff_data, sizeof(buff_data)); 26 | ringbuff_set_evt_fn(&buff, my_buff_evt_fn); 27 | -------------------------------------------------------------------------------- /docs/examples_src/example_index.c: -------------------------------------------------------------------------------- 1 | /* Buffer variables */ 2 | ringbuff_t buff; /* Declare ring buffer structure */ 3 | uint8_t buff_data[8]; /* Declare raw buffer data array */ 4 | 5 | /* Application variables */ 6 | uint8_t data[2]; /* Application working data */ 7 | size_t len; 8 | 9 | /* Application code ... */ 10 | ringbuff_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */ 11 | 12 | /* Write 4 bytes of data */ 13 | ringbuff_write(&buff, "0123", 4); 14 | 15 | /* Try to read buffer */ 16 | /* len holds number of bytes read */ 17 | /* Read until len == 0, when buffer is empty */ 18 | while ((len = ringbuff_read(&buff, data, sizeof(data))) > 0) { 19 | printf("Successfully read %d bytes\r\n", (int)len); 20 | } -------------------------------------------------------------------------------- /docs/examples_src/example_minimal.c: -------------------------------------------------------------------------------- 1 | #include "ringbuff/ringbuff.h" 2 | 3 | /* Buffer variables */ 4 | ringbuff_t buff; /* Declare ring buffer structure */ 5 | uint8_t buff_data[8]; /* Declare raw buffer data array */ 6 | 7 | /* Application variables 8 | uint8_t data[2]; /* Application working data */ 9 | 10 | /* Application code ... */ 11 | ringbuff_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */ 12 | 13 | /* Write 4 bytes of data */ 14 | ringbuff_write(&buff, "0123", 4); 15 | 16 | /* Print number of bytes in buffer */ 17 | printf("Bytes in buffer: %d\r\n", (int)ringbuff_get_full(&buff)); 18 | 19 | /* Will print "4" */ -------------------------------------------------------------------------------- /docs/examples_src/example_skip_1.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ringbuff/ringbuff.h" 3 | 4 | /* Declare buffer variables */ 5 | ringbuff_t buff; 6 | uint8_t buff_data[8]; 7 | 8 | size_t len; 9 | uint8_t* data; 10 | 11 | /* Initialize buffer, use buff_data as data array */ 12 | ringbuff_init(&buff, buff_data, sizeof(buff_data)); 13 | 14 | /* Use write, read operations, process data */ 15 | /* ... */ 16 | 17 | /* IMAGE PART A */ 18 | 19 | /* At this stage, we have buffer as on image above */ 20 | /* R = 5, W = 4, buffer is considered full */ 21 | 22 | /* Get length of linear memory at read pointer */ 23 | /* Function returns 3 as we can read 3 bytes from buffer in sequence */ 24 | /* When function returns 0, there is no memory available in the buffer for read anymore */ 25 | if ((len = ringbuff_get_linear_block_read_length(&buff)) > 0) { 26 | /* Get pointer to first element in linear block at read address */ 27 | /* Function returns &buff_data[5] */ 28 | data = ringbuff_get_linear_block_read_address(&buff); 29 | 30 | /* Send data via DMA and wait to finish (for sake of example) */ 31 | send_data(data, len); 32 | 33 | /* Now skip sent bytes from buffer = move read pointer */ 34 | ringbuff_skip(&buff, len); 35 | 36 | /* Now R points to top of buffer, R = 0 */ 37 | /* At this point, we are at image part B */ 38 | } 39 | 40 | /* IMAGE PART B */ 41 | 42 | /* Get length of linear memory at read pointer */ 43 | /* Function returns 4 as we can read 4 bytes from buffer in sequence */ 44 | /* When function returns 0, there is no memory available in the buffer for read anymore */ 45 | if ((len = ringbuff_get_linear_block_read_length(&buff)) > 0) { 46 | /* Get pointer to first element in linear block at read address */ 47 | /* Function returns &buff_data[0] */ 48 | data = ringbuff_get_linear_block_read_address(&buff); 49 | 50 | /* Send data via DMA and wait to finish (for sake of example) */ 51 | send_data(data, len); 52 | 53 | /* Now skip sent bytes from buffer = move read pointer */ 54 | /* Read pointer is moved for len bytes */ 55 | ringbuff_skip(&buff, len); 56 | 57 | /* Now R points to 4, that is R == W and buffer is now empty */ 58 | /* At this point, we are at image part C */ 59 | } 60 | 61 | /* IMAGE PART C */ 62 | 63 | /* Buffer is considered empty as R == W */ -------------------------------------------------------------------------------- /docs/examples_src/example_skip_2.c: -------------------------------------------------------------------------------- 1 | /* Initialization part skipped */ 2 | 3 | /* Get length of linear memory at read pointer */ 4 | /* When function returns 0, there is no memory available in the buffer for read anymore */ 5 | while ((len = ringbuff_get_linear_block_read_length(&buff)) > 0) { 6 | /* Get pointer to first element in linear block at read address */ 7 | data = ringbuff_get_linear_block_read_address(&buff); 8 | 9 | /* If max length needs to be considered */ 10 | /* simply decrease it and use smaller len on skip function */ 11 | if (len > max_len) { 12 | len = max_len; 13 | } 14 | 15 | /* Send data via DMA and wait to finish (for sake of example) */ 16 | send_data(data, len); 17 | 18 | /* Now skip sent bytes from buffer = move read pointer */ 19 | ringbuff_skip(&buff, len); 20 | } -------------------------------------------------------------------------------- /docs/examples_src/example_tt_buff_size.c: -------------------------------------------------------------------------------- 1 | #include "ringbuff/ringbuff.h" 2 | 3 | /* Number of data blocks to write */ 4 | #define N 3 5 | 6 | /* Create custom data structure */ 7 | /* Data is array of 2 32-bit words, 8-bytes */ 8 | uint32_t d[2]; 9 | 10 | /* Create buffer structures */ 11 | ringbuff_t buff_1; 12 | ringbuff_t buff_2; 13 | 14 | /* Create data for buffers. Use sizeof structure, multiplied by N (for N instances) */ 15 | /* Buffer with + 1 bytes bigger memory */ 16 | uint8_t buff_data_1[sizeof(d) * N + 1]; 17 | /* Buffer without + 1 at the end */ 18 | uint8_t buff_data_2[sizeof(d) * N]; 19 | 20 | /* Write result values */ 21 | size_t len_1; 22 | size_t len_2; 23 | 24 | /* Initialize buffers */ 25 | ringbuff_init(&buff_1, buff_data_1, sizeof(buff_data_1)); 26 | ringbuff_init(&buff_2, buff_data_2, sizeof(buff_data_2)); 27 | 28 | /* Write data to buffer */ 29 | for (size_t i = 0; i < N; ++i) { 30 | /* Prepare data */ 31 | d.a = i; 32 | d.b = i * 2; 33 | 34 | /* Write data to both buffers, memory copy from d to buffer */ 35 | len_1 = ringbuff_write(&buff_1, d, sizeof(d)); 36 | len_2 = ringbuff_write(&buff_2, d, sizeof(d)); 37 | 38 | /* Print results */ 39 | printf("Write buffer 1: %d/%d bytes; buffer 2: %d/%d\r\n", 40 | (int)len_1, (int)sizeof(d), 41 | (int)len_2, (int)sizeof(d)); 42 | } -------------------------------------------------------------------------------- /docs/examples_src/example_tt_buff_size_log.c: -------------------------------------------------------------------------------- 1 | Write: buffer 1: 8/8; buffer 2: 8/8 2 | Write: buffer 1: 8/8; buffer 2: 8/8 3 | Write: buffer 1: 8/8; buffer 2: 7/8 <-- See here --> -------------------------------------------------------------------------------- /docs/get-started/index.rst: -------------------------------------------------------------------------------- 1 | .. _getting_started: 2 | 3 | Getting started 4 | =============== 5 | 6 | .. _download_library: 7 | 8 | Download library 9 | ^^^^^^^^^^^^^^^^ 10 | 11 | Library is primarly hosted on `Github `_. 12 | 13 | * Download latest release from `releases area `_ on Github 14 | * Clone `develop` branch for latest development 15 | 16 | Download from releases 17 | ********************** 18 | 19 | All releases are available on Github `releases area `_. 20 | 21 | Clone from Github 22 | ***************** 23 | 24 | First-time clone 25 | """""""""""""""" 26 | 27 | * Download and install ``git`` if not already 28 | * Open console and navigate to path in the system to clone repository to. Use command ``cd your_path`` 29 | * Clone repository with one of available ``3`` options 30 | 31 | * Run ``git clone --recurse-submodules https://github.com/MaJerle/ringbuff`` command to clone entire repository, including submodules 32 | * Run ``git clone --recurse-submodules --branch develop https://github.com/MaJerle/ringbuff`` to clone `development` branch, including submodules 33 | * Run ``git clone --recurse-submodules --branch master https://github.com/MaJerle/ringbuff`` to clone `latest stable` branch, including submodules 34 | 35 | * Navigate to ``examples`` directory and run favourite example 36 | 37 | Update cloned to latest version 38 | """"""""""""""""""""""""""""""" 39 | 40 | * Open console and navigate to path in the system where your resources repository is. Use command ``cd your_path`` 41 | * Run ``git pull origin master --recurse-submodules`` command to pull latest changes and to fetch latest changes from submodules 42 | * Run ``git submodule foreach git pull origin master`` to update & merge all submodules 43 | 44 | .. note:: 45 | This is preferred option to use when you want to evaluate library and run prepared examples. 46 | Repository consists of multiple submodules which can be automatically downloaded when cloning and pulling changes from root repository. 47 | 48 | Add library to project 49 | ^^^^^^^^^^^^^^^^^^^^^^ 50 | 51 | At this point it is assumed that you have successfully download library, either cloned it or from releases page. 52 | 53 | * Copy ``ringbuff`` folder to your project 54 | * Add ``ringbuff/src/include`` folder to `include path` of your toolchain 55 | * Add source files from ``ringbuff/src/`` folder to toolchain build 56 | * Build the project 57 | 58 | Minimal example code 59 | ^^^^^^^^^^^^^^^^^^^^ 60 | 61 | Run below example to test and verify library 62 | 63 | .. literalinclude:: ../examples_src/example_minimal.c 64 | :language: c 65 | :linenos: 66 | :caption: Minimal example code -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Ringbuffer |version| documentation 2 | ================================== 3 | 4 | Welcome to the documentation for version |version|. 5 | 6 | Ring buffer is a generic *FIFO* (First In; First Out) buffer library optimized for embedded systems. 7 | 8 | .. image:: static/images/logo.svg 9 | :align: center 10 | 11 | .. rst-class:: center 12 | .. rst-class:: index_links 13 | 14 | :ref:`download_library` · :ref:`getting_started` · `Open Github `_ 15 | 16 | Features 17 | ^^^^^^^^ 18 | 19 | * Written in ANSI C99, compatible with ``size_t`` for size data types 20 | * Platform independent, no architecture specific code 21 | * FIFO (First In First Out) buffer implementation 22 | * No dynamic memory allocation, data is static array 23 | * Uses optimized memory copy instead of loops to read/write data from/to memory 24 | * Thread safe when used as pipe with single write and single read entries 25 | * Interrupt safe when used as pipe with single write and single read entries 26 | * Suitable for DMA transfers from and to memory with zero-copy overhead between buffer and application memory 27 | * Supports data peek, skip for read and advance for write 28 | * Implements support for event notifications 29 | * User friendly MIT license 30 | 31 | Requirements 32 | ^^^^^^^^^^^^ 33 | 34 | * C compiler 35 | * Less than ``1kB`` of non-volatile memory 36 | 37 | Contribute 38 | ^^^^^^^^^^ 39 | 40 | Fresh contributions are always welcome. Simple instructions to proceed: 41 | 42 | #. Fork Github repository 43 | #. Respect `C style & coding rules `_ used by the library 44 | #. Create a pull request to ``develop`` branch with new features or bug fixes 45 | 46 | Alternatively you may: 47 | 48 | #. Report a bug 49 | #. Ask for a feature request 50 | 51 | Example code 52 | ^^^^^^^^^^^^ 53 | 54 | Minimalistic example code to read and write data to buffer 55 | 56 | .. literalinclude:: examples_src/example_index.c 57 | :language: c 58 | :linenos: 59 | :caption: Example code 60 | 61 | License 62 | ^^^^^^^ 63 | 64 | .. literalinclude:: ../LICENSE 65 | 66 | Table of contents 67 | ^^^^^^^^^^^^^^^^^ 68 | 69 | .. toctree:: 70 | :maxdepth: 2 71 | 72 | self 73 | get-started/index 74 | user-manual/index 75 | tips-tricks/index 76 | api-reference/index 77 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | breathe>=4.9.1 2 | colorama 3 | docutils>=0.14 4 | sphinx>=2.0.1 5 | sphinx_rtd_theme 6 | sphinx-tabs 7 | sphinxcontrib-svg2pdfconverter 8 | sphinx-sitemap 9 | -------------------------------------------------------------------------------- /docs/static/css/common.css: -------------------------------------------------------------------------------- 1 | /* Center aligned text */ 2 | .center { 3 | text-align: center; 4 | } 5 | 6 | /* Paragraph with main links on index page */ 7 | .index-links { 8 | text-align: center; 9 | margin-top: 10px; 10 | } 11 | .index-links a { 12 | display: inline-block; 13 | border: 1px solid #0E4263; 14 | padding: 5px 20px; 15 | background: #2980B9; 16 | border-radius: 4px; 17 | color: #FFFFFF; 18 | } 19 | .index-links a:hover, .index-links a:active { 20 | background: #0E4263; 21 | } 22 | 23 | .index-links a table thead th { 24 | vertical-align: middle; 25 | } 26 | 27 | table thead th p { 28 | margin: 0; 29 | } 30 | 31 | /* Breathe output changes */ 32 | .breathe-sectiondef.container { 33 | background: #f9f9f9; 34 | padding: 10px; 35 | margin-bottom: 10px; 36 | border: 1px solid #efefef; 37 | } 38 | .breathe-sectiondef.container .breathe-sectiondef-title { 39 | background: #2980b9; 40 | color: #FFFFFF; 41 | padding: 4px; 42 | margin: -10px -10px 0 -10px; 43 | } 44 | .breathe-sectiondef.container .function, 45 | .breathe-sectiondef.container .member, 46 | .breathe-sectiondef.container .class, 47 | .breathe-sectiondef.container .type { 48 | border-bottom: 1px solid #efefef; 49 | } 50 | .breathe-sectiondef.container .function:last-child, 51 | .breathe-sectiondef.container .member:last-child, 52 | .breathe-sectiondef.container .class:last-child, 53 | .breathe-sectiondef.container .type:last-child { 54 | border-bottom: none; 55 | margin-bottom: 0; 56 | } 57 | 58 | /*# sourceMappingURL=common.css.map */ 59 | -------------------------------------------------------------------------------- /docs/static/css/custom.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuzhl2018/LwRB/3c8d3396e0c5c2cb4a63528811fa4c65f2c34f48/docs/static/css/custom.css -------------------------------------------------------------------------------- /docs/static/images/buff_cases.svg: -------------------------------------------------------------------------------- 1 | 2 |
R
R
W
[Not supported by viewer]
R
R
W
[Not supported by viewer]
R
R
W
[Not supported by viewer]
R
R
W
[Not supported by viewer]
R
R
W
[Not supported by viewer]
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
0
0
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
7
7
B
B
A
A
C
C
D
D
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
E
E
-------------------------------------------------------------------------------- /docs/static/images/buff_cases.xml: -------------------------------------------------------------------------------- 1 | 7ZxNc6JAEIZ/DcdUCcMMeIwas3vYy6ZqU7uXLQKjUEHHRYxmf/3yMSjSWpWtBHrI4MHCHuSjH3q631YwyHR1uE+8TfhNBDw2rFFwMMjMsKwxM7P33PBaGhiVhmUSBaWpZniI/nJpHEnrLgr49mzFVIg4jTbnRl+s19xPz2xekoj9+WoLEZ/vdeMtOTA8+F4MrY9RkIbSarLxaeALj5ah3LVrOeXAk+c/LxOxW8v9GRZZFK9yeOVV25Inug29QOxrJnJnkGkiRFourQ5THueurdxWfm9+ZfR43Alfp2/5wtfJ7JfnRL8PP/f3u5C8hOmP+Y1Dys28ePFOOuS7PNz0tXJRcZI838zIIJN9GKX8YeP5+eg+uyYyW5iu4uyTmS0uxDqVlM189UUUx1MRi6TYFvF9TjMXkck2TcQzr43MzfF0PD6OVDCO25THc+G8pemFJyk/1EzSD/dcrHiavGaryFHblkzkNWu68vP+dAVU2MIa+8rmyWtuedzyye/ZgnT9/2CwAYZHw2Jxtt/JU5ItLfOlVsEsFr5fcz8OGGo1wNjIYGwIRoP4MBvxgR0eNh3Co3CwpRYXqmX2sBSLDjokj2KUNJMHQwbDtAwPolh4sCE8yqK3ER5Hj2OBqS4MvcKDqqY9XBNg0DI+mGrpA2YPs86lBoP92eVdhMIlN9vCz7fZCuZocyjQVePtwIRormNsgJ8WrzYUDGvAHEGYrFOYLqBpaYjhQs7pFsMYYCAaYrjQVukUgw1TP9MPg4U9Kdkw9VP9MFyqwLrFYAEMtoYYLtRb3WKABZejH4ZLsrBTDHBOGr2fwtxbRXF+hrdJ5MU9RYM+TzGARk1F0gAUUO4GNnbXWDVFYjuA5gcrkl5gwJ7ubCgMP1iR9AIDuiKBwlADRdLEgK5IKBSGGigSEA3YmZ7CIkwDRQIwYCsSCoWhBooETErYKZrCv590IUn6kLfRJ6pBkrzjl3rVJAnVUpIADOjznZaSBGDAliS0dUnSBwzokqTaWXuSpA8Y0CUJa12S9AIDtiRhQy18jQ16hAy18Dv+HalaLcy0rIUBBuxamLVeC6vYggEYsGthpmUt3MSAXgs7WtbCIBqwM72jZXseYMCuhR0LYPjg9nwfogG9Pe8MkuQaG+yJirUeISpOVKCFhR4hUBlqcA/I8eqvMFCIodunPEBJd/v5MZjKYYCSbvr5MRDlMEBJN/v8GGzVMLgwRQ9dwzffzKta19CF9zBo0DUEGLALLhc+c0CDX9ABBuyuoQuVoQZdwyYG9K6hC+WHBl1DEA3YYtyF8kODriHAgN01dKH80KBrCCYl9BQN5YeuXcMmG+yJagx/ZbrTYKLqThlmH0/PnS3Gas/2JXf/AA== -------------------------------------------------------------------------------- /docs/static/images/buff_lin_read_skip.svg: -------------------------------------------------------------------------------- 1 | 2 |
R
R
W
[Not supported by viewer]
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
A
A
R
R
W
[Not supported by viewer]
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
B
B
R
R
W
[Not supported by viewer]
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
C
[Not supported by viewer]
6
6
-------------------------------------------------------------------------------- /docs/static/images/buff_lin_read_skip.xml: -------------------------------------------------------------------------------- 1 | 7VvLbqMwFP0alpWwDZQsG/qSRpGidtHHZkTBBFQnzhBnQubrh4edkNxU09EUTN1hEZlrx8bnXIzPSbBIMC9u8nCZTnhMmYXtuLDIpYUxcf3yswpsm4Dr2U1glmdxE0L7wH32i8qgarbOYro6aCg4ZyJbHgYjvljQSBzEwjznm8NmCWeHoy7DGQWB+yhkMPqQxSKVUeSN9hW3NJulcmgfnzcVL2H0Osv5eiHHszBJ6qOpnoeqLznRVRrGfNMKkSuLBDnnoinNi4CyCloFW/O96zdqd9ed04V4zxe28dofrZ+L6ZOYTsbf2eOteD6TvfwM2VricSevVmwVQvUcadWLbZHxJs0EvV+GUVW7KVOijKVizsozVBYTvhCSZFQ1TzLGAs54XvdFooi6JUJkvBI5f6Wtmms0CkYj1YMc/cQk1RXTXNCiFZKTvqF8TkW+LZuoWpWQMkGRL883e7oVR2mLaBULZYLNdj3vQS4LEue/wBwDzB8s7LFy2PFLXpZmValTFpIkimqs+2MBO0cseJpZIIAF1GahBb33Y13dozUkZ6sa1YuyAbKXRU2Uqu+Futilfuz0ewP5R9TZkDqvT+ocQB02HnOsGXMXYE6Mx9zRjLkHMPdMxxzrXlvOAeau6Zif2hD1irkPMHc+FvP3YgvYCepj90z/WNhP7IB6hX0EYD83PdWx7seoUr0t0O1/B/06nGesmuJFnoXsUzChe81BUPledJr9u6WkR81lH2W/q1lzISh9jbMbsPfHRO8Xcyh0v4DdQIZmNyAoWv/7DW/cQUPzGxAUv8YZDgB07TslqH6NcxwA6LodBwTlb7eWg45d0dAsBwT1b7eewwBA1+45IKh+TTQdAO66TQfVcW+uwwCSXbvrgKHY/RquwzETulcdtW9sEdHt9l1D9pOhuQ4YKmDjXAdy/CcH3XoXQ737BWwHZ2i2A4bS9VPYDjrWraHZDhgq4G5thyGArn2rBBVwt7bDEEDXbTtgqICNsx2OQdduO2CogI2zHUCm6xYABMpfE20HgLtu24FABWyc7QBWGN3PUgLVrgbbYQBMaF91oAIOehZjGlhwNBoR3ybu5dkVWhXTu0f+xJPpZLI69feHIW5zAMIneBjCryvl6f7tmbqu9YYSufoN -------------------------------------------------------------------------------- /docs/static/images/buff_lin_write_advance.svg: -------------------------------------------------------------------------------- 1 | 2 |
R
R
W
[Not supported by viewer]
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
A
A
R
R
W
[Not supported by viewer]
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
B
B
R
R
W
[Not supported by viewer]
1
[Not supported by viewer]
2
2
3
3
6
6
5
5
4
4
7
7
0
0
C
[Not supported by viewer]
-------------------------------------------------------------------------------- /docs/static/images/buff_lin_write_advance.xml: -------------------------------------------------------------------------------- 1 | 7ZvPc6IwFID/Go47QxKgemzZ2r3sZXvomUIEptG4MVbdv375kSj6cLYzuzxsXA8deEmI+V4I+QbrsXixe1LJqvguMy486mc7j331KA2YX/2tA/s2EN2RNpCrMmtDncBz+YuboGmXb8qMr08qaimFLlenwVQulzzVJ7FEKbk9rTaX4rTXVZJzEHhOEwGjL2WmizY6Cf1j/Bsv88L2THxT8pqkb7mSm6Xpz6Ns3nza4kVir2Xqr4skk9tOiD16LFZS6vZosYu5qNFabG272YXSw/dWfKk/0oC2Dd4TsTFD/2G+mN5bGM1weN3A99jDtig1f14laV26rbJfxQq9ENUZqQ7ncqlNPkldfV4KEUshVXMtlqY8rGCwh7VW8o13SmZkGk+n9gqm957xmNA7V5rvOiEzvicuF1yrfVXFlkaG9f7sfHvMrE1H0UmqjSVmLuWHKx95VgcGaT9eBvC+eDQSVQ8Pr6o6yuujQYHP52naYMUDToPxgAcAOOkC71COfm7qm6wZ/Zd1A/C+qkD81a7JiS1HyVLcfHBvi8lZlnyYpWigLIUgS9R5vBQPbwTwMufxBnh47wDeyHW8FHFxmAC8oet4D+cIeKcAb/Bv8X4U4+VEDEG4Zw8yFGErMR3Ed67PYIr4eCME8PX/nu8sWZSiHs29KhPxKaAjrhoEiuK9a3P68JCzczqEfIfyFgJN0TkRpyOKOIFieAMmzoI/LhiDAYeO99/EL9wXI5o4ga7onIoDvph7FSiLzrk44Ivo4gTa4rAynoV8kgWj8sWUcQJ1cVgbvwK+mDZurzGcjl8hX0QXp9AVh3XxK+CL6eJ2t3BzLn4OHXPNgK7o3J6YjejiPS8RnXNxNqKL97z+uwEXD87fivfskgcjDi3vU8j4CA9TNqKM97xZHFbGr4Ev5mYFyqJzMg74Isp4z7tF52T8nC+mjNtfVbos42D+Im6sGZRF52Qc8EWUcQZl0TkZB+sD4vONQTEcQcavADrmmgFlMUaWmRF2GQGenlenx5/DN2Wdfzlgj78B -------------------------------------------------------------------------------- /docs/static/images/logo.drawio: -------------------------------------------------------------------------------- 1 | 7Ztdb+I4FIZ/DZcT+TOOL1vo7FzsaitVq53Zu0BciCbgKqQF5tevQ2ywHVoMGSgSZKQRPnFO6vM+do5PoIf70+UfZfoy+UtmoughkC17eNBDKCGJ+r82rBoDSWBjGJd51pgsw1P+SzRGqo2veSbmTr9KyqLKX1zjSM5mYlQ5trQs5cLt9iwL96Yv6Vi0DE+jtGhb/82zaqJHRcHW/k3k44m5MwT6zDQ1nbVhPkkzubC84oce7pdSVs2n6bIvijp0JizNdV/fObv5w0oxq0IueC7/q379vRp8m/74p+intH+XD75g1Lh5S4tXPWL911YrEwLlRkVbNe4Xk7wSTy/pqD6zUHIr26SaFqoF1cd5VcqfmzCpAd4/50XRl4UsVXsmZ7WPLC+VTrmcKdNcvtZd79tD0aN7E2Ulln7MFGpCTkVVrlQXfRZzDYzGDHIaactiqxvEWoyJrZkxppqV8cb7Npzqg47oAdGFdH906yHmirc/06EoHuU817EZyqqSUxUc0+GuyMf1iUr6YZ+kL7Wz6XJcz8BomM7zUZSWo7UkaVndzcbru4FIBQnfi1m2tQDaEk6Fw1Wuh/Dz+th0tc7E66O+Qs4qy94cpxOcQOAIjiDYJTjYJTg4leAoYDqdVXDQEhx2FZwM6n/XJiy+MGFhS1jUVdgEDfF6Jl+VsOTChEUtYXFXYTPGhwBcm7CX9uzFLWFJZ2HjYUyvbsbGFyYsaQlLuwo7TCihVzdj2YUJS1vCxl2F5THD6Xln7KfLmlyYrHFLVtZVVjRg8foJ622CNldc1TzmFyY4awmedBUcgPjh7utN8KaIBC5M8KQlOO8qeJ9hepvhRnC4X/Ajq4bwrFVDgtyqIUK7qoZsR3DZyWIbsCGt0a5r29v4WPFU0ShX39fUY0KM4UczDRJkDIM6BGDTWtmtR1HmajSiNMZlXhmPsW5rh0w3t+7qxspq+M7elU3pWo5EAHZqso9F9VFHHTKROcX9NgaWyHSHyMZWiiKt8jf3lcAu5fUdHmWuxralDLtzGJPNHDZOmrHr65BVxPdc4cRzxVuumui0XK1h3Ay9A58B++pQPmPKfD5hNz6b7bDNJ7kBuh9QyiMjowEL4IiA7eH5DOWVEB4xyLeHexOMI0its+y8KAdUEkJR5iBxUWY87oYyBy7KjMMbyvtRTlTkbODiFtYxs04fuQ4Tte4S0CbXAhvg88IcUD0JgxlGQL822sBM96GsqYUOsfRjXnfhf4XA8iQi7wOLFGiJtyyGQkqRopB4/CfqIXteMAPqP+GrrJcwIIAD0awvRg6eCByeG9yg1assj7h9uMwen99StK7P7fF2amIDCljhKW7sEgsgDybWz2YBim/EHr/MQuKBpXLTxMpxvQd2OLNIpRyuawyjhJ8VWhJQhAuvG3jPf4D21g2sEgH1oL0ts6dJZhFmEUYWwB2SWfOWxrgGLOLxp+3MSEiBMRBmwFHPyxnIPpg/3pkB7hJ+TCJxhTBTHkHv0a4Ahl42ekhlIfHcqeTW7OnPBSrqCqqm6ovCqsllD9k+fbcb4Vu13wgjCoURXhSMmHu5AD06ZSUYtLiOz52ykoDvJ4YvmF7Kynj4JgtwtwbA9r0heG+pvTFKAIliL69kICL2voscyyxx9m+UHnSbU8Mc8ArMvA1+LsRSU31vAT4q0vk8H/mMZ+Y1I40QZCozIBQQiig03+HSvz/BapuGFfYQYEISxOoJsdhcaqw0iRGIea/1GnmYjpIM93Z+b6A+PsL5QuDDnEV7F7Vg3NQO6dNXyIBi/w2qE69ovxMqelKoVHP706ym+/bnbfjhfw== -------------------------------------------------------------------------------- /docs/static/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/static/images/logo_tm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuzhl2018/LwRB/3c8d3396e0c5c2cb4a63528811fa4c65f2c34f48/docs/static/images/logo_tm.png -------------------------------------------------------------------------------- /docs/static/images/logo_tm_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuzhl2018/LwRB/3c8d3396e0c5c2cb4a63528811fa4c65f2c34f48/docs/static/images/logo_tm_full.png -------------------------------------------------------------------------------- /docs/tips-tricks/index.rst: -------------------------------------------------------------------------------- 1 | .. _tips_tricks: 2 | 3 | Tips & tricks 4 | ============= 5 | 6 | Application buffer size 7 | ^^^^^^^^^^^^^^^^^^^^^^^ 8 | 9 | Buffer size shall always be ``1`` byte bigger than anticipated data size. 10 | 11 | When application uses buffer for some data block ``N`` times, it is advised to set buffer size to ``1`` byte more than ``N * block_size`` is. 12 | This is due to ``R`` and ``W`` pointers alignment. 13 | 14 | .. note:: 15 | For more information, check :ref:`how_it_works`. 16 | 17 | .. literalinclude:: ../examples_src/example_tt_buff_size.c 18 | :language: c 19 | :linenos: 20 | :caption: Application buffer size assignment 21 | 22 | When the code is executed, it produces following output: 23 | 24 | .. literalinclude:: ../examples_src/example_tt_buff_size_log.c 25 | :caption: Application buffer size assignment output 26 | 27 | .. toctree:: 28 | :maxdepth: 2 -------------------------------------------------------------------------------- /docs/user-manual/events.rst: -------------------------------------------------------------------------------- 1 | .. _events: 2 | 3 | Events 4 | ====== 5 | 6 | When using ringbuffer in the application, it may be useful to get notification on different events, 7 | such as info when something has been written or read to/from buffer. 8 | 9 | Library has support for events that get called each time there has been a modification 10 | in the buffer data, that means on every read or write operation. 11 | 12 | Some use cases: 13 | 14 | * Notify application layer that ringbuffer operation has been executed and send debug message 15 | * Unlock semaphore when sufficient amount of bytes have been written/read from/to buffer when application uses operating system 16 | * Write notification to message queue at operating system level to wakeup another task 17 | 18 | .. note:: Every operation that modified `read` or `write` internal pointers, 19 | is considered as read or write operation. An exception is *reset* event that sets 20 | both internal pointers to `0` 21 | 22 | .. literalinclude:: ../examples_src/example_events.c 23 | :language: c 24 | :linenos: 25 | :caption: Example code for events 26 | 27 | .. toctree:: 28 | :maxdepth: 2 -------------------------------------------------------------------------------- /docs/user-manual/how-it-works.rst: -------------------------------------------------------------------------------- 1 | .. _how_it_works: 2 | 3 | How it works 4 | ============ 5 | 6 | This section shows different buffer corner cases and provides basic understanding how data are managed internally. 7 | 8 | .. figure:: ../static/images/buff_cases.svg 9 | :align: center 10 | :alt: Different buffer corner cases 11 | 12 | Different buffer corner cases 13 | 14 | Let's start with reference of abbreviations in picture: 15 | 16 | * ``R`` represents `Read` pointer. Read on read/write operations. Modified on read operation only 17 | * ``W`` represents `Write` pointer. Read on read/write operations. Modified on write operation only 18 | * ``S`` represents `Size` of buffer. Used on all operations, never modified (atomic value) 19 | 20 | * Valid number of ``W`` and ``R`` pointers are between ``0`` and ``S - 1`` 21 | 22 | * Buffer size is ``S = 8``, thus valid number range for ``W`` and ``R`` pointers is ``0 - 7``. 23 | 24 | * ``R`` and ``W`` numbers overflow at ``S``, thus valid range is always ``0, 1, 2, 3, ..., S - 2, S - 1, 0, 1, 2, 3, ..., S - 2, S - 1, 0, ...`` 25 | * Example ``S = 4``: ``0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ...`` 26 | 27 | * Maximal number of bytes buffer can hold is always ``S - 1``, thus example buffer can hold up to ``7`` bytes 28 | * ``R`` and ``W`` pointers always point to the next read/write operation 29 | * When ``W == R``, buffer is considered empty. 30 | * When ``W == R - 1``, buffer is considered full. 31 | 32 | * ``W == R - 1`` is valid only if ``W`` and ``R`` overflow at buffer size ``S``. 33 | * Always add ``S`` to calculated number and then use modulus ``S`` to get final value 34 | 35 | .. note:: 36 | 37 | Example 1, add ``2`` numbers: ``2 + 3 = (3 + 2 + S) % S = (3 + 2 + 4) % 4 = (5 + 4) % 4 = 1`` 38 | 39 | Example 2, subtract ``2`` numbers: ``2 - 3 = (2 - 3 + S) % S = (2 - 3 + 4) % 4 = (-1 + 4) % 4 = 3`` 40 | 41 | 42 | .. figure:: ../static/images/buff_cases.svg 43 | :align: center 44 | :alt: Different buffer corner cases 45 | 46 | Different buffer corner cases 47 | 48 | Different image cases: 49 | 50 | * Case **A**: Buffer is empty as ``W == R = 0 == 0`` 51 | * Case **B**: Buffer holds ``W - R = 4 - 0 = 4`` bytes as ``W > R`` 52 | * Case **C**: Buffer is full as ``W == R - 1`` or ``7 == 0 - 1`` or ``7 = (0 - 1 + S) % S = (0 - 1 + 8) % 8 = (-1 + 8) % 8 = 7`` 53 | 54 | * ``R`` and ``W`` can hold ``S`` different values, from ``0`` to ``S - 1``, that is modulus of ``S`` 55 | * Buffer holds ``W - R = 7 - 0 = 7`` bytes as ``W > R`` 56 | * Case **D**: Buffer holds ``S - (R - W) = 8 - (5 - 3) = 6`` bytes as ``R > W`` 57 | * Case **E**: Buffer is full as ``W == R - 1`` (``4 = 5 - 1``) and holds ``S - (R - W) = 8 - (5 - 4) ) = 7`` bytes 58 | 59 | 60 | .. toctree:: 61 | :maxdepth: 2 -------------------------------------------------------------------------------- /docs/user-manual/hw-dma-usage.rst: -------------------------------------------------------------------------------- 1 | DMA on embedded systems 2 | ======================= 3 | 4 | One of the key features of ringbuffer library is that it can be seamlessly integrated with DMA controllers on embedded systems. 5 | 6 | .. note:: 7 | 8 | DMA stands for *Direct Memory Access* controller and is usually used to off-load CPU. 9 | More about DMA is available on `Wikipedia `_. 10 | 11 | DMA controllers normally use source and destination memory addresses to transfer data in-between. 12 | This features, together with ringbuffer, allows seamless integration and zero-copy of application data at interrupts after DMA transfer has been completed. 13 | Some manual work is necessary to be handled, but this is very minor in comparison of writing byte-by-byte to buffer at (for example) each received character. 14 | 15 | Below are ``2`` common use cases: 16 | 17 | * DMA transfers data from ringbuffer memory to (usually) some hardware IP 18 | * DMA transfers data from hardware IP to memory 19 | 20 | Zero-copy data from memory 21 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 22 | 23 | This describes how to pass ringbuffer output memory address as pointer to DMA (or any other processing function). 24 | After all the data are successfully processed, application can skip processed data and free ringbuff for new data being written to it. 25 | 26 | .. figure:: ../static/images/buff_lin_read_skip.svg 27 | :align: center 28 | :alt: Data transfer from memory to hardware IP 29 | 30 | Data transfer from memory to hardware IP 31 | 32 | * Case **A**: Initial state, buffer is full and holds ``7`` bytes 33 | * Case **B**: State after skipping ``R`` pointer for ``3`` bytes. Buffer now holds ``4`` remaining bytes 34 | * Case **C**: Buffer is empty, no more memory available for read operation 35 | 36 | Code example: 37 | 38 | .. literalinclude:: ../examples_src/example_skip_1.c 39 | :language: c 40 | :linenos: 41 | :caption: Skip buffer data after usage 42 | 43 | Part **A** on image clearly shows that not all data bytes are linked in single contiguous block of memory. 44 | To send all bytes from ringbuff, it might be necessary to repeat procedure multiple times 45 | 46 | .. literalinclude:: ../examples_src/example_skip_2.c 47 | :language: c 48 | :linenos: 49 | :caption: Skip buffer data for non-contiguous block 50 | 51 | Zero-copy data to memory 52 | ^^^^^^^^^^^^^^^^^^^^^^^^ 53 | 54 | Similar to reading data from buffer with zero-copy overhead, it is possible to write to ringbuff with zero-copy overhead too. 55 | Only difference is that application now needs pointer to write memory address and length of maximal number of bytes to directly copy in buffer. 56 | After processing is successful, buffer advance operation is necessary to manually increase write pointer and to increase number of bytes in buffer. 57 | 58 | .. figure:: ../static/images/buff_lin_write_advance.svg 59 | :align: center 60 | :alt: Data transfer from memory to hardware IP 61 | 62 | * Case **A**: Initial state, buffer is empty as ``R == W`` 63 | 64 | * Based on ``W`` pointer position, application could write ``4`` bytes to contiguous block of memory 65 | * Case **B**: State after advancing `W` pointer for `4` bytes. Buffer now holds `4` bytes and has ``3`` remaining available 66 | * Case **C**: Buffer is full, no more free memory available for write operation 67 | 68 | Code example: 69 | 70 | .. literalinclude:: ../examples_src/example_advance_1.c 71 | :language: c 72 | :linenos: 73 | :caption: Advance buffer pointer for manually written bytes 74 | 75 | Example for DMA transfer from memory 76 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 77 | 78 | This is an example showing pseudo code for implementing data transfer using DMA with zero-copy overhead. 79 | For read operation purposes, application gets direct access to ringbuffer read pointer and length of contigouos memory. 80 | 81 | It is assumed that after DMA transfer completes, interrupt is generated (embedded system) and buffer is skipped in the interrupt. 82 | 83 | .. note:: 84 | 85 | Buffer skip operation is used to mark sent data as processed and to free memory for new writes to buffer 86 | 87 | .. literalinclude:: ../examples_src/example_dma_skip.c 88 | :language: c 89 | :linenos: 90 | :caption: DMA usage with buffer 91 | 92 | .. tip:: 93 | Check `STM32 UART DMA TX RX Github `_ repository for use cases. 94 | 95 | .. toctree:: 96 | :maxdepth: 2 -------------------------------------------------------------------------------- /docs/user-manual/index.rst: -------------------------------------------------------------------------------- 1 | .. _um: 2 | 3 | User manual 4 | =========== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | how-it-works 10 | events 11 | hw-dma-usage -------------------------------------------------------------------------------- /lwrb/src/include/lwrb/lwrb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lwrb.h 3 | * \brief LwRB - Lightweight ring buffer 4 | */ 5 | 6 | /* 7 | * Copyright (c) 2020 Tilen MAJERLE 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 23 | * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | * 29 | * This file is part of LwRB - Lightweight ring buffer library. 30 | * 31 | * Author: Tilen MAJERLE 32 | * Version: v1.3.1 33 | */ 34 | #ifndef RINGBUFF_HDR_H 35 | #define RINGBUFF_HDR_H 36 | 37 | #include 38 | #include 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif /* __cplusplus */ 43 | 44 | /** 45 | * \defgroup RINGBUFF Lightweight ring buffer manager 46 | * \brief Lightweight ring buffer manager 47 | * \{ 48 | */ 49 | 50 | /** 51 | * \brief Enable buffer structure pointer parameter as volatile 52 | * To use this feature, uncomment keyword below 53 | */ 54 | #define RINGBUFF_VOLATILE /* volatile */ 55 | 56 | /** 57 | * \brief Adds 2 magic words to make sure if memory is corrupted 58 | * application can detect wrong data pointer and maximum size 59 | */ 60 | #define RINGBUFF_USE_MAGIC 1 61 | 62 | /** 63 | * \brief Event type for buffer operations 64 | */ 65 | typedef enum { 66 | RINGBUFF_EVT_READ, /*!< Read event */ 67 | RINGBUFF_EVT_WRITE, /*!< Write event */ 68 | RINGBUFF_EVT_RESET, /*!< Reset event */ 69 | } ringbuff_evt_type_t; 70 | 71 | /** 72 | * \brief Buffer structure forward declaration 73 | */ 74 | struct ringbuff; 75 | 76 | /** 77 | * \brief Event callback function type 78 | * \param[in] buff: Buffer handle for event 79 | * \param[in] evt: Event type 80 | * \param[in] bp: Number of bytes written or read (when used), depends on event type 81 | */ 82 | typedef void (*ringbuff_evt_fn)(RINGBUFF_VOLATILE struct ringbuff* buff, ringbuff_evt_type_t evt, size_t bp); 83 | 84 | /** 85 | * \brief Buffer structure 86 | */ 87 | typedef struct ringbuff { 88 | #if RINGBUFF_USE_MAGIC 89 | uint32_t magic1; /*!< Magic 1 word */ 90 | #endif /* RINGBUFF_USE_MAGIC */ 91 | uint8_t* buff; /*!< Pointer to buffer data. 92 | Buffer is considered initialized when `buff != NULL` and `size > 0` */ 93 | size_t size; /*!< Size of buffer data. Size of actual buffer is `1` byte less than value holds */ 94 | size_t r; /*!< Next read pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */ 95 | size_t w; /*!< Next write pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */ 96 | ringbuff_evt_fn evt_fn; /*!< Pointer to event callback function */ 97 | #if RINGBUFF_USE_MAGIC 98 | uint32_t magic2; /*!< Magic 2 word */ 99 | #endif /* RINGBUFF_USE_MAGIC */ 100 | } ringbuff_t; 101 | 102 | uint8_t ringbuff_init(RINGBUFF_VOLATILE ringbuff_t* buff, void* buffdata, size_t size); 103 | uint8_t ringbuff_is_ready(RINGBUFF_VOLATILE ringbuff_t* buff); 104 | void ringbuff_free(RINGBUFF_VOLATILE ringbuff_t* buff); 105 | void ringbuff_reset(RINGBUFF_VOLATILE ringbuff_t* buff); 106 | void ringbuff_set_evt_fn(RINGBUFF_VOLATILE ringbuff_t* buff, ringbuff_evt_fn fn); 107 | 108 | /* Read/Write functions */ 109 | size_t ringbuff_write(RINGBUFF_VOLATILE ringbuff_t* buff, const void* data, size_t btw); 110 | size_t ringbuff_read(RINGBUFF_VOLATILE ringbuff_t* buff, void* data, size_t btr); 111 | size_t ringbuff_peek(RINGBUFF_VOLATILE ringbuff_t* buff, size_t skip_count, void* data, size_t btp); 112 | 113 | /* Buffer size information */ 114 | size_t ringbuff_get_free(RINGBUFF_VOLATILE ringbuff_t* buff); 115 | size_t ringbuff_get_full(RINGBUFF_VOLATILE ringbuff_t* buff); 116 | 117 | /* Read data block management */ 118 | void* ringbuff_get_linear_block_read_address(RINGBUFF_VOLATILE ringbuff_t* buff); 119 | size_t ringbuff_get_linear_block_read_length(RINGBUFF_VOLATILE ringbuff_t* buff); 120 | size_t ringbuff_skip(RINGBUFF_VOLATILE ringbuff_t* buff, size_t len); 121 | 122 | /* Write data block management */ 123 | void* ringbuff_get_linear_block_write_address(RINGBUFF_VOLATILE ringbuff_t* buff); 124 | size_t ringbuff_get_linear_block_write_length(RINGBUFF_VOLATILE ringbuff_t* buff); 125 | size_t ringbuff_advance(RINGBUFF_VOLATILE ringbuff_t* buff, size_t len); 126 | 127 | /** 128 | * \} 129 | */ 130 | 131 | #ifdef __cplusplus 132 | } 133 | #endif /* __cplusplus */ 134 | 135 | #endif /* RINGBUFF_HDR_H */ 136 | -------------------------------------------------------------------------------- /lwrb/src/lwrb/lwrb.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file lwrb.c 3 | * \brief Lightweight ring buffer 4 | */ 5 | 6 | /* 7 | * Copyright (c) 2020 Tilen MAJERLE 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without restriction, 12 | * including without limitation the rights to use, copy, modify, merge, 13 | * publish, distribute, sublicense, and/or sell copies of the Software, 14 | * and to permit persons to whom the Software is furnished to do so, 15 | * subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 23 | * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | * 29 | * This file is part of LwRB - Lightweight ring buffer library. 30 | * 31 | * Author: Tilen MAJERLE 32 | * Version: v1.3.1 33 | */ 34 | #include "ringbuff/ringbuff.h" 35 | 36 | /* Memory set and copy functions */ 37 | #define BUF_MEMSET memset 38 | #define BUF_MEMCPY memcpy 39 | 40 | #if RINGBUFF_USE_MAGIC 41 | #define BUF_IS_VALID(b) ((b) != NULL && (b)->magic1 == 0xDEADBEEF && (b)->magic2 == ~0xDEADBEEF && (b)->buff != NULL && (b)->size > 0) 42 | #else 43 | #define BUF_IS_VALID(b) ((b) != NULL && (b)->buff != NULL && (b)->size > 0) 44 | #endif /* RINGBUFF_USE_MAGIC */ 45 | #define BUF_MIN(x, y) ((x) < (y) ? (x) : (y)) 46 | #define BUF_MAX(x, y) ((x) > (y) ? (x) : (y)) 47 | #define BUF_SEND_EVT(b, type, bp) do { if ((b)->evt_fn != NULL) { (b)->evt_fn((b), (type), (bp)); } } while (0) 48 | 49 | /** 50 | * \brief Initialize buffer handle to default values with size and buffer data array 51 | * \param[in] buff: Buffer handle 52 | * \param[in] buffdata: Pointer to memory to use as buffer data 53 | * \param[in] size: Size of `buffdata` in units of bytes 54 | * Maximum number of bytes buffer can hold is `size - 1` 55 | * \return `1` on success, `0` otherwise 56 | */ 57 | uint8_t 58 | ringbuff_init(RINGBUFF_VOLATILE ringbuff_t* buff, void* buffdata, size_t size) { 59 | if (buff == NULL || buffdata == NULL || size == 0) { 60 | return 0; 61 | } 62 | 63 | BUF_MEMSET((void*)buff, 0x00, sizeof(*buff)); 64 | 65 | buff->size = size; 66 | buff->buff = buffdata; 67 | 68 | #if RINGBUFF_USE_MAGIC 69 | buff->magic1 = 0xDEADBEEF; 70 | buff->magic2 = ~0xDEADBEEF; 71 | #endif /* RINGBUFF_USE_MAGIC */ 72 | 73 | return 1; 74 | } 75 | 76 | /** 77 | * \brief Check if ringbuff is initialized and ready to use 78 | * \param[in] buff: Buffer handle 79 | * \return `1` if ready, `0` otherwise 80 | */ 81 | uint8_t 82 | ringbuff_is_ready(RINGBUFF_VOLATILE ringbuff_t* buff) { 83 | return BUF_IS_VALID(buff); 84 | } 85 | 86 | /** 87 | * \brief Free buffer memory 88 | * \note Since implementation does not use dynamic allocation, 89 | * it just sets buffer handle to `NULL` 90 | * \param[in] buff: Buffer handle 91 | */ 92 | void 93 | ringbuff_free(RINGBUFF_VOLATILE ringbuff_t* buff) { 94 | if (BUF_IS_VALID(buff)) { 95 | buff->buff = NULL; 96 | } 97 | } 98 | 99 | /** 100 | * \brief Set event function callback for different buffer operations 101 | * \param[in] buff: Buffer handle 102 | * \param[in] evt_fn: Callback function 103 | */ 104 | void 105 | ringbuff_set_evt_fn(RINGBUFF_VOLATILE ringbuff_t* buff, ringbuff_evt_fn evt_fn) { 106 | if (BUF_IS_VALID(buff)) { 107 | buff->evt_fn = evt_fn; 108 | } 109 | } 110 | 111 | /** 112 | * \brief Write data to buffer. 113 | * Copies data from `data` array to buffer and marks buffer as full for maximum `btw` number of bytes 114 | * 115 | * \param[in] buff: Buffer handle 116 | * \param[in] data: Pointer to data to write into buffer 117 | * \param[in] btw: Number of bytes to write 118 | * \return Number of bytes written to buffer. 119 | * When returned value is less than `btw`, there was no enough memory available 120 | * to copy full data array 121 | */ 122 | size_t 123 | ringbuff_write(RINGBUFF_VOLATILE ringbuff_t* buff, const void* data, size_t btw) { 124 | size_t tocopy, free; 125 | const uint8_t* d = data; 126 | 127 | if (!BUF_IS_VALID(buff) || data == NULL || btw == 0) { 128 | return 0; 129 | } 130 | 131 | /* Calculate maximum number of bytes available to write */ 132 | free = ringbuff_get_free(buff); 133 | btw = BUF_MIN(free, btw); 134 | if (btw == 0) { 135 | return 0; 136 | } 137 | 138 | /* Step 1: Write data to linear part of buffer */ 139 | tocopy = BUF_MIN(buff->size - buff->w, btw); 140 | BUF_MEMCPY(&buff->buff[buff->w], d, tocopy); 141 | buff->w += tocopy; 142 | btw -= tocopy; 143 | 144 | /* Step 2: Write data to beginning of buffer (overflow part) */ 145 | if (btw > 0) { 146 | BUF_MEMCPY(buff->buff, &d[tocopy], btw); 147 | buff->w = btw; 148 | } 149 | 150 | /* Step 3: Check end of buffer */ 151 | if (buff->w >= buff->size) { 152 | buff->w = 0; 153 | } 154 | BUF_SEND_EVT(buff, RINGBUFF_EVT_WRITE, tocopy + btw); 155 | return tocopy + btw; 156 | } 157 | 158 | /** 159 | * \brief Read data from buffer. 160 | * Copies data from buffer to `data` array and marks buffer as free for maximum `btr` number of bytes 161 | * 162 | * \param[in] buff: Buffer handle 163 | * \param[out] data: Pointer to output memory to copy buffer data to 164 | * \param[in] btr: Number of bytes to read 165 | * \return Number of bytes read and copied to data array 166 | */ 167 | size_t 168 | ringbuff_read(RINGBUFF_VOLATILE ringbuff_t* buff, void* data, size_t btr) { 169 | size_t tocopy, full; 170 | uint8_t* d = data; 171 | 172 | if (!BUF_IS_VALID(buff) || data == NULL || btr == 0) { 173 | return 0; 174 | } 175 | 176 | /* Calculate maximum number of bytes available to read */ 177 | full = ringbuff_get_full(buff); 178 | btr = BUF_MIN(full, btr); 179 | if (btr == 0) { 180 | return 0; 181 | } 182 | 183 | /* Step 1: Read data from linear part of buffer */ 184 | tocopy = BUF_MIN(buff->size - buff->r, btr); 185 | BUF_MEMCPY(d, &buff->buff[buff->r], tocopy); 186 | buff->r += tocopy; 187 | btr -= tocopy; 188 | 189 | /* Step 2: Read data from beginning of buffer (overflow part) */ 190 | if (btr > 0) { 191 | BUF_MEMCPY(&d[tocopy], buff->buff, btr); 192 | buff->r = btr; 193 | } 194 | 195 | /* Step 3: Check end of buffer */ 196 | if (buff->r >= buff->size) { 197 | buff->r = 0; 198 | } 199 | BUF_SEND_EVT(buff, RINGBUFF_EVT_READ, tocopy + btr); 200 | return tocopy + btr; 201 | } 202 | 203 | /** 204 | * \brief Read from buffer without changing read pointer (peek only) 205 | * \param[in] buff: Buffer handle 206 | * \param[in] skip_count: Number of bytes to skip before reading data 207 | * \param[out] data: Pointer to output memory to copy buffer data to 208 | * \param[in] btp: Number of bytes to peek 209 | * \return Number of bytes peeked and written to output array 210 | */ 211 | size_t 212 | ringbuff_peek(RINGBUFF_VOLATILE ringbuff_t* buff, size_t skip_count, void* data, size_t btp) { 213 | size_t full, tocopy, r; 214 | uint8_t* d = data; 215 | 216 | if (!BUF_IS_VALID(buff) || data == NULL || btp == 0) { 217 | return 0; 218 | } 219 | 220 | r = buff->r; 221 | 222 | /* Calculate maximum number of bytes available to read */ 223 | full = ringbuff_get_full(buff); 224 | 225 | /* Skip beginning of buffer */ 226 | if (skip_count >= full) { 227 | return 0; 228 | } 229 | r += skip_count; 230 | full -= skip_count; 231 | if (r >= buff->size) { 232 | r -= buff->size; 233 | } 234 | 235 | /* Check maximum number of bytes available to read after skip */ 236 | btp = BUF_MIN(full, btp); 237 | if (btp == 0) { 238 | return 0; 239 | } 240 | 241 | /* Step 1: Read data from linear part of buffer */ 242 | tocopy = BUF_MIN(buff->size - r, btp); 243 | BUF_MEMCPY(d, &buff->buff[r], tocopy); 244 | btp -= tocopy; 245 | 246 | /* Step 2: Read data from beginning of buffer (overflow part) */ 247 | if (btp > 0) { 248 | BUF_MEMCPY(&d[tocopy], buff->buff, btp); 249 | } 250 | return tocopy + btp; 251 | } 252 | 253 | /** 254 | * \brief Get available size in buffer for write operation 255 | * \param[in] buff: Buffer handle 256 | * \return Number of free bytes in memory 257 | */ 258 | size_t 259 | ringbuff_get_free(RINGBUFF_VOLATILE ringbuff_t* buff) { 260 | size_t size, w, r; 261 | 262 | if (!BUF_IS_VALID(buff)) { 263 | return 0; 264 | } 265 | 266 | /* Use temporary values in case they are changed during operations */ 267 | w = buff->w; 268 | r = buff->r; 269 | if (w == r) { 270 | size = buff->size; 271 | } else if (r > w) { 272 | size = r - w; 273 | } else { 274 | size = buff->size - (w - r); 275 | } 276 | 277 | /* Buffer free size is always 1 less than actual size */ 278 | return size - 1; 279 | } 280 | 281 | /** 282 | * \brief Get number of bytes currently available in buffer 283 | * \param[in] buff: Buffer handle 284 | * \return Number of bytes ready to be read 285 | */ 286 | size_t 287 | ringbuff_get_full(RINGBUFF_VOLATILE ringbuff_t* buff) { 288 | size_t w, r, size; 289 | 290 | if (!BUF_IS_VALID(buff)) { 291 | return 0; 292 | } 293 | 294 | /* Use temporary values in case they are changed during operations */ 295 | w = buff->w; 296 | r = buff->r; 297 | if (w == r) { 298 | size = 0; 299 | } else if (w > r) { 300 | size = w - r; 301 | } else { 302 | size = buff->size - (r - w); 303 | } 304 | return size; 305 | } 306 | 307 | /** 308 | * \brief Resets buffer to default values. Buffer size is not modified 309 | * \param[in] buff: Buffer handle 310 | */ 311 | void 312 | ringbuff_reset(RINGBUFF_VOLATILE ringbuff_t* buff) { 313 | if (BUF_IS_VALID(buff)) { 314 | buff->w = 0; 315 | buff->r = 0; 316 | BUF_SEND_EVT(buff, RINGBUFF_EVT_RESET, 0); 317 | } 318 | } 319 | 320 | /** 321 | * \brief Get linear address for buffer for fast read 322 | * \param[in] buff: Buffer handle 323 | * \return Linear buffer start address 324 | */ 325 | void* 326 | ringbuff_get_linear_block_read_address(RINGBUFF_VOLATILE ringbuff_t* buff) { 327 | if (!BUF_IS_VALID(buff)) { 328 | return NULL; 329 | } 330 | return &buff->buff[buff->r]; 331 | } 332 | 333 | /** 334 | * \brief Get length of linear block address before it overflows for read operation 335 | * \param[in] buff: Buffer handle 336 | * \return Linear buffer size in units of bytes for read operation 337 | */ 338 | size_t 339 | ringbuff_get_linear_block_read_length(RINGBUFF_VOLATILE ringbuff_t* buff) { 340 | size_t w, r, len; 341 | 342 | if (!BUF_IS_VALID(buff)) { 343 | return 0; 344 | } 345 | 346 | /* Use temporary values in case they are changed during operations */ 347 | w = buff->w; 348 | r = buff->r; 349 | if (w > r) { 350 | len = w - r; 351 | } else if (r > w) { 352 | len = buff->size - r; 353 | } else { 354 | len = 0; 355 | } 356 | return len; 357 | } 358 | 359 | /** 360 | * \brief Skip (ignore; advance read pointer) buffer data 361 | * Marks data as read in the buffer and increases free memory for up to `len` bytes 362 | * 363 | * \note Useful at the end of streaming transfer such as DMA 364 | * \param[in] buff: Buffer handle 365 | * \param[in] len: Number of bytes to skip and mark as read 366 | * \return Number of bytes skipped 367 | */ 368 | size_t 369 | ringbuff_skip(RINGBUFF_VOLATILE ringbuff_t* buff, size_t len) { 370 | size_t full; 371 | 372 | if (!BUF_IS_VALID(buff) || len == 0) { 373 | return 0; 374 | } 375 | 376 | full = ringbuff_get_full(buff); /* Get buffer used length */ 377 | len = BUF_MIN(len, full); /* Calculate max skip */ 378 | buff->r += len; /* Advance read pointer */ 379 | if (buff->r >= buff->size) { /* Subtract possible overflow */ 380 | buff->r -= buff->size; 381 | } 382 | BUF_SEND_EVT(buff, RINGBUFF_EVT_READ, len); 383 | return len; 384 | } 385 | 386 | /** 387 | * \brief Get linear address for buffer for fast read 388 | * \param[in] buff: Buffer handle 389 | * \return Linear buffer start address 390 | */ 391 | void* 392 | ringbuff_get_linear_block_write_address(RINGBUFF_VOLATILE ringbuff_t* buff) { 393 | if (!BUF_IS_VALID(buff)) { 394 | return NULL; 395 | } 396 | return &buff->buff[buff->w]; 397 | } 398 | 399 | /** 400 | * \brief Get length of linear block address before it overflows for write operation 401 | * \param[in] buff: Buffer handle 402 | * \return Linear buffer size in units of bytes for write operation 403 | */ 404 | size_t 405 | ringbuff_get_linear_block_write_length(RINGBUFF_VOLATILE ringbuff_t* buff) { 406 | size_t w, r, len; 407 | 408 | if (!BUF_IS_VALID(buff)) { 409 | return 0; 410 | } 411 | 412 | /* Use temporary values in case they are changed during operations */ 413 | w = buff->w; 414 | r = buff->r; 415 | if (w >= r) { 416 | len = buff->size - w; 417 | /* 418 | * When read pointer is 0, 419 | * maximal length is one less as if too many bytes 420 | * are written, buffer would be considered empty again (r == w) 421 | */ 422 | if (r == 0) { 423 | /* 424 | * Cannot overflow: 425 | * - If r is not 0, statement does not get called 426 | * - buff->size cannot be 0 and if r is 0, len is greater 0 427 | */ 428 | --len; 429 | } 430 | } else { 431 | len = r - w - 1; 432 | } 433 | return len; 434 | } 435 | 436 | /** 437 | * \brief Advance write pointer in the buffer. 438 | * Similar to skip function but modifies write pointer instead of read 439 | * 440 | * \note Useful when hardware is writing to buffer and application needs to increase number 441 | * of bytes written to buffer by hardware 442 | * \param[in] buff: Buffer handle 443 | * \param[in] len: Number of bytes to advance 444 | * \return Number of bytes advanced for write operation 445 | */ 446 | size_t 447 | ringbuff_advance(RINGBUFF_VOLATILE ringbuff_t* buff, size_t len) { 448 | size_t free; 449 | 450 | if (!BUF_IS_VALID(buff) || len == 0) { 451 | return 0; 452 | } 453 | 454 | free = ringbuff_get_free(buff); /* Get buffer free length */ 455 | len = BUF_MIN(len, free); /* Calculate max advance */ 456 | buff->w += len; /* Advance write pointer */ 457 | if (buff->w >= buff->size) { /* Subtract possible overflow */ 458 | buff->w -= buff->size; 459 | } 460 | BUF_SEND_EVT(buff, RINGBUFF_EVT_WRITE, len); 461 | return len; 462 | } 463 | --------------------------------------------------------------------------------