*TITLE: ArgoTerm.S   --  Assembly Language Source Code for Jez's Terminal.
**************************************************************
* *                                                        * *
* * ATerm 0.20, by Jez San, (c)1986 Argonaut Software Ltd. * *
* *                                                        * *
* * 129, The Broadway, Mill Hill, London, NW7 4RN, ENGLAND * *
* *                                                        * *
* *    FrillFree Terminal Software For The Amiga A1000     * *
* *                                                        * *
* *                     -- Freeware --                     * *
* *                                                        * *
**************************************************************


* Some Include files that might be useful (Most aren't!)

         include  "exec/types.i"
         include  "exec/funcdef.i"
         include  "exec/exec_lib.i"

         include  "libraries/dos.i"
         include  "libraries/dos_lib.i"

         include  "devices/serial.i"
         include  "devices/narrator.i"

*                    Program History:
*                   ------------------

* (Once Upon A Time...) This prog was written on a boring day in January.

* During February, I decided that it should have been completed in January!!
* (But It wasn't!).   A Guilt complex set in, but a rare disease known as
* 'PAID WORK' caused me to spend my time trying to complete my arcade game
* for BT RAINBIRD, called "STARGLIDER"  (a 3d space battle simulator)

* Pressure from CBM Sysops on PLINK (thanks Harv!) made me add the final
* tweaks, and.. (suspense.....) Here it is, the first talking terminal!

* Disclaimers:

* I haven't read the Intuition manual yet, and thus there isn't a friendly
* user-interface in this program (.. yet!)  I will add it... eventually.

* PLEASE, People!! Improve this program!!  Ensure that it is in the
* Public domain, but feel free to add lotsa fun features to this 'frill
* free' Terminal program.

* Above all, this program was an exercise for me to learn about Amiga's OS
* and how to use it.  Unfortunately, machine code usage of Amiga OS is
* very poorly documented... All the manuals assume a working knowledge
* of 'C', but unfortunately (for me) I have not learned this language.

*  I had fun writing this; hope You enjoy using it.

*                    ---  Jez San,
*
*                      London, England.

* Tracking me down...
* In USA -> CIS '72247,3661', BIX 'jsan', PLINK 'UK JEZ', Source 'BCD776',
* In UK -> Prestel, '919991062', MUD 'Jez'.


* -------------------------------------------------------------- *



*  A Macro, cos I'm lazy at typing...

print    macro    * handle,messagepointer
         move.l   \1,d1
         lea      \2(PC),a0
         bsr      message
         endm



* Arbitrary Equates, and his pal; Label Definitions

sysbase  equ      $4                Base Pointer to the Exec
csi      equ      $9b               Control Sequence Introducer
keytime  equ      500               us timeout
myflags  equ      SERF_SHARED+SERF_XDISABLED+SERF_RAD_BOOGIE

* Popular Character Definitions

lf       equ      $a                Our Old Favourites!
cr       equ      $d
xon      equ      $11               CtrlQ
xoff     equ      $13               CtrlS
esc      equ      $1b
space    equ      $20

* Xmodem Definitions

soh      equ      $01               Start Of Header
eot      equ      $04               End Of Transmission
ack      equ      $06               Acknowledge
nak      equ      $15               No Acknowledge
can      equ      $18               Cancel

_LVOTranslate  equ   -30            Undefined in my Library file! Hope your
*                                   INCLUDE files are better than mine!



* .. And not forgetting The Program


startup  move.l   sp,saveSP        Save the stack pointer, just in case
         move.l   4(sp),d0         Size of our allocated Stack

* Point to our allocated memory (STACK! and bss)

         move.l   sp,a0             Current stack
         sub.l    #endbss-startbss+256,d0
         sub.l    d0,a0             Subtract our allowance to find start
         sub.l    #256,d0           Subtract safety margin Length
         and.w    #$ffff-3,d0       Mask to a Long Word boundary
         move.l   a0,bufstart       Start of Buffer value
         move.l   d0,buflen         Length of buffer value

* Open DOS library.

         move.l   sysbase,a6        Pointer to Exec Library
         lea      thedos(pc),a1     Point to title of DOS
         moveq    #0,d0             Version number
         jsr      _LVOOpenLibrary(a6)
         move.l   d0,dosbase        DOS library Pointer
         beq      openerr           Error, can't open library!

* Open Translator library.

         lea      thetrans(pc),a1   Point to title of Translator
         moveq    #0,d0             Version
         jsr      _LVOOpenLibrary(a6)
         move.l   d0,tranbase
         beq      openerr


* Open Console for I/O.

         lea      conname(pc),a1    Point to console definition text
         bsr      openfile          Open a DOS file
         beq      openerr
         move.l   d0,chandle        Console Handle

* Find what task we are in, and install it in the msg ports

         sub.l    a1,a1             We want *MY* task
         move.l   sysbase,a6        Exec Lib Ptr
         jsr      _LVOFindTask(a6)

         move.l   d0,MP_SIGTASK+write_reply
         move.l   d0,MP_SIGTASK+read_reply
         move.l   d0,MP_SIGTASK+nwriterep

* Add three Message Ports to the system, one for Input, one for Output,
* and one for Narrator.

         lea      read_reply,a1     Message Port
         jsr      _LVOAddPort(a6)   Add another Port to list

         lea      write_reply,a1    Repeat procedure for another Port
         jsr      _LVOAddPort(a6)

         lea      nwriterep,a1      Add the Narrator message port
         jsr      _LVOAddPort(a6)


* Open Serial.Device for Input

         lea      readreq,a1              IRequest area
         move.b   #myflags,IO_SERFLAGS(a1)
         move.l   #read_reply,$E(a1)      !!! Message.MN_REPLYPORT undefined

         moveq    #0,d0                   UnitNumber, ignored.
         moveq    #0,d1                   Flags, ignored.
         lea      serdevice(pc),a0        Point to the Device Name

         jsr      _LVOOpenDevice(a6)      Open it
         tst.l    d0                      Did it Open Okay?
         bne      openerr                 Zero is Successful (consistent!!?)

* Open Serial.Device for Output

         lea      writereq,a1             ORequest area
         move.b   #myflags,IO_SERFLAGS(a1)
         move.l   #write_reply,$E(a1)     Message.NN_REPLYPORT

         moveq    #0,d0
         moveq    #0,d1
         lea      serdevice(pc),a0        Device definition

         jsr      _LVOOpenDevice(a6)
         tst.l    d0
         bne      openerr

* Open Narrator device.

         lea      talkio,a1               Talk request block
         moveq    #0,d0                   Unit Number=0
         moveq    #0,d1                   Device number=0
         lea      nardevice(pc),a0        Device definition

         jsr      _LVOOpenDevice(a6)
         tst.l    d0
         bne      openerr

* Initialise the Narrator

         lea      talkio,a1               Talk Output request area
         move.l   #nwriterep,$E(a1)       Find the message port!
         move.l   #amaps,NDI_CHMASKS(a1)  Audio Channel Masks
         move.w   #4,NDI_NUMMASKS(a1)     Number of channels
         move.w   #210,NDI_RATE(a1)       Make it talk faster than average!

* Initialise the serial port here...

         lea      writereq,a1             Point to request block
         move.b   #8,IO_READLEN(a1)
         move.b   #8,IO_WRITELEN(a1)
         move.l   #0,IO_CTLCHAR(a1)       Should set to zero perhaps!?
         move.b   #myflags,IO_SERFLAGS(a1)
         move.w   #SDCMD_SETPARAMS,IO_COMMAND(a1)

         move.l   sysbase,a6
         jsr      _LVODoIO(a6)            Send it!

         bsr      initser

         print    chandle,welcome         Display the welcome Message

* Initialise a few variables

         st       squalking         Turn squalking off as default
         clr.b    fileflag          No file Transfer going on
         move.l   bufstart,bufptr   Buffer Empty
         clr.b    duplex            Default = Full Duplex
         clr.l    lengthin          No text in speech buffer
         move.l   #intext,textptr   Initial buffer pointer



* The Main loop!

mainloop bsr      scankey           User type a key?
         beq      notkeyu           Nope

         cmp.b    #csi,d0           Did User press a function key?
         beq      trycsi            Yes, so print up the menu

* -- Decode Function Keys here, if necessary!  --

         tst.b    duplex            Full or Half Duplex?
         beq.s    fulldup           Z=Full Duplex
         bsr      wrchar            Local echo
fulldup  bsr      sendser           Send the character
notkeyu  move.b   fileflag,d0       Are we Uploading the Buffer?
         cmp.b    #'U',d0           Yes??
         bne.s    notkey1           Nope!

         move.l   ubufptr,a0        Get Upload pointer
         move.l   bufptr,a1         Get Normal Buffer Pointer
         cmp.l    a1,a0             How are we doing?
         bge.s    finupl            Must have finished!
         move.b   (a0)+,d1          Get next character to Upload
         move.l   a0,ubufptr        Increment Upload buffer pointer
         bsr      sendser           Send the character
         bra.s    notkey1           ... and continue
finupl   clr.b    fileflag          Discontinue the Upload sequence
notkey1  bsr      scanser           Any chars waiting on the Ser port?
         bmi.s    mainloop          Nope, nothing there!
         and.w    #$7f,d0           Mask out Parity bit (Ignore Parity!)
         bsr      wrchar            Print it on the screen

         cmp.l    #255,lengthin     If buffer full, dont buffer anymore
         beq      dosqualk
         move.l   textptr,a0        Put character into Text buffer
         move.b   d0,(a0)+          ready for speech
         move.l   a0,textptr
         addq.l   #1,lengthin

         cmp.b    #cr,d0            Was it end of line?
         bne.s    nsqualk1          If so, Squalk it!
dosqualk bsr      squalk

nsqualk1 cmp.b    #'D',fileflag     Are we downloading text?
         bne      mainloop          Nope!

         move.l   bufptr,a0         We ARE downloading, so Where Buffer?
         move.b   d0,(a0)+          Insert Character into Buffer
         move.l   a0,bufptr         Increment buffer

* Test for Buffer Overflow?    Not properly implemented yet!
         move.l   a0,a1
         sub.l    bufstart,a1       current-start = Length
         cmp.l    buflen,a1         Is it too big?
         bcc      warnsave          Force user to Save Buffer if too big!

         bra      mainloop          .. And continue for more!

* User pressed a Special key, generating a Control Sequence Introducer

trycsi   bsr      rdchar            Get the next character
         cmp.b    #'?',d0           Was it HELP?
         bne.s    morecsi

         bsr      rdchar            Get next char
         cmp.b    #'~',d0           Caret is end of sequence
         beq      trymenu
         bra      mainloop

morecsi  bra      mainloop          Test for Function Keys here!


* User pressed HELP key, to display the menu

trymenu  bsr      sendxoff

* Open a new window stacked on top of the old one, for displaying
* the Menu.

         lea      conname(pc),a1    Point to console definition text
         bsr      openfile          Open it
         beq      openerr
         move.l   d0,mhandle        Console Window's handle

* Display the menu!

menuagn  print    mhandle,menutext  Display the menu

         bsr      infobuf           How many characters in buffer?

menuagn2 bsr      rdmenu            Get a key from Menu Console

         cmp.b    #esc,d0           Escape key pressed?
         beq      menuexit          So Return back to Terminal

         and.w    #$df,d0           Mask out Lower Case
         cmp.b    #'Q',d0           Q for Quit?
         beq      termmenu
         cmp.b    #'B',d0           B for Baudrate?
         beq      setbaud
         cmp.b    #'C',d0           C for Clear?
         beq      doclear
         cmp.b    #'D',d0           D for Download?
         beq      dodownl
         cmp.b    #'E',d0           E for Echo?
         beq      localec
         cmp.b    #'L',d0           L for Load Buffer?
         beq      loadbuf
         cmp.b    #'U',d0           U for Upload Buffer?
         beq      uplode
         cmp.b    #'X',d0           X for Xmodem Transfer?
         beq      xmodem
         cmp.b    #'T',d0           T for Talk mode?
         beq      talkmode

         bra      menuagn2          Go back for another choice perhaps?

menuexit bsr.s    closemenu         Close the menu console
         bsr      sendxon           Send an Xon to resmue host xmission

         bra      mainloop          Now back to the Terminal!

termmenu bsr.s    closemenu         Close the Menu console
         bra      terminate         Quit the program!


* Close the Menu Console window

closemenu
         move.l   mhandle,d1        Close the Menu window
         move.l   dosbase,a6        Dos library
         jmp      _LVOClose(a6)


* Clear the Capture Buffer

clear    move.l   bufstart,bufptr
         bra      trymenu


* Change the baud rate


* Clear the buffer

doclear  move.l   bufstart,bufptr
         bra      menuagn

* Start the Download in process

dodownl  move.b   fileflag,d0       Are we already downloading?
         cmp.b    #'D',d0           Yes??
         beq.s    down2             if so, stop downloading, and save buf!

* Print up a message saying that downloading is ON!  and do it!

         print    mhandle,down1m

         move.b   #'D',fileflag        Flag saying Download is on!
         move.l   bufstart,bufptr      Clear buffer contents!

         bra      menuagn              Go back to Main Loop

* Downloading must be turned OFF here, and buffer saved.

down2    move.l   bufptr,a0            Was there anything in the buffer?
         cmp.l    bufstart,a0          Yes?
         beq      down3                Turn off downloader, anyway!

         bsr      savebuf              Save the buffer
         bne      menuagn

down3    clr.b    fileflag             Stop Downloading,
         move.l   bufstart,bufptr      and clear buffer

         print    mhandle,down2m       Tell user that Download is OFF

         bra      menuagn              Go back to Main Loop

* Toggle the Local Echo mode

localec  print    mhandle,nowset2m

         not.b    duplex               Invert state
         beq.s    showfull

* Half duplex...

         print    mhandle,halfm
         bra      menuagn

* Full duplex...

showfull print    mhandle,fullm
         bra      menuagn              Back to the Menu


talkmode not.b    squalking
         beq.s    issqualk

         print    mhandle,notsqm
         bra      menuagn

issqualk print    mhandle,yessqm
         bra      menuagn


* Start an Upload

uplode   move.b   fileflag,d0          Are we already uploading?
         cmp.b    #'U',d0              Yes??
         beq      alredu               tell'em we already are!

         move.l   bufptr,a0            Anything in buffer?
         move.l   bufstart,a1          Start of buffer
         cmp.l    a0,a1                forget it if nothing in buffer
         beq      exitu1

         move.b   #'U',fileflag        Flag an Uplo0ad in progress
         move.l   a0,ubufptr           Point the Upload buffer to text.

         print    mhandle,upld1m       Tell user that Upload has started

exitu1   bra      menuagn              Go back to Main Loop

* Tell the User they are very naughty indeed!

alredu   print    mhandle,upld2m

         bra      menuagn              Back to Menu time!


* Display how many characters in Buffer

infobuf  move.l   bufptr,d0         Current buffer pointer - start = length
         sub.l    bufstart,d0
         bsr      bin2decl

         print    mhandle,infmess1

         move.l   buflen,d0
         bsr      bin2decl

         print    mhandle,infmess2
         rts


warnsave print    chandle,warnmes
         bsr      rdchar
         bra      trymenu


* Save the Buffer out to disk and Clear it.

savebuf  bsr      filename
         beq      badsave

         bsr      openup
         beq      badsave
         bsr      writefile
         bsr      closefile
         moveq    #0,d0          Signal an OKAY save.
         rts


* Load Buffer from disk

loadbuf  bsr      filename
         beq      badload

* Zero out entire buffer area prior to loading a flie
         move.l   bufstart,a0
         move.l   buflen,d0
         lsr.l    #2,d0

bufclrlp clr.l    (a0)+
         subq.l   #1,d0
         bne.s    bufclrlp


         bsr      openit
         beq      badload

         bsr      readfile
         bsr      closefile

         bra      menuagn

badload  print    mhandle,bloadmes
         bra      menuagn

badsave  print    mhandle,bsavemes
         moveq    #-1,d0
         rts


* Requests a filename

filename print    mhandle,filemes
         bsr      getline         Get a line of text

* Copy over filename from input buffer to file buffer

         lea      inputbuf,a2
         lea      filehead,a3
         moveq    #32,d2
copylp1  move.b   (a2)+,(a3)+
         dbra     d2,copylp1

         move.b   #13,d0
         bsr      wrmenu
         move.b   #10,d0
         bsr      wrmenu

         tst.b    inputbuf       Will be zero if no entry

         rts

* Gets a line of text from the user

getline  lea      inputbuf,a2
         clr.l    (a2)           Zero the first bit

getlin1  bsr      rdmenu         Get keyboard Input
         cmp.b    #8,d0          Backspace
         beq      backspace
         cmp.b    #127,d0        Delete
         beq      backspace
         bsr      wrmenu         Display it onscreen
         cmp.b    #13,d0         Return?
         beq      creturn
         move.b   d0,(a2)+       Put character into buffer
         bra      getlin1


* Return pressed... put a Null to terminate, and exit with d0=num of chars.
creturn  clr.b    (a2)+
         sub.l    #inputbuf,a2
         move.l   a2,d0
         rts

backspace
         cmp.l    #inputbuf,a2   Dont allow backspacing before the Start
         beq      getlin1
         move.b   #8,d0          Space
         bsr      wrmenu
         move.b   #32,d0         Space
         bsr      wrmenu
         move.b   #8,d0          Backspace
         bsr      wrmenu
         clr.b    (a2)           Zero the current character
         subq.l   #1,a2          Backtrack one character
         bra      getlin1

* Read in an entire file

readfile move.l   fhandle,d1           Handle of the flie

         move.l   bufstart,d2          Where to put the data
         move.l   buflen,d3            Length
         move.l   dosbase,a6           Library ptr
         jsr      _LVORead(a6)         Get the text from the file

* Update length of file to represent amount of text read

         move.l   bufstart,d1          Get start of buffer
         add.l    d0,d1                Add number of characters in file
         move.l   d1,bufptr            Save result as End of buffer

         rts

* Write out an entire file

writefile move.l  fhandle,d1           Handle of File

         move.l   bufstart,d2          Start of Buffer
         move.l   bufptr,d3            length = End of Buffer
         sub.l    bufstart,d3          Subtract Start of buffer = Length
         move.l   dosbase,a6           Library ptr
         jmp      _LVOWrite(a6)        Write the text to the console window

* Close the file

closefile move.l   fhandle,d1       Close the Menu window
         move.l   dosbase,a6        Dos library
         jmp      _LVOClose(a6)

* Open the file

openit   lea      filehead,a1
         bsr      openfile
         move.l   d0,fhandle
         tst.l    d0
         rts

* Open file for updating

openup   lea      filehead,a1
         bsr      openwrite
         move.l   d0,fhandle
         tst.l    d0
         rts






* Flush Serial Port, to ensure internal buffer is M.T.

flushser bsr      scanser        Try and get some characters from port
         bpl.s    flushser       If we get some, it aint M.T.
         rts

* Xmodem file transfer bits

xmodem   print    mhandle,xmes1

         bsr      rdmenu
         and.w    #$df,d0
         cmp.b    #'U',d0
         beq      xmodemup
         cmp.b    #'D',d0
         beq      xmodemdn

         bra      menuagn

xmodemup print    mhandle,exitmess

         bsr      sendxon           Get host transmitting again

         move.l   bufstart,a4       Start of Xmodem buffer
         moveq    #1,d2             Block number

* Start by waiting for an initial NAK from the receive side

xmodeup0 print    mhandle,upmes1

         move.w   #20,d6            Timeout
         bsr      waitser
         bmi.s    xsendblk
         cmp.b    #nak,d0
         bne.s    xmodeup0

* Check for End of file here

xsendblk move.b   d2,block
         bsr      scanmenu       Does User want to cancel?
         bne      xcancel
         move.b   block,d2

         move.l   bufptr,a0      Are we at end of buffer?
         cmp.l    a4,a0
         ble      finxup

         bsr      prblock
         clr.b    d3             Checksum

         move.b   #soh,d0        Start of block
         bsr      sendser

         move.b   d2,d0
         bsr      sendser        Block number
         move.b   d2,d0
         not.b    d0
         bsr      sendser

         move.w   #127,d4        Counter for block
xmodeulp move.b   (a4)+,d0       Get a byte
         add.b    d0,d3          Compute checksum
         bsr      sendser
         dbra     d4,xmodeulp

         move.b   d3,d0       Send checksum
         bsr      sendser

wait20s  move.w   #20,d6         Wait 20 seconds
         bsr      waitser
         bmi.s    upnogood

         cmp.b    #ack,d0
         beq.s    upgonext
         cmp.b    #can,d0
         beq.s    xcancel

         cmp.b    #nak,d0
         bne.s    wait20s

upnogood print    mhandle,uperr1

uretry   sub.l    #128,a4        Backtrack a block
         bra      xsendblk

upgonext addq.b   #1,d2              Increase block number
         bra      xsendblk

finxup   move.b   #eot,d0
         bsr      sendser

finxup1  move.w   #20,d6
         bsr      waitser
         bmi.s    finxup
         cmp.b    #ack,d0
         beq.s    finxup2
         bra.s    finxup1

finxup2  print    mhandle,updun1

         bra      menuagn

xcancel  print    mhandle,cancmes
         bsr      rdmenu
         bsr      nlmenu
         and.w    #$df,d0
         cmp.b    #'Y',d0
         beq      uretry
         move.b   #can,d0
         bsr      sendser
         bra      menuagn

nlmenu   move.l   d0,-(sp)
         move.b   #13,d0
         bsr      wrmenu
         move.b   #10,d0
         bsr      wrmenu
         move.l   (sp)+,d0
         rts

xrcancel print    mhandle,cancmes

         bsr      rdmenu
         bsr      nlmenu
         and.w    #$df,d0
         cmp.b    #'Y',d0
         beq      xreclp0
         move.b   #can,d0
         bsr      sendser
         bra      menuagn


xmodemdn print    mhandle,exitmess

         bsr      sendxon           Get host moving again

         move.l   bufstart,a4
         moveq    #1,d2

         print    mhandle,rstart1

* Send initial NAK
xreclp0  bsr      sendnak

xreclp1a bsr      scanmenu          Has user pressed a key?
         bne      xrcancel

         move.w   #20,d6            Wait for block
         bsr      waitser
         bpl.s    xrecok1           Keep doing it, if nothing going.

         print    mhandle,ret1mes
         bra.s    xreclp0

xrecok1  cmp.b    #soh,d0
         beq.s    xrecrcv
         cmp.b    #eot,d0
         beq      xreceot
         cmp.b    #can,d0
         beq      xrcancel

         bra.s    xreclp1a

* Block coming in...
xrecrcv   bsr      prblock

         bsr      wait10            Get block
         bmi      xrslowr

         cmp.b    d0,d2             Same as current one?
         bne      xrbadblk

         bsr      wait10            Get inversed block number
         bmi      xrslowr

         not.b    d0
         cmp.b    d0,d2             Okay?
         bne      xrbadbl2          Definitely a bad block

* Get the 128 data bytes

         move.w   #127,d4           Byte count
         clr.b    d3                Checksum

xrecrclp bsr      wait10            Timeout
         bmi.s    xrecnop3
         move.b   d0,(a4)+          Store the character
         add.b    d0,d3             Checksum
         dbra     d4,xrecrclp       Loop for more

         bsr      wait10
         bmi.s    xrcheckm
         cmp.b    d0,d3             Checksum any good?
         bne      xrchecks

* Block was Okay, so increment block counter
         addq.b   #1,d2             Increment block counter, and continue
         bsr      sendack
         bra      xreclp1a

* A character was missed from inside a block
xrecnop3 print    mhandle,misschm
         ext.l    d4
         add.w    d4,a4
         sub.w    #127,a4

         bsr      waitfin
         bra      xreclp0

* Missed checksum
xrcheckm print    mhandle,xchksm2
         bsr      waitfin
         bra      xreclp0

xrchecks sub.l    #128,a4
         move.l   d0,-(sp)
         print    mhandle,xchksm
         move.b   d3,d0
         and.w    #$ff,d0
         bsr      bin2decw
         print    mhandle,xchksm1
         move.l   (sp)+,d0
         and.w    #$ff,d0
         bsr      bin2decw
         bsr      nlmenu

         bsr      waitfin
         bra      xreclp0

xrslowr  print    mhandle,slowm1
         bsr      waitfin
         bra      xreclp0

xrbadblk addq.b   #1,d0
         cmp.b    d0,d2
         beq.s    xrbbb1
         subq.b   #1,d0

xrbadbl2 move.l   d0,-(sp)
         print    mhandle,badblkm
         move.l   (sp)+,d0
         and.w    #$ff,d0
         bsr      bin2decw
         bsr      nlmenu
         bsr      waitfin
         bra      xreclp0

* If previous block was repeated, then do an ACK to get it up to date
xrbbb1   bsr      waitfin
         bsr      sendack
         print    mhandle,dupmes1
         bra      xreclp1a

xreceot  bsr      sendack

         move.l   a4,bufptr         Update buffer size

         print    mhandle,xrecm2

* File downloaded, so now determine the ACCURATE length of file.

         bsr      rdmenu
         and.w    #$df,d0
         cmp.b    #'Y',d0
         bne      savedown

* Chop the file here...

         print    mhandle,xrecm3

         move.l   bufptr,d0         Current file's length
 ` ;     sub.l    bufstart,d0
         bsr      bin2decl

         print    mhandle,xrecm4

* Determine approximate length...

         move.l   bufptr,a0         Last byte=Null?
         move.b   -(a0),d1

detlp1   cmp.b    -(a0),d1          Is the previous byte the same?
         beq.s    detlp1

         addq.l   #1,a0             Forward one character again

         sub.l    bufstart,a0       Turn it into a Length
         move.l   a0,d0

         bsr      bin2decl          Print it
         bsr      nlmenu

* Perform decimal input value here and change bufptr accordingly!

         print    mhandle,askchop
         bsr      getline
         tst.l    d0
         beq      savedown

         lea      inputbuf,a0
         bsr      dec2bin

         tst.l    d0
         beq      savedown
         bmi      savedown

* Really ought to check that the CHOP value is within range here!!

         add.l    bufstart,d0
         move.l   d0,bufptr

savedown bsr      savebuf
         bra      menuagn

* Wait for ONE total second of nothingness!

waitfin  move.w   #2,d6
         bsr      waitser
         bpl.s    waitfin
         rts


* Print the current block number
prblock  movem.l  d0-d7/a0-a6,-(sp)
         print    mhandle,pblokm
         clr.l    d0
         move.b   d2,d0
         bsr      bin2decw
         move.b   #32,d0
         bsr      wrmenu
         bsr      wrmenu
         bsr      wrmenu
         move.b   #13,d0
         bsr      wrmenu
         movem.l  (sp)+,d0-d7/a0-a6
         rts


* Waits ten seconds for a character then gives up

wait10   move.w   #10,d6

* Scan for a character with wait for d6 number of seconds

waitser  bsr      scanser
         bpl.s    retwait1

         subq.w   #1,d6
waitser1 move.w   #17000,d7
waitser2 bsr      scanser
         bpl.s    retwait1
         dbra     d7,waitser2
         dbra     d6,waitser1
         moveq    #-1,d0         Necessary?
retwait1 tst.l    d0
         rts






* Terminate this program and return to CLI

terminate
         lea      read_reply,a1  Remove the Reply Port
         move.l   sysbase,a6     Exec Lib Ptr
         jsr      _LVORemPort(a6)

         lea      write_reply,a1 Remove this one too
         jsr      _LVORemPort(a6)

         lea      nwriterep,a1   Remove Narrator port
         jsr      _LVORemPort(a6)

         lea      readreq,a1     Close the Serial Device
         jsr      _LVOCloseDevice(a6)

         lea      writereq,a1    Again
         jsr      _LVOCloseDevice(a6)

         lea      talkio,a1      Narrator Device
         jsr      _LVOCloseDevice(a6)


         move.l   chandle,d1     Close Console window for final time
         move.l   dosbase,a6
         jsr      _LVOClose(a6)

         move.l   tranbase,a1    Close the translator library
         move.l   sysbase,a6
         jsr      _LVOCloseLibrary(a6)

         move.l   dosbase,a1     Close the DOS library
         jsr      _LVOCloseLibrary(a6)

         moveq    #0,d1          Return Code=Good
         move.l   d1,d0

exitprog move.l   saveSP,sp      Restore Old Stack Pointer
         rts                     Yea, a JMP would have sufficed!

* Dos command to open a file

openfile move.l   a1,d1             Wants it in Data register (weird!)
         move.l   #MODE_OLDFILE,d2  Signal not to create a new file
         move.l   dosbase,a6        Dos lib
         jsr      _LVOOpen(a6)      Open the file
         tst.l    d0                An Error perhaps?
         rts                        File's handle in d0

* Opens a file for writing!
openwrite
         move.l   a1,d1
         move.l   #MODE_NEWFILE,d2
         move.l   dosbase,a6
         jsr      _LVOOpen(a6)
         tst.l    d0
         rts


* Signal an error because something didn't Open properly!

*openerr move.l   chandle,d1     Close Console window for final time
         move.l   dosbase,a6
         jsr      _LVOClose(a6)
openerr
         move.l   dosbase,a1     Close the DOS library
         move.l   sysbase,a6
         jsr      _LVOCloseLibrary(a6)

         moveq    #-1,d1         Return code = BAD!
         move.l   d1,d0

         bra      exitprog


* Prints the message pointed to by a0, (Null terminated).

message  movem.l  d0-d3,-(sp)
         move.l   a0,d2                Start of message
         clr.l    d3                   Length is zero for the moment
message1 tst.b    (a0)+                End of message?
         beq.s    message2             Length known, go print it now!
         addq.l   #1,d3                Increment Length
         bra.s    message1             Back for more characters

* Ready to print message now: d1=dest handle, d2=ptr to text, d3=length.

message2 move.l   dosbase,a6           Library ptr
         jsr      _LVOWrite(a6)        Write the text to the console window
         movem.l  (sp)+,d0-d3
         rts

wrmenu   movem.l  d0-d7/a0-a6,-(sp)
         move.l   mhandle,d1
         bra.s    chrout2

* Write character in d0 to Console Window

wrchar   movem.l  d0-d7/a0-a6,-(sp)    Save World!  (MOVEM overkill!??)
         move.l   chandle,d1           handle of Console window

chrout2  lea      cbuff,a1             Point to the character buffer
         move.b   d0,(a1)              Put character in buffer
         move.l   a1,d2                Weird data register usage
         move.l   #1,d3                Length
         move.l   dosbase,a6           Library ptr
         jsr      _LVOWrite(a6)        Write the text to the console window

         movem.l  (sp)+,d0-d7/a0-a6    Restore World
         rts

* Shortened special-case Serial characters

sendxon  move.b   #xon,d0           Send an Xon to resume data flow
         bra.s    sendser

sendxoff move.b   #xoff,d0          Send an Xoff to freeze data flow
         bra.s    sendser

sendack  move.b   #ack,d0           Send an ACK for acknowledgement of block
         bra.s    sendser

sendnak  move.b   #nak,d0           Send a NAK to indicate error of block
         bra.s    sendser

newline  move.b   #cr,d0            Print a NEWLINE
         bsr.s    wrchar
         move.b   #lf,d0            carriage return + line feed
         bra.s    wrchar

dospace  move.b   #space,d0         Print a Space
         bra.s    wrchar


* Serial Character Input
serin    movem.l  d1-d7/a0-a6,-(sp) Save World!

* Do a WaitIO to get the char, and followed by a SendIO to initiate the
* next read!

         lea      readreq,a1           Ptr to Request Block
         move.l   sysbase,a6           Exec lib ptr
         jsr      _LVOWaitIO(a6)

         clr.l    d0
         move.b   bufin,d0             The byte returned
       I[KW	$H20,-(sp)

         lea      readreq,a1           Request block
         move.l   #1,IO_LENGTH(a1)
         jsr      _LVOSendIO(a6)       Initiate the NEXT read

         move.l   (sp)+,d0

         movem.l  (sp)+,d1-d7/a0-a6    Restore World
         tst.l    d0                   Always Positive, so set PL flag
         rts

sendser  movem.l  d0-d7/a0-a6,-(sp)    Save World

         lea      writereq,a1          Ptr to Write Request block
         move.w   #CMD_WRITE,IO_COMMAND(a1)
         move.l   #1,IO_LENGTH(a1)     One byte
         move.l   #bufout,IO_DATA(a1)  Buffer address

         move.l   sysbase,a6           Exec Lib Ptr
         move.b   d0,bufout            Put byte and send it

         jsr      _LVODoIO(a6)         Send Byte

         movem.l  (sp)+,d0-d7/a0-a6    Restore World
         rts

* Read character into d0 from Console Window

rdchar   movem.l  d1-d7/a0-a6,-(sp)    Save World!
         move.l   chandle,d1           handle of Console window
         bra.s    chrin2

rdmenu   movem.l  d1-d7/a0-a6,-(sp)    Save World!
         move.l   mhandle,d1           Handle of Menu window

chrin2   lea      cbuff,a1
         move.l   a1,d2                Point to the character
         move.l   #1,d3                Length
         move.l   dosbase,a6           Library ptr
         jsr      _LVORead(a6)         Write the text to the console window
         clr.l    d0                   Prepare for receipt of a Char
         move.b   cbuff,d0             Character returned in d0
         movem.l  (sp)+,d1-d7/a0-a6    Restore World
         rts

* Scans for a key from the Keyboard, if nothing there, sets MINUS flag!
* Otherwise, character in d0

scanmenu movem.l  d1-d2,-(sp)

         move.l   mhandle,d1
         move.l   #keytime,d2
         move.l   dosbase,a6
         jsr      _LVOWaitForChar(a6)

         movem.l  (sp)+,d1-d2

         tst.l    d0
         beq.s    nokey1

         bra      rdmenu




scankey  move.l   chandle,d1           Console Handle
         move.l   #keytime,d2          Timeout
         move.l   dosbase,a6           Dos library
         jsr      _LVOWaitForChar(a6)  Anything waiting for us?
         tst.l    d0                   False=0
         beq.s    nokey1               Nothing there!

         bra.s    rdchar               Proceed further to Get it

nokey1   rts

scanser  lea      readreq,a1           Check to see if a character is there
         move.l   sysbase,a6           exec lib ptr
         jsr      _LVOCheckIO(a6)      Anything there?
         tst.l    d0                   Z=nothing
         bne      serin

         moveq    #-1,d0
         rts


* Text to speech of serial input

squalk   tst.b    squalking         Am I enabled?
         bne      endsqualk

* Send an XOFF to prevent host from sending anymore
         bsr      sendxoff

* Clear output buffer before use

         move.w   #127,d0
         lea      outtext,a0
sqclrlp  clr.l    (a0)+
         dbra     d0,sqclrlp

* Use Translator to convert input text into output phonemes

         lea      intext,a0
         move.l   lengthin,d0

         lea      outtext,a1
         move.l   #512,d1             Fixed length output buffer
                             
         move.l   tranbase,a6
         jsr      _LVOTranslate(a6)

* Use narrator to speak the phoneme text

         lea      talkio,a1            Narrator Request block
         move.w   #CMD_WRITE,IO_COMMAND(a1)
         move.l   #512,IO_LENGTH(a1)  Fixed length!
         move.l   #outtext,IO_DATA(a1)

         move.l   sysbase,a6
         jsr      _LVODoIO(a6)         Should be SendIO perhaps!?

         bsr      sendxon              Allow HOST to continue sending

endsqualk
         clr.l    lengthin             Reset the text buffers
         move.l   #intext,textptr

         rts


* Power of Ten table! (for binary/ascii routines!)

tentable dc.l     1
         dc.l     10
         dc.l     100
         dc.l     1000
         dc.l     10000
tenbckw  dc.l     100000
         dc.l     1000000
         dc.l     10000000
         dc.l     100000000
tenback  dc.l     1000000000



* Print a number that is contained in binary in d0
bin2decw movem.l  d0-d7/a0,-(sp)
         clr.w    d4
         lea      tenbckw(pc),a0
         moveq    #4,d3
         tst.w    d0
         beq.s    binzero
         bpl.s    bindecl
         neg.w    d0
         bra.s    bindecw

* Print up a Long Word in binary
bin2decl movem.l  d0-d7/a0,-(sp)
         clr.w    d4
         lea      tenback(pc),a0
         moveq    #8,d3
         tst.l    d0
         beq.s    binzero
         bpl.s    bindecl
         neg.l    d0

bindecw  move.b   #'-',d1
         bsr      wrchd1

bindecl  move.l   -(a0),d1
         clr.w    d2

bindec1  sub.l    d1,d0
         bmi.s    bindec2
         addq.w   #1,d2
         bra.s    bindec1

bindec2  add.l    d1,d0

         tst.w    d2
         bne.s    bindecz
         tst.w    d4
         beq.s    bindec3

bindecz  move.w   d2,d1
         add.w    #$30,d1
         bsr      wrchd1
         moveq    #1,d4

bindec3  dbra     d3,bindecl
         movem.l  (sp)+,d0-d7/a0
         rts

* Special Case of Zero

binzero  move.b   #'0',d0
         bsr      wrmenu
         movem.l  (sp)+,d0-d7/a0
         rts

* Weird version of WRCHAR that uses d1 instead of d0

wrchd1   move.l   d0,-(sp)
         move.l   d1,d0
         bsr      wrmenu
         move.l   (sp)+,d0
         rts



* Decimal Ascii to Binary routine...

dec2bin  movem.l  d1-d5/a1,-(sp)

         clr.l    d0
         clr.l    d1
         clr.w    d4
         lea      tentable(pc),a1

         move.b   (a0)+,d1
         cmp.b    #'-',d1
         seq      d5
         beq.s    dnumlp
         cmp.b    #'+',d1
         bne.s    dnumlp1

* Main primary loop to find the last digit

dnumlp   move.b   (a0)+,d1
dnumlp1  cmp.b    #'0',d1
         blt.s    atend0
         cmp.b    #'9',d1
         bgt.s    atend0
         addq.w   #1,d4
         bra.s    dnumlp

atend0   subq.l   #1,a0
         subq.w   #1,d4
         move.l   a0,-(sp)

* Fall thru into secondary loop to evaluate digits

atend1   move.b   -(a0),d1
         move.l   (a1)+,d2
         and.w    #15,d1
         subq.w   #1,d1
         bmi.s    atend3
         clr.l    d3

atend2   add.l    d2,d3
         dbra     d1,atend2
         add.l    d3,d0

atend3   dbra     d4,atend1

* Finished conversion, so check sign here...

         tst.b    d5
         beq.s    fincon2
         neg.l    d0
fincon2  move.l   (sp)+,a0
         movem.l   (sp)+,d1-d5/a1
         rts



* Set the baud rate

setbaud  tst.l    baud
         beq      setbaud2

         print    mhandle,baudold
         move.l   baud,d0
         bsr      bin2decl
         bsr      nlmenu
setbaud2 bsr      nlmenu

         print    mhandle,baudmes
         bsr      getline
         tst.l    d0
         beq      menuagn

         lea      inputbuf,a0
         bsr      dec2bin

         move.l   d0,-(sp)
         bsr      nlmenu
         bsr      nlmenu
         move.l   (sp)+,d0

         tst.l    d0
         beq      menuagn
         bmi      menuagn

         move.l   d0,baud

         bsr      abortser

* Initialise the Serial Port to the selected baud rate.

         lea      readreq,a1              Point to write request block
         move.l   baud,IO_BAUD(a1)        Baud Rate
         move.b   #myflags,IO_SERFLAGS(a1)
         move.w   #SDCMD_SETPARAMS,IO_COMMAND(a1)

         move.l   sysbase,a6
         jsr      _LVODoIO(a6)            Send it!

         bsr      initser

         bra      menuagn



* Initiate the Serial Receive to get a character

initser  lea      readreq,a1        I request block
         move.l   #1,IO_LENGTH(a1)  How many characters
         move.w   #CMD_READ,IO_COMMAND(a1)
         move.l   #bufin,IO_DATA(a1)

         move.l   sysbase,a6
         jmp      _LVOSendIO(a6)

abortser lea      readreq,a1
         move.l   sysbase,a6
         jmp      _LVOAbortIO(a6)




* Library Definitions :

thedos   DOSNAME
         cnop     0,2

thetrans dc.b     'translator.library',0               * Where's the Macro!??
         cnop     0,2

* Device Definitions

serdevice SERIALNAME
         cnop     0,2

nardevice dc.b    'narrator.device',0
         cnop     0,2

amaps    dc.b     3,5,10,12            Audio Channel Maps
         cnop     0,2

* Textual Definitions

conname  dc.b     'RAW:0/0/640/200/ArgoTerm 0.20',0
         cnop     0,2
sername  dc.b     'SER:',0
         cnop     0,2
welcome  dc.b     'ArgoTerm, by Jez San, (c)1986 Argonaut Software Ltd.,'
         dc.b     ' London, England.',13,10
         dc.b     'Freeware: No profit must be made from the distribution'
         dc.b     ' of this program.',13,10
         dc.b     '[Use the AmigaDOS STACK command to allow a larger Capture '
         dc.b     'Buffer]',13,10,10
         dc.b     'Press the HELP key for the Command Menu.',13,10,10,0
         cnop     0,2
menutext dc.b     'You may choose from the following options :',13,10,10
         dc.b     'B - Configure the transmission speed (Baud Rate),',13,10
         dc.b     'C - Clear (wipe) the Capture Buffer,',13,10
         dc.b     'D - Download text into the Capture Buffer,',13,10
         dc.b     'E - Local Echo mode (Half Duplex) on/off,',13,10
         dc.b     'L - Load a disk file into the Buffer,',13,10
         dc.b     'Q - Quit this program; terminate session,',13,10
         dc.b     'T - Turn On/Off the Squalk Mode (narrator),',13,10
         dc.b     'U - Upload the contents of the Capture Buffer,',13,10
         dc.b     'X - Xmodem file transmission (aka MODEM7).',13,10,10
         dc.b     'There are ',0
         cnop     0,2
infmess1 dc.b     ' out of ',0
         cnop     0,2
infmess2 dc.b     ' characters in the Capture Buffer.',13,10,10
         dc.b     'Please select one of the above options,',13,10
         dc.b     'or ESC to return to the terminal session.',13,10,0
         cnop     0,2
down1m   dc.b     13,10,'Capturing text now, select DOWNLOAD again to '
         dc.b     ' finish and store.',13,10,10,0
         cnop     0,2
down2m   dc.b     13,10,'File saved, Download is complete.',13,10,10,0
         cnop     0,2
upld1m   dc.b     'Text will be upload when you return to the Terminal.'
         dc.b     13,10,10,0
         cnop     0,2
upld2m   dc.b     'Hmmm.. You ARE already uploading!!',13,10,10,0
         cnop     0,2
nowset2m dc.b     'Configured for: ',0
         cnop     0,2
fullm    dc.b     'Full Duplex.',13,10,10,0
         cnop     0,2
halfm    dc.b     'Half Duplex.',13,10,10,0
         cnop     0,2
ioerrmes dc.b     'Serial I/O Error!',13,10,0
         cnop     0,2
yessqm   dc.b     13,10,'Squalk Mode On!',13,10,10,0
         cnop     0,2
notsqm   dc.b     13,10,'Squalk Mode Off!',13,10,10,0
         cnop     0,2
warnmes  dc.b     13,10,10,'Memory Full!!  Please SAVE the Buffer!',13,10,10
         dc.b     'Press any key to enter the menu.',13,10,10,0
         cnop     0,2
savemes  dc.b     'Save Buffer.',13,10,10,0
         cnop     0,2
filemes  dc.b     13,10,'Please enter the filename : ',0
         cnop     0,2
bloadmes dc.b     13,10,10,'File not loaded!',13,10,10,0
         cnop     0,2
bsavemes dc.b     13,10,10,'File not saved!',13,10,10,0
         cnop     0,2
xmes1    dc.b     13,10,10,'Xmodem transfer; <U>pload or <D>ownload ?',13,10,0
         cnop     0,2
upmes1   dc.b     13,10,'Waiting for receiver to start the transfer...',13,10,0
         cnop     0,2
uperr1   dc.b     13,10,'Receiver not happy, retrying...',13,10,0
         cnop     0,2
updun1   dc.b     13,10,'File transferred safely.',13,10,0
         cnop     0,2
cancmes  dc.b     13,10,'For some reason, the transfer has been cancelled.'
         dc.b     13,10,'Bearing in mind that this could have been line'
         dc.b     13,10,'noise, you may press <Y> to continue, or any other'
         dc.b     13,10,'key to abort this transfer.',13,10,10,0
         cnop     0,2
rstart1  dc.b     13,10,10,'Initiating the transfer (my NAK has been sent!)'
         dc.b     13,10,0
         cnop     0,2
ret1mes  dc.b     13,10,'No response, re-requesting the block.',13,10,0
         cnop     0,2
xrecm2   dc.b     13,10,'File downloaded successfully.',13,10,10
         dc.b     'Due to XMODEM inaccuracies, the length of the file has '
         dc.b     'been rounded up to',13,10
         dc.b     'the next nearest block.  Do you wish to CHOP the '
         dc.b     'file to the correct length?',0
         cnop     0,2
xrecm3   dc.b     13,10,10,'The length of the file is currently : ',0
         cnop     0,2
xrecm4   dc.b     13,10,10,'My intelligent estimate of the file length is : ',0
         cnop     0,2
askchop  dc.b     13,10,10,'You may either use my Estimate, or your own '
         dc.b     'figures, or alternatively',13,10
         dc.b     'you may press RETURN to leave the file at its current '
         dc.b     'length.'
         dc.b     13,10,10,'What length would you like this file to be ? ',0
         cnop     0,2
slowm1   dc.b     13,10,'Slow (or not enough) response.',13,10,0
         cnop     0,2
badblkm  dc.b     13,10,'Bad block received was : ',0
         cnop     0,2
dupmes1  dc.b     13,10,'A duplicate block has been received.',13,10,0
         cnop     0,2
misschm  dc.b     13,10,'Missed a character in the block.',13,10,0
         cnop     0,2
xchksm   dc.b     13,10,'Checksum Error in the block, should have been ',0
         cnop     0,2
xchksm1  dc.b     ' but was ',0
         cnop     0,2
xchksm2  dc.b     13,10,'Checksum was missing from the block.',13,10,0
         cnop     0,2
exitmess dc.b     13,10,10,'To exit: hit a key, and wait patiently!',13,10,10
         dc.b     0
         cnop     0,2
pblokm   dc.b     'Current block : ',0
         cnop     0,2
baudmes  dc.b     13,10,10,'Please enter the baud rate, or RETURN to leave '
         dc.b     'it the same ? ',0
         cnop     0,2
baudold  dc.b     13,10,'Current baudrate is : ',0
         cnop     0,2


         section     vars,bss

startbss

            cnop     0,4

readreq     ds.l     20    Serial Input Request area
writereq    ds.l     20    Serial Output Request area
narread     ds.l     20    Narrator Input
talkio      ds.l     20    Narrator Output
read_reply  ds.l     8     Read Reply Port
write_reply ds.l     8     Write Reply port
nwriterep   ds.l     8     Narrator write reply
inputbuf    ds.l     20    Space for some keyboard text!
filehead    ds.l     8     Space for the filename

intext      ds.l     64    Input text buffer is 256 bytes
outtext     ds.l     128   Output phonetic text (512 bytes worth of phonemes!)


* Long Words

saveSP   ds.l     1     Initial Stack Pointer
dosbase  ds.l     1     Base of Dos library
tranbase ds.l     1     Base of Translator
chandle  ds.l     1     Handle for Console window
mhandle  ds.l     1     Handle for Menu Console window
fhandle  ds.l     1     Handle of diskfile
bufptr   ds.l     1     Pointer to Capture Buffer
ubufptr  ds.l     1     Pointer to Uploading text pointer
bufstart ds.l     1     Pointer to Start Of Buffer
buflen   ds.l     1     Total maximum size of buffer
cbuff    ds.l     1     Character Buffer, 1 byte used
textptr  ds.l     1     Ptr to intext buffer
lengthin ds.l     1     Length of text in intext

bufin    ds.l    1      Serial Input Buffer
bufout   ds.l    1      Serial Output Buffer
baud     ds.l    1      Current baud rate


* Words


* Bytes

         cnop     0,4
fileflag ds.b     1     Flag indicating Up/Download status
duplex   ds.b     1     Full Duplex=0, Half Duplex=$ff
squalking ds.b    1     Squalking enabled=0
block    ds.b     1     Block number
         cnop     0,4

endbss


         end
