1010
1111// Imports
1212use core:: fmt:: Write ;
13+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
1314use neotron_common_bios as bios;
1415
1516mod config;
@@ -31,6 +32,11 @@ static mut VGA_CONSOLE: Option<vgaconsole::VgaConsole> = None;
3132/// We store our VGA console here.
3233static mut SERIAL_CONSOLE : Option < SerialConsole > = None ;
3334
35+ /// Note if we are panicking right now.
36+ ///
37+ /// If so, don't panic if a serial write fails.
38+ static IS_PANIC : AtomicBool = AtomicBool :: new ( false ) ;
39+
3440static OS_MENU : menu:: Menu < Ctx > = menu:: Menu {
3541 label : "root" ,
3642 items : & [
@@ -58,6 +64,23 @@ static OS_MENU: menu::Menu<Ctx> = menu::Menu {
5864 command : "fill" ,
5965 help : Some ( "Fill the screen with characters" ) ,
6066 } ,
67+ & menu:: Item {
68+ item_type : menu:: ItemType :: Callback {
69+ function : cmd_config,
70+ parameters : & [
71+ menu:: Parameter :: Optional {
72+ parameter_name : "command" ,
73+ help : Some ( "Which operation to perform (try help)" ) ,
74+ } ,
75+ menu:: Parameter :: Optional {
76+ parameter_name : "value" ,
77+ help : Some ( "new value for the setting" ) ,
78+ } ,
79+ ] ,
80+ } ,
81+ command : "config" ,
82+ help : Some ( "Handle non-volatile OS configuration" ) ,
83+ } ,
6184 ] ,
6285 entry : None ,
6386 exit : None ,
@@ -121,20 +144,25 @@ struct SerialConsole(u8);
121144impl core:: fmt:: Write for SerialConsole {
122145 fn write_str ( & mut self , data : & str ) -> core:: fmt:: Result {
123146 let api = API . get ( ) ;
124- ( api. serial_write ) (
147+ let is_panic = IS_PANIC . load ( Ordering :: SeqCst ) ;
148+ let res = ( api. serial_write ) (
125149 // Which port
126150 self . 0 ,
127151 // Data
128152 bios:: ApiByteSlice :: new ( data. as_bytes ( ) ) ,
129153 // No timeout
130154 bios:: Option :: None ,
131- )
132- . unwrap ( ) ;
155+ ) ;
156+ if !is_panic {
157+ res. unwrap ( ) ;
158+ }
133159 Ok ( ( ) )
134160 }
135161}
136162
137- struct Ctx ;
163+ struct Ctx {
164+ config : config:: Config ,
165+ }
138166
139167impl core:: fmt:: Write for Ctx {
140168 fn write_str ( & mut self , data : & str ) -> core:: fmt:: Result {
@@ -191,7 +219,7 @@ pub extern "C" fn main(api: *const bios::Api) -> ! {
191219
192220 let config = config:: Config :: load ( ) . unwrap_or_default ( ) ;
193221
194- if config. has_vga_console ( ) {
222+ if config. get_vga_console ( ) {
195223 // Try and set 80x30 mode for maximum compatibility
196224 ( api. video_set_mode ) ( bios:: video:: Mode :: new (
197225 bios:: video:: Timing :: T640x480 ,
@@ -215,7 +243,7 @@ pub extern "C" fn main(api: *const bios::Api) -> ! {
215243 }
216244 }
217245
218- if let Some ( ( idx, serial_config) ) = config. has_serial_console ( ) {
246+ if let Some ( ( idx, serial_config) ) = config. get_serial_console ( ) {
219247 let _ignored = ( api. serial_configure ) ( idx, serial_config) ;
220248 unsafe { SERIAL_CONSOLE = Some ( SerialConsole ( idx) ) } ;
221249 println ! ( "Configured Serial console on Serial {}" , idx) ;
@@ -225,29 +253,14 @@ pub extern "C" fn main(api: *const bios::Api) -> ! {
225253 println ! ( "Welcome to {}!" , OS_VERSION ) ;
226254 println ! ( "Copyright © Jonathan 'theJPster' Pallant and the Neotron Developers, 2022" ) ;
227255
228- let mut found;
229-
230- println ! ( "Serial Ports:" ) ;
231- found = false ;
232- for device_idx in 0 ..=255 {
233- if let bios:: Option :: Some ( serial) = ( api. serial_get_info ) ( device_idx) {
234- println ! ( "Serial Device {}: {:?}" , device_idx, serial) ;
235- found = true ;
236- } else {
237- // Ran out of serial devices (we assume they are consecutive)
238- break ;
239- }
240- }
241- if !found {
242- println ! ( "None." ) ;
243- }
256+ let ctx = Ctx { config } ;
244257
245258 let mut keyboard = pc_keyboard:: EventDecoder :: new (
246259 pc_keyboard:: layouts:: AnyLayout :: Uk105Key ( pc_keyboard:: layouts:: Uk105Key ) ,
247260 pc_keyboard:: HandleControl :: MapLettersToUnicode ,
248261 ) ;
249262 let mut buffer = [ 0u8 ; 256 ] ;
250- let mut menu = menu:: Runner :: new ( & OS_MENU , & mut buffer, Ctx ) ;
263+ let mut menu = menu:: Runner :: new ( & OS_MENU , & mut buffer, ctx ) ;
251264
252265 loop {
253266 match ( api. hid_get_event ) ( ) {
@@ -343,10 +356,82 @@ fn cmd_fill(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _c
343356 }
344357}
345358
359+ /// Called when the "config" command is executed.
360+ fn cmd_config ( _menu : & menu:: Menu < Ctx > , _item : & menu:: Item < Ctx > , args : & [ & str ] , context : & mut Ctx ) {
361+ let command = args. get ( 0 ) . cloned ( ) . unwrap_or ( "print" ) ;
362+ match command {
363+ "reset" => match config:: Config :: load ( ) {
364+ Ok ( new_config) => {
365+ context. config = new_config;
366+ println ! ( "Loaded OK." ) ;
367+ }
368+ Err ( e) => {
369+ println ! ( "Error loading; {}" , e) ;
370+ }
371+ } ,
372+ "save" => match context. config . save ( ) {
373+ Ok ( _) => {
374+ println ! ( "Saved OK." ) ;
375+ }
376+ Err ( e) => {
377+ println ! ( "Error saving: {}" , e) ;
378+ }
379+ } ,
380+ "vga" => match args. get ( 1 ) . cloned ( ) {
381+ Some ( "on" ) => {
382+ context. config . set_vga_console ( true ) ;
383+ println ! ( "VGA now on" ) ;
384+ }
385+ Some ( "off" ) => {
386+ context. config . set_vga_console ( false ) ;
387+ println ! ( "VGA now off" ) ;
388+ }
389+ _ => {
390+ println ! ( "Give on or off as argument" ) ;
391+ }
392+ } ,
393+ "serial" => match ( args. get ( 1 ) . cloned ( ) , args. get ( 1 ) . map ( |s| s. parse :: < u32 > ( ) ) ) {
394+ ( _, Some ( Ok ( baud) ) ) => {
395+ println ! ( "Turning serial console on at {} bps" , baud) ;
396+ context. config . set_serial_console_on ( baud) ;
397+ }
398+ ( Some ( "off" ) , _) => {
399+ println ! ( "Turning serial console off" ) ;
400+ context. config . set_serial_console_off ( ) ;
401+ }
402+ _ => {
403+ println ! ( "Give off or an integer as argument" ) ;
404+ }
405+ } ,
406+ "print" => {
407+ println ! ( "VGA : {}" , context. config. get_vga_console( ) ) ;
408+ match context. config . get_serial_console ( ) {
409+ None => {
410+ println ! ( "Serial: off" ) ;
411+ }
412+ Some ( ( _port, config) ) => {
413+ println ! ( "Serial: {} bps" , config. data_rate_bps) ;
414+ }
415+ }
416+ }
417+ _ => {
418+ println ! ( "config print - print the config" ) ;
419+ println ! ( "config help - print this help text" ) ;
420+ println ! ( "config reset - load config from BIOS store" ) ;
421+ println ! ( "config save - save config to BIOS store" ) ;
422+ println ! ( "config vga on - turn VGA on" ) ;
423+ println ! ( "config vga off - turn VGA off" ) ;
424+ println ! ( "config serial off - turn serial console off" ) ;
425+ println ! ( "config serial <baud> - turn serial console on with given baud rate" ) ;
426+ }
427+ }
428+ }
429+
346430/// Called when we have a panic.
347431#[ inline( never) ]
348432#[ panic_handler]
349433fn panic ( info : & core:: panic:: PanicInfo ) -> ! {
434+ IS_PANIC . store ( true , Ordering :: SeqCst ) ;
350435 println ! ( "PANIC!\n {:#?}" , info) ;
351436 let api = API . get ( ) ;
352437 loop {
0 commit comments