Skip to main content
← PSoXide SDK guides and examples · SDK f2fec1c301f1 · All Cargo features enabled; check feature gates before use.

SectorReader

Struct SectorReader 

Source
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

Source

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.

Source

pub const fn new() -> SectorReader

👎Deprecated:

use SectorReader::with_cd with the Cd token

with_cd on a token the caller does not hold.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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).

Source

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.

Source

pub fn stop(&mut self)

Pause the ReadN stream (keeps the drive spun up), ack everything and put the interrupt mask prepare replaced back. Safe to call after failures; it tolerates a drive with no active read.

Trait Implementations§

Source§

impl Default for SectorReader

Source§

fn default() -> SectorReader

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for SectorReader

§

impl RefUnwindSafe for SectorReader

§

impl Send for SectorReader

§

impl Sync for SectorReader

§

impl Unpin for SectorReader

§

impl UnsafeUnpin for SectorReader

§

impl UnwindSafe for SectorReader

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.