Skip to content

Commit 4409e10

Browse files
committed
UART FIFO-buffered driver and Rust bindings
Allows wrapping the raw UART API with software RX and TX FIFOs that can be accessed from user space. Interrupt handlers move data between the hardware fifos and memory. This way, interrupt handlers do not need to be specifically written to deal with application-specific UART use cases from kernel mode. Signals are provided for a thread to be woken on read or write readiness. Behaves similarly to a UNIX file, supporting blocking and non-blocking reads and writes. Update serial example to use this and remove bindings for uart_pipe.
1 parent 90f828f commit 4409e10

File tree

23 files changed

+790
-190
lines changed

23 files changed

+790
-190
lines changed

.clang-format

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# clang-format configuration file. Intended for clang-format >= 4.
4+
#
5+
# For more information, see:
6+
#
7+
# Documentation/process/clang-format.rst
8+
# https://clang.llvm.org/docs/ClangFormat.html
9+
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
10+
#
11+
---
12+
AccessModifierOffset: -4
13+
AlignAfterOpenBracket: Align
14+
AlignConsecutiveAssignments: false
15+
AlignConsecutiveDeclarations: false
16+
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
17+
AlignOperands: true
18+
AlignTrailingComments: false
19+
AllowAllParametersOfDeclarationOnNextLine: false
20+
AllowShortBlocksOnASingleLine: false
21+
AllowShortCaseLabelsOnASingleLine: false
22+
AllowShortFunctionsOnASingleLine: None
23+
AllowShortIfStatementsOnASingleLine: false
24+
AllowShortLoopsOnASingleLine: false
25+
AlwaysBreakAfterDefinitionReturnType: None
26+
AlwaysBreakAfterReturnType: None
27+
AlwaysBreakBeforeMultilineStrings: false
28+
AlwaysBreakTemplateDeclarations: false
29+
BinPackArguments: true
30+
BinPackParameters: true
31+
BraceWrapping:
32+
AfterClass: false
33+
AfterControlStatement: false
34+
AfterEnum: false
35+
AfterFunction: true
36+
AfterNamespace: true
37+
AfterObjCDeclaration: false
38+
AfterStruct: false
39+
AfterUnion: false
40+
#AfterExternBlock: false # Unknown to clang-format-5.0
41+
BeforeCatch: false
42+
BeforeElse: false
43+
IndentBraces: false
44+
#SplitEmptyFunction: true # Unknown to clang-format-4.0
45+
#SplitEmptyRecord: true # Unknown to clang-format-4.0
46+
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
47+
BreakBeforeBinaryOperators: None
48+
BreakBeforeBraces: Custom
49+
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
50+
BreakBeforeTernaryOperators: false
51+
BreakConstructorInitializersBeforeComma: false
52+
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
53+
BreakAfterJavaFieldAnnotations: false
54+
BreakStringLiterals: false
55+
ColumnLimit: 80
56+
CommentPragmas: '^ IWYU pragma:'
57+
#CompactNamespaces: false # Unknown to clang-format-4.0
58+
ConstructorInitializerAllOnOneLineOrOnePerLine: false
59+
ConstructorInitializerIndentWidth: 8
60+
ContinuationIndentWidth: 8
61+
Cpp11BracedListStyle: false
62+
DerivePointerAlignment: false
63+
DisableFormat: false
64+
ExperimentalAutoDetectBinPacking: false
65+
#FixNamespaceComments: false # Unknown to clang-format-4.0
66+
67+
# Taken from:
68+
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
69+
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
70+
# | sort | uniq
71+
ForEachMacros:
72+
- 'FOR_EACH'
73+
- 'for_each_linux_bus'
74+
- 'for_each_linux_driver'
75+
- 'metal_bitmap_for_each_clear_bit'
76+
- 'metal_bitmap_for_each_set_bit'
77+
- 'metal_for_each_page_size_down'
78+
- 'metal_for_each_page_size_up'
79+
- 'metal_list_for_each'
80+
- 'RB_FOR_EACH'
81+
- 'RB_FOR_EACH_CONTAINER'
82+
- 'SYS_DLIST_FOR_EACH_CONTAINER'
83+
- 'SYS_DLIST_FOR_EACH_CONTAINER_SAFE'
84+
- 'SYS_DLIST_FOR_EACH_NODE'
85+
- 'SYS_DLIST_FOR_EACH_NODE_SAFE'
86+
- 'SYS_SFLIST_FOR_EACH_CONTAINER'
87+
- 'SYS_SFLIST_FOR_EACH_CONTAINER_SAFE'
88+
- 'SYS_SFLIST_FOR_EACH_NODE'
89+
- 'SYS_SFLIST_FOR_EACH_NODE_SAFE'
90+
- 'SYS_SLIST_FOR_EACH_CONTAINER'
91+
- 'SYS_SLIST_FOR_EACH_CONTAINER_SAFE'
92+
- 'SYS_SLIST_FOR_EACH_NODE'
93+
- 'SYS_SLIST_FOR_EACH_NODE_SAFE'
94+
- '_WAIT_Q_FOR_EACH'
95+
- 'Z_GENLIST_FOR_EACH_CONTAINER'
96+
- 'Z_GENLIST_FOR_EACH_CONTAINER_SAFE'
97+
- 'Z_GENLIST_FOR_EACH_NODE'
98+
- 'Z_GENLIST_FOR_EACH_NODE_SAFE'
99+
100+
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
101+
IncludeCategories:
102+
- Regex: '.*'
103+
Priority: 1
104+
IncludeIsMainRegex: '(Test)?$'
105+
IndentCaseLabels: false
106+
#IndentPPDirectives: None # Unknown to clang-format-5.0
107+
IndentWidth: 8
108+
IndentWrappedFunctionNames: false
109+
JavaScriptQuotes: Leave
110+
JavaScriptWrapImports: true
111+
KeepEmptyLinesAtTheStartOfBlocks: false
112+
MacroBlockBegin: ''
113+
MacroBlockEnd: ''
114+
MaxEmptyLinesToKeep: 1
115+
NamespaceIndentation: Inner
116+
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
117+
ObjCBlockIndentWidth: 8
118+
ObjCSpaceAfterProperty: true
119+
ObjCSpaceBeforeProtocolList: true
120+
121+
# Taken from git's rules
122+
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
123+
PenaltyBreakBeforeFirstCallParameter: 30
124+
PenaltyBreakComment: 10
125+
PenaltyBreakFirstLessLess: 0
126+
PenaltyBreakString: 10
127+
PenaltyExcessCharacter: 100
128+
PenaltyReturnTypeOnItsOwnLine: 60
129+
130+
PointerAlignment: Right
131+
ReflowComments: false
132+
SortIncludes: false
133+
#SortUsingDeclarations: false # Unknown to clang-format-4.0
134+
SpaceAfterCStyleCast: false
135+
SpaceAfterTemplateKeyword: true
136+
SpaceBeforeAssignmentOperators: true
137+
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
138+
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
139+
SpaceBeforeParens: ControlStatements
140+
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
141+
SpaceInEmptyParentheses: false
142+
SpacesBeforeTrailingComments: 1
143+
SpacesInAngles: false
144+
SpacesInContainerLiterals: false
145+
SpacesInCStyleCastParentheses: false
146+
SpacesInParentheses: false
147+
SpacesInSquareBrackets: false
148+
Standard: Cpp03
149+
TabWidth: 8
150+
UseTab: Always
151+
...

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
cmake_minimum_required(VERSION 3.13.1)
44

5+
add_subdirectory(uart-buffered)
6+
57
# Use a clang_target known to clang so headers will be processed correctly with
68
# bindgen. rust_target may point to a custom json target.
79
if(${ARCH} STREQUAL "posix" OR ${ARCH} STREQUAL "x86")

Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,16 @@ config RUST_HEAP_MEM_POOL_MIN_SIZE
4545
of the entire pool.
4646
endif
4747
endif
48+
49+
config UART_BUFFERED
50+
bool "UART fifo buffered driver"
51+
depends on SERIAL && UART_INTERRUPT_DRIVEN
52+
select POLL
53+
help
54+
Allows wrapping the raw UART API with software RX and TX FIFOs that
55+
can be accessed from user space. Interrupt handlers move data between
56+
the hardware fifos and memory. This way, interrupt handlers do not
57+
need to be specifically written to deal with application-specific
58+
UART use cases from kernel mode. Signals are provided for a thread to
59+
be woken on read or write readiness. Behaves similarly to a UNIX
60+
file, supporting blocking and non-blocking reads and writes.

rust/sysroot-stage2/Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/sysroot-stage2/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ path = "../zephyr-macros"
1212
[dependencies.zephyr-logger]
1313
path = "../zephyr-logger"
1414

15+
[dependencies.zephyr-uart-buffered]
16+
path = "../zephyr-uart-buffered"
17+
1518
[profile.release]
1619
lto = true
1720
panic = "abort"

rust/zephyr-sys/wrapper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <misc/mempool.h>
88
#include <device.h>
99
#include <uart.h>
10-
#include <drivers/console/uart_pipe.h>
10+
#include <uart_buffered.h>
1111

1212
// Create a constant we can use from Rust in all cases
1313
#ifdef CONFIG_USERSPACE

rust/zephyr-uart-buffered/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "zephyr-uart-buffered"
3+
version = "0.1.0"
4+
authors = ["Tyler Hall <tylerwhall@gmail.com>"]
5+
edition = "2018"
6+
7+
[dependencies]

rust/zephyr-uart-buffered/src/lib.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
extern crate zephyr_core;
2+
extern crate zephyr_sys;
3+
4+
use zephyr_core::poll::KPollSignal;
5+
use zephyr_core::NegErr;
6+
use zephyr_sys::raw::{uart_buffered_rx_handle, uart_buffered_tx_handle};
7+
8+
pub struct UartBufferedRx {
9+
handle: uart_buffered_rx_handle,
10+
}
11+
12+
impl UartBufferedRx {
13+
pub unsafe fn new(handle: uart_buffered_rx_handle) -> Self {
14+
UartBufferedRx { handle }
15+
}
16+
17+
/// Infallible read (lower level than `std::io::Read`)
18+
pub fn read(&mut self, buf: &mut [u8]) -> usize {
19+
unsafe {
20+
zephyr_sys::raw::uart_buffered_read(
21+
&self.handle as *const _ as *mut _,
22+
buf.as_mut_ptr(),
23+
buf.len(),
24+
)
25+
}
26+
}
27+
28+
/// Non blocking read. Returns None if nothing read, else returns number of bytes read.
29+
pub fn read_nb(&mut self, buf: &mut [u8]) -> Option<usize> {
30+
unsafe {
31+
zephyr_sys::raw::uart_buffered_read_nb(
32+
&self.handle as *const _ as *mut _,
33+
buf.as_mut_ptr(),
34+
buf.len(),
35+
)
36+
}
37+
.neg_err()
38+
.ok()
39+
.map(|len| len as usize)
40+
}
41+
42+
/// Get reference to signal to wait on for non-blocking readiness. Static
43+
/// lifetime because uart buffered can only be declared statically.
44+
pub fn get_signal(&self) -> &'static KPollSignal {
45+
unsafe { &*self.handle.fifo.signal }
46+
}
47+
}
48+
49+
pub struct UartBufferedTx {
50+
handle: uart_buffered_tx_handle,
51+
}
52+
53+
impl UartBufferedTx {
54+
pub unsafe fn new(handle: uart_buffered_tx_handle) -> Self {
55+
UartBufferedTx { handle }
56+
}
57+
58+
/// Infallible write (lower level than `std::io::Write`)
59+
pub fn write(&mut self, buf: &[u8]) {
60+
unsafe {
61+
zephyr_sys::raw::uart_buffered_write(
62+
&self.handle as *const _ as *mut _,
63+
buf.as_ptr(),
64+
buf.len(),
65+
)
66+
}
67+
}
68+
69+
/// Non blocking write. Returns None if nothing written, else returns number of bytes written.
70+
pub fn write_nb(&mut self, buf: &[u8]) -> Option<usize> {
71+
unsafe {
72+
zephyr_sys::raw::uart_buffered_write_nb(
73+
&self.handle as *const _ as *mut _,
74+
buf.as_ptr(),
75+
buf.len(),
76+
)
77+
}
78+
.neg_err()
79+
.ok()
80+
.map(|len| len as usize)
81+
}
82+
83+
/// Get reference to signal to wait on for non-blocking readiness. Static
84+
/// lifetime because uart buffered can only be declared statically.
85+
pub fn get_signal(&self) -> &'static KPollSignal {
86+
unsafe { &*self.handle.fifo.signal }
87+
}
88+
}

0 commit comments

Comments
 (0)