first commit

This commit is contained in:
doryan 2025-04-21 19:43:16 +04:00
commit 728e7d5be7
7 changed files with 266 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/target
*/target/
*/Cargo.lock/
Cargo.lock
.cargo

27
Cargo.toml Normal file
View File

@ -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"

4
rust-toolchain.toml Normal file
View File

@ -0,0 +1,4 @@
[toolchain]
channel = "nightly-2024-06-13"
components = [ "rust-src" ]
profile = "minimal"

49
src/lib.rs Normal file
View File

@ -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);
)+
}
}

View File

@ -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"

View File

@ -0,0 +1,4 @@
[toolchain]
channel = "nightly-2024-06-13"
components = [ "rust-src" ]
profile = "minimal"

View File

@ -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::<syn::Ident>(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!()
}
}