Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/docs/main/docs/features/usb_logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ rmk = { version = "0.9", default-features = false, features = [
] }
```

The default log level is debug. You can change the log level by enabling the `max_level_*` feature for the log crate in `Cargo.toml`:
```toml
log = {version = "0.4", features = [
"max_level_info",
]}
```

::: tip
Don't forget to re-enable the other default features you need (such as `storage`, `vial`, `host_lock`, and `watchdog`) — but not `defmt`: `usb_log` is based on the `log` crate, which cannot be enabled together with the `defmt` feature.
:::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async fn main(_spawner: Spawner) {
join3(
run_all!(matrix, storage, dfu_led, watchdog_runner),
run_rmk_split_peripheral(uart_instance),
rmk::dfu::run_peripheral_dfu(dfu_driver, dfu_device_config),
rmk::usb::run_peripheral_usb(dfu_driver, dfu_device_config),
)
.await;
}
73 changes: 33 additions & 40 deletions rmk-macro/src/codegen/split/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use syn::ItemMod;

use super::central::expand_serial_init;
use crate::codegen::chip::chip_init::expand_chip_init;
use crate::codegen::chip::comm::expand_usb_init;
use crate::codegen::chip::flash::expand_flash_init;
use crate::codegen::chip::gpio::expand_output_initialization;
use crate::codegen::display::{expand_display_config, expand_display_interrupt};
Expand Down Expand Up @@ -57,7 +58,8 @@ pub(crate) fn parse_split_peripheral_mod(

let dfu_enabled =
is_feature_enabled(&rmk_features, "dfu_rp") || is_feature_enabled(&rmk_features, "dfu_nrf");
let device_config = if dfu_enabled {
let usb_log_enabled = is_feature_enabled(&rmk_features, "usb_log");
let device_config = if dfu_enabled || usb_log_enabled {
let vid = identity.vendor_id;
let pid = identity.product_id;
let manufacturer = &identity.manufacturer;
Expand Down Expand Up @@ -143,11 +145,14 @@ fn expand_bind_interrupt_for_split_peripheral(
};
let iqs5xx_interrupt = expand_iqs5xx_interrupts(&chip.series, &iqs5xx_config_for_irq);

let dfu_enabled =
is_feature_enabled(rmk_features, "dfu_rp") || is_feature_enabled(rmk_features, "dfu_nrf");
let usb_log_enabled = is_feature_enabled(rmk_features, "usb_log");
let usb_enabled = dfu_enabled || usb_log_enabled;

match chip.series {
ChipSeries::Nrf52 => {
let dfu_enabled = is_feature_enabled(rmk_features, "dfu_rp")
|| is_feature_enabled(rmk_features, "dfu_nrf");
let usb_interrupt = if dfu_enabled {
let usb_interrupt = if usb_enabled {
quote! {
USBD => ::embassy_nrf::usb::InterruptHandler<::embassy_nrf::peripherals::USBD>;
}
Expand Down Expand Up @@ -207,7 +212,7 @@ fn expand_bind_interrupt_for_split_peripheral(
quote! {}
};

let clock_power_handler = if dfu_enabled {
let clock_power_handler = if usb_enabled {
quote! {
CLOCK_POWER => ::nrf_sdc::mpsl::ClockInterruptHandler, ::embassy_nrf::usb::vbus_detect::InterruptHandler;
}
Expand Down Expand Up @@ -267,14 +272,12 @@ fn expand_bind_interrupt_for_split_peripheral(
}
}
ChipSeries::Rp2040 => {
let dfu_enabled = is_feature_enabled(rmk_features, "dfu_rp")
|| is_feature_enabled(rmk_features, "dfu_nrf");
let usb_int = if usb_enabled {
quote! { USBCTRL_IRQ => ::embassy_rp::usb::InterruptHandler<::embassy_rp::peripherals::USB>; }
} else {
quote! {}
};
if communication.ble_enabled() {
let usb_int = if dfu_enabled {
quote! { USBCTRL_IRQ => ::embassy_rp::usb::InterruptHandler<::embassy_rp::peripherals::USB>; }
} else {
quote! {}
};
quote! {
use ::embassy_rp::bind_interrupts;
bind_interrupts!(struct Irqs {
Expand All @@ -290,11 +293,6 @@ fn expand_bind_interrupt_for_split_peripheral(
}
}
} else if !display_interrupt.is_empty() || !iqs5xx_interrupt.is_empty() || dfu_enabled {
let usb_int = if dfu_enabled {
quote! { USBCTRL_IRQ => ::embassy_rp::usb::InterruptHandler<::embassy_rp::peripherals::USB>; }
} else {
quote! {}
};
quote! {
use ::embassy_rp::bind_interrupts;
bind_interrupts!(struct Irqs {
Expand Down Expand Up @@ -326,6 +324,9 @@ fn expand_split_peripheral(
}
};

let dfu_enabled =
is_feature_enabled(rmk_features, "dfu_rp") || is_feature_enabled(rmk_features, "dfu_nrf");

let peripheral_config = split_config
.peripheral
.get(id)
Expand All @@ -340,37 +341,25 @@ fn expand_split_peripheral(
#flash_init
let mut storage = ::rmk::storage::new_storage_for_split_peripheral(flash, storage_config).await;
});
} else if is_feature_enabled(rmk_features, "dfu_rp")
|| is_feature_enabled(rmk_features, "dfu_nrf")
{
} else if dfu_enabled {
let flash_init = expand_flash_init(hardware);
chip_init.extend(quote! { #flash_init });
}

let dfu_enabled =
is_feature_enabled(rmk_features, "dfu_rp") || is_feature_enabled(rmk_features, "dfu_nrf");

// Mark booted when DFU is enabled so the bootloader doesn't
// revert the previous update.
if dfu_enabled {
chip_init.extend(quote! { ::rmk::dfu::mark_booted(); });
}
let usb_log_enabled = is_feature_enabled(rmk_features, "usb_log");
let usb_enabled = dfu_enabled || usb_log_enabled;

// Initialize USB driver for DFU on the peripheral side
// so it can be firmware-updated via USB.
let dfu_task_future = if dfu_enabled {
let usb_init = match hardware.chip.series {
ChipSeries::Nrf52 => quote! {
let driver = ::embassy_nrf::usb::Driver::new(p.USBD, Irqs, ::embassy_nrf::usb::vbus_detect::HardwareVbusDetect::new(Irqs));
},
ChipSeries::Rp2040 => quote! {
let driver = ::embassy_rp::usb::Driver::new(p.USB, Irqs);
},
_ => quote! {},
};
// Run usb device if dfu or usb_log is enabled.
let usb_task_future = if usb_enabled {
let usb_init = expand_usb_init(hardware, &item_mod);
chip_init.extend(usb_init);
Some(quote! {
async { ::rmk::dfu::run_peripheral_dfu(driver, KEYBOARD_DEVICE_CONFIG).await }
::rmk::usb::run_peripheral_usb(driver, KEYBOARD_DEVICE_CONFIG)
})
} else {
None
Expand Down Expand Up @@ -503,7 +492,7 @@ fn expand_split_peripheral(
processors,
registered_processors,
watchdog_task,
dfu_task_future,
usb_task_future,
);

quote! {
Expand Down Expand Up @@ -531,7 +520,7 @@ fn expand_split_peripheral_entry(
processors: Vec<TokenStream2>,
registered_processors: Vec<TokenStream2>,
watchdog_task: Option<TokenStream2>,
dfu_task_future: Option<TokenStream2>,
usb_task_future: Option<TokenStream2>,
) -> TokenStream2 {
// Add matrix to devices, and run all devices
let mut devs = devices.clone();
Expand Down Expand Up @@ -574,9 +563,11 @@ fn expand_split_peripheral_entry(
if let Some(t) = &watchdog_task {
tasks.push(t.clone());
}
if let Some(t) = &dfu_task_future {

if let Some(t) = &usb_task_future {
tasks.push(t.clone());
}

let run_rmk_peripheral = join_all_tasks(tasks);
quote! {
#run_rmk_peripheral
Expand Down Expand Up @@ -611,9 +602,11 @@ fn expand_split_peripheral_entry(
if let Some(t) = &watchdog_task {
tasks.push(t.clone());
}
if let Some(t) = &dfu_task_future {

if let Some(t) = &usb_task_future {
tasks.push(t.clone());
}

let run_rmk_peripheral = join_all_tasks(tasks);
quote! {
#serial_init
Expand Down
2 changes: 1 addition & 1 deletion rmk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ defmt = [
]

## Enable logging via usb
usb_log = ["dep:embassy-usb-logger", "log"]
usb_log = ["dep:embassy-usb-logger", "log", "log/max_level_debug"]
## Use log, this feature cannot be enabled when defmt is enabled
log = ["dep:log", "trouble-host?/log"]

Expand Down
33 changes: 0 additions & 33 deletions rmk/src/dfu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,39 +412,6 @@ pub fn register_dfu_interface<D: Driver<'static>>(
builder.handler(string_provider);
}

// ---------------------------------------------------------------------------
// run_peripheral_dfu
// ---------------------------------------------------------------------------

/// Run a USB DFU-only device on the peripheral side of a split keyboard.
#[cfg(any(feature = "dfu_rp", feature = "dfu_nrf"))]
pub async fn run_peripheral_dfu<D: Driver<'static>>(
driver: D,
device_config: crate::config::DeviceConfig<'static>,
) -> ! {
use crate::usb::new_usb_builder;

let mut builder = new_usb_builder(driver, device_config);

let product_name = device_config.product_name;
if let Some(mgr) = get_manager() {
register_dfu_interface(
&mut builder,
mgr,
product_name,
#[cfg(feature = "dfu_split")]
0,
);
}

let mut device = builder.build();

loop {
device.run_until_suspend().await;
device.wait_resume().await;
}
}

// ---------------------------------------------------------------------------
// dfu_lock
// ---------------------------------------------------------------------------
Expand Down
60 changes: 46 additions & 14 deletions rmk/src/usb/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use embassy_futures::join::join4;
use embassy_futures::select::{Either, select};
use embassy_sync::signal::Signal;
#[cfg(feature = "usb_log")]
use embassy_usb::class::cdc_acm::CdcAcmClass;
use embassy_usb::class::hid::{HidReader, HidWriter, ReportId, RequestHandler};
use embassy_usb::control::OutResponse;
use embassy_usb::driver::{Driver, EndpointError};
Expand Down Expand Up @@ -374,29 +376,59 @@ impl<D: Driver<'static>> Runnable for UsbTransport<'_, D> {
let host_task = core::future::pending::<()>();

#[cfg(feature = "usb_log")]
{
let logger_fut = {
let logger_class = logger.take().expect("UsbTransport::run called twice");
let logger_fut = embassy_usb_logger::with_custom_style!(
1024,
log::LevelFilter::Debug,
logger_class,
|record, writer| {
use core::fmt::Write;
let ms = embassy_time::Instant::now().as_millis();
let _ = write!(writer, "[{:>8}ms {:5}] {}\r\n", ms, record.level(), record.args());
}
);
embassy_futures::join::join(host_task, logger_fut).await;
}
run_usb_logger(logger_class)
};
#[cfg(not(feature = "usb_log"))]
host_task.await;
let logger_fut = core::future::pending::<()>();

embassy_futures::join::join(host_task, logger_fut).await;
};

join4(usb_device_task, writer_task, led_task, host_and_extras).await;
unreachable!("UsbTransport sub-tasks must run forever");
}
}

#[cfg(feature = "usb_log")]
async fn run_usb_logger<D: Driver<'static>>(logger_class: CdcAcmClass<'static, D>) {
// Add a usb logger with log filter set to `Trace` to catch all logs.
// The log level itself is set via the `max_level_*` feature of the log crate.
let logger_fut =
::embassy_usb_logger::with_custom_style!(1024, log::LevelFilter::Trace, logger_class, |record, writer| {
use core::fmt::Write;
let ms = embassy_time::Instant::now().as_millis();
let _ = write!(writer, "[{:>8}ms {:5}] {}\r\n", ms, record.level(), record.args());
});
logger_fut.await;
}

#[cfg(any(feature = "usb_log", feature = "dfu_nrf", feature = "dfu_rp"))]
pub async fn run_peripheral_usb<D: Driver<'static>>(driver: D, config: DeviceConfig<'static>) {
let mut builder = new_usb_builder(driver, config);

#[cfg(feature = "usb_log")]
let logger_fut = run_usb_logger(add_usb_logger!(&mut builder));
#[cfg(not(feature = "usb_log"))]
let logger_fut = ::core::future::pending::<()>();

#[cfg(any(feature = "dfu_rp", feature = "dfu_nrf"))]
if let Some(mgr) = crate::dfu::get_manager() {
::rmk::dfu::register_dfu_interface(
&mut builder,
mgr,
config.product_name,
#[cfg(feature = "dfu_split")]
0,
);
}

let mut usb_device = builder.build();

::embassy_futures::join::join(usb_device.run(), logger_fut).await;
}

#[cfg(feature = "usb_log")]
macro_rules! add_usb_logger {
($usb_builder:expr) => {{
Expand Down