pub struct SectorReader { /* private fields */ }Expand description
Moved to psx_io::cd::reader. Kept at this path for one stage so
psx_pack::cd::SectorReader still resolves; a re-export cannot carry a
deprecation.
Blocking, polled CD-ROM sector reader.
Owns the CD token, plus the state a polled stream needs: whether the
first prepare has drained boot-time IRQs, the interrupt mask to put back
at stop, and a one-sector bounce buffer that an unexpected data-ready IRQ
is drained into (the data FIFO must be emptied before the ack or the
controller wedges). Create one reader and reuse it for the program’s
lifetime; a fresh reader merely repeats the harmless first-time drain.
Typical use is not these raw methods but psx_pack::cd::load_chunk on top.
The raw sequence is: prepare(), start_read(lba), N times
read_sector(&mut buf), stop().
The reader owns the drive, so nothing else can command it meanwhile:
use psx_io::cd::reader::SectorReader;
use psx_io::periph::Cd;
// SAFETY: the doctest never runs a command; it only has to compile.
let mut cd = unsafe { Cd::steal() };
let mut reader = SectorReader::with_cd(cd);
// The token moved into the reader, so this is a use after move.
let _ = cd.play_track(2);
reader.stop();Implementations§
Source§impl SectorReader
impl SectorReader
Sourcepub const fn with_cd(cd: Cd) -> SectorReader
pub const fn with_cd(cd: Cd) -> SectorReader
A reader that has not yet drained boot-time IRQs. const so it can
sit in a static.
Sourcepub const fn new() -> SectorReader
👎Deprecated: use SectorReader::with_cd with the Cd token
pub const fn new() -> SectorReader
use SectorReader::with_cd with the Cd token
with_cd on a token the caller does not hold.
Sourcepub fn release(self) -> Cd
pub fn release(self) -> Cd
Give the token back, restoring the interrupt mask first if a stream
is still open. Call stop first to also pause the drive.
Sourcepub fn cd_mut(&mut self) -> &mut Cd
pub fn cd_mut(&mut self) -> &mut Cd
The token, lent for commands outside the reader’s own sequences (the drive’s audio mixer, a status poll). The reader stays borrowed meanwhile.
Sourcepub fn diagnostics(&self) -> u32
pub fn diagnostics(&self) -> u32
The last failure snapshot packed big-endian:
cause<<24 | status<<16 | command<<8 | flag_or_error. Zero when
nothing has failed yet. Causes are the DIAG_* constants; for
DIAG_CD_ERROR the status/flag bytes are the INT5 response pair,
otherwise status is the raw status register at failure and the low
byte is the last IRQ flag seen.
Sourcepub fn prepare(&mut self) -> bool
pub fn prepare(&mut self) -> bool
Take over the controller for polled data reads and set double-speed / 2048-byte-sector mode.
Sets I_MASK to VBlank-only until stop puts the
previous mask back; see the module docs for the full list of side
effects. Call it only from code that owns interrupt policy, a polling
main loop, and not from an IRQ handler. No CD-ROM IRQ handler may be
installed while a stream runs.
Returns false when the Setmode handshake times out (no drive, tray
open, dead controller); the reader is safe to retry.
Sourcepub fn prepare_single_speed(&mut self) -> bool
pub fn prepare_single_speed(&mut self) -> bool
prepare at single speed: half the throughput,
twice the per-sector margin. The demo-disc chain loader measured
silent payload corruption over hundreds of back-to-back
double-speed sectors on the project console (2026-08-01, the
loader’s RAM checksum against the disc build); the header sector
alone always read clean, so the failure scales with sustained
rate, and a loader that takes three extra seconds beats one that
jumps into a corrupt payload.
Sourcepub fn prepare_mode(&mut self, mode: u8) -> bool
pub fn prepare_mode(&mut self, mode: u8) -> bool
prepare with an explicit Setmode byte, for
streams that need more than plain data: e.g. 0x80 | 0x40 | 0x08
(double speed, XA-ADPCM on, file/channel filter) plays interleaved
XA audio through the SPU while video sectors still arrive as data.
Sourcepub fn set_filter(&mut self, file: u8, channel: u8) -> bool
pub fn set_filter(&mut self, file: u8, channel: u8) -> bool
Setfilter: the XA file and channel whose audio sectors the drive plays when the mode has the filter bit set.
Sourcepub fn unmute(&mut self) -> bool
pub fn unmute(&mut self) -> bool
Unmute the drive: let CD-DA and XA-ADPCM reach the SPU. The drive stays muted across programs, so a stream that plays XA audio must not assume the last tenant left it unmuted.
Sourcepub fn start_read(&mut self, lba: u32) -> bool
pub fn start_read(&mut self, lba: u32) -> bool
Seek to lba (Setloc with BCD MSF) and start a ReadN stream.
prepare must have succeeded first.
lba is relative to the start of this program’s own disc image; on a
multi-program disc crate::disc_base shifts it to where that image
actually landed.
Sourcepub fn start_read_seek_first(&mut self, lba: u32, seek_poll: u32) -> bool
pub fn start_read_seek_first(&mut self, lba: u32, seek_poll: u32) -> bool
start_read the way the real BIOS starts one:
SetLoc, then an EXPLICIT SeekL waited to completion, then ReadN.
Traced from a real SCPH-1001 boot (2026-08-01, emulator CD command log): the BIOS brackets every read – even a single sector – as SetLoc/SeekL/SetMode/ReadN/Pause. The implicit seek a bare SetLoc+ReadN performs starts data flowing while the mech is still settling; the same console that corrupts our sustained implicit-seek streams loads 1.4 MB EXEs through the BIOS bracket without fault.
Sourcepub fn read_sector(&mut self, buffer: &mut [u32; 512]) -> bool
pub fn read_sector(&mut self, buffer: &mut [u32; 512]) -> bool
Block until the next sector of the running ReadN stream is ready, then
pop its 2048 bytes into buffer. false on drive error or timeout
(the stream is acked/cleaned up; follow with stop). A
read must be running (a successful start_read).
Sourcepub fn try_read_sector(&mut self, buffer: &mut [u32; 512]) -> Result<bool, ()>
pub fn try_read_sector(&mut self, buffer: &mut [u32; 512]) -> Result<bool, ()>
Non-blocking read_sector: check the controller
once and, if the next sector of the running ReadN stream is ready,
pop its 2048 bytes into buffer and ack it.
Ok(true) means buffer holds a new sector, Ok(false) that none
has arrived yet. Err(()) is a drive error; the stream is acked and
the caller should stop (the diag snapshot is set as
for read_sector).
Streaming consumers (FMV) call this between units of other work so the drive never runs ahead of the CPU by more than the controller can hold. At double speed a sector lands every ~6.7 ms.