11#![ no_std]  
22#![ no_main]  
3+ #![ allow( static_mut_refs) ]  
34
45use  metro_m4 as  bsp; 
56
67use  bsp:: ehal; 
78use  bsp:: hal; 
89use  bsp:: pac; 
910
11+ use  core:: cell:: OnceCell ; 
1012use  cortex_m:: asm:: delay as  cycle_delay; 
1113use  cortex_m:: peripheral:: NVIC ; 
1214use  ehal:: digital:: StatefulOutputPin ; 
@@ -40,20 +42,20 @@ fn main() -> ! {
4042    let  mut  red_led:  bsp:: RedLed  = pins. d13 . into ( ) ; 
4143
4244    let  bus_allocator = unsafe  { 
43-         USB_ALLOCATOR  =  Some ( bsp:: usb_allocator ( 
45+         let  _ =  USB_ALLOCATOR . set ( bsp:: usb_allocator ( 
4446            peripherals. usb , 
4547            & mut  clocks, 
4648            & mut  peripherals. mclk , 
4749            pins. usb_dm , 
4850            pins. usb_dp , 
4951        ) ) ; 
50-         USB_ALLOCATOR . as_ref ( ) . unwrap ( ) 
52+         USB_ALLOCATOR . get ( ) . unwrap ( ) 
5153    } ; 
5254
5355    unsafe  { 
54-         USB_SERIAL  =  Some ( SerialPort :: new ( bus_allocator) ) ; 
55-         USB_BUS  =  Some ( 
56-             UsbDeviceBuilder :: new ( bus_allocator,  UsbVidPid ( 0x2222 ,   0x3333 ) ) 
56+         let  _ =  USB_SERIAL . set ( SerialPort :: new ( bus_allocator) ) ; 
57+         let  _ =  USB_BUS . set ( 
58+             UsbDeviceBuilder :: new ( bus_allocator,  UsbVidPid ( 0x16c0 ,   0x27dd ) ) 
5759                . strings ( & [ StringDescriptors :: new ( LangID :: EN ) 
5860                    . manufacturer ( "Fake company" ) 
5961                    . product ( "Serial port" ) 
@@ -65,44 +67,110 @@ fn main() -> ! {
6567    } 
6668
6769    unsafe  { 
70+         core. NVIC . set_priority ( interrupt:: USB_OTHER ,  1 ) ; 
6871        core. NVIC . set_priority ( interrupt:: USB_TRCPT0 ,  1 ) ; 
69-         NVIC :: unmask ( interrupt:: USB_TRCPT0 ) ; 
7072        core. NVIC . set_priority ( interrupt:: USB_TRCPT1 ,  1 ) ; 
71-         NVIC :: unmask ( interrupt:: USB_TRCPT1 ) ; 
72-         core. NVIC . set_priority ( interrupt:: USB_SOF_HSOF ,  1 ) ; 
73-         NVIC :: unmask ( interrupt:: USB_SOF_HSOF ) ; 
74-         core. NVIC . set_priority ( interrupt:: USB_OTHER ,  1 ) ; 
7573        NVIC :: unmask ( interrupt:: USB_OTHER ) ; 
74+         NVIC :: unmask ( interrupt:: USB_TRCPT0 ) ; 
75+         NVIC :: unmask ( interrupt:: USB_TRCPT1 ) ; 
7676    } 
7777
7878    // Flash the LED in a spin loop to demonstrate that USB is 
7979    // entirely interrupt driven. 
8080    loop  { 
8181        cycle_delay ( 5  *  1024  *  1024 ) ; 
8282        red_led. toggle ( ) . unwrap ( ) ; 
83-         // Turn off interrupts so we don't fight with the interrupt 
84-         cortex_m:: interrupt:: free ( |_| unsafe  { 
85-             if  USB_BUS . as_mut ( ) . is_some ( )  { 
86-                 if  let  Some ( serial)  = USB_SERIAL . as_mut ( )  { 
87-                     let  _ = serial. write ( "Hello USB\n " . as_bytes ( ) ) ; 
88-                 } 
89-             } 
90-         } ) ; 
83+ 
84+         serial_writeln ! ( "Hello USB" ) ; 
9185    } 
9286} 
9387
94- static  mut  USB_ALLOCATOR :  Option < UsbBusAllocator < UsbBus > >  = None ; 
95- static  mut  USB_BUS :  Option < UsbDevice < UsbBus > >  = None ; 
96- static  mut  USB_SERIAL :  Option < SerialPort < UsbBus > >  = None ; 
88+ static  mut  USB_ALLOCATOR :  OnceCell < UsbBusAllocator < UsbBus > >  = OnceCell :: new ( ) ; 
89+ static  mut  USB_BUS :  OnceCell < UsbDevice < UsbBus > >  = OnceCell :: new ( ) ; 
90+ static  mut  USB_SERIAL :  OnceCell < SerialPort < UsbBus > >  = OnceCell :: new ( ) ; 
91+ 
92+ /// Borrows the global singleton `UsbSerial` for a brief period with interrupts 
93+ /// disabled 
94+ /// 
95+ /// # Arguments 
96+ /// `borrower`: The closure that gets run borrowing the global `UsbSerial` 
97+ /// 
98+ /// # Safety 
99+ /// the global singleton `UsbSerial` can be safely borrowed because we disable 
100+ /// interrupts while it is being borrowed, guaranteeing that interrupt handlers 
101+ /// like `USB` cannot mutate `UsbSerial` while we are as well. 
102+ /// 
103+ /// # Panic 
104+ /// If `init` has not been called and we haven't initialized our global 
105+ /// singleton `UsbSerial`, we will panic. 
106+ fn  usbserial_get < T ,  R > ( borrower :  T )  -> R 
107+ where 
108+     T :  Fn ( & mut  SerialPort < UsbBus > )  -> R , 
109+ { 
110+     usb_free ( |_| unsafe  { 
111+         let  usb_serial = USB_SERIAL . get_mut ( ) . expect ( "UsbSerial not initialized" ) ; 
112+         borrower ( usb_serial) 
113+     } ) 
114+ } 
115+ 
116+ /// Execute closure `f` in an interrupt-free context. 
117+ /// 
118+ /// This as also known as a "critical section". 
119+ #[ inline]  
120+ fn  usb_free < F ,  R > ( f :  F )  -> R 
121+ where 
122+     F :  FnOnce ( & cortex_m:: interrupt:: CriticalSection )  -> R , 
123+ { 
124+     NVIC :: mask ( interrupt:: USB_OTHER ) ; 
125+     NVIC :: mask ( interrupt:: USB_TRCPT0 ) ; 
126+     NVIC :: mask ( interrupt:: USB_TRCPT1 ) ; 
127+ 
128+     let  r = f ( unsafe  {  & cortex_m:: interrupt:: CriticalSection :: new ( )  } ) ; 
129+ 
130+     unsafe  { 
131+         NVIC :: unmask ( interrupt:: USB_OTHER ) ; 
132+         NVIC :: unmask ( interrupt:: USB_TRCPT0 ) ; 
133+         NVIC :: unmask ( interrupt:: USB_TRCPT1 ) ; 
134+     } ; 
135+ 
136+     r
137+ } 
138+ 
139+ /// Writes the given message out over USB serial. 
140+ /// 
141+ /// # Arguments 
142+ /// * println args: variable arguments passed along to `core::write!` 
143+ /// 
144+ /// # Warning 
145+ /// as this function deals with a static mut, and it is also accessed in the 
146+ /// USB interrupt handler, we both have unsafe code for unwrapping a static mut 
147+ /// as well as disabling of interrupts while we do so. 
148+ /// 
149+ /// # Safety 
150+ /// the only time the static mut is used, we have interrupts disabled so we know 
151+ /// we have sole access 
152+ #[ macro_export]  
153+ macro_rules!  serial_writeln { 
154+     ( $( $tt: tt) +)  => { { 
155+         use  core:: fmt:: Write ; 
156+ 
157+         let  mut  s:  heapless:: String <256 > = heapless:: String :: new( ) ; 
158+         core:: write!( & mut  s,  $( $tt) * ) . unwrap( ) ; 
159+         usbserial_get( |usbserial| { 
160+             usbserial. write( s. as_bytes( ) ) . ok( ) ; 
161+             usbserial. write( "\r \n " . as_bytes( ) ) . ok( ) ; 
162+         } ) ; 
163+     } } ; 
164+ } 
97165
98166fn  poll_usb ( )  { 
99167    unsafe  { 
100-         if  let  Some ( usb_dev)  = USB_BUS . as_mut ( )  { 
101-             if  let  Some ( serial)  = USB_SERIAL . as_mut ( )  { 
168+         if  let  Some ( usb_dev)  = USB_BUS . get_mut ( )  { 
169+             if  let  Some ( serial)  = USB_SERIAL . get_mut ( )  { 
102170                usb_dev. poll ( & mut  [ serial] ) ; 
103171
104172                // Make the other side happy 
105-                 let  mut  buf = [ 0u8 ;  16 ] ; 
173+                 let  mut  buf = [ 0u8 ;  64 ] ; 
106174                let  _ = serial. read ( & mut  buf) ; 
107175            } ; 
108176        } 
@@ -119,11 +187,6 @@ fn USB_TRCPT1() {
119187    poll_usb ( ) ; 
120188} 
121189
122- #[ interrupt]  
123- fn  USB_SOF_HSOF ( )  { 
124-     poll_usb ( ) ; 
125- } 
126- 
127190#[ interrupt]  
128191fn  USB_OTHER ( )  { 
129192    poll_usb ( ) ; 
0 commit comments