Skip to content

Commit

Permalink
feat(joystick): add feature about joystick
Browse files Browse the repository at this point in the history
support input devices with 2 analog inputs
somthing might be ruined by my faults :(
tests are insufficient
  • Loading branch information
drindr committed Dec 16, 2024
1 parent 8302bdd commit d66deae
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 38 deletions.
33 changes: 18 additions & 15 deletions rmk-macro/src/analog.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use proc_macro2::TokenStream;
use proc_macro2::{TokenStream, Ident};
use quote::{ quote, format_ident };
use crate::keyboard_config::{ KeyboardConfig, CommunicationConfig };

pub fn expand_analog(keyboard_config: &KeyboardConfig) -> (TokenStream, TokenStream) {
pub fn expand_analog(keyboard_config: &KeyboardConfig, channel_config:Vec<(Vec<TokenStream>, Ident)>) -> (TokenStream, TokenStream) {
let mut config = TokenStream::new();
let mut task = TokenStream::new();
let mut pins = vec!();
let mut channels = vec!();
let mut channel_sep = vec!(0usize);
let mut pin_channels = vec!();
Expand All @@ -20,27 +19,30 @@ pub fn expand_analog(keyboard_config: &KeyboardConfig) -> (TokenStream, TokenStr
quote! { p.#adc_pin_ident.degrade_saadc() }
};
let channel_cfg = format_ident!("channel_cfg_{}", channel_sep.len());
pins.push(quote! {
// use ::embassy_nrf::saadc::Input as _;
// Then we initialize the ADC. We are only using one channel in this example.
let #channel_cfg = ::embassy_nrf::saadc::ChannelConfig::single_ended(#adc_pin_def);
});
pin_channels.push(channel_cfg);
channels.push(quote!{ ::rmk::ble::nrf::BLE_BATTERY_CHANNEL.try_send });
pin_channels.push(quote!{ ::embassy_nrf::saadc::ChannelConfig::single_ended(#adc_pin_def) });
channels.push(quote!{ ::rmk::ble::nrf::BLE_BATTERY_CHANNEL });
channel_sep.push(channel_sep.last().unwrap() + 1);
}
}
}
_ => {}
};

channel_config.into_iter().for_each(|(mut channel_config, channel_ident)| {
channel_sep.push(channel_sep.last().unwrap() + channel_config.len());
pin_channels.append(&mut channel_config);
channels.push(quote!{ #channel_ident });
});

let rev_side = channel_sep.iter().rev().collect::<Vec<_>>();
let range = rev_side[1..].into_iter().rev().zip(channel_sep[1..].into_iter());
let send_expr = range.zip(channels).map(|((l, r), c)| {
let idx = **l..*r;
quote!{
match #c([#(buf[#idx]), *]) {
Ok(_) => break,
Err(e) => warn!("failed to send analog info between {}, {}", #l, #r),
if !#c.is_full() {
if let Err(e) = #c.try_send([#(buf[#idx]), *]) {
warn!("failed to send analog info between {}, {}, because {}", #l, #r, e);
}
}
}
});
Expand All @@ -49,7 +51,6 @@ pub fn expand_analog(keyboard_config: &KeyboardConfig) -> (TokenStream, TokenStr

config.extend(quote! {
let run_analog_monitor = {
#(#pins) *
let config = ::embassy_nrf::saadc::Config::default();
::embassy_nrf::interrupt::SAADC.set_priority(::embassy_nrf::interrupt::Priority::P3);
let mut saadc = ::embassy_nrf::saadc::Saadc::new(p.SAADC, Irqs, config, [#(#pin_channels), *]);
Expand All @@ -59,8 +60,10 @@ pub fn expand_analog(keyboard_config: &KeyboardConfig) -> (TokenStream, TokenStr
|| async move {
let mut buf = [0i16; #buf_size];
loop {
//info!("start to sample!");
saadc.sample(&mut buf).await;
info!("saadc sample: {}", buf);

//info!("saadc sample: {}", buf);
#(#send_expr)*
}
}
Expand Down
32 changes: 18 additions & 14 deletions rmk-macro/src/chip_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,24 @@ pub(crate) fn chip_init_default(chip: &ChipModel) -> TokenStream2 {
quote! {}
};
quote! {
use embassy_nrf::interrupt::InterruptExt;
let mut config = ::embassy_nrf::config::Config::default();
// config.hfclk_source = ::embassy_nrf::config::HfclkSource::ExternalXtal;
// config.lfclk_source = ::embassy_nrf::config::LfclkSource::ExternalXtal;
config.gpiote_interrupt_priority = ::embassy_nrf::interrupt::Priority::P3;
config.time_interrupt_priority = ::embassy_nrf::interrupt::Priority::P3;
#usb_related_config
::embassy_nrf::interrupt::POWER_CLOCK.set_priority(::embassy_nrf::interrupt::Priority::P2);
let p = ::embassy_nrf::init(config);
// Disable external HF clock by default, reduce power consumption
// let clock: ::embassy_nrf::pac::CLOCK = unsafe { ::core::mem::transmute(()) };
// info!("Enabling ext hfosc...");
// clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
// while clock.events_hfclkstarted.read().bits() != 1 {}
use embassy_nrf::{ interrupt::InterruptExt, config::Reg0Voltage};
let mut config = ::embassy_nrf::config::Config::default();

// https://github.com/embassy-rs/embassy/issues/3134
config.dcdc.reg0 = true;
config.dcdc.reg0_voltage = Some(Reg0Voltage::_3v3);
// config.hfclk_source = ::embassy_nrf::config::HfclkSource::ExternalXtal;
// config.lfclk_source = ::embassy_nrf::config::LfclkSource::ExternalXtal;
config.gpiote_interrupt_priority = ::embassy_nrf::interrupt::Priority::P3;
config.time_interrupt_priority = ::embassy_nrf::interrupt::Priority::P3;
#usb_related_config
::embassy_nrf::interrupt::POWER_CLOCK.set_priority(::embassy_nrf::interrupt::Priority::P2);
let p = ::embassy_nrf::init(config);
// Disable external HF clock by default, reduce power consumption
// let clock: ::embassy_nrf::pac::CLOCK = unsafe { ::core::mem::transmute(()) };
// info!("Enabling ext hfosc...");
// clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
// while clock.events_hfclkstarted.read().bits() != 1 {}
}
}
ChipSeries::Rp2040 => {
Expand Down
10 changes: 10 additions & 0 deletions rmk-macro/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ pub struct SplitBoardConfig {
/// Serial config, the vector length should be 1 for peripheral
pub serial: Option<Vec<SerialConfig>>,
pub matrix: MatrixConfig,
/// Joystick
pub joystick: Option<Vec<JoystickConfig>>,
}

/// Serial port config
Expand All @@ -196,6 +198,14 @@ pub struct SerialConfig {
pub rx_pin: String,
}

#[derive(Clone, Debug, Default, Deserialize)]
pub struct JoystickConfig {
pub instance: String,
pub axis: [String; 2],
pub dead: Option<[u8; 2]>,
pub transform: Option<[[i8; 2]; 2]>
}

/// Duration in milliseconds
#[derive(Clone, Debug, Deserialize)]
pub struct DurationMillis(#[serde(deserialize_with = "parse_duration_millis")] pub u64);
Expand Down
78 changes: 78 additions & 0 deletions rmk-macro/src/joystick.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//! Joystick
//!
use quote::{format_ident, quote};
use crate::{config::JoystickConfig, ChipModel, ChipSeries};

pub(crate) fn expand_joystick(
chip: &ChipModel,
joystick_config: Vec<JoystickConfig>
) -> Vec<(proc_macro2::TokenStream, (Vec<proc_macro2::TokenStream>, proc_macro2::Ident), proc_macro2::TokenStream)> {
let mut ret = vec!();
if chip.series == ChipSeries::Nrf52 {
for conf in joystick_config.into_iter() {
let mut task = proc_macro2::TokenStream::new();
let mut channel_config = vec!();
let joystick_ident = format_ident!("joystick_{}", conf.instance);
let mut num = 2usize;
for (idx, axis_pin) in conf.axis.iter().enumerate() {
if axis_pin != "_" {
let pin = convert_gpio_str_to_adc_pin(chip, axis_pin.to_string());
channel_config.push(quote!{ {
use ::embassy_nrf::saadc::{Reference, Gain, Time};
let mut p = ::embassy_nrf::saadc::ChannelConfig::single_ended(#pin);
p.reference = Reference::VDD1_4;
p.gain = Gain::GAIN1_4;
p
} });
} else {
num = 1;
}
}
let trans_config = conf.transform.unwrap_or([[1i8, 1i8], [1i8, 1i8]]);
let trans = trans_config.map(|n| {
quote!{ [#(#n), *] }
});
let channel_name = format_ident!("joystick_channel_{}", conf.instance);
let channel_sender_name = format_ident!("joystick_channel_send_{}", conf.instance);
let channel_receiver_name = format_ident!("joystick_channel_recv_{}", conf.instance);

let joystick_run_ident = format_ident!("joystick_run_{}", conf.instance);
let initializer = quote!{
let #channel_name = Channel::<CriticalSectionRawMutex, [i16; #num], 4>::new();
use ::embassy_sync::{
channel::Channel,
blocking_mutex::raw::CriticalSectionRawMutex
};
let #channel_sender_name = #channel_name.sender();
let #channel_receiver_name = #channel_name.receiver();

let #joystick_run_ident = || async move {
use ::embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
::rmk::joystick::run_joystick::<#num, 1600, 4, CriticalSectionRawMutex>([#(#trans), *], #channel_receiver_name).await;
};
};

task.extend(quote!{
#joystick_run_ident()
});

ret.push((initializer, (channel_config, channel_sender_name), task))
};
ret
} else {
vec!((quote!{ compile_error!("\"Joystick\" only support Nrf52 now"); },
(vec!(), proc_macro2::Ident::new("Useless", proc_macro2::Span::call_site())),
proc_macro2::TokenStream::new()))
}

}

pub(crate) fn convert_gpio_str_to_adc_pin(chip: &ChipModel, axis_pin: String) -> proc_macro2::TokenStream {
if chip.series == ChipSeries::Nrf52 {
let axis_ident = format_ident!("{}", axis_pin);
quote!{ p.#axis_ident }
} else {
quote!{ compile_error!("\"Joystick\" only support for Nrf52 now"); }
}
}
1 change: 1 addition & 0 deletions rmk-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod layout;
mod light;
mod matrix;
mod split;
mod joystick;
mod analog;
#[rustfmt::skip]
mod usb_interrupt_map;
Expand Down
41 changes: 33 additions & 8 deletions rmk-macro/src/split/central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ use crate::{
feature::{get_rmk_features, is_feature_enabled},
flash::expand_flash_init,
import::expand_imports,
analog::expand_analog,
joystick::expand_joystick,
keyboard::gen_imports,
keyboard_config::{read_keyboard_toml_config, BoardConfig, KeyboardConfig},
light::expand_light_config,
matrix::{expand_matrix_direct_pins, expand_matrix_input_output_pins},
analog::expand_analog,
ChipModel, ChipSeries,
ChipModel, ChipSeries
};

/// Parse split central mod and generate a valid RMK main function with all needed code
Expand Down Expand Up @@ -129,10 +130,31 @@ fn expand_split_central(

let split_communication_config =
expand_split_communication_config(&keyboard_config.chip, split_config);

let (ble_config, set_ble_config) = expand_ble_config(keyboard_config);
let (analog_config, analog_task) = expand_analog(keyboard_config);
let run_rmk = expand_split_central_entry(keyboard_config, split_config, vec!(analog_task));

let mut other_tasks = vec!();

// (joystick_config, joystick_channel, joystick_task)
let joystick = if let Some(joystick_conf) = split_config.central.joystick.clone() {
expand_joystick(&keyboard_config.chip, joystick_conf)
} else {
vec!()
};

let mut analog_channel = vec!();
let mut joystick_config = vec!();
joystick.into_iter().for_each(|(config, channel, task)| {
joystick_config.push(config);
analog_channel.push(channel);
other_tasks.push(task);
});

let (analog_config, analog_task) = expand_analog(keyboard_config, analog_channel);
other_tasks.push(analog_task);

let run_rmk = expand_split_central_entry(keyboard_config, split_config, other_tasks);

let main_function_sig = if keyboard_config.chip.series == ChipSeries::Esp32 {
quote! {
use ::esp_idf_svc::hal::gpio::*;
Expand All @@ -150,7 +172,7 @@ fn expand_split_central(
#imports

#bind_interrupt

#main_function_sig {
::defmt::info!("RMK start!");
// Initialize peripherals as `p`
Expand All @@ -171,11 +193,13 @@ fn expand_split_central(
// Initialize matrix config as `(input_pins, output_pins)`
#matrix_config

#(#joystick_config); *

#analog_config

// Initialize split central ble config
#ble_config

#analog_config

// Set all keyboard config
let keyboard_config = ::rmk::config::RmkConfig {
usb_config: KEYBOARD_USB_CONFIG,
Expand Down Expand Up @@ -275,6 +299,7 @@ fn expand_split_central_entry(
});
});

other_tasks.into_iter().for_each(|t| { tasks.push(t); });
join_all_tasks(tasks)
}
ChipSeries::Nrf52 => {
Expand Down Expand Up @@ -328,7 +353,7 @@ fn expand_split_central_entry(
)
});
});
other_tasks.into_iter().for_each(|t|{ tasks.push(t); });
other_tasks.into_iter().for_each(|t| { tasks.push(t); });
join_all_tasks(tasks)
}
ChipSeries::Rp2040 => {
Expand Down
3 changes: 3 additions & 0 deletions rmk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ rapid_debouncer = []
## Feature for split keyboard
split = []

## Feature for analog joystick
joystick = []

## Internal feature that indicates no USB is used, this feature will be auto-activated for some chips
_no_usb = []

Expand Down
2 changes: 1 addition & 1 deletion rmk/src/ble/nrf/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl<'a, const N: usize> HidWriterWrapper for BleHidWriter<'a, N> {
error!("Send ble report error: {}", e);
match e {
gatt_server::NotifyValueError::Disconnected => HidError::BleDisconnected,
gatt_server::NotifyValueError::Raw(_) => HidError::BleRawError,
gatt_server::NotifyValueError::Raw(_) => {HidError::BleRawError},
}
})
}
Expand Down
Loading

0 comments on commit d66deae

Please sign in to comment.