common: Add the buffer module.
authorTilman Sauerbeck <tilman@code-monkey.de>
Tue, 25 Jun 2019 04:23:40 +0000 (06:23 +0200)
committerTilman Sauerbeck <tilman@code-monkey.de>
Sun, 5 Jan 2020 19:38:08 +0000 (20:38 +0100)
This comes with a C API, so it can be used by the USB serial code.

SConscript.libcommon
src/common/buffer.h [new file with mode: 0644]
src/common/buffer.rs [new file with mode: 0644]
src/common/lib.rs

index 2680a978fb56638f37869c5abaae1c3252b68903..0696528474f9302de0079bc8bb67330d340114b4 100644 (file)
@@ -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 (file)
index 0000000..0a80666
--- /dev/null
@@ -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 <stdlib.h> /* size_t */
+#include <sys/types.h> /* 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 (file)
index 0000000..deb8ef7
--- /dev/null
@@ -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
+    }
+}
index b1fd694e04a895c5650d919a7374699b97c15950..dfe7b40bc094b832a4f003c200de7f36f2efea2a 100644 (file)
@@ -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;