Skip to content

Commit b804868

Browse files
authored
Merge pull request #38 from Neotron-Compute/add-pc-speaker
Add pc speaker
2 parents 238cd78 + 4d09817 commit b804868

2 files changed

Lines changed: 97 additions & 36 deletions

File tree

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ pio = "0.2.1"
3232
pio-proc = "0.2"
3333
# Hardware locks for sharing data with interrupts
3434
critical-section = "1.0"
35+
# Commands for talking to a Neotron BMC. The tag is for the repo as a whole, of which the commands crate is a small part.
36+
neotron-bmc-commands = { version = "0.1.0", git = "https://github.com/neotron-compute/neotron-bmc", tag="v0.5.2" }
3537
# Protocol for talking to a Neotron BMC. The tag is for the repo as a whole, of which the protocol crate is a small part.
36-
neotron-bmc-protocol = { version = "0.1.0", git = "https://github.com/neotron-compute/neotron-bmc", tag="v0.4.0" }
38+
neotron-bmc-protocol = { version = "0.1.0", git = "https://github.com/neotron-compute/neotron-bmc", tag="v0.5.2", features = ["defmt"] }
3739
# Time and frequency related functions
3840
fugit = "0.3"
3941
# PS/2 scancode decoding

src/main.rs

Lines changed: 94 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ use rp_pico::{
8383

8484
// Other Neotron Crates
8585
use common::MemoryRegion;
86+
use neotron_bmc_commands::Command;
8687
use neotron_bmc_protocol::Receivable;
8788
use neotron_common_bios as common;
8889

@@ -714,7 +715,7 @@ impl Hardware {
714715
/// These are connected to the bit 4 of GPIOA on the MCP23S17.
715716
fn set_hdd_led(&mut self, enabled: bool) {
716717
// LEDs are active-low.
717-
self.led_state = (self.led_state & 0x1e) | if enabled { 0 } else { 1 };
718+
self.led_state = (self.led_state & 0x1e) | u8::from(!enabled);
718719
self.io_chip_write(0x12, self.led_state << 3 | self.last_cs);
719720
}
720721

@@ -825,33 +826,39 @@ impl Hardware {
825826
self.io_chip_read(Self::MCP23S17_GPIOB)
826827
}
827828

828-
/// Read from a BMC register.
829+
/// Send a request to the BMC (a register read or a register write) and get
830+
/// the response.
829831
///
830-
/// It will perform a couple of retries, and then panic if the BMC did not respond correctly. It
831-
/// sets the Chip Select line and controls the IO chip automatically.
832+
/// It will perform a couple of retries, and then panic if the BMC did not
833+
/// respond correctly. It sets the Chip Select line and controls the IO chip
834+
/// automatically.
832835
///
833-
/// The number of bytes you want is set by the length of the `buffer` argument.
834-
///
835-
fn bmc_read_register(&mut self, register: u8, buffer: &mut [u8]) -> Result<(), ()> {
836+
/// The `buffer` argument may contain a mutable buffer for received data.
837+
fn bmc_do_request(
838+
&mut self,
839+
req: neotron_bmc_protocol::Request,
840+
buffer: Option<&mut [u8]>,
841+
) -> Result<(), ()> {
836842
const MAX_LATENCY: usize = 128;
837843

838-
if buffer.len() > self.bmc_buffer.len() {
839-
defmt::error!("Asked for too much data ({})", buffer.len());
840-
return Err(());
841-
}
842-
if buffer.len() > usize::from(u8::MAX) {
843-
defmt::error!("Asked for too much data ({})", buffer.len());
844-
return Err(());
844+
if let Some(buffer) = buffer.as_ref() {
845+
if buffer.len() > self.bmc_buffer.len() {
846+
defmt::error!("Asked for too much data ({})", buffer.len());
847+
return Err(());
848+
}
849+
if buffer.len() > usize::from(u8::MAX) {
850+
defmt::error!("Asked for too much data ({})", buffer.len());
851+
return Err(());
852+
}
845853
}
846-
let req =
847-
neotron_bmc_protocol::Request::new_read(USE_ALT.get(), register, buffer.len() as u8);
854+
848855
let req_bytes = req.as_bytes();
849856
for _retries in 0..4 {
850857
// Clear the input buffer
851858
for byte in self.bmc_buffer.iter_mut() {
852859
*byte = 0xFF;
853860
}
854-
let expected_response_len = buffer.len() + 2;
861+
let expected_response_len = buffer.as_ref().map(|b| b.len()).unwrap_or(0) + 2;
855862
defmt::debug!("req: {=[u8; 4]:02x}", req_bytes);
856863
let mut latency = 0;
857864
self.with_bus_cs(0, |spi, borrowed_buffer| {
@@ -878,16 +885,25 @@ impl Hardware {
878885
let response_portion = &self.bmc_buffer[0..expected_response_len];
879886
match neotron_bmc_protocol::Response::from_bytes(response_portion) {
880887
Ok(res) => {
881-
if res.result == neotron_bmc_protocol::ResponseResult::Ok
882-
&& res.data.len() == buffer.len()
883-
{
884-
buffer.copy_from_slice(res.data);
888+
if res.result == neotron_bmc_protocol::ResponseResult::Ok {
889+
if let Some(buffer) = buffer {
890+
if res.data.len() == buffer.len() {
891+
buffer.copy_from_slice(res.data);
892+
} else {
893+
defmt::warn!(
894+
"Mismatch between received and expected data: expected {}, got {} bytes - {=[u8]:X}",
895+
buffer.len(),
896+
res.data.len(),
897+
res.data
898+
);
899+
return Err(());
900+
}
901+
}
885902
return Ok(());
886903
} else {
887904
defmt::warn!(
888-
"Error reading {} bytes from {}: Error from BMC {:?} {=[u8]:x}",
889-
buffer.len(),
890-
register,
905+
"Error executing {:?}: Error from BMC {:?} {=[u8]:x}",
906+
req,
891907
res.result,
892908
response_portion
893909
);
@@ -897,9 +913,8 @@ impl Hardware {
897913
}
898914
Err(e) => {
899915
defmt::warn!(
900-
"Error reading {} bytes from {}: Decoding Error {:?} {=[u8]:x}",
901-
buffer.len(),
902-
register,
916+
"Error executing {:?}: Decoding Error {:?} {=[u8]:x}",
917+
req,
903918
e,
904919
response_portion
905920
);
@@ -911,12 +926,45 @@ impl Hardware {
911926
panic!("Failed to talk to BMC after several retries.");
912927
}
913928

929+
/// Make the BMC produce a sequence of beeps using the Speaker
930+
fn play_startup_tune(&mut self) -> Result<(), ()> {
931+
// (delay (ms), command, data)
932+
let seq: &[(u16, Command, u8)] = &[
933+
(0, Command::SpeakerPeriodLow, 137),
934+
(0, Command::SpeakerPeriodHigh, 0),
935+
(0, Command::SpeakerDutyCycle, 127),
936+
(0, Command::SpeakerDuration, 7),
937+
(0, Command::SpeakerPeriodLow, 116),
938+
(70, Command::SpeakerDuration, 7),
939+
(0, Command::SpeakerPeriodLow, 97),
940+
(70, Command::SpeakerDuration, 7),
941+
];
942+
943+
for (delay, reg, val) in seq {
944+
if *delay > 0 {
945+
self.delay.delay_ms(*delay as u32);
946+
}
947+
self.bmc_do_request(
948+
neotron_bmc_protocol::Request::new_short_write(USE_ALT.get(), (*reg).into(), *val),
949+
None,
950+
)?;
951+
}
952+
Ok(())
953+
}
954+
914955
/// Read the BMC firmware version string.
915956
///
916957
/// You get 32 bytes of probably UTF-8 data.
917958
fn bmc_read_firmware_version(&mut self) -> Result<[u8; 32], ()> {
918959
let mut firmware_version = [0u8; 32];
919-
self.bmc_read_register(0x01, &mut firmware_version)?;
960+
self.bmc_do_request(
961+
neotron_bmc_protocol::Request::new_read(
962+
USE_ALT.get(),
963+
Command::FirmwareVersion.into(),
964+
firmware_version.len() as u8,
965+
),
966+
Some(&mut firmware_version),
967+
)?;
920968
Ok(firmware_version)
921969
}
922970

@@ -938,7 +986,14 @@ impl Hardware {
938986
}
939987

940988
let mut fifo_data = [0u8; 9];
941-
self.bmc_read_register(0x40, &mut fifo_data)?;
989+
self.bmc_do_request(
990+
neotron_bmc_protocol::Request::new_read(
991+
USE_ALT.get(),
992+
Command::Ps2KbBuffer.into(),
993+
fifo_data.len() as u8,
994+
),
995+
Some(&mut fifo_data),
996+
)?;
942997
let bytes_in_fifo = fifo_data[0];
943998
if bytes_in_fifo == 0 {
944999
defmt::trace!("Got no PS/2 bytes");
@@ -948,15 +1003,15 @@ impl Hardware {
9481003
for (dest, src) in out_buffer.iter_mut().zip(fifo_data.iter().skip(1)) {
9491004
*dest = *src;
9501005
}
951-
return Ok(bytes_in_fifo as usize);
1006+
Ok(bytes_in_fifo as usize)
9521007
}
9531008
}
9541009

9551010
fn sign_on() {
9561011
static LICENCE_TEXT: &str = "\
957-
Copyright © Jonathan 'theJPster' Pallant and the Neotron Developers, 2022\n\
958-
\n\
959-
This program is free software under GPL v3 (or later)\n";
1012+
Copyright © Jonathan 'theJPster' Pallant and the Neotron Developers, 2022\n\
1013+
\n\
1014+
This program is free software under GPL v3 (or later)\n";
9601015

9611016
// Create a new temporary console for some boot-up messages
9621017
let tc = vga::TextConsole::new();
@@ -975,13 +1030,17 @@ fn sign_on() {
9751030
let bmc_ver = critical_section::with(|cs| {
9761031
let mut lock = HARDWARE.borrow_ref_mut(cs);
9771032
let hw = lock.as_mut().unwrap();
978-
hw.bmc_read_firmware_version()
1033+
let ver = hw.bmc_read_firmware_version();
1034+
if let Err(e) = hw.play_startup_tune() {
1035+
writeln!(&tc, "BMC error: {e:?}").unwrap();
1036+
}
1037+
ver
9791038
});
9801039

9811040
match bmc_ver {
9821041
Ok(string_bytes) => match core::str::from_utf8(&string_bytes) {
9831042
Ok(s) => {
984-
writeln!(&tc, "BMC Version: {}", s).unwrap();
1043+
writeln!(&tc, "BMC Version: {s}").unwrap();
9851044
}
9861045
Err(_e) => {
9871046
writeln!(&tc, "BMC Version: Unknown").unwrap();

0 commit comments

Comments
 (0)