Skip to content

Instantly share code, notes, and snippets.

@timokroeger
Created October 28, 2019 08:30
Show Gist options
  • Select an option

  • Save timokroeger/e240a4ac2154bd405d8af99ce401aaa8 to your computer and use it in GitHub Desktop.

Select an option

Save timokroeger/e240a4ac2154bd405d8af99ce401aaa8 to your computer and use it in GitHub Desktop.
GPIO builder pattern prototype
use std::marker::PhantomData;
fn main() {
let parts = Parts::new();
// Disabled by default
let pa0: Pin<_, Disabled> = parts.pa0.into();
// Pull-up input
let pa1: Pin<_, Input> = parts.pa1.pull_up().into();
// Push-pull output
let pb0: Pin<_, Output<PushPull>> = parts.pb0.into();
// Push-pull output with pull-up not possible:
// let pb1: Pin<_, Output<PushPull>> = parts.pb1.pull_up().into();
// ^^^^ the trait `std::convert::From<PinBuilder<PB1, PullUp>>` is not implemented for `Pin<_, Output<PushPull>>`
// Open-drain output can be used with a pull-up
let pb1: Pin<_, Output<OpenDrain>> = parts.pb1.pull_up().into();
}
// ------------------------------------------------------------------------- //
trait Mode {}
struct Disabled;
impl Mode for Disabled {}
struct Input;
impl Mode for Input {}
struct Output<OM: OutputMode>(OM);
impl<OM: OutputMode> Mode for Output<OM> {}
trait OutputMode {}
struct PushPull;
impl OutputMode for PushPull {}
struct OpenDrain;
impl OutputMode for OpenDrain {}
// ------------------------------------------------------------------------- //
struct PinBuilder<T: PinTrait, P: Pull> {
ty: T,
_pull: P,
}
impl<T: PinTrait> PinBuilder<T, Floating>
{
fn pull_up(self) -> PinBuilder<T, PullUp> {
PinBuilder {
ty: self.ty,
_pull: PullUp,
}
}
}
trait Pull {}
struct Floating;
impl Pull for Floating {}
struct PullUp;
impl Pull for PullUp {}
// ------------------------------------------------------------------------- //
struct Pin<T: PinTrait, M: Mode> {
ty: T,
_mode: PhantomData<M>,
}
impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Disabled> {
fn from(mut pb: PinBuilder<T, Floating>) -> Self {
pb.ty.modify_regs();
Self {
ty: pb.ty,
_mode: PhantomData,
}
}
}
impl<T: PinTrait> From<PinBuilder<T, PullUp>> for Pin<T, Disabled> {
fn from(mut pb: PinBuilder<T, PullUp>) -> Self {
pb.ty.modify_regs();
Self {
ty: pb.ty,
_mode: PhantomData,
}
}
}
impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Input> {
fn from(mut pb: PinBuilder<T, Floating>) -> Self {
pb.ty.modify_regs();
Self {
ty: pb.ty,
_mode: PhantomData,
}
}
}
impl<T: PinTrait> From<PinBuilder<T, PullUp>> for Pin<T, Input> {
fn from(mut pb: PinBuilder<T, PullUp>) -> Self {
pb.ty.modify_regs();
Self {
ty: pb.ty,
_mode: PhantomData,
}
}
}
impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Output<PushPull>> {
fn from(mut pb: PinBuilder<T, Floating>) -> Self {
pb.ty.modify_regs();
Self {
ty: pb.ty,
_mode: PhantomData,
}
}
}
impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Output<OpenDrain>> {
fn from(mut pb: PinBuilder<T, Floating>) -> Self {
pb.ty.modify_regs();
Self {
ty: pb.ty,
_mode: PhantomData,
}
}
}
impl<T: PinTrait> From<PinBuilder<T, PullUp>> for Pin<T, Output<OpenDrain>> {
fn from(mut pb: PinBuilder<T, PullUp>) -> Self {
pb.ty.modify_regs();
Self {
ty: pb.ty,
_mode: PhantomData,
}
}
}
/// Implemented by types that represent a specific pin.
///
/// Register manipulation code generated by macros.
trait PinTrait {
fn modify_regs(&mut self);
}
macro_rules! pins {
($($pxy:ident, $PXy:ident;)*) => {
$(
struct $PXy;
impl PinTrait for $PXy {
fn modify_regs(&mut self) {
// Something something
}
}
)*
struct Parts {
$(
$pxy: PinBuilder<$PXy, Floating>,
)*
}
impl Parts {
fn new() -> Self {
Self {
$(
$pxy: PinBuilder {
ty: $PXy,
_pull: Floating,
},
)*
}
}
}
}
}
pins!(
pa0, PA0;
pa1, PA1;
// ...
pb0, PB0;
pb1, PB1;
// ...
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment