1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
extern crate proc_macro;
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::parse_macro_input;

#[proc_macro]
pub fn fgpio(item: TokenStream) -> TokenStream {
    let name = parse_macro_input!(item as syn::Ident).to_string();
    let name_uc = name.to_uppercase();

    let fgpio = format_ident!("fgpio{}", name);
    let fgpio_uc = format_ident!("FGPIO{}", name_uc);
    let port = format_ident!("PORT{}", name_uc);

    let pin_fields = (0..32 as usize).map(|i| {
        let pxi = format_ident!("p{}{}", name, i);
        let pxi_uc = format_ident!("P{}{}", name_uc, i);
        quote! { pub #pxi: #pxi_uc<IN> }
    });

    let pin_init = (0..32 as usize).map(|i| {
        let pxi = format_ident!("p{}{}", name, i);
        let pxi_uc = format_ident!("P{}{}", name_uc, i);
        quote! { #pxi: #pxi_uc::<IN>{_mode: PhantomData} }
    });

    let pin = (0..32 as usize).map(|i| {
        let pxi_uc = format_ident!("P{}{}", name_uc, i);
        let pcr = format_ident!("pcr{}", i);
        quote! {
            pub struct #pxi_uc<MODE> {
                _mode: PhantomData<MODE>
            }

            impl<MODE> #pxi_uc<MODE> {
                pub fn enable(&self) {
                    unsafe { &(*#port::ptr()) }.#pcr.write(|w| w.mux()._001());
                }

                pub fn into_input(self) -> #pxi_uc<IN> {
                    self.regblock().pddr.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << #i)) });
                    #pxi_uc{_mode: PhantomData}
                }

                pub fn into_output(self) -> #pxi_uc<OUT> {
                    self.regblock().pddr.modify(|r, w| unsafe { w.bits(r.bits() | (1 << #i)) });
                    #pxi_uc{_mode: PhantomData}
                }

                fn regblock(&self) -> &#fgpio::RegisterBlock {
                    unsafe { &(*#fgpio_uc::ptr()) }
                }

                fn value(&self) -> u32 {
                    self.regblock().pdir.read().pdi().bits() & (1 << #i)
                }
            }

            impl InputPin for #pxi_uc<IN> {
                type Error = Void;

                fn is_high(&self) -> Result<bool, Self::Error> {
                    Ok(self.value() != 0)
                }

                fn is_low(&self) -> Result<bool, Self::Error> {
                    Ok(self.value() == 0)
                }
            }

            impl OutputPin for #pxi_uc<OUT> {
                type Error = Void;

                fn set_low(&mut self) -> Result<(), Self::Error> {
                    self.regblock().pcor.write(|w| unsafe { w.bits(1<<#i) });
                    Ok(())
                }

                fn set_high(&mut self) -> Result<(), Self::Error> {
                    self.regblock().psor.write(|w| unsafe { w.bits(1<<#i) });
                    Ok(())
                }
            }

            impl #pxi_uc<OUT> {
                pub fn toggle(&mut self) {
                    self.regblock().ptor.write(|w| unsafe { w.bits(1<<#i) });
                }
            }
        }
    });

    let result = quote! {
        pub mod #fgpio {
            use core::marker::PhantomData;
            use embedded_hal::digital::v2::{InputPin, OutputPin};
            use void::Void;
            use crate::dev::{#fgpio_uc, #port, #fgpio};
            use super::{FgpioExt, IN, OUT};

            pub struct Parts {
                pub #fgpio: #fgpio_uc,
                #(#pin_fields,)*
            }

            impl Parts {
                pub fn into_fgpio(self) -> #fgpio_uc {
                    self.#fgpio
                }
            }

            impl FgpioExt for #fgpio_uc {
                type Parts = Parts;
                fn split(self) -> Parts {
                    Parts {
                        #fgpio: self,
                        #(#pin_init,)*
                    }
                }
            }

            #(#pin)*
        }
    };

    TokenStream::from(result)
}