diff --git a/boards/nano33ble/src/io.rs b/boards/nano33ble/src/io.rs index 62ce09bb8a..0465ab6444 100644 --- a/boards/nano33ble/src/io.rs +++ b/boards/nano33ble/src/io.rs @@ -86,47 +86,52 @@ impl IoWrite for Writer { // and not much we can do. Don't want to double fault, // so just return. super::CDC_REF_FOR_PANIC.map(|cdc| { - // Lots of unsafe dereferencing of global static mut objects here. - // However, this should be okay, because it all happens within - // a single thread, and: - // - This is the only place the global CDC_REF_FOR_PANIC is used, the logic is the same - // as applies for the global CHIP variable used in the panic handler. - // - We do create multiple mutable references to the STATIC_PANIC_BUF, but we never - // access the STATIC_PANIC_BUF after a slice of it is passed to transmit_buffer - // until the slice has been returned in the uart callback. - // - Similarly, only this function uses the global DUMMY variable, and we do not - // mutate it. - let usb = &mut cdc.controller(); - STATIC_PANIC_BUF[..max].copy_from_slice(&buf[..max]); - let static_buf = &mut STATIC_PANIC_BUF; - cdc.set_transmit_client(&DUMMY); - match cdc.transmit_buffer(static_buf, max) { - Ok(()) => {} - _ => {} - } - let mut interrupt_count = 0; - loop { - if let Some(interrupt) = cortexm4::nvic::next_pending() { - if interrupt == 39 { - interrupt_count += 1; - if interrupt_count >= 2 { + super::NRF52_RTC.map(|rtc| { + // Lots of unsafe dereferencing of global static mut objects here. + // However, this should be okay, because it all happens within + // a single thread, and: + // - This is the only place the global CDC_REF_FOR_PANIC is used, the logic is the same + // as applies for the global CHIP variable used in the panic handler. + // - We do create multiple mutable references to the STATIC_PANIC_BUF, but we never + // access the STATIC_PANIC_BUF after a slice of it is passed to transmit_buffer + // until the slice has been returned in the uart callback. + // - Similarly, only this function uses the global DUMMY variable, and we do not + // mutate it. + let usb = &mut cdc.controller(); + STATIC_PANIC_BUF[..max].copy_from_slice(&buf[..max]); + let static_buf = &mut STATIC_PANIC_BUF; + cdc.set_transmit_client(&DUMMY); + match cdc.transmit_buffer(static_buf, max) { + Ok(()) => {} + _ => {} + } + let mut interrupt_count = 0; + loop { + if let Some(interrupt) = cortexm4::nvic::next_pending() { + if interrupt == 39 { + interrupt_count += 1; + if interrupt_count >= 2 {} led.on(); + usb.handle_interrupt(); + // } else if interrupt < 25 { + } else { + // led.on(); + // rtc.handle_interrupt(); } - usb.handle_interrupt(); + let n = cortexm4::nvic::Nvic::new(interrupt); + n.clear_pending(); + n.enable(); } - let n = cortexm4::nvic::Nvic::new(interrupt); - n.clear_pending(); - n.enable(); - } - if DUMMY.fired.get() == true { - // buffer finished transmitting, return so we can output additional - // messages when requested by the panic handler. - // led.on(); - break; + if DUMMY.fired.get() == true { + // buffer finished transmitting, return so we can output additional + // messages when requested by the panic handler. + // led.on(); + break; + } } - } - DUMMY.fired.set(false); + DUMMY.fired.set(false); + }); }); } buf.len() @@ -147,6 +152,12 @@ pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! { // debug::panic_blink_forever(&mut [led]) + cortexm4::nvic::disable_all(); + cortexm4::nvic::clear_all_pending(); + + let n = cortexm4::nvic::Nvic::new(39); + n.enable(); + // loop {} let writer = &mut WRITER; debug::panic_print( diff --git a/boards/nano33ble/src/main.rs b/boards/nano33ble/src/main.rs index b901ddb447..f07d97e14a 100644 --- a/boards/nano33ble/src/main.rs +++ b/boards/nano33ble/src/main.rs @@ -100,6 +100,7 @@ static mut CDC_REF_FOR_PANIC: Option< >, > = None; static mut NRF52_POWER: Option<&'static nrf52840::power::Power> = None; +static mut NRF52_RTC: Option<&'static nrf52840::rtc::Rtc> = None; /// Dummy buffer that causes the linker to reserve enough space for the stack. #[no_mangle] @@ -246,6 +247,7 @@ pub unsafe fn start() -> ( // Save a reference to the power module for resetting the board into the // bootloader. NRF52_POWER = Some(&base_peripherals.pwr_clk); + NRF52_RTC = Some(&base_peripherals.rtc); let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); diff --git a/boards/nordic/nrf52840dk/src/io.rs b/boards/nordic/nrf52840dk/src/io.rs index 92d4e8c773..fb05b0e507 100644 --- a/boards/nordic/nrf52840dk/src/io.rs +++ b/boards/nordic/nrf52840dk/src/io.rs @@ -2,40 +2,60 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT // Copyright Tock Contributors 2022. +use kernel::utilities::cells::VolatileCell; + use core::fmt::Write; use core::panic::PanicInfo; +use kernel::hil::uart::Transmit; +use kernel::ErrorCode; + use cortexm4; use kernel::debug; use kernel::debug::IoWrite; use kernel::hil::led; +use kernel::hil::led::Led; use kernel::hil::uart; use kernel::hil::uart::Configure; +use kernel::hil::uart::Receive; use nrf52840::gpio::Pin; use crate::CHIP; use crate::PROCESSES; use crate::PROCESS_PRINTER; -enum Writer { - WriterUart(/* initialized */ bool), - WriterRtt(&'static capsules_extra::segger_rtt::SeggerRttMemory<'static>), -} +// enum Writer { +// WriterUart(/* initialized */ bool), +// WriterRtt(&'static capsules_extra::segger_rtt::SeggerRttMemory<'static>), +// } -static mut WRITER: Writer = Writer::WriterUart(false); +// static mut WRITER: Writer = Writer::WriterUart(false); -fn wait() { - for _ in 0..100 { - cortexm4::support::nop(); - } -} +// fn wait() { +// for _ in 0..100 { +// cortexm4::support::nop(); +// } +// } + +// /// Set the RTT memory buffer used to output panic messages. +// pub unsafe fn set_rtt_memory( +// rtt_memory: &'static capsules_extra::segger_rtt::SeggerRttMemory<'static>, +// ) { +// WRITER = Writer::WriterRtt(rtt_memory); +// } -/// Set the RTT memory buffer used to output panic messages. -pub unsafe fn set_rtt_memory( - rtt_memory: &'static capsules_extra::segger_rtt::SeggerRttMemory<'static>, -) { - WRITER = Writer::WriterRtt(rtt_memory); +// impl Write for Writer { +// fn write_str(&mut self, s: &str) -> ::core::fmt::Result { +// self.write(s.as_bytes()); +// Ok(()) +// } +// } + +struct Writer { + writes: usize, } +static mut WRITER: Writer = Writer { writes: 0 }; + impl Write for Writer { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { self.write(s.as_bytes()); @@ -43,64 +63,254 @@ impl Write for Writer { } } +const BUF_LEN: usize = 512; +static mut STATIC_PANIC_BUF: [u8; BUF_LEN] = [0; BUF_LEN]; + +static mut DUMMY: DummyUsbClient = DummyUsbClient { + fired: VolatileCell::new(false), +}; + +struct DummyUsbClient { + fired: VolatileCell, +} + +impl uart::TransmitClient for DummyUsbClient { + fn transmitted_buffer(&self, _: &'static mut [u8], _: usize, _: Result<(), ErrorCode>) { + // led.on(); + self.fired.set(true); + } +} + +impl uart::ReceiveClient for DummyUsbClient { + fn received_buffer( + &self, + _rx_buffer: &'static mut [u8], + _rx_len: usize, + _rval: Result<(), ErrorCode>, + _error: uart::Error, + ) { + } +} + impl IoWrite for Writer { fn write(&mut self, buf: &[u8]) -> usize { - match self { - Writer::WriterUart(ref mut initialized) => { - // Here, we create a second instance of the Uarte struct. - // This is okay because we only call this during a panic, and - // we will never actually process the interrupts - let uart = nrf52840::uart::Uarte::new(); - if !*initialized { - *initialized = true; - let _ = uart.configure(uart::Parameters { - baud_rate: 115200, - stop_bits: uart::StopBits::One, - parity: uart::Parity::None, - hw_flow_control: false, - width: uart::Width::Eight, - }); - } - for &c in buf { - unsafe { - uart.send_byte(c); + let led2_pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_14); + let led2 = &mut led::LedLow::new(led2_pin); + let led_kernel_pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_13); + let led = &mut led::LedLow::new(led_kernel_pin); + // led.init(); + // led.off(); + + // Here we mimic a synchronous UART output by calling transmit_buffer + // on the CDC stack and then spinning on USB interrupts until the transaction + // is complete. If the USB or CDC stack panicked, this may fail. It will also + // fail if the panic occurred prior to the USB connection being initialized. + // In the latter case, the LEDs should still blink in the panic pattern. + + // spin so that if any USB DMA is ongoing it will finish + // we should only need this on the first call to write() + // if self.writes == 0 { + // let mut i = 0; + // loop { + // i += 1; + // cortexm4::support::nop(); + // if i > 1000 { + // break; + // } + // } + // } + + // self.writes += 1; + + // copy_from_slice() requires equal length slices + // This will truncate any writes longer than BUF_LEN, but simplifies the + // code. In practice, BUF_LEN=512 always seems sufficient for the size of + // individual calls to write made by the panic handler. + let mut max = BUF_LEN; + if buf.len() < BUF_LEN { + max = buf.len(); + } + + unsafe { + // If CDC_REF_FOR_PANIC is not yet set we panicked very early, + // and not much we can do. Don't want to double fault, + // so just return. + super::CDC_REF_FOR_PANIC.map(|cdc| { + // super::NRF52_RTC.map(|rtc| { + // Lots of unsafe dereferencing of global static mut objects here. + // However, this should be okay, because it all happens within + // a single thread, and: + // - This is the only place the global CDC_REF_FOR_PANIC is used, the logic is the same + // as applies for the global CHIP variable used in the panic handler. + // - We do create multiple mutable references to the STATIC_PANIC_BUF, but we never + // access the STATIC_PANIC_BUF after a slice of it is passed to transmit_buffer + // until the slice has been returned in the uart callback. + // - Similarly, only this function uses the global DUMMY variable, and we do not + // mutate it. + let usb = &mut cdc.controller(); + STATIC_PANIC_BUF[..max].copy_from_slice(&buf[..max]); + let static_buf = &mut STATIC_PANIC_BUF; + cdc.set_transmit_client(&DUMMY); + cdc.set_receive_client(&DUMMY); + match cdc.transmit_buffer(static_buf, max) { + Ok(()) => { + led.on(); + } + _ => { + led2.on(); } - while !uart.tx_ready() {} } - } - Writer::WriterRtt(rtt_memory) => { - let up_buffer = unsafe { &*rtt_memory.get_up_buffer_ptr() }; - let buffer_len = up_buffer.length.get(); - let buffer = unsafe { - core::slice::from_raw_parts_mut( - up_buffer.buffer.get() as *mut u8, - buffer_len as usize, - ) - }; - - let mut write_position = up_buffer.write_position.get(); - - for &c in buf { - buffer[write_position as usize] = c; - write_position = (write_position + 1) % buffer_len; - up_buffer.write_position.set(write_position); - wait(); + + // let mut i = 0; + // loop { + // i += 1; + // cortexm4::support::nop(); + // if i > 10000 { + // break; + // } + // } + + let mut interrupt_count = 0; + loop { + // if DUMMY.fired.get() == true { + // led.on(); + // // break; + // } + + if let Some(interrupt) = cortexm4::nvic::next_pending() { + if interrupt == 39 { + led.off(); + interrupt_count += 1; + if interrupt_count >= 2 {} + // led.on(); + + let n = cortexm4::nvic::Nvic::new(interrupt); + + // n.disable(); + n.clear_pending(); + n.enable(); + + usb.handle_interrupt(); + + // let mut i = 0; + // loop { + // i += 1; + // cortexm4::support::nop(); + // if i > 10000 { + // break; + // } + // } + + // } else if interrupt < 25 { + } else { + // led.off(); + if interrupt == 6 { + // led.off(); + } + // rtc.handle_interrupt(); + + let n = cortexm4::nvic::Nvic::new(interrupt); + n.clear_pending(); + n.enable(); + // n.clear_pending(); + } + } else { + cortexm4::support::wfi(); + } + + if DUMMY.fired.get() == true { + // buffer finished transmitting, return so we can output additional + // messages when requested by the panic handler. + // led.off(); + break; + } } - } - }; + DUMMY.fired.set(false); + // }); + }); + } buf.len() } } +// impl IoWrite for Writer { +// fn write(&mut self, buf: &[u8]) -> usize { +// match self { +// Writer::WriterUart(ref mut initialized) => { +// // Here, we create a second instance of the Uarte struct. +// // This is okay because we only call this during a panic, and +// // we will never actually process the interrupts +// let uart = nrf52840::uart::Uarte::new(); +// if !*initialized { +// *initialized = true; +// let _ = uart.configure(uart::Parameters { +// baud_rate: 115200, +// stop_bits: uart::StopBits::One, +// parity: uart::Parity::None, +// hw_flow_control: false, +// width: uart::Width::Eight, +// }); +// } +// for &c in buf { +// unsafe { +// uart.send_byte(c); +// } +// while !uart.tx_ready() {} +// } +// } +// Writer::WriterRtt(rtt_memory) => { +// let up_buffer = unsafe { &*rtt_memory.get_up_buffer_ptr() }; +// let buffer_len = up_buffer.length.get(); +// let buffer = unsafe { +// core::slice::from_raw_parts_mut( +// up_buffer.buffer.get() as *mut u8, +// buffer_len as usize, +// ) +// }; + +// let mut write_position = up_buffer.write_position.get(); + +// for &c in buf { +// buffer[write_position as usize] = c; +// write_position = (write_position + 1) % buffer_len; +// up_buffer.write_position.set(write_position); +// wait(); +// } +// } +// }; +// buf.len() +// } +// } + #[cfg(not(test))] #[no_mangle] #[panic_handler] /// Panic handler pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! { + cortexm4::nvic::disable_all(); + cortexm4::nvic::clear_all_pending(); + + let n = cortexm4::nvic::Nvic::new(39); + n.enable(); + // The nRF52840DK LEDs (see back of board) let led_kernel_pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_13); let led = &mut led::LedLow::new(led_kernel_pin); let writer = &mut WRITER; + + // let led_kernel_pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_13); + // let led = &mut led::LedLow::new(led_kernel_pin); + led.init(); + led.off(); + + let led2pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_14); + let led2 = &mut led::LedLow::new(led2pin); + led2.init(); + led2.off(); + + // debug::panic_banner(writer, pi); + // loop {} + debug::panic( &mut [led], writer, diff --git a/boards/nordic/nrf52840dk/src/main.rs b/boards/nordic/nrf52840dk/src/main.rs index b92122bc61..d6b2dd50a8 100644 --- a/boards/nordic/nrf52840dk/src/main.rs +++ b/boards/nordic/nrf52840dk/src/main.rs @@ -151,6 +151,14 @@ static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] static mut CHIP: Option<&'static nrf52840::chip::NRF52> = None; static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None; +static mut CDC_REF_FOR_PANIC: Option< + &'static capsules_extra::usb::cdc::CdcAcm< + 'static, + nrf52840::usbd::Usbd, + capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>, + >, +> = None; + /// Dummy buffer that causes the linker to reserve enough space for the stack. #[no_mangle] #[link_section = ".stack_buffer"] @@ -165,12 +173,12 @@ pub struct Platform { >, ieee802154_radio: &'static capsules_extra::ieee802154::RadioDriver<'static>, button: &'static capsules_core::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>, - pconsole: &'static capsules_core::process_console::ProcessConsole< - 'static, - { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN }, - VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>, - components::process_console::Capability, - >, + // pconsole: &'static capsules_core::process_console::ProcessConsole< + // 'static, + // { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN }, + // VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>, + // components::process_console::Capability, + // >, console: &'static capsules_core::console::Console<'static>, gpio: &'static capsules_core::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>, led: &'static capsules_core::led::LedDriver< @@ -330,7 +338,7 @@ pub unsafe fn main() { // rtt_memory. This aliases reference is only used inside a panic // handler, which should be OK, but maybe we should use a const // reference to rtt_memory and leverage interior mutability instead. - self::io::set_rtt_memory(&*rtt_memory_refs.get_rtt_memory_ptr()); + // self::io::set_rtt_memory(&*rtt_memory_refs.get_rtt_memory_ptr()); UartChannel::Rtt(rtt_memory_refs) } else { @@ -464,10 +472,38 @@ pub unsafe fn main() { // UART & CONSOLE & DEBUG //-------------------------------------------------------------------------- + let serial_number_buf = static_init!([u8; 17], [0; 17]); + let serial_number_string: &'static str = + nrf52840::ficr::FICR_INSTANCE.address_str(serial_number_buf); + let strings = static_init!( + [&str; 3], + [ + "Arduino", // Manufacturer + "Nano 33 BLE - TockOS", // Product + serial_number_string, // Serial number + ] + ); + + let cdc = components::cdc::CdcAcmComponent::new( + &nrf52840_peripherals.usbd, + capsules_extra::usb::cdc::MAX_CTRL_PACKET_SIZE_NRF52840, + 0x2341, + 0x005a, + strings, + mux_alarm, + None, + ) + .finalize(components::cdc_acm_component_static!( + nrf52840::usbd::Usbd, + nrf52840::rtc::Rtc + )); + CDC_REF_FOR_PANIC = Some(cdc); //for use by panic handler + let uart_channel = nrf52_components::UartChannelComponent::new( uart_channel, mux_alarm, &base_peripherals.uarte0, + // cdc, ) .finalize(nrf52_components::uart_channel_component_static!( nrf52840::rtc::Rtc @@ -479,6 +515,7 @@ pub unsafe fn main() { PROCESS_PRINTER = Some(process_printer); // Virtualize the UART channel for the console and for kernel debug. + // let uart_mux = components::console::UartMuxComponent::new(cdc, 115200) let uart_mux = components::console::UartMuxComponent::new(uart_channel, 115200) .finalize(components::uart_mux_component_static!()); @@ -800,6 +837,10 @@ pub unsafe fn main() { // keyboard_hid.enable(); // keyboard_hid.attach(); + // Configure the USB stack to enable a serial port over CDC-ACM. + cdc.enable(); + cdc.attach(); + //-------------------------------------------------------------------------- // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP //-------------------------------------------------------------------------- @@ -811,7 +852,7 @@ pub unsafe fn main() { button, ble_radio, ieee802154_radio, - pconsole, + // pconsole, console, led, gpio, @@ -833,15 +874,15 @@ pub unsafe fn main() { systick: cortexm4::systick::SysTick::new_with_calibration(64000000), }; - let _ = platform.pconsole.start(); + let _ = pconsole.start(); base_peripherals.adc.calibrate(); // test::aes_test::run_aes128_ctr(&base_peripherals.ecb); // test::aes_test::run_aes128_cbc(&base_peripherals.ecb); // test::aes_test::run_aes128_ecb(&base_peripherals.ecb); - debug!("Initialization complete. Entering main loop\r"); - debug!("{}", &nrf52840::ficr::FICR_INSTANCE); + // debug!("Initialization complete. Entering main loop\r"); + // debug!("{}", &nrf52840::ficr::FICR_INSTANCE); // alarm_test_component.run(); diff --git a/capsules/core/src/button.rs b/capsules/core/src/button.rs index 0597360c69..ac246ddea4 100644 --- a/capsules/core/src/button.rs +++ b/capsules/core/src/button.rs @@ -232,6 +232,8 @@ impl<'a, P: gpio::InterruptPin<'a>> gpio::ClientWithValue for Button<'a, P> { let button_state = self.get_button_state(pin_num); let interrupt_count = Cell::new(0); + panic!("BUTTON PANIC"); + // schedule callback with the pin number and value self.apps.each(|_, cntr, upcalls| { if cntr.subscribe_map & (1 << pin_num) != 0 { diff --git a/capsules/extra/src/usb/cdc.rs b/capsules/extra/src/usb/cdc.rs index ef76d2bf71..9f28c4f9b6 100644 --- a/capsules/extra/src/usb/cdc.rs +++ b/capsules/extra/src/usb/cdc.rs @@ -699,7 +699,8 @@ impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> uart::Transmit<'a> // a deferred callback to return the buffer immediately. self.deferred_call_pending_droptx.set(true); self.deferred_call.set(); - Ok(()) + // Ok(()) + Err((ErrorCode::FAIL, self.tx_buffer.take().unwrap())) } } }