Skip to content

Commit

Permalink
[software] add usb HID, implement samsung tv remote protocol for arro…
Browse files Browse the repository at this point in the history
…w keys, emulate them as a keyboard
  • Loading branch information
Kezii committed Sep 9, 2024
1 parent 109b081 commit 8cc242f
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 33 deletions.
19 changes: 2 additions & 17 deletions antani_sw/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions antani_sw/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ embassy-sync = { version = "0.6.0", git = "https://github.com/embassy-rs/embassy
embassy-executor = { version = "0.6.0", git = "https://github.com/embassy-rs/embassy.git", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.3.2", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-rp = { version = "0.2.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] }
embassy-usb = { version = "0.3.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt","max-interface-count-6"] }
embassy-usb = { version = "0.3.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt","max-interface-count-8"] }
embassy-futures = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git" }
embassy-usb-logger = { version = "0.2.0", git = "https://github.com/embassy-rs/embassy.git" }

Expand All @@ -26,7 +26,7 @@ fixed-macro = "1.2"

cortex-m = { version = "0.7.7", features = ["inline-asm"] }
cortex-m-rt = "0.7.3"
panic-probe = { version = "0.3", features = ["print-rtt"] }
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
heapless = "0.8"

Expand Down Expand Up @@ -59,6 +59,7 @@ infrared = "0.14.2"
num-traits = { version = "0.2", default-features = false, features = ["libm"] }

capnp = { version = "0.19.6", default-features = false }
usbd-hid = "0.8.2"


# cargo build/run
Expand Down
66 changes: 59 additions & 7 deletions antani_sw/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ enum TaskCommand {
SetBrightness(OutputPower),
ResetTime,
UsbActivity,
SendHidKeyboard(usbd_hid::descriptor::KeyboardUsage),
Error,
None,
}
Expand Down Expand Up @@ -257,9 +258,9 @@ impl OutputPower {
}
}

enum WhiteLedCommand{
enum WhiteLedCommand {
Communication,
Error
Error,
}

static WHITE_LED_SIGNAL: Signal<CriticalSectionRawMutex, WhiteLedCommand> = Signal::new();
Expand Down Expand Up @@ -317,11 +318,13 @@ fn main() -> ! {

executor0.run(|spawner| {
unwrap!(spawner.spawn(temperature(adc, ts, MEGA_CHANNEL.publisher().unwrap())));
unwrap!(spawner.spawn(usb::usb_main(p.USB, MEGA_CHANNEL.publisher().unwrap())));
unwrap!(spawner.spawn(button_tsk(user_btn, MEGA_CHANNEL.publisher().unwrap())));
unwrap!(spawner.spawn(white_led_task(
white_led
unwrap!(spawner.spawn(usb::usb_main(
p.USB,
MEGA_CHANNEL.publisher().unwrap(),
MEGA_CHANNEL.subscriber().unwrap()
)));
unwrap!(spawner.spawn(button_tsk(user_btn, MEGA_CHANNEL.publisher().unwrap())));
unwrap!(spawner.spawn(white_led_task(white_led)));
unwrap!(spawner.spawn(ir_receiver(
p.PIN_10.pin(),
MEGA_CHANNEL.publisher().unwrap()
Expand Down Expand Up @@ -460,6 +463,55 @@ async fn main_tsk(mut ws2812: Ws2812<'static, PIO0, 0, 9>, scenes: &'static Scen
.await;
}

// samsung tv remote, arrow right
(7, 98, false) => {
mega_publisher
.publish(TaskCommand::SendHidKeyboard(
usbd_hid::descriptor::KeyboardUsage::KeyboardRightArrow,
))
.await;
}
// left
(7, 101, false) => {
mega_publisher
.publish(TaskCommand::SendHidKeyboard(
usbd_hid::descriptor::KeyboardUsage::KeyboardLeftArrow,
))
.await;
}
// up
(7, 96, false) => {
mega_publisher
.publish(TaskCommand::SendHidKeyboard(
usbd_hid::descriptor::KeyboardUsage::KeyboardUpArrow,
))
.await;
}
// down
(7, 97, false) => {
mega_publisher
.publish(TaskCommand::SendHidKeyboard(
usbd_hid::descriptor::KeyboardUsage::KeyboardDownArrow,
))
.await;
}
// exit
(7, 102, false) => {
mega_publisher
.publish(TaskCommand::SendHidKeyboard(
usbd_hid::descriptor::KeyboardUsage::KeyboardEscape,
))
.await;
}
// enter
(7, 104, false) => {
mega_publisher
.publish(TaskCommand::SendHidKeyboard(
usbd_hid::descriptor::KeyboardUsage::KeyboardEnter,
))
.await;
}

_ => {}
}
WHITE_LED_SIGNAL.signal(WhiteLedCommand::Communication);
Expand Down Expand Up @@ -552,7 +604,7 @@ async fn main_tsk(mut ws2812: Ws2812<'static, PIO0, 0, 9>, scenes: &'static Scen
WHITE_LED_SIGNAL.signal(WhiteLedCommand::Error);
}

TaskCommand::None => {}
TaskCommand::None | TaskCommand::SendHidKeyboard(_) => {}
}
}

Expand Down
67 changes: 60 additions & 7 deletions antani_sw/src/usb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ use embassy_futures::join::join;
use embassy_rp::bind_interrupts;
use embassy_rp::peripherals::USB;
use embassy_rp::usb::{Driver, Instance, InterruptHandler};
use embassy_time::{Duration, Timer};
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
use embassy_usb::class::hid::{self, HidWriter};
use heapless::Vec;
use log::{error, info};
use static_cell::StaticCell;
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};

use crate::MegaPublisher;
use crate::{MegaPublisher, MegaSubscriber, TaskCommand};
use embassy_usb::class::midi::MidiClass;
use embassy_usb::driver::EndpointError;
use embassy_usb::{Builder, Config};
Expand All @@ -21,12 +24,13 @@ bind_interrupts!(struct Irqs {

static STATE: StaticCell<State> = StaticCell::new();
static LOGGER_STATE: StaticCell<State> = StaticCell::new();
static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
static HID_STATE: StaticCell<hid::State> = StaticCell::new();
static CONFIG_DESCRIPTOR: StaticCell<[u8; 512]> = StaticCell::new();
static BOS_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
static CONTROL_BUF: StaticCell<[u8; 64]> = StaticCell::new();

#[embassy_executor::task]
pub async fn usb_main(usb: USB, publisher: MegaPublisher) {
pub async fn usb_main(usb: USB, publisher: MegaPublisher, mut subscriber: MegaSubscriber) {
// Create the driver, from the HAL.
let driver = Driver::new(usb, Irqs);

Expand All @@ -45,7 +49,7 @@ pub async fn usb_main(usb: USB, publisher: MegaPublisher) {
config.device_protocol = 0x01;
config.composite_with_iads = true;

let config_descriptor = CONFIG_DESCRIPTOR.init([0; 256]);
let config_descriptor = CONFIG_DESCRIPTOR.init([0; 512]);
let bos_descriptor = BOS_DESCRIPTOR.init([0; 256]);
let control_buf = CONTROL_BUF.init([0; 64]);

Expand All @@ -62,6 +66,15 @@ pub async fn usb_main(usb: USB, publisher: MegaPublisher) {

let state = STATE.init(State::new());
let logger_state = LOGGER_STATE.init(State::new());
let hid_state = HID_STATE.init(hid::State::new());

let config = embassy_usb::class::hid::Config {
report_descriptor: KeyboardReport::desc(),
request_handler: None,
poll_ms: 60,
max_packet_size: 64,
};
let mut hid_writer = HidWriter::<_, 8>::new(&mut builder, hid_state, config);

let mut cdc_class = CdcAcmClass::new(&mut builder, state, 64);
let logger_class = CdcAcmClass::new(&mut builder, logger_state, 64);
Expand All @@ -81,6 +94,42 @@ pub async fn usb_main(usb: USB, publisher: MegaPublisher) {

let usb_fut = usb.run();

let hid_fut = async {
loop {
if let TaskCommand::SendHidKeyboard(cmd) = subscriber.next_message_pure().await {
let report = KeyboardReport {
keycodes: [cmd as u8, 0, 0, 0, 0, 0],
leds: 0,
modifier: 0,
reserved: 0,
};
// Send the report.
match hid_writer.write_serialize(&report).await {
Ok(()) => {}
Err(e) => {
warn!("Failed to send report: {:?}", e);
publisher.publish(TaskCommand::Error).await;
}
};
Timer::after(Duration::from_millis(100)).await;

let report = KeyboardReport {
keycodes: [0, 0, 0, 0, 0, 0],
leds: 0,
modifier: 0,
reserved: 0,
};
match hid_writer.write_serialize(&report).await {
Ok(()) => {}
Err(e) => {
warn!("Failed to send report: {:?}", e);
publisher.publish(TaskCommand::Error).await;
}
};
}
}
};

let midi_fut = async {
loop {
midi_class.wait_connection().await;
Expand All @@ -93,13 +142,17 @@ pub async fn usb_main(usb: USB, publisher: MegaPublisher) {
let control_fut = async {
loop {
cdc_class.wait_connection().await;
log::info!("Connected");
info!("Connected");
let _ = usb_control(&mut cdc_class, &publisher).await;
log::info!("Disconnected");
info!("Disconnected");
}
};

join(usb_fut, join(control_fut, join(log_fut, midi_fut))).await;
join(
usb_fut,
join(control_fut, join(log_fut, join(hid_fut, midi_fut))),
)
.await;
}

struct Disconnected {}
Expand Down

0 comments on commit 8cc242f

Please sign in to comment.