Skip to content

Commit

Permalink
Fix readmes, rename examples (#19)
Browse files Browse the repository at this point in the history
* Move README.md into wii-ext so docs.rs will accept it

* Re-add readme in repo root

* Add links to example projects in repo README.md

* Add blocking nunchuk example

* Rename examples to make them consistent

* Remove readmes from examples
  • Loading branch information
9names authored Apr 25, 2024
1 parent 6eb4218 commit c16dffb
Show file tree
Hide file tree
Showing 27 changed files with 297 additions and 68 deletions.
64 changes: 7 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,13 @@ This is a platform agnostic Rust driver for Wiimote Extension controllers (Nunch

This driver allows you to read all axes and buttons for Wiimote Extension controllers

## Physical protocol details

Wiimote extension controllers are designed to talk to a Wiimote over an I2C interface at 3.3V.
The official controllers are capable of operating in fast-mode (400Khz) though some clones require normal-mode (100Khz).
The protocol is quite simple - it's not officially documented, but it has been reverse-engineered.

- <http://wiibrew.org/wiki/Wiimote/Extension_Controllers>
- <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck>
- <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller>

High Resolution mode is a recent addition and was only discovered once the NES Classic console was released. It is described here:
- <https://www.raphnet-tech.com/support/classic_controller_high_res>


Wii Motion Plus support is planned, both in standalone and combo mode

## Usage

To use this driver, import this crate and an `embedded_hal`/`embedded_hal_async` implementation,
then instantiate the appropriate device.

```rust
use ::I2C; // insert an include for your HAL i2c peripheral name here
// use the synchronous/blocking driver
use wii_ext::blocking_impl::classic::Classic;
// use the asynchronous driver
// use wii_ext::async_impl::classic::Classic;

fn main() {
let i2c = I2C::new(); // insert your HAL i2c init here
let mut delay = cortex_m::delay::Delay::new(); // some delay source as well
// Create, initialise and calibrate the controller
// You could use Nunchuk::new() instead of Classic::new() here
let mut controller = Classic::new(i2c, delay).unwrap();
// Enable hi-resolution mode. This also updates calibration
// Only supported for Classic controllers
controller.enable_hires().unwrap();
loop {
// read_blocking returns calibrated data: joysticks and
// triggers will return signed integers, relative to calibration
// position. Eg: center is (0,0), left is (-90,0) in standard resolution
// or (-126,0) in HD, etc
let input = controller.read().unwrap();
// You can read individual buttons...
let a = input.button_a;
let b = input.button_b;
// or joystick axes
let x = input.joystick_left_x;
let y = input.joystick_left_y;
// the data structs optionally support defmt::debug
// if you enable features=["defmt_print"]
info!("{:?}", input);
// Calibration can be manually performed as needed
controller.update_calibration().unwrap();
}
}
```
Driver docs are available in [the wii-ext directory](wii-ext/README.md)

Examples:
- [using the async api for classic controller](examples/classic-async-embassy-rp)
- [using the async api for the nunchuk controller](examples/nunchuk-async-embassy-rp)
- [using the blocking api for classic controller](examples/classic-blocking-rp2040-hal)
- [using the blocking api for the nunchuk controller](examples/nunchuk-blocking-rp2040-hal)

## Status

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[package]
edition = "2021"
name = "embassy_rp_async"
name = "classic-async-embassy-rp"
version = "0.1.0"
license = "MIT OR Apache-2.0"
resolver = "2"

publish = false

[dependencies]
wii-ext = { version = "0.4.0", features = [
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
[package]
authors = ["9names"]
edition = "2018"
readme = "README.md"
name = "wii-ext_blocking_demo"
name = "classic-blocking-rp2040-hal"
version = "0.1.0"
resolver = "2"
publish = false
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions examples/nunchuk-async-embassy-rp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[package]
edition = "2021"
name = "nunchuk_async_embassy_rp"
name = "nunchuk-async-embassy-rp"
version = "0.1.0"
license = "MIT OR Apache-2.0"
resolver = "2"

publish = false

[dependencies]
wii-ext = { version = "0.4.0", features = [
Expand Down
15 changes: 15 additions & 0 deletions examples/nunchuk-blocking-rp2040-hal/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip RP2040 --protocol swd"
# runner = "elf2uf2-rs -d"

rustflags = [
"-C", "link-arg=--nmagic",
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]

[build]
target = "thumbv6m-none-eabi"

[env]
DEFMT_LOG = "debug"
14 changes: 14 additions & 0 deletions examples/nunchuk-blocking-rp2040-hal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
**/*.rs.bk
.#*
.gdb_history
Cargo.lock
target/

# editor files
.vscode/*
!.vscode/*.md
!.vscode/*.svd
!.vscode/launch.json
!.vscode/tasks.json
!.vscode/extensions.json
!.vscode/settings.json
8 changes: 8 additions & 0 deletions examples/nunchuk-blocking-rp2040-hal/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"rust-analyzer.cargo.target": "thumbv6m-none-eabi",
"rust-analyzer.checkOnSave.allTargets": false,
"editor.formatOnSave": true,
"[toml]": {
"editor.formatOnSave": false,
}
}
22 changes: 22 additions & 0 deletions examples/nunchuk-blocking-rp2040-hal/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
authors = ["9names"]
edition = "2018"
name = "nunchuk-blocking-rp2040-hal"
version = "0.1.0"
resolver = "2"
publish = false

[dependencies]
cortex-m = "0.7.3"
cortex-m-rt = "0.7.0"
embedded-hal = "1"
embedded-time = "0.12.0"
defmt = "0.3.0"
defmt-rtt = "0.4.0"
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
fugit = "0.3.6"
wii-ext = { version = "0.4.0", features = ["defmt_print",], path = "../../wii-ext" }
rp-pico = "0.9.0"

[profile.release]
debug = 2
31 changes: 31 additions & 0 deletions examples/nunchuk-blocking-rp2040-hal/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());

// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
}
15 changes: 15 additions & 0 deletions examples/nunchuk-blocking-rp2040-hal/memory.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}

EXTERN(BOOT2_FIRMWARE)

SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;
79 changes: 79 additions & 0 deletions examples/nunchuk-blocking-rp2040-hal/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Interact with a Wii extension controller via the wii-ext crate on a Pico board
//!
//! It will enumerate as a USB joystick, which you can use to control a game
#![no_std]
#![no_main]

use defmt::*;
use defmt_rtt as _;
use panic_probe as _;

use bsp::hal::{
self, clocks::init_clocks_and_plls, entry, gpio, pac, sio::Sio, watchdog::Watchdog, Timer,
};
use embedded_hal::delay::DelayNs;
use fugit::RateExtU32;
use rp_pico as bsp;
use wii_ext::blocking_impl::nunchuk::Nunchuk;

#[entry]
fn main() -> ! {
info!("Program start");
let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let sio = Sio::new(pac.SIO);

// External high-speed crystal on the pico board is 12Mhz
let external_xtal_freq_hz = 12_000_000u32;
let clocks = init_clocks_and_plls(
external_xtal_freq_hz,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();

let mut delay = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);

let pins = bsp::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);

let sda_pin: gpio::Pin<_, gpio::FunctionI2C, _> = pins.gpio8.reconfigure();
let scl_pin: gpio::Pin<_, gpio::FunctionI2C, _> = pins.gpio9.reconfigure();

let i2c = hal::I2C::i2c0(
pac.I2C0,
sda_pin,
scl_pin,
100.kHz(),
&mut pac.RESETS,
&clocks.peripheral_clock,
);

// Create, initialise and calibrate the controller
let mut controller = Nunchuk::new(i2c, delay).unwrap();

loop {
// Some controllers need a delay between reads or they become unhappy
delay.delay_ms(10);

// Capture the current button and axis values
let input = controller.read();
if let Ok(input) = input {
// Print inputs from the controller
debug!("{:?}", input);
} else {
let _ = controller.init();
}
}
}

// End of file
4 changes: 0 additions & 4 deletions examples/rp2040-hal-blocking/README.md

This file was deleted.

1 change: 1 addition & 0 deletions wii-ext/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
authors = ["9names"]
repository = "https://github.com/9names/wii-ext-rs"
license = "MIT OR Apache-2.0"
readme = "README.md"

[dependencies]
embedded-hal = "1"
Expand Down
Loading

0 comments on commit c16dffb

Please sign in to comment.