@@ -52,18 +52,15 @@ pub mod vga;
5252// -----------------------------------------------------------------------------
5353
5454// Standard Library Stuff
55- use core:: {
56- fmt:: Write ,
57- sync:: atomic:: { AtomicBool , AtomicU8 , Ordering } ,
58- } ;
55+ use core:: { fmt:: Write , sync:: atomic:: AtomicBool } ;
5956
6057// Third Party Stuff
6158use cortex_m_rt:: entry;
6259use critical_section:: Mutex ;
6360use defmt:: info;
6461use defmt_rtt as _;
6562use embedded_hal:: {
66- blocking:: spi:: Transfer as _SpiTransfer, blocking :: spi :: Write as _SpiWrite,
63+ blocking:: spi:: { Transfer as _SpiTransfer, Write as _SpiWrite} ,
6764 digital:: v2:: OutputPin ,
6865} ;
6966use fugit:: RateExtU32 ;
@@ -104,6 +101,8 @@ struct Hardware {
104101 keyboard : pc_keyboard:: Keyboard < pc_keyboard:: layouts:: Uk105Key , pc_keyboard:: ScancodeSet2 > ,
105102 /// Our queue of HID events
106103 event_queue : heapless:: Deque < neotron_common_bios:: hid:: HidEvent , 16 > ,
104+ /// A place to send/receive bytes to/from the BMC
105+ bmc_buffer : [ u8 ; 64 ] ,
107106}
108107
109108/// Flips between true and false so we always send a unique read request
@@ -393,6 +392,9 @@ impl Hardware {
393392 /// Give the device 10us when we do a retry.
394393 const SPI_RETRY_CPU_CLOCKS : u32 = 10_000 / Self :: NS_PER_CLOCK_CYCLE ;
395394
395+ /// Give the BMC 4us to calculate its response
396+ const BMC_REQUEST_RESPONSE_DELAY_CLOCKS : u32 = 4_000 / Self :: NS_PER_CLOCK_CYCLE ;
397+
396398 /// Data Direction Register A on the MCP23S17
397399 const MCP23S17_DDRA : u8 = 0x00 ;
398400
@@ -553,18 +555,19 @@ impl Hardware {
553555 i2s_lr_clock : hal_pins. gpio28 . into_mode ( ) ,
554556 pico_led : hal_pins. led . into_mode ( ) ,
555557 } ,
556- // Set SPI up for 2 MHz clock, 8 data bits.
558+ // Set SPI up for 4 MHz clock, 8 data bits.
557559 spi_bus : hal:: Spi :: new ( spi) . init (
558560 resets,
559561 clocks. peripheral_clock . freq ( ) ,
560- 2_000_000 . Hz ( ) ,
562+ 4_000_000 . Hz ( ) ,
561563 & embedded_hal:: spi:: MODE_0 ,
562564 ) ,
563565 delay,
564566 debug_leds : 0 ,
565567 last_cs : 0 ,
566568 keyboard : pc_keyboard:: Keyboard :: new ( pc_keyboard:: HandleControl :: Ignore ) ,
567569 event_queue : heapless:: Deque :: new ( ) ,
570+ bmc_buffer : [ 0u8 ; 64 ] ,
568571 }
569572 }
570573
@@ -647,7 +650,7 @@ impl Hardware {
647650 /// SPI bus object), then de-activates the CS pin.
648651 fn with_bus_cs < F > ( & mut self , cs : u8 , func : F )
649652 where
650- F : FnOnce ( & mut hal:: Spi < hal:: spi:: Enabled , pac:: SPI0 , 8_u8 > ) ,
653+ F : FnOnce ( & mut hal:: Spi < hal:: spi:: Enabled , pac:: SPI0 , 8_u8 > , & mut [ u8 ] ) ,
651654 {
652655 // Only CS0..CS7 is valid
653656 let cs = cs & 0b111 ;
@@ -665,7 +668,7 @@ impl Hardware {
665668 cortex_m:: asm:: delay ( Self :: CS_BUS_SETUP_CPU_CLOCKS ) ;
666669
667670 // Call function
668- func ( & mut self . spi_bus ) ;
671+ func ( & mut self . spi_bus , & mut self . bmc_buffer ) ;
669672
670673 // Hold the CS pin a bit longer
671674 cortex_m:: asm:: delay ( Self :: CS_BUS_HOLD_CPU_CLOCKS ) ;
@@ -685,6 +688,11 @@ impl Hardware {
685688 self . pins . noutput_en . set_high ( ) . unwrap ( ) ;
686689 }
687690
691+ /// Configure the MCP23S17 correctly.
692+ ///
693+ /// We have GPIOA as outputs (for the debug LEDs, HDD LED and 3-bit
694+ /// chip-select number). We have GPIOB as pulled-up inputs (for the eight
695+ /// interrupts).
688696 fn init_io_chip ( & mut self ) {
689697 // Undrive CS lines from decoder/buffer
690698 self . release_cs_lines ( ) ;
@@ -705,122 +713,116 @@ impl Hardware {
705713 self . io_chip_write ( Self :: MCP23S17_GPPUB , 0xFF ) ;
706714 }
707715
708- /// Read the BMC firmware version string .
716+ /// Read from a BMC register .
709717 ///
710- /// You get 32 bytes of probably UTF-8 data.
711- fn bmc_read_firmware_version ( & mut self ) -> Result < [ u8 ; 32 ] , ( ) > {
712- let req = neotron_bmc_protocol:: Request :: new_read ( false , 0x01 , 32 ) ;
713- let mut buffer = [ 0xFF ; 64 ] ;
714- buffer[ 0 ..=3 ] . copy_from_slice ( & req. as_bytes ( ) ) ;
715- self . with_bus_cs ( 0 , |spi| {
716- spi. transfer ( & mut buffer) . unwrap ( ) ;
717- } ) ;
718- defmt:: info!( "buffer: {=[u8]:x}" , buffer) ;
719- let mut result = & buffer[ ..] ;
720- let mut latency = 0 ;
721- while !result. is_empty ( ) && ( ( result[ 0 ] == 0xFF ) || ( result[ 0 ] == 0x00 ) ) {
722- latency += 1 ;
723- result = & result[ 1 ..] ;
718+ /// It will perform a couple of retries, and then panic if the BMC did not respond correctly. It
719+ /// sets the Chip Select line and controls the IO chip automatically.
720+ ///
721+ /// The number of bytes you want is set by the length of the `buffer` argument.
722+ ///
723+ fn bmc_read_register ( & mut self , register : u8 , buffer : & mut [ u8 ] ) -> Result < ( ) , ( ) > {
724+ if buffer. len ( ) > self . bmc_buffer . len ( ) {
725+ defmt:: error!( "Asked for too much data ({})" , buffer. len( ) ) ;
726+ return Err ( ( ) ) ;
724727 }
725- defmt:: info!( "latency: {}" , latency) ;
726- // 32 bytes of data requested, plus one bytes of response code and one byte of CRC
727- if result. len ( ) >= 34 {
728- match neotron_bmc_protocol:: Response :: from_bytes ( & result[ 0 ..34 ] ) {
729- Ok ( res) => {
730- if res. result == neotron_bmc_protocol:: ResponseResult :: Ok
731- && res. data . len ( ) == 32
732- {
733- defmt:: info!( "Got BMC version {=[u8]:a}" , res. data) ;
734- let mut string_bytes = [ 0u8 ; 32 ] ;
735- string_bytes. copy_from_slice ( res. data ) ;
736- return Ok ( string_bytes) ;
737- } else {
738- defmt:: warn!(
739- "Error getting BMC version: Error from BMC {:?} {=[u8]:x}" ,
740- res. result,
741- res. data
742- ) ;
743- }
744- }
745- Err ( e) => {
746- defmt:: warn!(
747- "Error getting BMC version: Decoding Error {:?} {=[u8]:x}" ,
748- e,
749- result
750- ) ;
751- }
752- }
728+ if buffer. len ( ) > usize:: from ( u8:: MAX ) {
729+ defmt:: error!( "Asked for too much data ({})" , buffer. len( ) ) ;
730+ return Err ( ( ) ) ;
753731 }
754-
755- Err ( ( ) )
756- }
757-
758- /// Read the BMC PS/2 keyboard FIFO.
759- ///
760- /// We ask for 8 bytes of data. We get `1` byte of 'length', then `N` bytes of valid data, and `32 - (N + 1)` bytes of padding.
761- fn bmc_read_ps2_keyboard_fifo ( & mut self , out_buffer : & mut [ u8 ; 8 ] ) -> Result < usize , ( ) > {
762- static COUNTER : AtomicU8 = AtomicU8 :: new ( 0 ) ;
763- let req = neotron_bmc_protocol:: Request :: new_read ( USE_ALT . get ( ) , 0x40 , 8 ) ;
764- for _retry in 0 ..4 {
765- let mut buffer = [ 0xFF ; 32 ] ;
766- buffer[ 0 ..=3 ] . copy_from_slice ( & req. as_bytes ( ) ) ;
767- buffer[ 4 ] = COUNTER . load ( Ordering :: Relaxed ) ;
768- COUNTER . store ( buffer[ 4 ] . wrapping_add ( 1 ) , Ordering :: Relaxed ) ;
769- defmt:: trace!( "out: {=[u8]:02x}" , buffer) ;
770- self . with_bus_cs ( 0 , |spi| {
771- spi. transfer ( & mut buffer) . unwrap ( ) ;
732+ let req =
733+ neotron_bmc_protocol:: Request :: new_read ( USE_ALT . get ( ) , register, buffer. len ( ) as u8 ) ;
734+ let req_bytes = req. as_bytes ( ) ;
735+ for _retries in 0 ..4 {
736+ // Clear the input buffer
737+ for byte in self . bmc_buffer . iter_mut ( ) {
738+ * byte = 0xFF ;
739+ }
740+ defmt:: debug!( "req: {=[u8; 4]:02x}" , req_bytes) ;
741+ self . with_bus_cs ( 0 , |spi, buffer| {
742+ // Send the request
743+ spi. write ( & req_bytes) . unwrap ( ) ;
744+ cortex_m:: asm:: delay ( Self :: BMC_REQUEST_RESPONSE_DELAY_CLOCKS ) ;
745+ // Get the response
746+ spi. transfer ( buffer) . unwrap ( ) ;
772747 } ) ;
773- defmt:: trace!( "in : {=[u8]:02x}" , buffer) ;
774- // Skip the first four bytes at least (that's our command, and also
775- // the BMC FIFO length which might have crud in it). Then trip any padding.
776- let mut result = & buffer[ 4 ..] ;
748+ // Trim the padding off the front
749+ let mut response_buffer = & self . bmc_buffer [ ..] ;
777750 let mut latency = 0 ;
778- while !result. is_empty ( ) && ( result[ 0 ] == 0xFF || result[ 0 ] == 0x00 ) {
751+ while response_buffer. len ( ) > 0
752+ && ( ( response_buffer[ 0 ] == 0x00 ) || ( response_buffer[ 0 ] == 0xFF ) )
753+ {
754+ response_buffer = & response_buffer[ 1 ..] ;
779755 latency += 1 ;
780- result = & result[ 1 ..] ;
781756 }
782- defmt:: trace!( "latency: {}" , latency) ;
757+ defmt:: debug!( "res: {=[u8]:02x} ({})" , response_buffer, latency) ;
758+ let expected_response_len = buffer. len ( ) + 2 ;
783759 // 8 bytes of data requested, plus one bytes of response code and one byte of CRC
784- if result. len ( ) >= 10 {
785- match neotron_bmc_protocol:: Response :: from_bytes ( & result[ 0 ..10 ] ) {
760+ if response_buffer. len ( ) >= expected_response_len {
761+ match neotron_bmc_protocol:: Response :: from_bytes (
762+ & response_buffer[ 0 ..expected_response_len] ,
763+ ) {
786764 Ok ( res) => {
787765 if res. result == neotron_bmc_protocol:: ResponseResult :: Ok
788- && res. data . len ( ) == 8
766+ && res. data . len ( ) == buffer . len ( )
789767 {
790- if res. data [ 0 ] == 0 {
791- defmt:: trace!( "Got no PS/2 bytes" ) ;
792- } else {
793- defmt:: debug!( "Got PS/2 bytes {=[u8]:x}" , res. data) ;
794- }
795- for ( dest, src) in out_buffer. iter_mut ( ) . zip ( res. data . iter ( ) . skip ( 1 ) ) {
796- * dest = * src;
797- }
798- return Ok ( res. data [ 0 ] as usize ) ;
768+ buffer. copy_from_slice ( res. data ) ;
769+ return Ok ( ( ) ) ;
799770 } else {
800771 defmt:: warn!(
801- "Error getting keyboard bytes: Error from BMC {:?} {=[u8]:x}" ,
772+ "Error reading {} bytes from {}: Error from BMC {:?} {=[u8]:x}" ,
773+ buffer. len( ) ,
774+ register,
802775 res. result,
803776 res. data
804777 ) ;
778+ // No point retrying - we heardly them perfectly
779+ return Err ( ( ) ) ;
805780 }
806781 }
807782 Err ( e) => {
808783 defmt:: warn!(
809- "Error getting BMC keyboard bytes: Decoding Error {:?} {=[u8]:x}" ,
784+ "Error reading {} bytes from {}: Decoding Error {:?} {=[u8]:x}" ,
785+ buffer. len( ) ,
786+ register,
810787 e,
811- result
788+ response_buffer
812789 ) ;
813790 }
814791 }
815792 } else {
816- defmt:: warn!( "Short packet!?" ) ;
793+ defmt:: warn!( "Short packet {=[u8]:x}" , response_buffer ) ;
817794 }
818-
819795 // Wait a bit before we try again
820796 cortex_m:: asm:: delay ( Self :: SPI_RETRY_CPU_CLOCKS ) ;
821797 }
822- // Ran out of retries
823- panic ! ( "KB retry timeout" ) ;
798+ panic ! ( "Failed to talk to BMC after several retries." ) ;
799+ }
800+
801+ /// Read the BMC firmware version string.
802+ ///
803+ /// You get 32 bytes of probably UTF-8 data.
804+ fn bmc_read_firmware_version ( & mut self ) -> Result < [ u8 ; 32 ] , ( ) > {
805+ let mut firmware_version = [ 0u8 ; 32 ] ;
806+ self . bmc_read_register ( 0x01 , & mut firmware_version) ?;
807+ Ok ( firmware_version)
808+ }
809+
810+ /// Read the BMC PS/2 keyboard FIFO.
811+ ///
812+ /// We ask for 8 bytes of data. We get `1` byte of 'length', then `N` bytes of valid data, and `32 - (N + 1)` bytes of padding.
813+ fn bmc_read_ps2_keyboard_fifo ( & mut self , out_buffer : & mut [ u8 ; 8 ] ) -> Result < usize , ( ) > {
814+ let mut fifo_data = [ 0u8 ; 9 ] ;
815+ self . bmc_read_register ( 0x40 , & mut fifo_data) ?;
816+ let bytes_in_fifo = fifo_data[ 0 ] ;
817+ if bytes_in_fifo == 0 {
818+ defmt:: trace!( "Got no PS/2 bytes" ) ;
819+ } else {
820+ defmt:: debug!( "Got PS/2 bytes {=[u8]:x}" , & fifo_data[ ..] ) ;
821+ }
822+ for ( dest, src) in out_buffer. iter_mut ( ) . zip ( fifo_data. iter ( ) . skip ( 1 ) ) {
823+ * dest = * src;
824+ }
825+ return Ok ( bytes_in_fifo as usize ) ;
824826 }
825827}
826828
@@ -1147,7 +1149,7 @@ pub extern "C" fn hid_get_event() -> common::Result<common::Option<common::hid::
11471149 Ok ( None ) => {
11481150 // Need more data
11491151 }
1150- Err ( e ) => {
1152+ Err ( _e ) => {
11511153 panic ! ( "Keyboard decode error!" ) ;
11521154 }
11531155 }
@@ -1378,14 +1380,14 @@ extern "C" fn video_get_palette(index: u8) -> common::Option<common::video::RGBC
13781380}
13791381
13801382/// Update the RGB palette
1381- extern "C" fn video_set_palette ( index : u8 , rgb : common:: video:: RGBColour ) {
1383+ extern "C" fn video_set_palette ( _index : u8 , _rgb : common:: video:: RGBColour ) {
13821384 // TODO set the palette when we actually have one
13831385}
13841386
13851387/// Update all the RGB palette
13861388unsafe extern "C" fn video_set_whole_palette (
1387- palette : * const common:: video:: RGBColour ,
1388- length : usize ,
1389+ _palette : * const common:: video:: RGBColour ,
1390+ _length : usize ,
13891391) {
13901392 // TODO set the palette when we actually have one
13911393}
@@ -1561,7 +1563,7 @@ pub extern "C" fn block_verify(
15611563 common:: Result :: Err ( common:: Error :: Unimplemented )
15621564}
15631565
1564- extern "C" fn block_dev_eject ( dev_id : u8 ) -> common:: Result < ( ) > {
1566+ extern "C" fn block_dev_eject ( _dev_id : u8 ) -> common:: Result < ( ) > {
15651567 common:: Result :: Ok ( ( ) )
15661568}
15671569
0 commit comments