commit 728e7d5be723b9673fb0e33c8dd417427f38b817 Author: doryan Date: Mon Apr 21 19:43:16 2025 +0400 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf414ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target +*/target/ +*/Cargo.lock/ +Cargo.lock +.cargo diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c970929 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "static_pins" +version = "0.1.0" +edition = "2021" + +[lib] +test = false + +[dependencies.static_pins_macros] +path = "static_pins_macros" + +[dependencies.arduino-hal] +git = "https://github.com/rahix/avr-hal" +rev = "3e362624547462928a219c40f9ea8e3a64f21e5f" +features = ["sparkfun-promicro"] + +[profile.dev] +panic = "abort" +lto = true +opt-level = "s" + +[profile.release] +panic = "abort" +codegen-units = 1 +debug = true +lto = true +opt-level = "s" diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..29c2b6d --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2024-06-13" +components = [ "rust-src" ] +profile = "minimal" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a6177b9 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,49 @@ +#![no_std] + +pub use static_pins_macros::*; + +pub trait StaticPinOps { + type Port; + const PIN_NUM: u8; + const PIN_POS: u8; + + fn into_input(); + fn into_output(); + fn into_output_high(); + fn into_pull_up_input(); + + fn write(data: u8); + fn read() -> u8; + + fn set_low(); + fn set_high(); +} + +#[macro_export] +macro_rules! impl_static_pins { + ($($pin:expr), +) => { + pub trait StaticPinOps { + type Port; + const PIN_NUM: u8; + const PIN_POS: u8; + + fn into_input(); + fn into_output(); + fn into_output_high(); + fn into_pull_up_input(); + + fn write(data: u8); + fn read() -> u8; + + fn is_low() -> bool; + fn is_high() -> bool; + + fn set_low(); + fn set_high(); + } + + $( + impl_static_pin!($pin); + )+ + } +} diff --git a/static_pins_macros/Cargo.toml b/static_pins_macros/Cargo.toml new file mode 100644 index 0000000..65ec818 --- /dev/null +++ b/static_pins_macros/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "static_pins_macros" +version = "0.1.0" +edition = "2021" + +[lib] +test = false +proc_macro = true + +[dependencies] +quote = "1.0.39" +syn = "2.0.58" +proc-macro2 = "1.0.94" + +[dependencies.arduino-hal] +git = "https://github.com/rahix/avr-hal" +rev = "3e362624547462928a219c40f9ea8e3a64f21e5f" +features = ["sparkfun-promicro"] + +[profile.dev] +panic = "abort" +lto = true +opt-level = "s" + +[profile.release] +panic = "abort" +codegen-units = 1 +debug = true +lto = true +opt-level = "s" diff --git a/static_pins_macros/rust-toolchain.toml b/static_pins_macros/rust-toolchain.toml new file mode 100644 index 0000000..29c2b6d --- /dev/null +++ b/static_pins_macros/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2024-06-13" +components = [ "rust-src" ] +profile = "minimal" diff --git a/static_pins_macros/src/lib.rs b/static_pins_macros/src/lib.rs new file mode 100644 index 0000000..63cf380 --- /dev/null +++ b/static_pins_macros/src/lib.rs @@ -0,0 +1,147 @@ +#![feature(proc_macro_quote)] + +use core::str::FromStr; + +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use syn::parse; + +const ASCII_DIGIT_OFFSET: u8 = 48; + +#[proc_macro] +pub fn impl_static_pin(pin: TokenStream) -> TokenStream { + let parsing_result = parse::(pin.clone()); + + if let Ok(pin) = parsing_result { + let mut port = pin.to_string(); + let writer_method = format_ident!("{}", port.to_ascii_lowercase()); + port.insert_str(1, "ORT"); + + let pin_num = match port.pop() { + Some(num) if num.is_ascii_digit() => (num as u8) - ASCII_DIGIT_OFFSET, + _ => panic!("Pin number is incorrect"), + }; + + let pin_pos = 1u8 << pin_num; + + let port_type = proc_macro2::TokenStream::from_str(&port).unwrap(); + + let port_register_name = match port.chars().last() { + Some(register) if register.is_ascii_alphabetic() => register, + _ => panic!("Register name is incorrect"), + }; + + let target_port = proc_macro2::TokenStream::from_str(&port.to_ascii_lowercase()).unwrap(); + let target_pin = format_ident!("pin{}", port_register_name.to_ascii_lowercase()); + let target_data_direction = format_ident!("ddr{}", port_register_name.to_ascii_lowercase()); + + let trait_name = proc_macro2::TokenStream::from_str("StaticPinOps").unwrap(); + + let impl_trait = quote! { + impl #trait_name for #pin { + type Port = #port_type; + const PIN_NUM: u8 = #pin_num; + const PIN_POS: u8 = #pin_pos; + + #[inline(always)] + fn write(data: u8) { + unsafe { + (*Self::Port::ptr()) + .#target_port + .write(|w| w.bits(data)); + } + } + + #[inline(always)] + fn read() -> u8 { + unsafe { + (*Self::Port::ptr()) + .#target_pin + .read() + .bits() + } + } + + #[inline(always)] + fn set_low() { + unsafe { + (*Self::Port::ptr()) + .#target_port + .modify(|_r, w| w.#writer_method().clear_bit()) + } + } + + #[inline(always)] + fn set_high() { + unsafe { + (*Self::Port::ptr()) + .#target_port + .modify(|_r, w| w.#writer_method().set_bit()) + } + } + + #[inline(always)] + fn is_low() -> bool { + (Self::read() & Self::PIN_POS) == 0 + } + + #[inline(always)] + fn is_high() -> bool { + (Self::read() & Self::PIN_POS) != 0 + } + + #[inline(always)] + fn into_input() { + unsafe { + (*Self::Port::ptr()) + .#target_data_direction + .modify(|_r, w| w.#writer_method().clear_bit()); + (*Self::Port::ptr()) + .#target_port + .modify(|_r, w| w.#writer_method().clear_bit()); + } + } + + #[inline(always)] + fn into_output() { + unsafe { + (*Self::Port::ptr()) + .#target_data_direction + .modify(|_r, w| w.#writer_method().set_bit()); + (*Self::Port::ptr()) + .#target_port + .modify(|_r, w| w.#writer_method().clear_bit()); + } + } + + #[inline(always)] + fn into_output_high() { + unsafe { + (*Self::Port::ptr()) + .#target_data_direction + .modify(|_r, w| w.#writer_method().set_bit()); + (*Self::Port::ptr()) + .#target_port + .modify(|_r, w| w.#writer_method().set_bit()); + } + } + + #[inline(always)] + fn into_pull_up_input() { + unsafe { + (*Self::Port::ptr()) + .#target_data_direction + .modify(|_r, w| w.#writer_method().clear_bit()); + (*Self::Port::ptr()) + .#target_port + .modify(|_r, w| w.#writer_method().set_bit()); + } + } + } + }; + + TokenStream::from(impl_trait) + } else { + unreachable!() + } +}