├── .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 |
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------