forked from NaxdyOrg/NaxGCC-FW
Compare commits
1 commit
main
...
work/impro
Author | SHA1 | Date | |
---|---|---|---|
1d51c12bc1 |
9 changed files with 35 additions and 59 deletions
|
@ -1,7 +0,0 @@
|
||||||
This is mainly a QoL and performance update for the NaxGCC. The following changes have been made:
|
|
||||||
|
|
||||||
- Added a MSOS descriptor to the USB device, allowing the NaxGCC to be immediately recognized on Windows, without the need for a custom driver. This should make it plug-and-play for Dolphin on Windows.
|
|
||||||
- Improved the "rate limiting" of SuperHack mode, which should make it more consistent and less likely to drop inputs compared to "Consistency" mode.
|
|
||||||
- Added a new "PC" mode which polls at 1000Hz, for use on PC or other consoles that don't have any issues with 1000Hz polling. The "OG" mode now polls at 125Hz always, regardless of which device it is connected to.
|
|
||||||
|
|
||||||
To update your firmware, plug in your controller while keeping the `A+X+Y` buttons held. Then drag & drop the `.uf2` file (found below, under Downloads) onto the storage device that appears.
|
|
|
@ -1 +0,0 @@
|
||||||
v1.1.0.md
|
|
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -875,7 +875,7 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naxgcc-fw"
|
name = "naxgcc-fw"
|
||||||
version = "1.1.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "naxgcc-fw"
|
name = "naxgcc-fw"
|
||||||
version = "1.1.1"
|
version = "1.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -58,7 +58,7 @@ codegen-units = 1
|
||||||
debug = 2
|
debug = 2
|
||||||
debug-assertions = true
|
debug-assertions = true
|
||||||
incremental = false
|
incremental = false
|
||||||
opt-level = 3
|
opt-level = 1
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
overflow-checks = true
|
overflow-checks = true
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ incremental = false
|
||||||
lto = 'fat'
|
lto = 'fat'
|
||||||
# opt level needs to be benchmarked after every major feature
|
# opt level needs to be benchmarked after every major feature
|
||||||
# due to the changes in binary size and alignment
|
# due to the changes in binary size and alignment
|
||||||
opt-level = 3
|
opt-level = 1
|
||||||
overflow-checks = false
|
overflow-checks = false
|
||||||
|
|
||||||
# do not optimize proc-macro crates = faster builds from scratch
|
# do not optimize proc-macro crates = faster builds from scratch
|
||||||
|
|
|
@ -34,7 +34,7 @@ use embassy_sync::{
|
||||||
pubsub::Subscriber,
|
pubsub::Subscriber,
|
||||||
signal::Signal,
|
signal::Signal,
|
||||||
};
|
};
|
||||||
use embassy_time::Timer;
|
use embassy_time::{Duration, Ticker, Timer};
|
||||||
|
|
||||||
use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE};
|
use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE};
|
||||||
|
|
||||||
|
@ -558,9 +558,6 @@ pub enum InputConsistencyMode {
|
||||||
/// to something your opponent does.
|
/// to something your opponent does.
|
||||||
/// The name is not meant to imply that this is a hack that is super, but rather that this is super hacky.
|
/// The name is not meant to imply that this is a hack that is super, but rather that this is super hacky.
|
||||||
SuperHack = 2,
|
SuperHack = 2,
|
||||||
/// Transmit inputs every 1 ms, for use on PC or other devices that are not garbage.
|
|
||||||
/// This is not recommended for use on the Switch!
|
|
||||||
PC = 3,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Format, PackedStruct)]
|
#[derive(Debug, Clone, Format, PackedStruct)]
|
||||||
|
@ -1057,6 +1054,8 @@ impl<'a> StickCalibrationProcess<'a> {
|
||||||
|
|
||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
|
let mut ticker = Ticker::every(Duration::from_millis(20));
|
||||||
|
|
||||||
let notch_idx = NOTCH_ADJUSTMENT_ORDER
|
let notch_idx = NOTCH_ADJUSTMENT_ORDER
|
||||||
[self.calibration_step as usize - NO_OF_CALIBRATION_POINTS];
|
[self.calibration_step as usize - NO_OF_CALIBRATION_POINTS];
|
||||||
|
|
||||||
|
@ -1098,7 +1097,7 @@ impl<'a> StickCalibrationProcess<'a> {
|
||||||
None => self.adjust_notch(NotchAdjustmentType::None),
|
None => self.adjust_notch(NotchAdjustmentType::None),
|
||||||
};
|
};
|
||||||
|
|
||||||
Timer::after_millis(1).await;
|
ticker.next().await;
|
||||||
yield_now().await;
|
yield_now().await;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1690,8 +1689,7 @@ async fn configuration_main_loop<
|
||||||
// input consistency toggle
|
// input consistency toggle
|
||||||
37 => {
|
37 => {
|
||||||
final_config.input_consistency_mode = match final_config.input_consistency_mode {
|
final_config.input_consistency_mode = match final_config.input_consistency_mode {
|
||||||
InputConsistencyMode::Original => InputConsistencyMode::PC,
|
InputConsistencyMode::Original => InputConsistencyMode::ConsistencyHack,
|
||||||
InputConsistencyMode::PC => InputConsistencyMode::ConsistencyHack,
|
|
||||||
InputConsistencyMode::ConsistencyHack => InputConsistencyMode::SuperHack,
|
InputConsistencyMode::ConsistencyHack => InputConsistencyMode::SuperHack,
|
||||||
InputConsistencyMode::SuperHack => InputConsistencyMode::Original,
|
InputConsistencyMode::SuperHack => InputConsistencyMode::Original,
|
||||||
};
|
};
|
||||||
|
@ -1715,7 +1713,6 @@ async fn configuration_main_loop<
|
||||||
stick_y: (127_i8
|
stick_y: (127_i8
|
||||||
+ match final_config.input_consistency_mode {
|
+ match final_config.input_consistency_mode {
|
||||||
InputConsistencyMode::Original => -69,
|
InputConsistencyMode::Original => -69,
|
||||||
InputConsistencyMode::PC => -42,
|
|
||||||
InputConsistencyMode::ConsistencyHack => 42,
|
InputConsistencyMode::ConsistencyHack => 42,
|
||||||
InputConsistencyMode::SuperHack => 69,
|
InputConsistencyMode::SuperHack => 69,
|
||||||
}) as u8,
|
}) as u8,
|
||||||
|
|
|
@ -179,7 +179,7 @@ pub struct KalmanState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KalmanState {
|
impl KalmanState {
|
||||||
#[inline(never)]
|
// runs kalman filter
|
||||||
#[link_section = ".time_critical.run_kalman"]
|
#[link_section = ".time_critical.run_kalman"]
|
||||||
pub fn run_kalman(
|
pub fn run_kalman(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -292,7 +292,6 @@ impl KalmanState {
|
||||||
/// output at the rim longer when released.
|
/// output at the rim longer when released.
|
||||||
///
|
///
|
||||||
/// Output is a tuple of the x and y positions.
|
/// Output is a tuple of the x and y positions.
|
||||||
#[inline(never)]
|
|
||||||
#[link_section = ".time_critical.run_waveshaping"]
|
#[link_section = ".time_critical.run_waveshaping"]
|
||||||
pub fn run_waveshaping(
|
pub fn run_waveshaping(
|
||||||
x_pos: f32,
|
x_pos: f32,
|
||||||
|
|
|
@ -17,7 +17,6 @@ use embassy_time::{Duration, Instant, Timer};
|
||||||
use embassy_usb::{
|
use embassy_usb::{
|
||||||
class::hid::{HidReaderWriter, ReportId, RequestHandler, State},
|
class::hid::{HidReaderWriter, ReportId, RequestHandler, State},
|
||||||
control::OutResponse,
|
control::OutResponse,
|
||||||
msos::{self, windows_version},
|
|
||||||
Builder, Handler,
|
Builder, Handler,
|
||||||
};
|
};
|
||||||
use libm::powf;
|
use libm::powf;
|
||||||
|
@ -37,9 +36,6 @@ pub static MUTEX_INPUT_CONSISTENCY_MODE: Mutex<
|
||||||
Option<InputConsistencyMode>,
|
Option<InputConsistencyMode>,
|
||||||
> = Mutex::new(None);
|
> = Mutex::new(None);
|
||||||
|
|
||||||
/// Vendor-defined property data
|
|
||||||
const DEVICE_INTERFACE_GUID: &str = "{ecceff35-146c-4ff3-acd9-8f992d09acdd}";
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub const GCC_REPORT_DESCRIPTOR: &[u8] = &[
|
pub const GCC_REPORT_DESCRIPTOR: &[u8] = &[
|
||||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||||
|
@ -306,7 +302,6 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: Driver<'static, USB>
|
||||||
InputConsistencyMode::Original => "NaxGCC (OG Mode)",
|
InputConsistencyMode::Original => "NaxGCC (OG Mode)",
|
||||||
InputConsistencyMode::ConsistencyHack => "NaxGCC (Consistency Mode)",
|
InputConsistencyMode::ConsistencyHack => "NaxGCC (Consistency Mode)",
|
||||||
InputConsistencyMode::SuperHack => "NaxGCC (SuperHack Mode)",
|
InputConsistencyMode::SuperHack => "NaxGCC (SuperHack Mode)",
|
||||||
InputConsistencyMode::PC => "NaxGCC (PC Mode)",
|
|
||||||
});
|
});
|
||||||
usb_config.serial_number = Some(serial);
|
usb_config.serial_number = Some(serial);
|
||||||
usb_config.max_power = 200;
|
usb_config.max_power = 200;
|
||||||
|
@ -338,26 +333,12 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: Driver<'static, USB>
|
||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
builder.msos_descriptor(windows_version::WIN8_1, 2);
|
|
||||||
|
|
||||||
let msos_writer = builder.msos_writer();
|
|
||||||
msos_writer.device_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
|
|
||||||
msos_writer.device_feature(msos::RegistryPropertyFeatureDescriptor::new(
|
|
||||||
"DeviceInterfaceGUID",
|
|
||||||
msos::PropertyData::Sz(DEVICE_INTERFACE_GUID),
|
|
||||||
));
|
|
||||||
|
|
||||||
builder.handler(&mut device_handler);
|
builder.handler(&mut device_handler);
|
||||||
|
|
||||||
let hid_config = embassy_usb::class::hid::Config {
|
let hid_config = embassy_usb::class::hid::Config {
|
||||||
report_descriptor: GCC_REPORT_DESCRIPTOR,
|
report_descriptor: GCC_REPORT_DESCRIPTOR,
|
||||||
request_handler: Some(&request_handler),
|
request_handler: Some(&request_handler),
|
||||||
poll_ms: match input_consistency_mode {
|
poll_ms: 1,
|
||||||
InputConsistencyMode::Original => 8,
|
|
||||||
InputConsistencyMode::ConsistencyHack
|
|
||||||
| InputConsistencyMode::SuperHack
|
|
||||||
| InputConsistencyMode::PC => 1,
|
|
||||||
},
|
|
||||||
max_packet_size_in: 37,
|
max_packet_size_in: 37,
|
||||||
max_packet_size_out: 5,
|
max_packet_size_out: 5,
|
||||||
};
|
};
|
||||||
|
@ -380,7 +361,8 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: Driver<'static, USB>
|
||||||
let mut gcc_subscriber = CHANNEL_GCC_STATE.subscriber().unwrap();
|
let mut gcc_subscriber = CHANNEL_GCC_STATE.subscriber().unwrap();
|
||||||
|
|
||||||
let mut last_report_time = Instant::now();
|
let mut last_report_time = Instant::now();
|
||||||
let mut rate_limit_end_time = Instant::now();
|
let mut frame_ready_time = Instant::now() + Duration::from_micros(8333);
|
||||||
|
let mut usb_ready_time = Instant::now() + Duration::from_millis(8);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// This is what we like to call a "hack".
|
// This is what we like to call a "hack".
|
||||||
|
@ -393,11 +375,29 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: Driver<'static, USB>
|
||||||
// a minimum of 333 extra us to send a report every time it's polled, but it
|
// a minimum of 333 extra us to send a report every time it's polled, but it
|
||||||
// works to our advantage.
|
// works to our advantage.
|
||||||
match input_consistency_mode {
|
match input_consistency_mode {
|
||||||
InputConsistencyMode::SuperHack | InputConsistencyMode::ConsistencyHack => {
|
InputConsistencyMode::SuperHack => {
|
||||||
// "Ticker at home", so we can use this for both consistency and SuperHack mode
|
// In SuperHack mode, we send reports only if the state changes, but
|
||||||
Timer::at(rate_limit_end_time).await;
|
// in order to not mess up very fast inputs (like sticks travelling, for example),
|
||||||
|
// we still need to "rate limit" the reports to every 8.33ms at most.
|
||||||
|
// This does rate limit it to ~8.33ms fairly well, my only
|
||||||
|
// gripe with it is that I hate it :)
|
||||||
|
Timer::at(last_report_time + Duration::from_micros(8100)).await;
|
||||||
}
|
}
|
||||||
InputConsistencyMode::Original | InputConsistencyMode::PC => {}
|
InputConsistencyMode::ConsistencyHack => {
|
||||||
|
// Ensure we report in multiples of 1 (not in decimals, like 8.33ms)
|
||||||
|
Timer::at(usb_ready_time).await;
|
||||||
|
while Instant::now() < frame_ready_time {
|
||||||
|
Timer::after_micros(1000).await;
|
||||||
|
}
|
||||||
|
// has to be done this way in case we're behind through e.g. suspends
|
||||||
|
while frame_ready_time < Instant::now() {
|
||||||
|
frame_ready_time += Duration::from_micros(8333);
|
||||||
|
}
|
||||||
|
while usb_ready_time < Instant::now() {
|
||||||
|
usb_ready_time += Duration::from_millis(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputConsistencyMode::Original => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match writer
|
match writer
|
||||||
|
@ -414,13 +414,6 @@ pub async fn usb_transfer_task(raw_serial: [u8; 8], driver: Driver<'static, USB>
|
||||||
let polltime = currtime.duration_since(last_report_time);
|
let polltime = currtime.duration_since(last_report_time);
|
||||||
let micros = polltime.as_micros();
|
let micros = polltime.as_micros();
|
||||||
debug!("Report written in {}us", micros);
|
debug!("Report written in {}us", micros);
|
||||||
if input_consistency_mode != InputConsistencyMode::Original
|
|
||||||
&& input_consistency_mode != InputConsistencyMode::PC
|
|
||||||
{
|
|
||||||
while rate_limit_end_time < currtime {
|
|
||||||
rate_limit_end_time += Duration::from_micros(8333);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_report_time = currtime;
|
last_report_time = currtime;
|
||||||
}
|
}
|
||||||
Err(e) => warn!("Failed to send report: {:?}", e),
|
Err(e) => warn!("Failed to send report: {:?}", e),
|
||||||
|
|
|
@ -82,7 +82,6 @@ pub enum StickAxis {
|
||||||
YAxis,
|
YAxis,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
|
||||||
#[link_section = ".time_critical.read_ext_adc"]
|
#[link_section = ".time_critical.read_ext_adc"]
|
||||||
pub fn read_ext_adc<
|
pub fn read_ext_adc<
|
||||||
'a,
|
'a,
|
||||||
|
@ -126,7 +125,6 @@ pub fn read_ext_adc<
|
||||||
/// Gets the average stick state over a 1ms interval in a non-blocking fashion.
|
/// Gets the average stick state over a 1ms interval in a non-blocking fashion.
|
||||||
/// Will wait until end_time is reached before continuing after reading the ADCs.
|
/// Will wait until end_time is reached before continuing after reading the ADCs.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[inline(never)]
|
|
||||||
#[link_section = ".time_critical.update_stick_states"]
|
#[link_section = ".time_critical.update_stick_states"]
|
||||||
async fn update_stick_states(
|
async fn update_stick_states(
|
||||||
current_stick_state: &StickState,
|
current_stick_state: &StickState,
|
||||||
|
@ -542,7 +540,6 @@ pub async fn update_button_state_task(
|
||||||
///
|
///
|
||||||
/// Has to run on core0 because it makes use of SPI0.
|
/// Has to run on core0 because it makes use of SPI0.
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
#[inline(never)]
|
|
||||||
#[link_section = ".time_critical.update_stick_states_task"]
|
#[link_section = ".time_critical.update_stick_states_task"]
|
||||||
pub async fn update_stick_states_task(
|
pub async fn update_stick_states_task(
|
||||||
spi: Spi<'static, SPI0, embassy_rp::spi::Blocking>,
|
spi: Spi<'static, SPI0, embassy_rp::spi::Blocking>,
|
||||||
|
|
|
@ -882,7 +882,6 @@ pub fn calc_stick_values(angle: f32) -> (f32, f32) {
|
||||||
(x, y)
|
(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
|
||||||
#[link_section = ".time_critical.linearize"]
|
#[link_section = ".time_critical.linearize"]
|
||||||
pub fn linearize(point: f32, coefficients: &[f32; NUM_COEFFS]) -> f32 {
|
pub fn linearize(point: f32, coefficients: &[f32; NUM_COEFFS]) -> f32 {
|
||||||
coefficients[0] * (point * point * point)
|
coefficients[0] * (point * point * point)
|
||||||
|
@ -891,7 +890,6 @@ pub fn linearize(point: f32, coefficients: &[f32; NUM_COEFFS]) -> f32 {
|
||||||
+ coefficients[3]
|
+ coefficients[3]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
|
||||||
#[link_section = ".time_critical.notch_remap"]
|
#[link_section = ".time_critical.notch_remap"]
|
||||||
pub fn notch_remap(
|
pub fn notch_remap(
|
||||||
x_in: f32,
|
x_in: f32,
|
||||||
|
|
Loading…
Reference in a new issue