feat(procon): implement spi functionality
All checks were successful
Code quality / check (pull_request) Successful in 3m46s

This commit is contained in:
Naxdy 2024-10-14 20:45:32 +02:00
parent 3b60499fff
commit e12666cf50
Signed by: Naxdy
GPG key ID: CC15075846BCE91B
2 changed files with 164 additions and 25 deletions

View file

@ -228,18 +228,23 @@ impl ProconByteReport {
self[26] = 0x02;
}
fn sw_spi_readfromaddress(&mut self, offset_address: u8, address: u8, length: u8) {
fn sw_spi_readfromaddress(
&mut self,
offset_address: u8,
address: u8,
length: u8,
switch_host_address: &[u8],
) {
let read_info = [address, offset_address, 0x00, 0x00, length];
self[15..(15 + read_info.len())].copy_from_slice(&read_info);
let mut output_spi_data = [0u8; 30];
output_spi_data
.iter_mut()
.enumerate()
.for_each(|(i, e)| *e = sw_spi_getaddressdata(offset_address, address + i as u8));
output_spi_data.iter_mut().enumerate().for_each(|(i, e)| {
*e = sw_spi_getaddressdata(offset_address, address + i as u8, switch_host_address)
});
self[19..(19 + length as usize)].copy_from_slice(&output_spi_data[..(length as usize)]);
self[20..(20 + length as usize)].copy_from_slice(&output_spi_data[..(length as usize)]);
}
fn set_trigerret(&mut self, time_10_ms: u16) {
@ -252,9 +257,133 @@ impl ProconByteReport {
}
}
fn sw_spi_getaddressdata(_offset_address: u8, _address: u8) -> u8 {
// TODO
0
fn sw_spi_getaddressdata(offset_address: u8, address: u8, switch_host_address: &[u8]) -> u8 {
match offset_address {
0x00 => 0x00,
0x20..=0x40 => match address {
0x26 | 0x00 => 0x95,
// Size of pairing data
0x27 | 0x01 => 0x22,
// Checksum
0x28 | 0x29 | 0x02 | 0x03 => 0x00,
// Host BT address (Big-endian)
0x2A..=0x2F => switch_host_address[(address - 0x2a) as usize],
0x04..=0x09 => switch_host_address[(address - 4) as usize],
// Bluetooth LTK (Little-endian) NOT IMPLEMENTED YET
0x30..=0x3F => 0x00,
0x0A..=0x19 => 0x00,
// Host capability 0x68 is Nintendo Switch. 0x08 is PC
0x4A | 0x24 => 0x68,
0x4B | 0x25 => 0,
_ => 0x00,
},
0x50 => 0x00,
0x60 => match address {
0x00..0x0f => 0xff,
0x12 => 0x03,
0x13 => 0x02,
0x1b => 0x01,
0x20 => 35,
0x21 => 0,
0x22 => 185,
0x23 => 255,
0x24 => 26,
0x25 => 1,
0x26 => 0,
0x27 => 64,
0x28 => 0,
0x29 => 64,
0x2A => 0,
0x2B => 64,
0x2C => 1,
0x2D => 0,
0x2E => 1,
0x2F => 0,
0x30 => 1,
0x31 => 0,
0x32 => 0x3B,
0x33 => 0x34,
0x34 => 0x3B,
0x35 => 0x34,
0x36 => 0x3B,
0x37 => 0x34,
0x3d..=0x45 => mk_switch_analog_calibration_data()[(address - 0x3d) as usize],
0x46..=0x4e => mk_switch_analog_calibration_data()[(address - 0x3d) as usize],
0x4F => 0xFF,
0x50 => 26,
0x51 => 26,
0x52 => 26,
0x53..=0x55 => 94,
0x56 => 255,
0x57 => 255,
0x58 => 255,
0x59..=0x5B => 255,
0x5C => 0x01,
0x80 => 80,
0x81 => 253,
0x82 => 0,
0x83 => 0,
0x84 => 198,
0x85 => 15,
0x98 | 0x86 => 15,
0x99 | 0x87 => 48,
0x9A | 0x88 => 97,
0x9B | 0x89 => 174,
0x9C | 0x8A => 144,
0x9D | 0x8B => 217,
0x9E | 0x8C => 212,
0x9F | 0x8D => 20,
0xA0 | 0x8E => 84,
0xA1 | 0x8F => 65,
0xA2 | 0x90 => 21,
0xA3 | 0x91 => 84,
0xA4 | 0x92 => 199,
0xA5 | 0x93 => 121,
0xA6 | 0x94 => 156,
0xA7 | 0x95 => 51,
0xA8 | 0x96 => 54,
0xA9 | 0x97 => 99,
_ => 0,
},
0x80 => match address {
0x10..=0x1a => 0xff,
0x1b..=0x25 => 0xff,
0x26..=0x3f => 0xff,
_ => 0xff,
},
_ => 0xff,
}
}
fn mk_switch_analog_calibration_data() -> [u8; 18] {
fn switch_analog_encode(in_lower: u16, in_upper: u16) -> [u8; 3] {
let mut out = [0u8; 3];
[out[0], out[1]] = in_lower.to_le_bytes();
out[1] |= ((in_upper & 0xf) << 4) as u8;
out[2] = ((in_upper & 0xff0) >> 4) as u8;
out
}
const MIN: u16 = 128 << 4;
const MAXX: u16 = 128 << 4;
const CENTER: u16 = 128 << 4;
let mut out = [0u8; 18];
out[0..3].copy_from_slice(&switch_analog_encode(MAXX, MAXX));
out[3..6].copy_from_slice(&switch_analog_encode(CENTER, CENTER));
out[6..9].copy_from_slice(&switch_analog_encode(MIN, MIN));
out[9..12].copy_from_slice(&switch_analog_encode(CENTER, CENTER));
out[12..15].copy_from_slice(&switch_analog_encode(MIN, MIN));
out[15..18].copy_from_slice(&switch_analog_encode(MAXX, MAXX));
info!("Returning switch data: {:x}", out);
out
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
@ -321,7 +450,7 @@ pub struct ProconButtonsLeft {
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
#[packed_struct(bit_numbering = "msb0", endian = "msb", size_bytes = "9")]
#[packed_struct(bit_numbering = "msb0", endian = "lsb", size_bytes = "9")]
pub struct ProconState {
#[packed_field(bits = "0..=7")]
pub buttons_right: ProconButtonsRight,
@ -333,7 +462,7 @@ pub struct ProconState {
pub lstick_x: u16,
#[packed_field(bits = "40..=47")]
pub lstick_y: u8,
#[packed_field(bits = "48..=60")]
#[packed_field(bits = "48..=63")]
pub rstick_x: u16,
#[packed_field(bits = "64..=71")]
pub rstick_y: u8,
@ -374,8 +503,8 @@ impl From<&GcState> for ProconState {
button_b: value.buttons_1.button_b,
button_x: value.buttons_1.button_x,
button_y: value.buttons_1.button_y,
trigger_r: value.buttons_2.button_r,
trigger_zr: value.buttons_2.button_z,
trigger_r: value.buttons_2.button_z,
trigger_zr: value.buttons_2.button_r,
..Default::default()
},
buttons_shared: ProconButtonsShared {
@ -383,9 +512,9 @@ impl From<&GcState> for ProconState {
button_home: value.buttons_2.button_start && value.buttons_2.button_z,
..Default::default()
},
lstick_x: value.stick_x as u16 * 257,
lstick_x: value.stick_x as u16 * 16,
lstick_y: value.stick_y,
rstick_x: value.cstick_x as u16 * 257,
rstick_x: value.cstick_x as u16 * 16,
rstick_y: value.cstick_y,
}
}
@ -394,6 +523,7 @@ impl From<&GcState> for ProconState {
pub struct ProconReportBuilder {
switch_reporting_mode: u8,
switch_mac_address: [u8; 6],
switch_host_address: [u8; 6],
switch_ltk: [u8; 16],
}
@ -401,12 +531,26 @@ impl Default for ProconReportBuilder {
fn default() -> Self {
Self {
switch_reporting_mode: 0,
switch_mac_address: [0u8; 6],
switch_mac_address: gen_switch_mac_address(),
switch_host_address: [0u8; 6],
switch_ltk: gen_switch_ltk(),
}
}
}
fn gen_switch_mac_address() -> [u8; 6] {
let mut mac_addr = [0u8; 6];
mac_addr.iter_mut().for_each(|e| {
*e = RoscRng.next_u64() as u8;
});
mac_addr[0] &= 0xfe;
mac_addr[5] = 0x9b;
mac_addr
}
fn gen_switch_ltk() -> [u8; 16] {
let mut switch_ltk = [0u8; 16];
@ -495,6 +639,7 @@ impl ProconReportBuilder {
current_report_info.raw_data[12],
current_report_info.raw_data[11],
current_report_info.raw_data[15],
&self.switch_host_address,
);
}
SW_CMD_SET_SHIPMODE => {
@ -526,18 +671,12 @@ impl ProconReportBuilder {
match pairing_phase {
1 => {
self.switch_mac_address
self.switch_host_address
.iter_mut()
.enumerate()
.for_each(|(i, e)| *e = host_address[5 - i]);
self.switch_mac_address
.iter()
.rev()
.enumerate()
.for_each(|(i, e)| {
report[16 + i] = *e;
});
report[16..=21].copy_from_slice(&self.switch_mac_address);
report[22..(22 + PRO_CONTROLLER_STRING.len())]
.copy_from_slice(&PRO_CONTROLLER_STRING);

View file

@ -551,7 +551,7 @@ pub async fn update_stick_states_task(
spi_acs: Output<'static>,
spi_ccs: Output<'static>,
) {
Timer::after_secs(1).await;
Timer::after_secs(3).await;
*SPI_SHARED.lock().await = Some(spi);
*SPI_ACS_SHARED.lock().await = Some(spi_acs);
*SPI_CCS_SHARED.lock().await = Some(spi_ccs);