muforth/lib/terminal.mu4

( This file is part of muFORTH: http://pages.nimblemachines.com/muforth

  Copyright 2002-2008 David Frech. All rights reserved, and all wrongs
  reversed. (See the file COPYRIGHT for details.)

( Simple terminal and serial expect/send code.)

( 2007-jan-15. Moved v25 and ARM things elsewhere.)
( 2002-mar-27. Converted to muforth.)

( Created 5-aug-1999.)

cr " Terminal "  file[#

decimal

( Open serial device.)
variable fd-target
( used /dev/cuad0 on FreeBSD)
: tty-target  z" /dev/ttyS0" r/w  open-file  fd-target ! ;

: bps   ( speed)
   fd-target @ ram get-termios drop ( returns size of struct)
      ( speed) ram set-termios-speed
   fd-target @ ram set-termios ;

( Keymaps)
-: ( self)  emit  0 ;  256 defarray term-keys
   ( nop)       ' 0    256 defarray term-esc-keys
-: drop ( ESC)  key term-esc-keys @execute ;  #ESC term-keys !
: esc:  -:  \f char  term-esc-keys ! ;

comment %use-typing%
  256 constant #serialbuf
  #serialbuf buffer serialbuf ( serial input buffer)
%use-typing%

comment %coroutines-broken%
( 2003-mar-13. It's coroutine time!)

: coroutine  ( dstack-safety dstack-size - s0)
   cells allot ( size)  cells ( safety)  ram  swap -  constant ;

coroutine serial-s0
%coroutines-broken%

variable fdmax
: new-fd-set  ram fd!  buffer ;
new-fd-set fds

: te-select  ( fd0 .. fdn n)
   fds fd! drop  fdmax off
   for  fds over fd-set   fdmax @ max  fdmax !  next
   fdmax @ 1+  fds  0  0  0  select  drop  ;

( Serial input to screen, keyboard input to serial.)

: serial->screen
   fds fd-target @ fd-in-set? if
     fd-target @ reads  tty writes  typing type
  then ;

: keyboard->serial  ( - done?)
   fds tty fd-in-set? if
     tty reads  fd-target @ writes  key dup term-keys @execute ^
   then  0 ;

: te-stream
   begin  tty fd-target @ 2 te-select
      serial->screen  keyboard->serial  until  tty writes  ;

: <drain  begin  fd-target @ 1 te-select  serial->screen  until
   fd-target @ writes  ;

: te  ( terminal)
   tty-target  fd-target @ raw  ( disallows signals)
   115200 bps  ( default to hi speed)
   radix @ push  tty raw   ['] te-stream catch
                 tty cooked  fd-target @ close-file  pop radix !  throw ;

( Special keys.)

( Echo ESC [ back to serial port, followed by the rest of the chars in the
  keyboard buffer. This makes AEB-1 autobauding - which works by sending
  `ESC [5n' - status query - and the Linux console answers with `ESC [0n' -
  terminal Ok. By echoing the ESC and [ that were eaten by our ESC-dispatch
  mechanism, we cause the AEB-1 autobaud feature to magically work.

  This only sort of "works". While the Linux console obliges - as do rxvt
  and xterm - the FreeBSD syscons driver does _not_. [I have no idea what
  the NetBSD wscons driver will do.] So rather than be at the mercy of an
  environment that we cannot control, we handle this ourselves, right
  here.)

: CSI  ( handle ESC [ )
  #ESC emit  char [ emit
  key dup char 5 = if
    key dup char n = if  ( got ESC [5n, so answer accordingly)
      nip  char 0
    then swap emit
  then emit ;

esc: [  ( vt10x)  CSI  0 ;

-: drop  #BS emit  0 ;   #DEL term-keys !  ( DEL sends BS)

esc: q  ( quit)  -1 ;

00 [if]

( Test code.)
: kb  raw  begin  key  dup <ESC> xor while  u.  repeat  cooked  ;
: wr  ( a #)  tty-target -rot write drop  ;
: kb-test
   if  tty keyboard-in 1 read   tty keyboard-in 1 write  2drop  then  ;

: kb    fds fd! drop  fds tty fd-set  raw
   begin  te-select drop  kb-test  again  [

[then]

#]file