11//! Program Loading and Execution
22
3- use crate :: { fs, osprintln, refcell:: CsRefCell , FILESYSTEM } ;
3+ use neotron_api:: FfiByteSlice ;
4+
5+ use crate :: { fs, osprintln, refcell:: CsRefCell , API , FILESYSTEM } ;
46
57#[ allow( unused) ]
68static CALLBACK_TABLE : neotron_api:: Api = neotron_api:: Api {
@@ -41,6 +43,8 @@ pub enum OpenHandle {
4143 ///
4244 /// This is the default state for handles.
4345 Closed ,
46+ /// Represents the audio device,
47+ Audio ,
4448}
4549
4650/// The open handle table
@@ -334,6 +338,17 @@ impl TransientProgramArea {
334338 }
335339}
336340
341+ /// Store an open handle, or fail if we're out of space
342+ fn allocate_handle ( h : OpenHandle ) -> Result < usize , OpenHandle > {
343+ for ( idx, slot) in OPEN_HANDLES . lock ( ) . iter_mut ( ) . enumerate ( ) {
344+ if matches ! ( * slot, OpenHandle :: Closed ) {
345+ * slot = h;
346+ return Ok ( idx) ;
347+ }
348+ }
349+ Err ( h)
350+ }
351+
337352/// Open a file, given a path as UTF-8 string.
338353///
339354/// If the file does not exist, or is already open, it returns an error.
@@ -344,6 +359,19 @@ extern "C" fn api_open(
344359 path : neotron_api:: FfiString ,
345360 _flags : neotron_api:: file:: Flags ,
346361) -> neotron_api:: Result < neotron_api:: file:: Handle > {
362+ // Check for special devices
363+ if path. as_str ( ) . eq_ignore_ascii_case ( "AUDIO:" ) {
364+ match allocate_handle ( OpenHandle :: Audio ) {
365+ Ok ( n) => {
366+ return neotron_api:: Result :: Ok ( neotron_api:: file:: Handle :: new ( n as u8 ) ) ;
367+ }
368+ Err ( _f) => {
369+ return neotron_api:: Result :: Err ( neotron_api:: Error :: OutOfMemory ) ;
370+ }
371+ }
372+ }
373+
374+ // OK, let's assume it's a file relative to the root of our one and only volume
347375 let f = match FILESYSTEM . open_file ( path. as_str ( ) , embedded_sdmmc:: Mode :: ReadOnly ) {
348376 Ok ( f) => f,
349377 Err ( fs:: Error :: Io ( embedded_sdmmc:: Error :: NotFound ) ) => {
@@ -355,19 +383,9 @@ extern "C" fn api_open(
355383 } ;
356384
357385 // 1. Put the file into the open handles array and get the index (or return an error)
358- let mut result = None ;
359- for ( idx, slot) in OPEN_HANDLES . lock ( ) . iter_mut ( ) . enumerate ( ) {
360- if matches ! ( * slot, OpenHandle :: Closed ) {
361- result = Some ( idx) ;
362- * slot = OpenHandle :: File ( f) ;
363- break ;
364- }
365- }
366-
367- // 2. give the caller the index into the open handles array
368- match result {
369- Some ( n) => neotron_api:: Result :: Ok ( neotron_api:: file:: Handle :: new ( n as u8 ) ) ,
370- None => neotron_api:: Result :: Err ( neotron_api:: Error :: OutOfMemory ) ,
386+ match allocate_handle ( OpenHandle :: File ( f) ) {
387+ Ok ( n) => neotron_api:: Result :: Ok ( neotron_api:: file:: Handle :: new ( n as u8 ) ) ,
388+ Err ( _f) => neotron_api:: Result :: Err ( neotron_api:: Error :: OutOfMemory ) ,
371389 }
372390}
373391
@@ -391,8 +409,11 @@ extern "C" fn api_write(
391409 buffer : neotron_api:: FfiByteSlice ,
392410) -> neotron_api:: Result < ( ) > {
393411 let mut open_handles = OPEN_HANDLES . lock ( ) ;
394- match open_handles. get_mut ( fd. value ( ) as usize ) {
395- Some ( OpenHandle :: StdErr | OpenHandle :: Stdout ) => {
412+ let Some ( h) = open_handles. get_mut ( fd. value ( ) as usize ) else {
413+ return neotron_api:: Result :: Err ( neotron_api:: Error :: BadHandle ) ;
414+ } ;
415+ match h {
416+ OpenHandle :: StdErr | OpenHandle :: Stdout => {
396417 // Treat stderr and stdout the same
397418 let mut guard = crate :: VGA_CONSOLE . lock ( ) ;
398419 if let Some ( console) = guard. as_mut ( ) {
@@ -405,11 +426,27 @@ extern "C" fn api_write(
405426 }
406427 neotron_api:: Result :: Ok ( ( ) )
407428 }
408- Some ( OpenHandle :: File ( f) ) => match f. write ( buffer. as_slice ( ) ) {
429+ OpenHandle :: File ( f) => match f. write ( buffer. as_slice ( ) ) {
409430 Ok ( _) => neotron_api:: Result :: Ok ( ( ) ) ,
410431 Err ( _e) => neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific ) ,
411432 } ,
412- Some ( OpenHandle :: StdIn | OpenHandle :: Closed ) | None => {
433+ OpenHandle :: Audio => {
434+ let api = API . get ( ) ;
435+ let mut slice = buffer. as_slice ( ) ;
436+ // loop until we've sent all of it
437+ while !slice. is_empty ( ) {
438+ let result = unsafe { ( api. audio_output_data ) ( FfiByteSlice :: new ( slice) ) } ;
439+ let this_time = match result {
440+ neotron_common_bios:: FfiResult :: Ok ( n) => n,
441+ neotron_common_bios:: FfiResult :: Err ( _e) => {
442+ return neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific ) ;
443+ }
444+ } ;
445+ slice = & slice[ this_time..] ;
446+ }
447+ neotron_api:: Result :: Ok ( ( ) )
448+ }
449+ OpenHandle :: StdIn | OpenHandle :: Closed => {
413450 neotron_api:: Result :: Err ( neotron_api:: Error :: BadHandle )
414451 }
415452 }
@@ -423,16 +460,19 @@ extern "C" fn api_read(
423460 mut buffer : neotron_api:: FfiBuffer ,
424461) -> neotron_api:: Result < usize > {
425462 let mut open_handles = OPEN_HANDLES . lock ( ) ;
426- match open_handles. get_mut ( fd. value ( ) as usize ) {
427- Some ( OpenHandle :: StdIn ) => {
463+ let Some ( h) = open_handles. get_mut ( fd. value ( ) as usize ) else {
464+ return neotron_api:: Result :: Err ( neotron_api:: Error :: BadHandle ) ;
465+ } ;
466+ match h {
467+ OpenHandle :: StdIn => {
428468 if let Some ( buffer) = buffer. as_mut_slice ( ) {
429469 let count = { crate :: STD_INPUT . lock ( ) . get_data ( buffer) } ;
430470 Ok ( count) . into ( )
431471 } else {
432472 neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific )
433473 }
434474 }
435- Some ( OpenHandle :: File ( f) ) => {
475+ OpenHandle :: File ( f) => {
436476 let Some ( buffer) = buffer. as_mut_slice ( ) else {
437477 return neotron_api:: Result :: Err ( neotron_api:: Error :: InvalidArg ) ;
438478 } ;
@@ -441,7 +481,17 @@ extern "C" fn api_read(
441481 Err ( _e) => neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific ) ,
442482 }
443483 }
444- Some ( OpenHandle :: Stdout | OpenHandle :: StdErr | OpenHandle :: Closed ) | None => {
484+ OpenHandle :: Audio => {
485+ let api = API . get ( ) ;
486+ let result = unsafe { ( api. audio_input_data ) ( buffer) } ;
487+ match result {
488+ neotron_common_bios:: FfiResult :: Ok ( n) => neotron_api:: Result :: Ok ( n) ,
489+ neotron_common_bios:: FfiResult :: Err ( _e) => {
490+ neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific )
491+ }
492+ }
493+ }
494+ OpenHandle :: Stdout | OpenHandle :: StdErr | OpenHandle :: Closed => {
445495 neotron_api:: Result :: Err ( neotron_api:: Error :: BadHandle )
446496 }
447497 }
@@ -483,12 +533,84 @@ extern "C" fn api_rename(
483533}
484534
485535/// Perform a special I/O control operation.
536+ ///
537+ /// # Audio Devices
538+ ///
539+ /// * `0` - get output sample rate/format (0xN000_0000_<sample_rate_u32>) where N indicates the sample format
540+ /// * N = 0 => Eight bit mono, one byte per sample
541+ /// * N = 1 => Eight bit stereo, two byte per samples
542+ /// * N = 2 => Sixteen bit mono, two byte per samples
543+ /// * N = 3 => Sixteen bit stereo, four byte per samples
544+ /// * `1` - set output sample rate/format
545+ /// * As above
546+ /// * `2` - get output sample space available
547+ /// * Gets a value in bytes
486548extern "C" fn api_ioctl (
487- _fd : neotron_api:: file:: Handle ,
488- _command : u64 ,
489- _value : u64 ,
549+ fd : neotron_api:: file:: Handle ,
550+ command : u64 ,
551+ value : u64 ,
490552) -> neotron_api:: Result < u64 > {
491- neotron_api:: Result :: Err ( neotron_api:: Error :: Unimplemented )
553+ let mut open_handles = OPEN_HANDLES . lock ( ) ;
554+ let Some ( h) = open_handles. get_mut ( fd. value ( ) as usize ) else {
555+ return neotron_api:: Result :: Err ( neotron_api:: Error :: BadHandle ) ;
556+ } ;
557+ let api = API . get ( ) ;
558+ match ( h, command) {
559+ ( OpenHandle :: Audio , 0 ) => {
560+ // Getting sample rate
561+ let neotron_common_bios:: FfiResult :: Ok ( config) = ( api. audio_output_get_config ) ( ) else {
562+ return neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific ) ;
563+ } ;
564+ let mut result: u64 = config. sample_rate_hz as u64 ;
565+ let nibble = match config. sample_format . make_safe ( ) {
566+ Ok ( neotron_common_bios:: audio:: SampleFormat :: EightBitMono ) => 0 ,
567+ Ok ( neotron_common_bios:: audio:: SampleFormat :: EightBitStereo ) => 1 ,
568+ Ok ( neotron_common_bios:: audio:: SampleFormat :: SixteenBitMono ) => 2 ,
569+ Ok ( neotron_common_bios:: audio:: SampleFormat :: SixteenBitStereo ) => 3 ,
570+ _ => {
571+ return neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific ) ;
572+ }
573+ } ;
574+ result |= nibble << 60 ;
575+ neotron_api:: Result :: Ok ( result)
576+ }
577+ ( OpenHandle :: Audio , 1 ) => {
578+ // Setting sample rate
579+ let sample_rate = value as u32 ;
580+ let format = match value >> 60 {
581+ 0 => neotron_common_bios:: audio:: SampleFormat :: EightBitMono ,
582+ 1 => neotron_common_bios:: audio:: SampleFormat :: EightBitStereo ,
583+ 2 => neotron_common_bios:: audio:: SampleFormat :: SixteenBitMono ,
584+ 3 => neotron_common_bios:: audio:: SampleFormat :: SixteenBitStereo ,
585+ _ => {
586+ return neotron_api:: Result :: Err ( neotron_api:: Error :: InvalidArg ) ;
587+ }
588+ } ;
589+ let config = neotron_common_bios:: audio:: Config {
590+ sample_format : format. make_ffi_safe ( ) ,
591+ sample_rate_hz : sample_rate,
592+ } ;
593+ match ( api. audio_output_set_config ) ( config) {
594+ neotron_common_bios:: FfiResult :: Ok ( _) => {
595+ osprintln ! ( "audio {}, {:?}" , sample_rate, format) ;
596+ neotron_api:: Result :: Ok ( 0 )
597+ }
598+ neotron_common_bios:: FfiResult :: Err ( _) => {
599+ neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific )
600+ }
601+ }
602+ }
603+ ( OpenHandle :: Audio , 2 ) => {
604+ // Setting sample space
605+ match ( api. audio_output_get_space ) ( ) {
606+ neotron_common_bios:: FfiResult :: Ok ( n) => neotron_api:: Result :: Ok ( n as u64 ) ,
607+ neotron_common_bios:: FfiResult :: Err ( _) => {
608+ neotron_api:: Result :: Err ( neotron_api:: Error :: DeviceSpecific )
609+ }
610+ }
611+ }
612+ _ => neotron_api:: Result :: Err ( neotron_api:: Error :: InvalidArg ) ,
613+ }
492614}
493615
494616/// Open a directory, given a path as a UTF-8 string.
0 commit comments