From: Tilman Sauerbeck Date: Tue, 25 Jun 2019 04:23:40 +0000 (+0200) Subject: common: Add the buffer module. X-Git-Url: http://git.code-monkey.de/?a=commitdiff_plain;h=1989d593a5511a6a766d432c48f79412416b3700;p=gps-watch.git common: Add the buffer module. This comes with a C API, so it can be used by the USB serial code. --- diff --git a/SConscript.libcommon b/SConscript.libcommon index 2680a97..0696528 100644 --- a/SConscript.libcommon +++ b/SConscript.libcommon @@ -7,6 +7,7 @@ source_files_rs = [ 'src/common/nvic.rs', 'src/common/clock.rs', 'src/common/crc32.rs', + 'src/common/buffer.rs', 'src/common/usb_serial.rs', ] diff --git a/src/common/buffer.h b/src/common/buffer.h new file mode 100644 index 0000000..0a80666 --- /dev/null +++ b/src/common/buffer.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BUFFER_H +#define BUFFER_H + +#include /* size_t */ +#include /* ssize_t */ + +typedef ssize_t (*buffer_func_t)(void *user_data, void *buf, size_t bufsiz, size_t count); + +struct buffer { + char *buf; + buffer_func_t callback; + void *user_data; + size_t allocated; + size_t length; +}; + +void buffer_init (struct buffer *sb, void *buf, size_t bufsiz, buffer_func_t callback, void *user_data); + +int buffer_flush (struct buffer *sb); +ssize_t buffer_write (struct buffer *sb, const void *src, size_t srcsiz); +int buffer_write_all (struct buffer *sb, const void *src, size_t srcsiz); + +#endif diff --git a/src/common/buffer.rs b/src/common/buffer.rs new file mode 100644 index 0000000..deb8ef7 --- /dev/null +++ b/src/common/buffer.rs @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2017-2019 Tilman Sauerbeck (tilman at code-monkey de) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +use core::ptr; + +pub enum BufferUserData { +} + +#[repr(C)] +pub struct Buffer { + buf: *mut u8, + callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, + user_data: *mut BufferUserData, + allocated: usize, + length: usize, +} + +extern fn dummy_callback(_: *mut BufferUserData, _: *const u8, _: usize, _: usize) -> isize { + -1 +} + +#[no_mangle] +pub unsafe extern fn buffer_init(_buffer: *mut Buffer, buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) { + let buffer = &mut *_buffer; + + buffer.buf = buf; + buffer.allocated = bufsiz; + buffer.callback = callback; + buffer.user_data = user_data; + buffer.length = 0; +} + +unsafe fn buffer_consume(buffer: &mut Buffer, length: usize) { + buffer.length -= length; + + ptr::copy(buffer.buf.offset(length as isize), buffer.buf, buffer.length); +} + +#[no_mangle] +pub unsafe extern fn buffer_flush(_buffer: *mut Buffer) -> i32 { + let buffer = &mut *_buffer; + + while buffer.length > 0 { + let nwritten = (buffer.callback)(buffer.user_data, buffer.buf, buffer.allocated, buffer.length); + + if nwritten == -1 { + return -1; + } + + buffer_consume(buffer, nwritten as usize); + } + + 0 +} + +fn min(a: usize, b: usize) -> usize { + if a < b { + a + } else { + b + } +} + +#[no_mangle] +pub unsafe extern fn buffer_write(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize { + let buffer = &mut *_buffer; + + if buffer.allocated == buffer.length { + if buffer_flush(_buffer) < 0 { + return -1; + } + } + + let nwrite = min(buffer.allocated - buffer.length, srcsiz); + + ptr::copy_nonoverlapping(src, buffer.buf.offset(buffer.length as isize), nwrite); + + buffer.length += nwrite; + + nwrite as isize +} + +#[no_mangle] +pub unsafe extern fn buffer_write_all(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize { + let mut offset = 0; + let mut left = srcsiz; + + while left > 0 { + let data = src.offset(offset); + let nwritten = buffer_write(_buffer, data, left); + + if nwritten < 0 { + return -1; + } + + left -= nwritten as usize; + offset += nwritten; + } + + 0 +} + +impl Buffer { + // Allocates and initializes a buffer. + pub fn new(buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) -> Buffer { + Buffer { + buf: buf, + callback: callback, + user_data: user_data, + allocated: bufsiz, + length: 0, + } + } + + // Allocates a buffer, but does not initialize it. + // The buffer won't be usable until the init() function is called on it. + pub fn alloc() -> Buffer { + Buffer { + buf: 0 as *mut u8, + callback: dummy_callback, + user_data: 0 as *mut BufferUserData, + allocated: 0, + length: 0, + } + } + + pub fn init(&mut self, buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) { + unsafe { + buffer_init(self, buf, bufsiz, callback, user_data); + } + } + + pub fn write(&mut self, data: &[u8]) { + unsafe { + buffer_write_all(self, data.as_ptr(), data.len()); + } + } + + pub fn flush(&mut self) -> i32 { + unsafe { + buffer_flush(self) + } + } + + pub fn len(&self) -> usize { + self.length + } +} diff --git a/src/common/lib.rs b/src/common/lib.rs index b1fd694..dfe7b40 100644 --- a/src/common/lib.rs +++ b/src/common/lib.rs @@ -29,6 +29,7 @@ pub mod register; pub mod nvic; pub mod clock; pub mod crc32; +pub mod buffer; pub mod usb_serial; use core::panic::PanicInfo;