** morse.s Version 1.1
** A program in assembly language to make morse code sending and
** random code generating routines.  Started on April 30, 1097.
** By        Peter V. Inskeep    ars/ NO2D
**           6 Clearview Drive
**           Long Valley, N. J., 07853
**           CIS  72017,1211
**           CIS E-Mail inquiries encouraged
** Created primarily as an exploration of assembly language programming
** on the Amiga.  But it would be nice also if this adventure in morse
** code created enough enthusiasm to cause you to look into ham radio
** if you are not already a ham.  Contact a ham (look for big antennas
** in the back yard), or call ARRL in Newington, Ct., for the name of
** a ham club near you.
*  = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = -   *
***  Special thanks to Darrel Schneider, Author of SpriteClock, on ***
***  Fred Fish Disk # 43.  That program gave me the clues on how   ***
***  to open the timer.device and get it to _LVODoIO.  The source  ***
***  to Sclock has many very interesting assembly language ideas.  ***
**  INCLUDE files normally used in compiling an assembly language
** program are not needed if the equates listed below are used.  There
** are obscure switches included to turn the equates on or off as
** you desire.  They are on now, so no INCLUDE directives are not needed.
** The equates are used to speed assembly, as running the assembler
** through many INCLUDE files takes a long time.

;   INCLUDE    'exec/types.i' ;these will conflict with the equates
;   INCLUDE    'exec/io.i'    ;so are turned off by the [ ; ].
;   INCLUDE    'intuition/intuition.i' 
;   INCLUDE    'outfile.equ'  ;use this only if you have outfile.equ
; file built and installed in the include directory on assembly disk
** Some switches
useoutfile  equ  1  ;equ 1 if you are not using outfile.equ
useincludes equ  1  ;equ 1 if you are not using any includes at all
   XREF   _LVOGetMsg
   XREF   _LVOReplyMsg
   XREF   _LVOAddPort
   XREF   _LVORemPort
   XREF   _LVOSetMenuStrip
   XREF   _LVOClearMenuStrip
   XREF   _LVOPrintIText
   XREF   _LVODrawBorder
   XREF   _LVOOpenWindow
   XREF   _LVOCloseWindow
   XREF   _LVOAddDevice
   XREF   _LVOOpenDevice
   XREF   _LVOCloseDevice
   XREF   _LVORemDevice
   XREF   _LVOOpenLibrary
   XREF   _LVOCloseLibrary
   XREF   _LVODoIO
   XREF   _LVOSendIO
   XREF   _LVOWait
   XREF   _LVOAddGadget
   XREF   _LVOAllocMem
   XREF   _LVOFreeMem
   XREF   _LVOAllocSignal
   XREF   _LVOFreeSignal
   XREF   _LVOFindTask

** Outfile.equ equates - the following items are defined in a file called
** outfile.equ.  This file is created by assembling all of the desired
** INCLUDE files with the -e outfile.equ switch turned on.  The -e
** directive is not well documented in the literature, but is explained
** in one of the back issues of Transactor.  I can not remember which.

   IFEQ  1-useoutfile  ;IF NOT EQUAL ZERO THEN THESE ARE NOT USED
AbsExecBase  EQU  $04
NT_MSGPORT   EQU  $04
NT_MESSAGE   EQU  $05
LN_TYPE      EQU  $08
LN_PRI       EQU  $09
LN_NAME      EQU  $0A
LN_SIZE      EQU  $0E
MEMF_PUBLIC  EQU  $01
MEMF_CHIP    EQU  $02
MEMF_FAST    EQU  $04
MEMF_CLEAR   EQU  $10000
  ENDC
***   DMA CHIP ADDRESSES - FROM THE HARDWARE MANUAL
***   NOT CURRENTLY IN INCLUDE OR OUTFILE.EQU SO ALWAYS USE  
Chipadr   equ $dff000      ;base address of chip
DMAconw   equ Chipadr+$96  ;DMA control write register
Aud0Lc    equ Chipadr+$a0  ;Channel 0 waveform sample location
Aud0Len   equ Chipadr+$a4  ;Channel 0 waveform sample length
Aud0per   equ Chipadr+$a6  ;channel 0 period
Aud0vol   equ Chipadr+$a8  ;channel 0 volume
Aud1Lc    equ Chipadr+$b0  ;Channel 1 waveform sample location
Aud1Len   equ Chipadr+$b4  ;Channel 1 waveform sample length
Aud1per   equ Chipadr+$b6  ;channel 1 period
Aud1vol   equ Chipadr+$b8  ;channel 1 volume
Setclr    equ $08000       ;DMA SEETCLR bit
OffDMA    equ 0            ;Disable DMA
Aud0en    equ $01          ;enable/disable Channel 0
Aud1en    equ $02          ;Enable/disable Channel 1
DMAen     equ $0200        ;Enable DMA
timelsb   equ $bfe801      ;timer a Least sig byte - read last
timemid   equ $bfe901      ;timer a middle byte
timemsb   equ $bfea01      ;timer a MSB - read stops clock til LSB read 
timecrb   equ $bfef01      ;timer a control register bit 7=0 is write

**  INCLUDE EQUATES FROM EITHER INCLUDE OR OUTFILE.EQU
**  Do not use these [set not =] if using include or outfile.equ
   IFEQ  1-useincludes  ;IF NOT ZERO THEN WILL NOT BE EQUATED
wd_RPort   equ  $32
wd_FirstGadget  equ  $3e
wd_Size    equ  $7c
ig_ImageData  equ  $0a
ig_SIZEOF  EQU  $14
wd_UserPort   equ   $56
nw_FirstGadget equ  $12
im_Class   equ   $14
im_Code    equ   $18
im_MouseX  equ   $20
im_MouseY  equ   $22
im_Seconds equ   $24
im_Micros  equ   $28
MP_FLAGS   EQU   $0E
MP_SIGBIT  equ   $0f
MP_SIGTASK EQU   $10
MP_MSGLIST EQU   $14
MP_SIZE    EQU   $22
MENUENABLED   equ   $01
MIDRAWN   equ   $100
ITEMTEXT   equ   $02
ITEMENABLED   equ   $10
WBENCHSCREEN   equ   $01
HIGHCOMP   equ   $40
WINDOWSIZING   equ   $01
WINDOWDRAG   equ   $02
WINDOWDEPTH   equ   $04
WINDOWCLOSE   equ   $08
SMART_REFRESH   equ   $00
ACTIVATE   equ   $1000
GIMMEZEROZERO   equ   $400
VANILLAKEY    EQU  $00200000    ;SEE OPENWINDOW IN INTUITION REF MANL
FOLLOWMOUSE  EQU   $08
CHECKIT  EQU $01        ;
COMMSEQ  EQU $04
MENUTOGGLE   EQU  $08
TR_GETSYSTIME  EQU  $0A  ;used with the timer.device
TR_SETSYSTIME  EQU  $0B
TR_ADDREQUEST  EQU  $09
CMD_READ  EQU  $02
CMD_WRITE  EQU $03
CMD_NONSTD EQU $09
MN_REPLYPORT equ $0e
MN_SIZE  EQU   $14
IO_DEVICE  EQU   $14  ;THE IO_STDREQ STRUCTURE IS BEST DESCRIBED IN THE
IO_UNIT    EQU   $18  ;ROM KERNAL SERIAL.DEVICE ON PG D40.
IO_COMMAND  EQU  $1C
IO_FLAGS   EQU   $1E
IO_ERROR   EQU   $1F
IO_ACTUAL  EQU   $20
IO_LENGTH  EQU   $24
IO_DATA    EQU   $28
IO_OFFSET  EQU   $2C
IOSTD_SIZE  EQU  $30
IO_SIZE    EQU   $20
IOTV_TIME  EQU   $20
TV_SIZE    EQU   $08
IOTV_SIZE  EQU   $28
TV_SECS    EQU   $00
TV_MICRO   EQU   $04
UNIT_MICROHZ EQU $00
UNIT_VBLANK  EQU $01
pi_SIZEOF   EQU  $16
pi_Flags    EQU  $00
pi_HorizPot EQU  $02
pi_VertPot  EQU  $04
pi_HorizBody  EQU  $06
pi_VertBody   EQU  $08
pi_HPotRes  EQU  $0e
pi_VPotRes  EQU  $10
AUTOKNOB   EQU  $01
FREEHORIZ  EQU  $02
FREEVERT   EQU  $04
KNOBHIT    EQU  $0100
KNOBHMIN   EQU  6
KNOBVMIN   EQU  4
gg_NextGadget equ  $00
gg_LeftEdge   equ  $04
gg_TopEdge    equ  $06
gg_Width      equ  $08
gg_Height     equ  $0a
gg_Flags      equ  $0c
gg_Activation  equ  $0e
gg_GadgetType  equ  $10
gg_GadgetRender equ  $12
gg_SelectRender  equ  $16
gg_GadgetText  equ  $1a
gg_MutualExclude  equ  $1e
gg_SpecialInfo   equ  $22
gg_GadgetID    equ  $26
gg_UserData    equ  $28
gg_SIZEOF    equ  $1c
RELVERIFY  EQU  $01
RIGHTBORDER  EQU  $10
BOTTOMBORDER  EQU  $80
PROPGADGET  EQU  $03
GZZGADGET  EQU  $2000
CLOSEWINDOW  EQU  $0200
GADGETUP  EQU  $40
MENUPICK  EQU  $0100
GRELRIGHT  EQU  $10
GRELHEIGHT  EQU  $40
GRELWIDTH  EQU  $20
GRELBOTTOM  EQU  $08
GADGIMAGE  EQU  $04
GADGHIMAGE  EQU  $02
GADGHCOMP  EQU  $00
RP_JAM1  EQU  $00
RP_JAM2  EQU  $01

   ENDC
***  Program equates not defined in Include or Outfile.equ
million   equ  1000000
Priority  equ  $00
maxspeed   equ  $a00
linelen    equ 54      ;set to typed line length
Count      equ $ffff   ;counter for delay timer
bufferlen  equ 400  ;keyboard buffer length not more than #keybuf
gwide   equ   22  ;how wide the gadget box is ( -GRELWIDTH)
ghigh   equ  -40  ;how high the gadget box is (-GRELHEIGHT
gleft   equ  -22  ;where the left edge of the box is (-GRELRIGHT)
gtop    equ   15  ; -40  ;where the top of the box is (-GRELBOTTOM)
g1wide  equ  300
g1high  equ   12      ; -15
g1left  equ   100
g1top   equ  -12
** The following macro added by P.V.Inskeep, on 30,May,1987, to
** accomodate the need to copy a structure size into a program
** being written, and to consume the correct number of BYTES!
** It is also initialized to zero with the dcb.b command
  IFND  MYSTRUCT	
MYSTRUCT    MACRO     ;mystructname,mystructendaddr
\1          dcb.b      \2,0
        ENDM
  ENDC
start:
***   Open the Intuition Library ***
   movea.l    #IntuitionName,a1     ;ask for intuition.library
   clr.l      d0                    ;accept any version 0 or greater
   movea.l    AbsExecBase,a6       ;the one fixed location in Amiga
   jsr        _LVOOpenLibrary(a6)   ;assembly language programming
   move.l     d0,IntuitionLibrary   ;store the pointer here
   beq        Abort      ;if zero then open failed so we go away
** Open graphics - need for clear screen
   movea.l    #GraphicsName,a1     ;ask for the graphics.library
   clr.l      d0                   ;any version
   movea.l    AbsExecBase,a6
   jsr        _LVOOpenLibrary(a6)
   move.l     d0,GraphicsLibrary   ;store the pointer here
   beq        Abort

***  Get some Chip Memory for Images, etc.
getmem:      ;for image and audio
    move.l   #imagebytes,d0   ;establish chip memory space for the 
    move.l   #(MEMF_CHIP!MEMF_PUBLIC),d1   ;proportional gadgets and
    movea.l  AbsExecBase,a6     ;the audio wave sample
    jsr      _LVOAllocMem(a6)
    tst.l    d0   ;a ptr to the memoryblock or 0 if error
    beq      close2_image
    move.l   d0,memblock   ;ptr to reserved memory block
    move.l   d0,a0   ;ptr to reserved mem block
    clr.l    d0    ;set up dbra register
    move.l   #imagebytes,d0   ;#sizepubmem,d0   ;how many iterations
    sub.l    #1,d0   ;goes to minus 1
    lea.l    theimage,a1   ;ptr to beginning of initial data
1$  move.b   (a1)+,(a0)+   ;move data from begin to memblock
    dbra     d0,1$  ;loop until all copied
;image2 - pitch - transformation
    move.l   #pitchbytes,d0  
    move.l   #(MEMF_CHIP!MEMF_PUBLIC),d1
    movea.l  AbsExecBase,a6
    jsr      _LVOAllocMem(a6)
    tst.l    d0   ;a ptr to the memoryblock or 0 if error
    beq      close3_pitch
    move.l   d0,pitchblock   ;ptr to reserved memory block
    move.l   d0,a0   ;ptr to reserved mem block
    clr.l    d0    ;set up dbra register
    move.l   #pitchbytes,d0   ;how many iterations
    sub.l    #1,d0   ;goes to minus 1
    lea.l    pitchimage,a1   ;ptr to beginning of initial data
3$  move.b   (a1)+,(a0)+   ;move data from begin to memblock
    dbra     d0,3$  ;loop until all copied
;now the audio block moves to chip memory
    move.l   #sizeaudio,d0
    move.l   #(MEMF_CHIP!MEMF_PUBLIC),d1
    movea.l  AbsExecBase,a6
    jsr      _LVOAllocMem(a6)
    tst.l    d0   ;a ptr to the memoryblock or 0 if error
    beq      close4_audio
    move.l   d0,audioblock   ;ptr to reserved memory block
    move.l   d0,a0   ;ptr to reserved mem block
    clr.l    d0    ;set up dbra register
    move.l   #sizeaudio,d0   ;how many iterations
    sub.l    #1,d0   ;goes to minus 1
    lea.l    Wavesample,a1   ;ptr to beginning of initial data
2$  move.b   (a1)+,(a0)+   ;move data from begin to memblock
    dbra     d0,2$  ;loop until all copied
***  Now initialize and open window and set pointers ***    
   jsr    inits   ;set up some chip mem pointers
   jsr    initializations  ;set lots of pointers and buckets
********** create timer port **********
init_timerport:
;get a signal bit
    moveq.l   #-1,d0
    jsr       _LVOAllocSignal(a6)
    move.l    d0,MP_Signalbit   ;d2
    bmi       close5_sigbit   ; if -1 AllocSignal failed so abort
; alloc port structure
    moveq.l   #MP_SIZE,d0  ;set aside this many bytes for message port
    move.l    #(MEMF_CLEAR!MEMF_PUBLIC),d1 ;fill it with zeros
    movea.l   AbsExecBase,a6
    jsr       _LVOAllocMem(a6)  ;needs d0 and d1, if successful returns
    move.l    d0,timerportptr  ;ptr to the memory set aside
    beq       close6_MP        ;failed if zero

; fill port fields
    movea.l   timerportptr,a2      ;ptr to our MP_ structure
    move.b    #NT_MSGPORT,LN_TYPE(a2)    ;Exec book pg A-30
    move.b    #Priority,LN_PRI(a2) ;Priority = priority level 0
    lea.l     TimerPortName,a1   ;name is "timer"
    move.l    a1,LN_NAME(a2)     ; LN_NAME gets TimerPortName "timer"
    move.l    MP_Signalbit,d2    ;bring back the signal bit. This puts the
    move.w    d2,MP_FLAGS(a2)    ;signal bit in the lower 16 bits of d2,
; and writes them to the BYTES MP_FLAGS AND MP_SIGBIT
; Now find a task to put in the MP_SIGTASK field of the structure    
    moveq.l   #0,d0  ;zero in a1 
    movea.l   d0,a1  ;an odd way to zero out a1
    jsr       _LVOFindTask(a6)  ;needs task or zero in a1
    movea.l   timerportptr,a1     ;now switch ptr to a1
    move.l    d0,MP_SIGTASK(a1)  ;task returned in d0, init sigtask
; add the port
    movea.l   timerportptr,a1   ;there is no failure code for this,but
    jsr       _LVOAddPort(a6)   ;it must be removed before the message
; initialize timerequest structure  ;port is closed 
    moveq.l   #IOTV_SIZE,d0  ;Enough bytes for IO Timerequest Structure
    move.l    #(MEMF_CLEAR!MEMF_PUBLIC),d1
    jsr       _LVOAllocMem(a6)
    tst.l     d0
    beq   close7_remport  ;remove the port above and close out
    move.l    d0,timeIOTVptr   ;save the IOTV ptr
    move.l    d0,a0  ;now init our IOTV block.  This next step puts the
;message bit in high byte of word and priority bit in low byte, and
;stores them in a0+8 and a0+9 respectively
    move.w    #((NT_MESSAGE<<8)+Priority),LN_TYPE(a0)
    move.l    timerportptr,MN_REPLYPORT(a0) ; into a0+$0e
; the following flags should be cleared, and were in the AllocMem call
; but if not: clr.w  IO_FLAGS(timeIOTVptr)  ; this also zeros IO_ERROR
    move.w    #TR_ADDREQUEST,IO_COMMAND(a0) ;this tells _LVODoIO what
;command we want it to do for us.
OpenDeviceLOOP:
    lea.l     timername,a0      ;name is "timer.device
    movea.l   timeIOTVptr,a1    ;ptr to IOTV structure
    moveq.l   #UNIT_MICROHZ,d0   ;use UNIT_MICROHZ or UNIT_VBLANK
    moveq.l   #0,d1
    movea.l   AbsExecBase,a6
    jsr       _LVOOpenDevice(a6)  ;error if not successful
    tst.l     d0
    bne       close8_IOTV
    bra       IntroMessage

delay3secs    movea.l   timeIOTVptr,a1   ;load our fully initialized IOTV ptr 
    move.l    #3,IO_SIZE+TV_SECS(a1)  ;delay 3 seconds
    move.l    #10,IO_SIZE+TV_MICRO(a1)  ;delay 10 microseconds
    movea.l   AbsExecBase,a6  ;needs IO block in a1, returns error in
    jsr       _LVODoIO(a6)    ;d0 or zero if successful
    rts 

dotpause   movem.l  d0-d4/a0-a4,-(sp)    ;save the registers
    jsr    conchar    ;get a key      
    movea.l   timeIOTVptr,a1   ;load our fully initialized IOTV ptr 
    move.l    secs,IO_SIZE+TV_SECS(a1)  ;for dot & space elements
    move.l    micros,IO_SIZE+TV_MICRO(a1)  
    movea.l   AbsExecBase,a6  ;needs IO block in a1, returns error in
    jsr       _LVODoIO(a6)    ;d0 or zero if successful
    movem.l  (sp)+,d0-d4/a0-a4
    rts
dashpause  movem.l  d0-d4/a0-a4,-(sp)    ;save the registers
    jsr    conchar    ;get a key      
    movea.l   timeIOTVptr,a1   ;load our fully initialized IOTV ptr 
    move.l    dashsecs,IO_SIZE+TV_SECS(a1)  ;just for dashes
    move.l    dashmicros,IO_SIZE+TV_MICRO(a1)
    movea.l   AbsExecBase,a6  ;needs IO block in a1, returns error in
    jsr       _LVODoIO(a6)    ;d0 or zero if successful
    movem.l  (sp)+,d0-d4/a0-a4
    rts
initializations:   ; nothing works unless these are initialized before
; being used in the various routines.
   move.l    #1,randflag  ;set random for keyboard input
   move.l    #0,codecntr  ;zero out code counter
   move.l    #0,kbcntr    ;zero out keyboard counter
   move.l    #keybuf,kbptr     ;the current keyboard buffer position
   move.l    #keybuf,codeptr   ;the current code char position
   move.l    #keybuf,d0     
   add.l     #bufferlen,d0      ;get to end of keybuf
   move.l    d0,kbendptr  ;the end of keybuf
   move.l    d0,consoleflag  ;make these two flags any non-zero
   move.l    d0,timerflag    ;value so close1 works properly
   move.l    #mymenu,menupoint   ;initialize pointer to menu structure
   move.l    #menuitemone,firstmenuitem    ;init 1st menuitem pointer
   move.l    #firstitemtext,itemonetext    ;init 1st item intuitext struct
   move.l    #fititle,fitext               ;init title in 1st menu item
   move.l    #menuitemtwo,menuitemone      ;init the second menu item
   move.l    #seconditemtext,itemtwotext   ;and its text
   move.l    #sititle,sitext
   move.l    #menuitem3,menuitemtwo      ;init third menu item
   move.l    #thirditemtext,item3text    ;and its text
   move.l    #tititle,titext
   move.l    #menuitem4,menuitem3
   move.l    #forthitemtext,item4text
   move.l    #fotitle,fotext
   move.l    #onelinelist,oneline1    ;init drawline border coordinates
   move.l    #onecharbuf,onecharptr   ;for writing one char
   move.l    #5,ranword   ;for random char generator spacing
   lea       buffer,a1    ;initialize the buffer
   move.l    a1,bufptr    ;pointer
   move.l    #0,secs      ;initialize the counters for dot and dash
   move.l    #32000,micros   ;three to one ratio
   move.l    #0,dashsecs
   move.l    #112000,dashmicros
   move.l    #2,factor    ;the speed factor menu adjuster
** Set the Menu Strip
   movea.l   MyWindow,a0    ;pointers to window and to menu structure
   movea.l   menupoint,a1   ;needed to call SetMenuStrip
   movea.l   IntuitionLibrary,a6
   jsr       _LVOSetMenuStrip(a6)
   rts
IntroMessage:
   jsr   welcomssg  ;see if the messages work
   move.l  #100,d0   ;this is a short pause routine to let
                    ;the user read the intro message
   jsr   pause      ;time to read the screen
   jsr   setmessage     ;set up the message center
   bra      openconsole
*****  We went to the openconsole routine *****
   cnop   0,4
** set up the IORequest block structure here
   MYSTRUCT  myio,IOSTD_SIZE
   cnop 0,4
**  Open Console.Device
**  Start by init the iodata field to a pointer to  MyWindow
**  The open console device fills in all the rest.
**  for the specific commands.  see Intuition manual pg 174
openconsole:
;initialize to call adddevice
   move.l   #myio,a0   ;the reserved block pointer is ioreqptr
   move.l   a0,ioreqptr   ;set up a ioblock pointer
   move.l   MyWindow,d1   ;get the window pointer
   move.l   d1,IO_DATA(a0)  ;put the window ptr in IO_DATA
   move.l   #wd_Size,IO_LENGTH(a0)   ;poke size of a window structure
**open device
   movea.l  #consolename,a0    ;console.device any other not do anything
   move.l   #0,d0   ;unit number
   movea.l  ioreqptr,a1   ;IORequest block structure i built
   move.l   #0,d1  ;flags dont know what to put
   movea.l  AbsExecBase,a6
   jsr      _LVOOpenDevice(a6)  ;returns 0 if success, error if not
   move.l   d0,consoleflag  ;keeps track of successful console open   
   tst.l    d0    ;zero is success, not zero is error number
   beq      success
   bra      cl9_timerdevice ;close timer console et all
success:
   move.l  #iobuffer,d4  ;load a zero term mssg to print
   jsr     conwrite   ;a short success message
   tst.l   d0     ;zero is success
   bne     close10  ;everything opened, but it didn't work
   bra     passover  ;pass over the morse gadget initializations

** put the message pointer in d4, with zero terminated
conwrite:
   movea.l  ioreqptr,a0   ;pointer to iorequestblock structure
   move.l  #-1,IO_LENGTH(A0)  ;use -1 only if text null terminated.
;   otherwise, load iolength with buffer text length
   move.l  d4,IO_DATA(A0)
   move.w  #CMD_WRITE,IO_COMMAND(a0)    ;WORD LENGTH
   movea.l a0,a1    ;iorequestblock structure
   movea.l AbsExecBase,a6
   jsr     _LVOSendIO(a6) ;DoIO works but waits for write to finish
   rts                    ;and is therefore slower
conread:
   movea.l  ioreqptr,a0 
   move.l  #10,IO_LENGTH(a0)   ;read a maximum of ten chars.
   move.w  #CMD_READ,IO_COMMAND(a0)   ;set up the read command
   move.l  a0,a1
   move.l  bufptr,IO_DATA(a0)  ;fill the buffer from dos
   movea.l AbsExecBase,a6
   jsr     _LVOSendIO(a6)   ;88888errorcheck
   rts
**  Write one char in kbptr to the screen
conwone:
   movea.l  ioreqptr,a1   ;pointer to iorequestblock structure
   move.l   #1,IO_LENGTH(a1)  ;use 1 to write one character
   move.l   kbptr,IO_DATA(a1)
   move.w   #CMD_WRITE,IO_COMMAND(a1)    ;WORD LENGTH
   movea.l  AbsExecBase,a6
   jsr      _LVOSendIO(a6)
   rts
** Read one char fm keyboard (kbptr) 
conrone:
   movea.l  ioreqptr,a1  ;get ioreqblock base pointer
   move.l   #1,IO_LENGTH(a1)   ;read 1 char
   move.w   #CMD_READ,IO_COMMAND(a1)   ;set the read command
   move.l   kbptr,IO_DATA(a1)  ;pointer where to store char
   movea.l  AbsExecBase,a6     ;needs base ptr in a1
   jsr      _LVOSendIO(a6)
   rts
** gets a char if there is one in keyboard, and writes it.  This is called
conchar:   ;during sounds of dots and dashes (dotpause-dashpause)
   clr.l    d4   ;sending a dot or dash
   movea.l  ioreqptr,a0
   move.w   30(a0),d4  ;bit 6 of #30 in iorequest block will be 
   btst     #14,d4   ;1 if a char is available in read, otherwise
   beq      1$      ;it will be zero
   jsr   conrone
   jsr   conwone    ;there was a char
   jsr   addkeyst   ;increment keyboard buffer ptr
1$  rts

*  Initialize the variables
inits:
   lea       image1,a0   ;gadget1 image structure ptr
   movea.l   memblock,a1  ;ptr to gadget knob image data
   move.l    a1,ig_ImageData(a0)  ;initialize image1 data ptr
   lea       image2,a0
   movea.l   pitchblock,a1
   move.l    a1,ig_ImageData(a0)  ;init image2 data ptr
   jsr   sound  ;initialize the sound subroutine
***   Open our window now that the propgadgets have been initialized
   movea.l    #newwindow,a0
   movea.l    IntuitionLibrary,a6
   jsr        _LVOOpenWindow(a6)
   move.l     d0,MyWindow        ;pointer to newly opened window
   beq        Abort              ;the rastport pointer is located
   movea.l    MyWindow,a0        ;at an address which is offset from
   movea.l    wd_RPort(a0),a1    ;the window pointer by the value of
   move.l     a1,myrport         ;wd_RPort, which is hex $32
   rts
passover:
   jsr   setmessage   ;init these so DoIO can have a port
   jsr   getmessage
   jsr   sound    ;initialize the sound
   clr.l  d0
   move.w   #200,Aud0per   ;make a two tone sound to start up
   move.w   #250,Aud1per   ;second channel should be lower pitch?
   jsr    ChanneL0 ;make a noise
   jsr    sound    ;reinit the sound
   move.l #40,d0
   jsr    pause 
   jsr    sndon 
   jsr    delay3secs ;just to see if it works
   move.l #timertest,d4
   jsr    conwrite
   jsr    sndoff
   move.l #40,d0
   jsr    pause
   jsr    clear
   movea.l  #cqmssg,a5  ;addr of message to send
   jsr    sendmorse
   move.l  #endline,d4
   jsr     conwrite
   move.l   #testmsg,d4
   jsr   conwrite  ;print instructions
   tst.l  d0
   bne    close1   ;if it fails
   jsr    zerokeybuf   ;fill keybuf with zeros
   jsr    conrone   ;read once to set to #14 bit  
   bra   ponder3    ;to the main loop
sendmorse:  ;expects pointer to 0 terminate string in a5
2$   clr.l   d0
   move.b  (a5)+,d0     ;get 1st character from mssg
   tst.b   d0    ;if 0 then done
   beq     1$
   move.l  a5,-(a7)   ;save mssg ptr
   move.l  d0,-(a7)   ;save letter
   move.b  d0,prtachar   ;load buffer
   move.l  #prtachar,d4  ;prepare for conwrite
   jsr     conwrite      ;write 0 terminated buffer
   move.l  (a7)+,d0   ;get character back
   jsr     sendone    ;send it as morse code sounds
   move.l  (a7)+,a5   ;get mssg ptr back
   bra     2$         
1$  rts

zerokeybuf:
   move.l    #keybuf,a0  ;start of keyboard buffer
   clr.l     d1
   move.l    #bufferlen,d1    ;one less than buffer length
   sub.l     #1,d1           
1$   move.b   #0,(a0)+   ;zero fill
   dbra      d1,1$   ;decrement and branch
   rts

** The main routine for the menuitem selection.
** The Message Reading SubRoutine **
ponder3:
   jsr     getmessage  ;go see if there is a message to read
   tst.l   d0    ;returns zero if none
   beq     ponder5     ;return if no message
   clr.l   d0  ;myclass contains the idcmp message upon [ponder4]
   move.l  myclass,d0    ;return from getmessage
   cmp.w   #MENUPICK,d0  ;was a menu picked
   beq     whichmenu     ;if so, then go find out which menu item
   cmp.w   #CLOSEWINDOW,d0   ;or was it the closewindow gadget?
   beq     close1        ;if so, go close everything out
   cmp.w   #GADGETUP,D0  ;or was the gadget hit to change speed
   beq     chgspeed      ;change the delay loop values 
ponder5:                 ;bra  keytest  ;no message
   jsr    conchar     ;is there a char at keyboard
   jsr    codetable   ;see if there is a char to send
   bra    ponder3     ;loop back and do it again

** Which Menu Item was selected?
whichmenu:
   clr.l   d0  ;mycode shows which menu item was selected
   move.w   mycode,d0  ;mycode is word, not longword
**  The next instructions masks mycode to isolate the six middle bits
**  which contain the item number, and then compare it to item 1
   and.w    #%0000011111100000,d0   ;15-11=sub; 10-5=item; 4-0=menu
   cmp.w    #%0000000000000000,d0    ;0 is the 1st item #
   beq      itemnr1    ;the 1st menu item was picked
   cmp.w    #%0000000000100000,d0    ;1 is the 2nd item #
   beq      itemnr2    ;the 2nd menu item was picked
   cmp.w    #%0000000001000000,d0    ;10 is the 3rd item #
   beq      itemnr3    ;the 3rd item was picked
   cmp.w    #%0000000001100000,d0    ;11 is the 4th item#
   beq      itemnr4    ;toggle the letter only switch
   jsr      erase      ;erase rectangle bounded by above
   move.l   #playmouse,IntuMsg    ;if not either of the above
   move.w   #280,offsetleft       ;print the message play with
   move.w   #5,offsettop         ;your mouse
   jsr      printthis  ;prints string pointed to by IntuMsg
   bra      ponder5    ;loop back to the beginning
itemnr1:  ;send faster
   jsr      erase
   move.l   #pickitem1,IntuMsg  ;first item picked so
   move.w   #270,offsetleft     ;print the message on the screen
   move.w   #5,offsettop
   jsr      printthis
   jsr      meitem1    ;send faster
   bra      chgspeed   ;thence to ponder5
itemnr2:               ;send slower
   jsr      erase
   move.l   #pickitem2,IntuMsg  ;second item picked so
   move.w   #270,offsetleft
   move.w   #5,offsettop
   jsr      printthis
   jsr      meitem2   ;send slower
   bra      chgspeed  ;thence to ponder5
itemnr3:              ;switch random
   jsr      erase
   jsr      clear
   move.l   #pickitem3,IntuMsg    ;third item picked
   move.w   #270,offsetleft
   move.w   #5,offsettop
   jsr      printthis
   jsr      meitem3   ;switch random on/off
   bra      ponder5   ;use the same exit point
itemnr4:
   jsr      erase
   move.l   #pickitem4,IntuMsg    ;Letter only Toggle Switch
   move.w   #270,offsetleft
   move.w   #5,offsettop
   jsr      printthis
   jsr      meitem4
   bra      ponder5
**  Random Number Generator  **
random:
    clr.l    d4
    jsr      GETRANDOM  ;a random byte number in d0
    and.l    #$7f,d0   ;want only letters
    cmp.l    #43,d0    ;elim less than comma {,}
    ble      random    ;go get another
    cmp.l    #123,d0   ;letter z
    bge      random
    cmp.l    #97,d0    ;letter a or better
    bge      1$
    tst.l    letterflag   ;if not 0 then only letters
    bne      random
    cmp.l    #58,d0    ;number 9
    bge      random
1$  cmp.l    lastrandom,d0
    beq      random   ;if they are the same dont use it
    jsr      aspace  ;see if time for a space
    move.l   d0,-(sp)
    lea      onecharbuf,a0
    move.l   a0,d4
    move.b   d0,(a0) 
    jsr      conwrite  ;write it out
    move.l   (sp)+,d0  ;get the character back
    move.l   d0,lastrandom  ;store for comparison
    rts   

GETRANDOM:
   JSR   onerandom    ;make a random number
   moveq    #0,d0      ;clear d0 long
   MOVE.B   CELL1,D0   ;get the random # always in cell1
   RTS      ;to from whence it came
** GENERATE RANDOM #'S FROM TRANSACTOR, MAY, 1987 
** MUST INITIALIZE WITH 21 RANDOM bytes
onerandom:
   moveq     #0,d0
   moveq     #0,d1
   moveq     #0,d2
   move.b    CELL21,D0
   add.b     CELL2,D0
   move.b    d0,TMP
   movea.l   #CBASE+21,a0
   movea.l   #CBASE+22,a1
   move.l    #19,D1
1$  move.b  -(A0),-(a1)        ;d2
    dbra    d1,1$
    move.b  TMP,CELL1  ;this is the random digit 
    rts
aspace:
    move.l  ranword,d5  ;what's in ranword
    tst.l   d5   ;if zero, then reseed
    beq     1$
    sub.l   #1,ranword  ;if not, reduce and return
2$  rts
1$  jsr     GETRANDOM  ;reseed the ranword
    and.l   #$07,d0
    or.l    #$01,d0
    move.l  d0,ranword
    move.l  #32,d0   ;put a space in the character generator
    bra     2$
    
* CLEAR THE SCREEN**
clear:
   move.l   #clrscreen,d4  ;ascii 12,13,10,13,10,0
   jsr      conwrite
   rts   

setmessage:
   movea.l  MyWindow,a0   ;pointer to my window
   movea.l  wd_UserPort(a0),a0  ;pointer to our window's userport
   move.l   a0,userport         ;save it
   rts
getmessage:
   clr.l    d4               ;need this for junk
   movea.l  userport,a0      ;get userport pointer for call to GetMsg
   movea.l  AbsExecBase,a6  ;GetMsg is exec.lib, not intuition.lib
   jsr      _LVOGetMsg(a6)
   tst.l     d0               ;returns null if no message
   beq      1$         ;escape if null
   move.l   d0,idcmpmessage  ;pointer to this message structure needed
   movea.l  idcmpmessage,a1  ;for address indirect with displacement
   move.l   im_Class(a1),myclass  ;which ICDMP flag ie., MENUPICK
   move.w   im_Code(a1),mycode    ;word-which menu item # 0,1,etc.
   movea.l  AbsExecBase,a6  ;is pointed to by idcmpmessage, so that
   jsr      _LVOReplyMsg(a6) ;messages don't pile up
   move.l   idcmpmessage,d0  ;if d0 not 0 then return with message
1$    rts

** Intuition Message
welcomssg:
   move.w   #10,offsettop
   move.w   #50,offsetleft
   move.l   #line1,IntuMsg    ;get pointer for first line to be
   bsr      lineprint    ;printed
   move.l   #line2,IntuMsg   ;second line
   bsr   lineprint
   move.l   #line3,IntuMsg
   bsr   lineprint
   move.l   #line4,IntuMsg
   bsr   lineprint
   move.l   #line5,IntuMsg
   bsr   lineprint
   move.l   #line6,IntuMsg
   bsr   lineprint
   move.l   #line7,IntuMsg
   bsr   lineprint
   rts
lineprint   add.w    #20,offsettop
   jsr      printthis
   rts

** the following will print what is in "IntuMsg"
printthis:
   movea.l   #0,a0   ;clear these else doesn't work
   movea.l  #0,a1
   clr.l    d0
   clr.l    d1
   movea.l  myrport,a0           ;pointer to rastport struct
   movea.l  #intuitext,a1        ;pointer to intuitext struct
   move.w   offsetleft,d0        ;leftedge offset
   move.w   offsettop,d1         ;top edge offset
   movea.l  IntuitionLibrary,a6  ;set library pointer
   jsr      _LVOPrintIText(a6)   ;call print
   rts

** Pause routine expects delay value in d0, with constant 10000
pause:
   move.l   #10000,d1
   move.l   d0,d2       ;put outter loop value in d2
pause1   move.l  d1,d3  ;inner loop value in d3
pause2      nop
   dbra     d3,pause2   ;decrease inner loop till minus 1
   dbra     d2,pause1   ;same for outter loop
   rts                  ;all done

** ERASE Part of Screen Routine - Fills a rectangle with the  **
** background color.  The rectangle is bounded by the starting
** and ending x,y coordinates (top left & bottom right)
** Start x pos in d0, end x pos in d1, both y pos' in d2
** Start at the bottom of the rectangleand draw lines in
** the background color up to the top of the screen
erase:
   move.w   #00,d0    ;now always erases the top 15 lines of screen
   move.w   #612,d1
   move.w   #15,d2
   move.w   d0,stx         ;starting x position
   move.w   d1,endx        ;ending x position
   move.w   d2,sty         ;starting y position
   move.w   d2,endy        ;ending y position
grids1   jsr  drawline     ;draw one horizontal line a pixel high
   subi.w   #1,sty         ;reduce y position
   subi.w   #1,endy        ;reduce y position
   dbra     d2,grids1      ;go back and draw another line
   rts

**  call this subroutine to draw a single line from coordinates
**  stx,sty to endx,endy - initialize those values before calling
**  the subroutine by move.w   #nn,stx etc
drawline:
   movea.l  myrport,a0       ;pointer to our rastport
   movea.l  #oneline,a1      ;pointer to border structure
   move.l   #0,d0            ;offsets-left & top
   move.l   #0,d1
   move.l   IntuitionLibrary,a6
   jsr      _LVODrawBorder(a6)
   rts    

***  Exit program -- Close all open whatevers  ***
close1:
   jsr   clear   ;clr the screen
   lea.l   bestdx,a5
   jsr   sendmorse
close10:
   movea.l  ioreqptr,a1
   movea.l  AbsExecBase,a6
   jsr      _LVOCloseDevice(a6)
cl9_timerdevice    movea.l  timeIOTVptr,a1    ;ptr to IOTV structure
   movea.l  AbsExecBase,a6
   jsr      _LVOCloseDevice(a6)
close8_IOTV
   move.l   #IOTV_SIZE,d0   ;release timer IO Timerequest Structure
   movea.l   timeIOTVptr,a1
   movea.l   AbsExecBase,a6
   jsr       _LVOFreeMem(a6)
close7_remport   movea.l  timerportptr,a1  ;this closes both the port and
   movea.l  AbsExecBase,a6  ;the MP_SIZE memory since the addport does not
   jsr      _LVORemPort(a6) ;have a close of its own
   move.l    #MP_SIZE,d0    ;release the timer message port
   movea.l   timerportptr,a1
   movea.l   AbsExecBase,a6
   jsr       _LVOFreeMem(a6)
close6_MP    move.l  MP_Signalbit,d0  ;free the signal bit
   movea.l  AbsExecBase,a6
   jsr      _LVOFreeSignal(a6)
close5_sigbit   move.l    #sizeaudio,d0   ;this releases back to main memory the
   movea.l   audioblock,a1   ;three blocks of memory that I allocated
   movea.l   AbsExecBase,a6  ;for the speed prop gadget image, the 
   jsr       _LVOFreeMem(a6) ;pitch prop gadget image and the audio
close4_audio   move.l  #pitchbytes,d0  ;wave form
   movea.l   pitchblock,a1
   jsr       _LVOFreeMem(a6)
close3_pitch   move.l  #imagebytes,d0
   movea.l   memblock,a1
   jsr       _LVOFreeMem(a6)
   move.w   #200,offsetleft  ;position a goodbye message
   move.w   #50,offsettop
   move.l   #goodbye,IntuMsg
   jsr      printthis
   move.l   #50,d0 
   jsr      pause           
close2_image   movea.l   MyWindow,a0    ;clear the menu strip to
   movea.l  IntuitionLibrary,a6      ;avoid conflicts when the
   jsr      _LVOClearMenuStrip(a6)   ;program is ended
   movea.l   MyWindow,a0
   movea.l  IntuitionLibrary,a6
   jsr      _LVOCloseWindow(a6)      ;now close the window
Abort:
   clr.l     d0
   rts        ;all done, program has ended

**   The Code Table
**   code element to be sent is in d0
codetable:
   jsr    getcodechar   ;get the next char fm keybuf
   cmpi.b   #0,d0
   beq      codet3  ;leave if char zero
   jsr      seedrandom
sendone   cmpi.b   #32,d0   ;is it a space? if so, skip code
   beq      endword
   movea.l  #alphacode,a0     ;get table pointer
   clr.l    d1                ;clr counter
   move.b   (a0),d1           ;set count at # of chars in table
   adda.l   #1,a0             ;move up to beginning of table
codet1   cmp.b  0(a0,d1),d0   ;index into table d1 bytes & compare
   beq      codet2            ;char found
   dbra     d1,codet1         ;decrement counter & try again
   bra      codet3            ;exit-no match found
codet2   move.b  d1,ltrcode   ;save the letter code number
   jmp      findltr           ;get the letter
codet4:
   bne      codet3
   move.l   d0,-(sp)        ;save char
   move.l   #linelen,carreturn
   move.l   (sp)+,d0        ;restore char
codet3    rts   ;to keytest and start again

endword:
   clr.l   d0
   move.b  wordspce,d0       ;set up dbra loop
endword1  jsr  dotpause      ;element    ;basic element spacing
   dbra    d0,endword1
   jmp     codet4            ;go update the line counter

findltr  move.b   ltrcode,d0  ;get the number back
   add.b    d0,d0             ;double it
   movea.l  #dotdash,a0       ;get table base
   move.b   0(a0,d0),d1       ;the length of the code elements
   subq.b   #1,d1             ;dec by one for dbra ending in -1
   addq.b   #1,d0             ;up addr to code description
   move.b   0(a0,d0),d2       ;get the morse letter
nextelm  btst     d1,d2       ;if bit 1 then dash
   bne.s    dash
dot   jsr   sndon       ;turn on the sound
   jsr    dotpause      ;element     ;sound one dot element
elmstart jsr   sndoff   ;turn sound off
   jsr    dotpause      ;noelement      ;char space
elmdone  dbra     d1,nextelm  ;if not -1 then get next element
endchar  clr.l    d1
   move.b   charspce,d1       ;do the character space-3 elms
endchar1 jsr   dotpause    ;element  ;make space rem to make charspce one
   dbra     d1,endchar1       ;less than desired spaceing.
   jmp      codet4            ;all done-get next character
dash  jsr   sndon
   jsr      dashpause   ;element ;this is longer by the weighting ratio
   jmp      elmstart    ;the dash is done

***  KeyBuffer Maintainence routine. Does not alter d0 ***
addkeyst:
   add.l   #1,kbptr
   add.l   #1,kbcntr ;increment the keyboard counter
   move.l  kbendptr,d4   ;set up a compare
   cmp.l   kbptr,d4   ;is ptr less?
   bgt     1$     ;d4 is > kbptr so branch
   move.l  #keybuf,kbptr  ;reset to the beginnng
1$  rts

** This gets a char and increments codeptr
getcodechar:
   clr.l   d1
   clr.l   d0
   move.l  randflag,d1
   tst.l   d1           ;if zero, then fetch code from random routine
   beq     random       ;this will send random code until menu changed
   move.l  codecntr,d1  ;see that code does not get ahead of keyboard
   cmp.l   kbcntr,d1    ;is d0 bigger, then dont send anything
   bge     1$           ;just return until keyboard catches up
   clr.l   d0
   movea.l  codeptr,a0   ;set up indirect to get char to send
   move.b  (a0),d0    ;get the char
   add.l   #1,codeptr  ;increment before testing
   add.l   #1,codecntr  ;increment the code counter
   move.l  kbendptr,d4     ;are we at the end of the buffer
   move.l  codeptr,d5
   cmp.l   d5,d4 
   bgt     1$     ;branch if d4 > codeptr
   move.l  #keybuf,codeptr   ;reset to the beginning
1$   rts    ;returns with char in d0, & pointer incremented

** Chage Speed With Proportional Gadget **
chgspeed:
    clr.l    d0  ;cuz we're going from word to long
    clr.l    d1
    moveq.l  #0,d2
    lea.l    prop1,a0   ;get the prop struct base ptr
    move.w   pi_VertPot(a0),d0   ;must be word length
    move.l   factor,d1
    mulu.w   d1,d0  ;this should max at 983040 microseconds
    move.l   d0,micros
    move.l   #0,secs   ;keep this at zero
    move.l   d0,d1     ;triple this
    add.l    d0,d1
    add.l    d0,d1     ;now triple & perhaps over 1 meg
    lsr.l    #1,d0        ;add 1/2 to make dash stretch a bit
    add.l    d0,d1     ;now dash ratio is 3&1/2
1$   cmp.l  #million,d1  ;is d1 over one million
    bls    2$      ;LS is low or same
    sub.l   #million,d1
    add.l   #1,d2  ;increase dashsecs
    bra     1$     ;go back and try again
2$  move.l  d2,dashsecs
    move.l  d1,dashmicros
    lea.l    prop2,a0   ;get pitch prop struct base ptr
    clr.l    d0
    move.w   pi_HorizPot(a0),d0   ;frequency  ;also word length
    divu     #40,d0     ;divide down by 40
    move.w   d0,frequency  ;store the new frequency
    jsr   sound
;tell the screen that we did this
   jsr      erase
   clr.l    d0
   move.w   frequency,d0   ;check the pitch
   jsr      printhex       ;convert it to hex
   move.l   #hexprint,IntuMsg    ;print it
   move.w   #270,offsetleft   
   move.w   #5,offsettop      
   jsr      printthis
   clr.l    d0
   move.l   micros,d0    ;check the speed [dot unit]
   jsr      printhex       ;convert and print it
   move.l   #hexprint,IntuMsg
   move.w   #550,offsetleft
   move.w   #5,offsettop
   jsr      printthis
   move.l   #pitchmssg,IntuMsg
   move.w   #190,offsetleft
   jsr      printthis
   move.l   #speedmssg,IntuMsg
   move.w   #470,offsetleft
   jsr      printthis
   move.l   factor,d0    ;check the speed [dot unit]
   jsr      printhex       ;convert and print it
   move.l   #hexprint,IntuMsg
   move.w   #400,offsetleft
   move.w   #5,offsettop
   jsr      printthis
   bra      ponder5    

** Independant Menu Picks **
** send faster
meitem1:
   move.l   factor,d0
   subi.l   #1,d0     ;decrease factor if one or more
   move.l   d0,factor
   beq      meitem2   ;unless we get to zero
   rts
**  send slower
meitem2:
   addi.l   #1,factor
   move.l   factor,d0  ;factor should not be greater than 14
   cmp.l    #14,d0     ;or the program goes too slow.
   beq      meitem1
   rts
**  switch random = 0  keyboard = 1
meitem3:
   tst.l   randflag    ;what is current state?
   beq.s   1$    ;its zero, so we want to make it one
   move.l   #0,randflag  ;it was one, so make it zero
2$  rts
1$  move.l  #1,randflag  ;make it one
   move.l   codeptr,d4   ;reprint remaining keyboard buffer
   jsr      conwrite
   bra   2$    ;exit at one place
meitem4:
   tst.l  letterflag
   beq.s  1$   ;reverse switch
   move.l   #0,letterflag
2$  rts
1$  move.l  #1,letterflag
   bra   2$

sound:  ;Hardware Reference Manual describes this stuff
    movea.l audioblock,a2  ;Find address of waveform sample data
    move.l  a2,Aud0Lc      ;set waveform location channel 0
    move.l  a2,Aud1Lc      ;set waveform location channel 1
* Length = number of WORDS (not bytes) in waveform sample
    move.w  #16,Aud0Len    ;Set sample length channel 0
    move.w  #16,Aud1Len    ;set sample length channel 1
* volume can go up to 64
    move.w  #64,Aud0vol    ;Set channel 0 volume at maximum
    move.w  #64,Aud1vol    ;Set Channel 1 volume at maximum
    move.w  frequency,d0   ;bigger period higher sound
    move.w  d0,Aud0per     ;reset channel 0 period
    move.w  d0,Aud1per     ;set channel 1 period
    rts
ChanneL0:
    move.w  #(Setclr+DMAen+Aud0en),DMAconw     ;enable channel 0
    move.l  #30,d0
    bsr     pause 
    move.w  #(OffDMA+Aud0en),DMAconw           ;disable channel 0
ChanneL1:
    move.w  #(Setclr+DMAen+Aud1en),DMAconw     ;enable channel 1
    move.l  #45,d0
    jsr     pause 
    move.w  #(OffDMA+Aud1en),DMAconw           ;disable channel 1
    rts
sndon:
   move.w  #(Setclr+DMAen+Aud1en),DMAconw     ;turn sound on
   move.w  #(Setclr+DMAen+Aud0en),DMAconw     ;ch 0 & 1
   rts
sndoff:
   move.w  #(OffDMA+Aud1en),DMAconw   ;turn sound off
   move.w  #(OffDMA+Aud0en),DMAconw   ;ch 0 & 1
   rts

printhex:
;prints a 16-bit hex number using d0 and hexfield
   clr.l   d1  ;nibble holder
   clr.l   d2  ;downcounter
   moveq   #3,d2
   lea.l   hexfield,a0
   lea.l   hexlist,a1
   bra     1$
2$ sub.l   #1,d2
   asr.l   #4,d0  ;shift to next nibble 
1$ move.l  d0,d1  ;move it 
   andi.l  #$0f,d1  ;what is the nibble
   move.b  0(a1,d1.l),d1  ;get the ascii equivalent
   move.b  d1,0(a0,d2.l)  ;put it in the hexfield
   tst.l   d2
   beq     3$
   bra     2$
3$ rts

seedrandom:
   lea   CBASE,a0        ;this subroutine seeds the random # generator
   move.l basecounter,d1 ;when the user types in some letters to send
   move.b  d0,0(a0,d1.l) ;code.
   sub.l  #1,d1
   bmi    2$
1$   rts
2$   move.l  #19,basecounter
   bra    1$

yestheend:
      
   SECTION     data,DATA

CBASE    DC.B     19
CELL1    DC.B     24
CELL2    DC.B     37,42,55,68,73,86,91,100,112,128,134,146,159
         DC.B     165,171,180,197,205,212
CELL21   DC.B     223
TMP      DC.B     0,0,0,0
         CNOP     0,4

TimerPortName  dc.b  'timer',0
hexlist  dc.b  '0123456789abcdef',0
consolename  dc.b  'console.device',0
timername    dc.b  'timer.device',0
IntuitionName   dc.b  'intuition.library',0
GraphicsName    dc.b  'graphics.library',0
clrscreen       dc.b   12,13,10,13,10,0
    cnop   0,4    ;this is used to allign following stuff on a
**  long word address. If not done disaster can strike

menuflags   EQU   MENUENABLED!MIDRAWN   ;FROM INTUITION MENU STRUCTURE
itemflags   EQU   ITEMTEXT!ITEMENABLED!HIGHCOMP!COMMSEQ
item3flags  EQU   ITEMTEXT!ITEMENABLED!HIGHCOMP!CHECKIT!COMMSEQ!MENUTOGGLE
MyGadgets   EQU   WINDOWSIZING!WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE
MyFeatures  EQU   SMART_REFRESH!ACTIVATE!GIMMEZEROZERO   ;!VANILLAKEY
MyFlags     EQU   MyGadgets!MyFeatures
gadgrel     EQU   GRELRIGHT!GRELHEIGHT   ; !GRELBOTTOM
gadg1rel    EQU   GRELHEIGHT!GRELBOTTOM
gadgflags   EQU   GADGHIMAGE!GADGIMAGE
gadg1flags  EQU   GADGHIMAGE!GADGIMAGE
gadgtype    EQU   PROPGADGET!GZZGADGET
propflags   EQU   FREEVERT!KNOBHIT      ;!FREEHORIZ  !AUTOKNOB
prop1flags  EQU   KNOBHIT!FREEHORIZ           ;!AUTOKNOB
menupick    EQU   MENUPICK
MyTitle:    dc.b  '  Morse Code Practice by NO2D',0 ;title of our window
iobuffer    dc.b  ' All windows, structures & devices have opened.',10,10,13,0
menutitle   dc.b  ' Morse Menu',0      ;null term string
fititle     dc.b  '  Send Faster',0    ;first item in menu
sititle     dc.b  '  Send Slower',0   ;second item in menu
tititle     dc.b  '   Send Random',0   ;third menu item
fotitle     dc.b  '   Letters Only',0  ;forth menu item
offsetleft  dc.w  0
offsettop   dc.w  0
frequency   dc.w  420
      cnop   0,4

**  MENU and MENU ITEM STRUCTURES
mymenu:
   dc.l  0    ;menu pointer
   dc.w  0,0,200,100  ;leftedge,topedge,width,height
   dc.w  MIDRAWN!MENUENABLED  ;menuflags MENUENABLED & MIDRAWN
   dc.l  menutitle    ;pointer to title string
firstmenuitem  dc.l  0   ;pointer to first menu item (menuitemone)
   dc.w   0,0,0,0     ;for the jazz-beat (who knows what that means)

** The first menu item structure **
menuitemone  dc.l  0     ;pointer to second menuitem
   dc.w  0,0,180,11      ;left,top,width,height of select box
   dc.w   itemflags      ;see flags set above
   dc.l   0              ;mutual exclude null=no item excluded
itemonetext   dc.l   0   ;pointer to intuitext struct for item text
   dc.l   0              ;pointer to highlight alternate image/text
   dc.b   70,0     ;set if COMMSEQ flag is set & a kluge byte 'f'
   dc.l   0       ;subitem if any
   dc.w   0       ;next selected item in drag 'mi_NextSelect'
** remember to initialize all of these things
firstitemtext:
   dc.b  0,1,4,0  ;pens drawmode & kluge
   dc.w  0,0      ;leftedge,topedge
   dc.l  0        ;textfont null = default
fitext  dc.l  0   ;textpointer
   dc.l  0        ;pointer to next intuitext struct

** The second menu item structure **
menuitemtwo  dc.l  0  ;pointer to third menuitem
   dc.w  0,15,180,11  ;left,top,width,height of select box
   dc.w   itemflags   ;see flags set above
   dc.l   0           ;mutual exclude null=no item excluded
itemtwotext   dc.l   0   ;aptr to intuitext struct for this item text
   dc.l   0              ;aptr to highlight alternate image/text
   dc.b   83,0     ;set if COMMSEQ flag is set & a kluge byte 's'
   dc.l   0       ;subitem if any
   dc.w   0       ;next selected item in drag 'mi_NextSelect'
** remember to initialize all of these things
seconditemtext:
   dc.b  0,1,4,0  ;pens drawmode & kluge
   dc.w  0,0      ;leftedge,topedge
   dc.l  0        ;textfont null = default
sitext  dc.l  0   ;textpointer
   dc.l  0        ;pointer to next intuitext struct
   cnop  0,4
   
** The forth menu item structure **
menuitem4  dc.l  0     ;pointer to second menuitem
   dc.w  0,45,180,11   ;left,top,width,height of select box
   dc.w   item3flags   ;see flags set above
   dc.l   0            ;mutual exclude null=no item excluded
item4text   dc.l   0   ;pointer to intuitext struct for item text
   dc.l   0            ;pointer to highlight alternate image/text
   dc.b   76,0     ;set only if COMMSEQ flag is set & a kluge byte
   dc.l   0       ;subitem if any
   dc.w   0       ;next selected item in drag 'mi_NextSelect'
** remember to initialize all of these things
forthitemtext:
   dc.b  0,1,4,0  ;pens drawmode & kluge
   dc.w  0,0      ;leftedge,topedge
   dc.l  0        ;textfont null = default
fotext  dc.l  0   ;textpointer
   dc.l  0        ;pointer to next intuitext struct
   cnop   0,4

** The third menu item structure **
menuitem3  dc.l  0     ;pointer to second menuitem
   dc.w  0,30,180,11   ;left,top,width,height of select box
   dc.w   item3flags   ;see flags set above
   dc.l   0            ;mutual exclude null=no item excluded
item3text   dc.l   0   ;pointer to intuitext struct for item text
   dc.l   0            ;pointer to highlight alternate image/text
   dc.b   65,0     ;set only if COMMSEQ flag is set & a kluge byte
   dc.l   0       ;subitem if any
   dc.w   0       ;next selected item in drag 'mi_NextSelect'
** remember to initialize all of these things
thirditemtext:
   dc.b  0,1,4,0  ;pens drawmode & kluge
   dc.w  12,0      ;leftedge,topedge
   dc.l  0        ;textfont null = default
titext  dc.l  0   ;textpointer
   dc.l  0        ;pointer to next intuitext struct

**  An IntuiText Structure.  Use this to do the "printthis"
**  routine, with pointer to message in IntuMsg
intuitext:
  dc.b  1,1,2,0   ;FT & bk pen, drawmode, kluge
  dc.w  0,0       ;leftedge topedge
  dc.l  0         ;textfont normal if 0
IntuMsg  dc.l  0  ;pointer to null terminated text to be printed
  dc.l  0         ;next intuitext structure-null if none`
   cnop   0,4

line1  dc.b  'Welcome to the Morse Code Practice Program.',0
line2  dc.b  'It is designed to help you improve your Morse Code',0
line3  dc.b  'sending and receiving speed, with the hope that it',0
line4  dc.b  'will encourage you to get your amatuer radio license',0
line5  dc.b  'or to upgrade.  This is written in Assembly Language,',0
line6  dc.b  'and free distribution is encouraged.',0
line7  dc.b  'by Peter V. Inskeep, NO2D  -- CIS  72017,1211.',0
pitchmssg   dc.b  'Pitch =',0
speedmssg   dc.b  'Speed =',0
bestdx      dc.b  'best dx es 73 tu de no2d = \',0
goodbye     dc.b  'GOOD BYE NOW!  73 de  NO2D',0
pickgadget  dc.b  'Gadget Picked',0
pickitem1   dc.b  'Send Faster',0
pickitem2   dc.b  'Send Slower',0
pickitem3   dc.b  'Switch Code Source',0
pickitem4   dc.b  'Letter Only Toggle Switch',0
playmouse   dc.b  'Playing with your Mouse?',0
   cnop  0,2
cqmssg     dc.b   'cq cq cq de no2d no2d k',0
   cnop  0,4
longnull   dc.b   32,0,0,0,0
   cnop  0,4
hexprint   dc.b   '$ '
hexfield   dc.b   'fedc',0  ;five bytes, four used zero ends it
   cnop  0,4
** A border structure to support the erase routine.
oneline:
  dc.w  0,0    ;left & top offsets
  dc.b  2,2    ;1,2 forground and background pens  ;33333
  dc.b  0      ;jam1 drawing modes
  dc.b  2      ;number of xy coordinates to be drawn
oneline1  dc.l  0    ;where the coordinates are (onelinelist)
  dc.l  0      ;next border structure-null if none
   cnop   0,4
onelinelist:
stx   dc.w  1    ;stuff these with the line starting and ending
sty   dc.w  1    ;coordinates for each line you want to draw
endx  dc.w  1    ;then call the border subroutine with the
endy  dc.w  1    ;oneline border structure address
   cnop    0,4
************** Gadget Rendering Section  **************************;  
image2:
   dc.w   0,0,64,11,1
   dc.l   0   ;image data pointer
   dc.b   1,0
   dc.l   0
   cnop   0,4
image1:
   dc.w   0    ;left
   dc.w   0    ;top
   dc.w   16   ;no. of pixels wide 
   dc.w   14   ;no. of rows high
   dc.w   1    ;bitplane depth 1 or 2 for what I am doing use 1
im1addr   dc.l   0   ;testimage
   dc.b   1    ;PlanePick
   dc.b   0    ;PlaneOnOff
   dc.l   0    ;next image
prop2:
   dc.w   prop1flags 
   dc.w   $3000 ;pi_HorizPot  
   dc.w   $0   
   dc.w   $600   
   dc.w   $0   
   dc.w   20      
   dc.w   20      
   dc.w   500     
   dc.w   500     
   dc.w   0   ;g1left   
   dc.w   0   ;g1top    
prop1:
   dc.w   propflags    ;flags  00
   dc.w   0       ;pi_HorizPot  02
   dc.w   $4000   ;pi_VertPot   04  ;code speed for propgadget
   dc.w   $0      ;pi_HorizBody the portion of the total that will  06
   dc.w   $300    ;pi_VertBody show in the gadget window  08
   dc.w   20      ;pi_CWidth  0a
   dc.w   20      ;pi_CHeight  0c
   dc.w   500     ;pi_HPotRes  0e
   dc.w   500     ;pi_VPotRes  10
   dc.w   gleft   ;pi_LeftBorder  12
   dc.w   gtop    ;pi_TopBorder  14
gadget2:
   dc.l   0        ;ptr to next gadget in list
   dc.w   g1left    ;left edge of gadget relative or absolute
   dc.w   g1top     ;top edge of gadget relative or absolute
   dc.w   g1wide    ;width of the gadget itself
   dc.w   g1high    ;height of the gadget
   dc.w   gadg1flags!gadg1rel   ;flags
   dc.w   RELVERIFY!BOTTOMBORDER    ;!TOPBORDER ;activation
   dc.w   PROPGADGET!GZZGADGET   ;gadget type  (03) & ($2000)
   dc.l   image2   ;ptr- border, image, or none(0)
   dc.l   0   ;select render alternate border, image
   dc.l   0   ;g1itxt   ;gadget text if any
   dc.l   0   ;mutual exclude
   dc.l   prop2   ;special info for prop, string and interger gadgets
   dc.w   1   ;user defined gadget id field
   dc.l   0   ;pointer to user data

gadget1:
   dc.l   gadget2        ;ptr to next gadget in list
   dc.w   gleft    ;left edge of gadget relative or absolute
   dc.w   gtop     ;top edge of gadget relative or absolute
   dc.w   gwide    ;width of the gadget itself
   dc.w   ghigh    ;height of the gadget
   dc.w   gadgflags!gadgrel   ;flags
   dc.w   RELVERIFY!RIGHTBORDER    ;!TOPBORDER ;activation
   dc.w   PROPGADGET!GZZGADGET   ;gadget type  (03) & ($2000)
   dc.l   image1   ;ptr- border, image, or none(0)
   dc.l   0   ;select render alternate border, image
   dc.l   0   ;g1itxt   ;gadget text if any
   dc.l   0   ;mutual exclude
   dc.l   prop1   ;special info for prop, string and interger gadgets
   dc.w   1   ;user defined gadget id field
   dc.l   0   ;pointer to user data
   
**  A NEW WINDOW STRUCTURE - GADGETUP ADDED 8/27/87  **
newwindow:
  dc.w  0,0,640,200   ;Left,Top,Width,Height
  dc.b  0,1           ;DetailPen, BlockPen
  dc.l  CLOSEWINDOW!MENUPICK!GADGETUP         ;!FOLLOWMOUSE;IDCMFlags
  dc.l  MyFlags       ;Flags-described above
  dc.l  gadget1       ;gadget pointer load yours here 
  dc.l  0             ;CheckMark    Default
  dc.l  MyTitle       ;Title-see above
  dc.l  0             ;Screen: 0=Default
  dc.l  0             ;BitMap   Default
  dc.w  50,150,640,200 ;Minwidth,height;Maxwidth,height
  dc.w  WBENCHSCREEN  ;Type- customscreen is more work
  cnop   0,4
onecharbuf  dc.b  0,0,0,0,0,0,0,0  ;buffer for onechar (onecharptr)
   cnop   0,4
timertest dc.b 'Timer.device open and 3 sec delay executed',13,13,10,0   
testmsg  dc.b  ' MORSE CODE TEST PROGRAM  Ver. 1.1',13,10
  dc.b  '   by Peter Inskeep - NO2D',13,10
  dc.b  '   Original dated January 10, 1987',13,10,13,10
  dc.b  ' Type lower case characters on the keyboard.  Each',13,10
  dc.b  ' character should print on the screen and its morse',13,10
  dc.b  ' code will sound through both speakers.',13,10,10
  dc.b  ' Use the Prop Gadgets at the right edge and the bottom of',13,10
  dc.b  ' the window to change sending speed and pitch.',13,10,10
  dc.b  ' Or, use the Menu to send faster or slower,',13,10
  dc.b  ' or to switch between keyboard and random sending.',13,10
  dc.b  ' Choose to send random letters, or also numbers and',13,10
  dc.b  ' punctuation.',13,10,10
  dc.b  ' Learn morse code and become a Ham Radio Operator.',13,10,0

endline   dc.b  13,10,10,0
testbuff dc.b  '0',13,10,0

** Timing counters for dot and dash sound elements
basecounter dc.l  19
charspce    dc.b  2
wordspce    dc.b  7
prtachar    dc.b  0,0,0,0
     cnop   0,4
alphacode:
  dc.b  43            ;44 chars in table [0-43]
  dc.b  '?.,-/=\;'    ;8 char ;=(._._.) \(..._._) ;(_..._)
  dc.b  '0987654321'  ;10 char
  dc.b  'jqyzxcpbvflowgdkurhsmnaite',0  ;26 char
dotdash:
  dc.b  6,%00001100   ; ?
  dc.b  6,%00010101   ; .
  dc.b  6,%00110011   ; ,
  dc.b  5,%00010001   ; -
  dc.b  5,%00010010   ; /
  dc.b  5,%00001010   ; =  .-.-.
  dc.b  6,%00000101   ; \  ...-.-
  dc.b  5,%00010001   ; ;  -...-
  dc.b  5,%00011111   ; 0
  dc.b  5,%00011110   ; 9
  dc.b  5,%00011100   ; 8
  dc.b  5,%00011000   ; 7
  dc.b  5,%00010000   ; 6
  dc.b  5,%00000000   ; 5
  dc.b  5,%00000001   ; 4
  dc.b  5,%00000011   ; 3
  dc.b  5,%00000111   ; 2
  dc.b  5,%00001111   ; 1
  dc.b  4,%00000111   ; j
  dc.b  4,%00001101   ; q
  dc.b  4,%00001011   ; y
  dc.b  4,%00001100   ; z
  dc.b  4,%00001001   ; x
  dc.b  4,%00001010   ; c
  dc.b  4,%00000110   ; p
  dc.b  4,%00001000   ; b
  dc.b  4,%00000001   ; v
  dc.b  4,%00000010   ; f
  dc.b  4,%00000100   ; l
  dc.b  3,%00000111   ; o
  dc.b  3,%00000011   ; w
  dc.b  3,%00000110   ; g
  dc.b  3,%00000100   ; d
  dc.b  3,%00000101   ; k
  dc.b  3,%00000001   ; u
  dc.b  3,%00000010   ; r
  dc.b  4,%00000000   ; h
  dc.b  3,%00000000   ; s
  dc.b  2,%00000011   ; m
  dc.b  2,%00000010   ; n
  dc.b  2,%00000001   ; a
  dc.b  2,%00000000   ; i
  dc.b  1,%00000001   ; t
  dc.b  1,%00000000   ; e
   cnop   0,4  
  SECTION   IMAGEDATA,DATA
beginpubmem:  
theimage:
   dc.w   %1111111111111111
   dc.w   %1100000000000011
   dc.w   %1100000000000011
   dc.w   %1100011111100011
   dc.w   %1100110000110011
   dc.w   %1100110000000011
   dc.w   %1100001111000011
   dc.w   %1100000000110011
   dc.w   %1100000000110011
   dc.w   %1100110000110011
   dc.w   %1100011111100011
   dc.w   %1100000000000011
   dc.w   %1100000000000011
   dc.w   %1111111111111111
imagebytes  equ *-beginpubmem
pitchimage:
 dc.w  %1111111111111111,%1111111111111111,%1111111111111111,%1111111111111111
 dc.w  %1100000000000000,%0000000000000000,%0000000000000000,%0000000000000011
 dc.w  %1100111110000111,%1111100001111111,%1110000001111000,%0001100000110011
 dc.w  %1100110001100000,%1100000001000110,%0010000011000110,%0001100000110011
 dc.w  %1100110001100000,%1100000000000110,%0000000110000000,%0001100000110011
 dc.w  %1100111110000000,%1100000000000110,%0000000110000000,%0001111111110011
 dc.w  %1100110000000000,%1100000000000110,%0000000110000000,%0001100000110011
 dc.w  %1100110000000000,%1100000000000110,%0000000011000110,%0001100000110011
 dc.w  %1100110000000111,%1111100000000110,%0000000001111000,%0001100000110011
 dc.w  %1100000000000000,%0000000000000000,%0000000000000000,%0000000000000011
 dc.w  %1111111111111111,%1111111111111111,%1111111111111111,%1111111111111111
pitchbytes  equ *-pitchimage
   dcb.w   50,1
sizepubmem equ *-beginpubmem
   cnop 0,4
beginaudio:  
Wavesample:
        dc.b 0,32,64,96,120,120,120,120,120,120,120,120
        dc.b 90,64,32,0,-32,-64,-90,-120,-120,-120
        dc.b -120,-120,-120,-120,-120,-120,-96,-64,-32,0
sizeaudio  equ *-beginaudio
  SECTION   mem,BSS
IntuitionLibrary   ds.l  1   ;keep address of Intuition here
GraphicsLibrary    ds.l  1   ;keep address of Graphics here
readbufptr    ds.l  1   ;for conread a 0 term string 
readbuffer    ds.l  100 ;storage for readbufptr
onecharptr    ds.l  1   ;pointer for one character write buffer
bufptr        ds.l  1   ;a general buffer pointer
buffer        ds.l  20  ;a one screen line buffer
;handle        ds.l  1   ;console file read handle
prtbuff       ds.l  25  ;buffer for special print (end in 0)
prtptr        ds.l  1   :pointer for the spec.print buffer
codecntr      ds.l  1   ;counter for code sending
kbcntr        ds.l  1   ;counter for keyboard usage (with codecntr)
ltrcode       ds.l  1   ;store letter number here
carreturn     ds.l  1   ;holds carriage return in linelen
MyWindow      ds.l  1   ;address of the structure describing our window
mywdsize      ds.l  1   ;size of the window 
bucket        ds.l  1   ;a place to dump things
userport      ds.l  1   ;pointer to wd_UserPort structure
myclass       ds.l  1   ;ICDMP Class or equal to flag ie., MENUPICK
menupoint     ds.l  1   ;pointer to menu structure
idcmpmessage  ds.l  1   ;the message class reported by intuimessage
myrport     ds.l   1   ;this windows rastport
secs        ds.l   1   ;seconds in IntuiMessage
micros      ds.l   1   ;microseconds in IntuiMessage
dashsecs    ds.l   1   ;for the dash seconds
dashmicros  ds.l   1   ;for the dash micros
keybuf      ds.l  bufferlen    ;keystroke buffer 
kbptr       ds.l   1   ;keybuf current position pointer
kbendptr    ds.l   1   ;end of keybuf pointer
codeptr     ds.l   1   ;code sending current position (not same as kbptr)
randflag    ds.l   1   ;random flag 1=keyboard 0=random
consoleflag  ds.l  1   ;flag for success opening console 0=success
timerflag   ds.l   1   ;same for timer
letterflag  ds.l   1   ;letter only flag switch
timerbase   ds.l   1   ;see pg b3, Rom Kernal Manual
ioreadbuffer   ds.l   20 ;read buffer 80 characters max
iowritbuf   ds.l   1   ;one char write buffer, but longword
ioreadbuf   ds.l   1   ;one char read buffer, but longword
ioreqptr    ds.l   1   ;pointer to io request block
ranword     ds.l   1   ;a cntr for random word space
memblock    ds.l   1   ;pointer to image data in memory
pitchblock  ds.l   1   ;ptr to pitch image data
audioblock  ds.l   1   ;ptr to audio data block
lastrandom  ds.l   1   ;store the last random # here
counter     ds.l   1   ;a general counter 
timerportptr  ds.l   1   ;pointer to chip reply messageport structure
timeIOTVptr   ds.l   1  ;a pointer to timerequest structure IOTV_
MP_Signalbit  ds.l   1  ;signal bit for the timerportptr
factor        ds.l   1  ;times factor for speed
mousex      ds.w   1   ;x mouse coordinate
mousey      ds.w   1   ;y mouse coordinate
mycode      ds.w   1   ;for things line menu# ie, 0,1,2,3, etc.
infrequency ds.w   1   ;holds sound frequency fm horizpot

   END    
