(FILECREATED "10-Apr-85 11:15:35" {ERIS}<SPEECH>MAILREADER>CALLTEXT>PROSE-PHONE.;14 14940  

      changes to:  (FNS HAS.USER.TIMED.OUT? PROSE.OPERATOR SETUP.PHONE)

      previous date: " 3-Apr-85 18:51:10" {ERIS}<SPEECH>MAILREADER>CALLTEXT>PROSE-PHONE.;11)


(* Copyright (c) 1984, 1985 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT PROSE-PHONECOMS)

(RPAQQ PROSE-PHONECOMS ((FNS NO.WAIT.READ.TTS START.OPERATOR.PROCESS PROSE.OPERATOR 
			     START.CALLTEXT.MONITOR.PROCESS CALLTEXT.MONITOR.PROCESS 
			     HAS.USER.TIMED.OUT? PHONEINPUT.MONITOR READ.TTS READ.DTMF 
			     READ.PHONECONTROL SETUP.PHONE SPEAK FLUSH.ESC.SEQ)
			(VARS OFF.THE.HOOK PHONE.ARM PHONE.AUTO.ANSWER PHONE.DTMF PHONE.HANGUP 
			      PHONE.INIT PHONE.NO.DTMF TTS.STOP)
			(VARS REQUESTED.DATA UNREQUESTED.DATA)))
(DEFINEQ

(NO.WAIT.READ.TTS
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 11:21")
    (PROG (INPUT)
          (SETQ INPUT (fetch (STATE TTSINPUT) of STATE))
          (WITH.MONITOR TTS.LOCK (replace (STATE TTSINPUT) of STATE with NIL))
          (RETURN INPUT])

(START.OPERATOR.PROCESS
  [LAMBDA NIL                                                (* pkh: "19-Dec-84 18:36")

          (* * comment)


    (USEDFREE \PROSE.OPERATOR.PROCESS)
    (COND
      ((AND (BOUNDP (QUOTE \PROSE.OPERATOR.PROCESS))
	    (PROCESSP \PROSE.OPERATOR.PROCESS))              (* Checking to see whether there is a running process 
							     already)
	(replace (STATE OPERATORPROCESS) of STATE with \PROSE.OPERATOR.PROCESS))
      (T [SETQ \PROSE.OPERATOR.PROCESS (ADD.PROCESS (QUOTE (PROSE.OPERATOR]
	 (replace (STATE OPERATORPROCESS) of STATE with \PROSE.OPERATOR.PROCESS])

(PROSE.OPERATOR
  [LAMBDA NIL                                                (* BBB "10-Apr-85 10:47")
                                                             (* Waits for an incoming call;
							     answers, wakes up the touch tone monitoring process;
							     and loops back to the call waiting state)
    (while T bind READ.RESULT
       do                                                    (* Get Acknowledge.)
	  (FLUSH.ESC.SEQ)                                    (* Flush out previous junk.)
	  (SPEAK PHONE.NO.DTMF)                              (* Disable DTMF.)
	  (SETQ READ.RESULT (READ.PHONECONTROL))
	  (SETQ OFF.THE.HOOK T)                              (* The line was seized.)
	  (SETQ READ.RESULT (READ.TTS))                      (* We have finished uttering the greeting.)
	  [if (AND (BOUNDP (QUOTE MAILREADERLOGFILE))
		   (OPENP MAILREADERLOGFILE))
	      then (printout MAILREADERLOGFILE (DATE)
			     ": Call received." T)
	    else (SETQ MAILREADERLOGFILE (OPENFILE (QUOTE {DSK}MAILREADERLOG)
						   (QUOTE APPEND]
	  [if (NOT (OPENP (QUOTE {DSK}NAME.HASH)))
	      then (SETQ MAILREADERUSERSFILE (OPENHASHFILE (QUOTE {DSK}NAME.HASH)
							   (QUOTE BOTH]
	  (P.RESET.TIMER)
	  (IGNORETIMER NIL)
	  (SUSPEND.PROCESS \PROSE.OPERATOR.PROCESS)
	  (printout MAILREADERLOGFILE (DATE)
		    ": Call completed." T])

(START.CALLTEXT.MONITOR.PROCESS
  [LAMBDA NIL                                                (* BBB " 3-Apr-85 15:54")

          (* Starts the process which monitors the RS232 port which is connected to the CallText 5050.0 The process divides up
	  DTMF input and TTS input.)

                                                             (* The handle on this process may not need to be kept)
    (USEDFREE \CALLTEXT.MONITOR.PROCESS)
    (SETQ \TIMEOUTFLG NIL)
    (IGNORETIMER T)
    (COND
      ((AND (BOUNDP (QUOTE \CALLTEXT.MONITOR.PROCESS))
	    (PROCESSP \CALLTEXT.MONITOR.PROCESS))            (* Checking to see whether there is a running process 
							     already)
	(replace (STATE CALLTEXTPROCESS) of STATE with \CALLTEXT.MONITOR.PROCESS))
      (T [SETQ \CALLTEXT.MONITOR.PROCESS (ADD.PROCESS (QUOTE (CALLTEXT.MONITOR.PROCESS]
	 (replace (STATE CALLTEXTPROCESS) of STATE with \CALLTEXT.MONITOR.PROCESS])

(CALLTEXT.MONITOR.PROCESS
  [LAMBDA NIL                                                (* BBB " 3-Apr-85 11:39")
    (while T do (PROG (C ESC.TYPE FINISHED.ESC.SEQ)
		  TOP                                        (* Has the user timed out?)
		      (if (HAS.USER.TIMED.OUT?)
			  then (GO TOP))
		      (SETQ ESC.TYPE NIL)
		      (while (NULL (SETQ C (RS232READBYTE)))
			 do (DISMISS 1000)
			    (if (HAS.USER.TIMED.OUT?)
				then (GO TOP)))              (* Sequence must start with ESCAPE.)
		      (if (NEQ C (CHARCODE ESC))
			  then (GO TOP))
		      (while (NULL (SETQ C (RS232READBYTE)))
			 do (DISMISS 1000)
			    (if (HAS.USER.TIMED.OUT?)
				then (GO TOP)))
		      (SELCHARQ C
				(%[ (SETQ ESC.TYPE (QUOTE TTS))
                                                             (* Mark as a text-to-speech sequence.)
				    )
				(* (SETQ ESC.TYPE (QUOTE PHONE))
                                                             (* Mark as a phone sequence.)
				   )
				(GO TOP))

          (* * Now go through and read to the end of the escape sequence.)


		      (until FINISHED.ESC.SEQ bind CHARACTERS (DTMF.IN ← T)
						   NEGATIVE.FLAG POSSIBLY.MULTIDIGIT
			 do (while (NULL (SETQ C (RS232READBYTE)))
			       do (DISMISS 1000)
				  (if (HAS.USER.TIMED.OUT?)
				      then (GO TOP)))
			    (COND
			      ((AND (IGEQ C (CHARCODE 0))
				    (ILEQ C (CHARCODE 9)))   (* Convert to decimal.)
				(if NEGATIVE.FLAG
				    then (SETQ NEGATIVE.FLAG NIL)
					 [push CHARACTERS (MINUS (IDIFFERENCE C (CHARCODE 0]
					 (SETQ POSSIBLY.MULTIDIGIT T)
				  elseif (EQ ESC.TYPE (QUOTE PHONE))
				    then (push CHARACTERS (IDIFFERENCE C (CHARCODE 0)))
					 (SETQ POSSIBLY.MULTIDIGIT NIL)
				  elseif POSSIBLY.MULTIDIGIT
				    then [push CHARACTERS (PLUS (ITIMES (OR (pop CHARACTERS)
									    0)
									10)
								(IDIFFERENCE C (CHARCODE 0]
				  else (push CHARACTERS (IDIFFERENCE C (CHARCODE 0)))
				       (SETQ POSSIBLY.MULTIDIGIT T)))
			      ((OR (EQ C (CHARCODE *))
				   (EQ C (CHARCODE #)))
				(push CHARACTERS (CHARACTER C))
				(SETQ POSSIBLY.MULTIDIGIT NIL))
			      ((EQ C (CHARCODE -))
				(SETQ NEGATIVE.FLAG T)       (* Mark as negative.)
				(SETQ DTMF.IN NIL)
				(SETQ POSSIBLY.MULTIDIGIT T)
                                                             (* Not a DTMF String.)
				)
			      ((EQ C (CHARCODE ;))
				(SETQ POSSIBLY.MULTIDIGIT (NEQ ESC.TYPE (QUOTE TTS)))
				(SETQ DTMF.IN NIL))
			      (T 

          (* * Assume command argument character. Convert integer to ASCII string for DTMF digits.)


				 [COND
				   ([AND (EQ ESC.TYPE (QUOTE PHONE))
					 DTMF.IN
					 (OR (EQ C (CHCON1 REQUESTED.DATA))
					     (EQ C (CHCON1 UNREQUESTED.DATA]
				     (P.RESET.TIMER)
				     (SETQ \TIMEOUTFLG NIL)
				     (WITH.MONITOR DTMF.LOCK (replace (STATE DTMFINPUT) of STATE
								with CHARACTERS))
				     (PHONEINPUT.MONITOR))
				   [(EQ ESC.TYPE (QUOTE PHONE))
				     (push CHARACTERS (CHARACTER C))
				     (WITH.MONITOR PHONECONTROL.LOCK (replace (STATE 
										PHONECONTROLINPUT)
									of STATE with (DREVERSE
											CHARACTERS]
				   (T (push CHARACTERS (CHARACTER C))
				      (WITH.MONITOR TTS.LOCK (replace (STATE TTSINPUT) of STATE
								with (DREVERSE CHARACTERS]
				 (SETQ FINISHED.ESC.SEQ T])

(HAS.USER.TIMED.OUT?
  [LAMBDA NIL                                                (* BBB "10-Apr-85 11:09")
    (COND
      (\IGNORETIMER NIL)
      ((AND (NOT \IGNORETIMER)
	    (TIMEREXPIRED? P.TIMEOUTTIMER (QUOTE TICKS))
	    (NOT \TIMEOUTFLG))
	(SETQ \TIMEOUTFLG T)
	(P.CHUNK "Please keep pushing the keys to maintain the connection.")
	(P.RESET.TIMER)
	T)
      ((AND (TIMEREXPIRED? P.TIMEOUTTIMER (QUOTE TICKS))
	    \TIMEOUTFLG)
	(SETQ \TIMEOUTFLG NIL)                               (* We want to log the user out so we shall make it look
							     like they logged out themselves.)
	[WITH.MONITOR DTMF.LOCK (replace (STATE DTMFINPUT) of STATE with (QUOTE (*]
	(replace (STATE QUIT) of STATE with T)
	(replace (STATE MESSAGEQUERY?) of STATE with NIL)
	(PHONEINPUT.MONITOR)
	(BLOCK 2000)
	T)
      (T NIL])

(PHONEINPUT.MONITOR
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 15:45")
                                                             (* Wakes up the P.PROCESS whenever a command has been 
							     completed as determined by the contents of PHONEINPUT 
							     and the state of the mailreader)
    (PROG NIL                                                (* Interrupt)
          [COND
	    ((AND (EQ (fetch (STATE STATEINFO TALKING) of STATE)
		      (QUOTE TALKING))
		  (EQ (CAR (fetch DTMFINPUT of STATE))
		      (QUOTE *)))
	      (RETURN (replace (STATE STATEINFO HALTSPEECH) of STATE with T]
          (COND
	    ([OR (EQ (QUOTE #)
		     (CAR (fetch DTMFINPUT of STATE)))
		 (EQ (QUOTE *)
		     (CAR (fetch DTMFINPUT of STATE]
	      (COND
		((PROCESSP (fetch PROCESS of STATE)))
		(T                                           (* There was no live process so we have to start one)
		   (START.PROSE.PROCESS)                     (* Has to block to make sure the process gets started 
							     before we try to wake it in the next statement)
		   (BLOCK 1000)))
	      (WAKE.PROCESS (fetch PROCESS of STATE)
			    T])

(READ.TTS
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 11:21")
    (PROG (INPUT)
          (while (NULL (SETQ INPUT (fetch (STATE TTSINPUT) of STATE))) do (DISMISS 1000))
          (WITH.MONITOR TTS.LOCK (replace (STATE TTSINPUT) of STATE with NIL))
          (RETURN INPUT])

(READ.DTMF
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 11:19")
    (PROG (INPUT)
          (while (NULL (SETQ INPUT (fetch (STATE DTMFINPUT) of STATE))) do (DISMISS 1000))
          (WITH.MONITOR DTMF.LOCK (replace (STATE DTMFINPUT) of STATE with NIL))
          (RETURN INPUT])

(READ.PHONECONTROL
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 11:21")
    (PROG (INPUT)
          (while (NULL (SETQ INPUT (fetch (STATE PHONECONTROLINPUT) of STATE))) do (DISMISS 1000))
          (WITH.MONITOR PHONECONTROL.LOCK (replace (STATE PHONECONTROLINPUT) of STATE with NIL))
          (RETURN INPUT])

(SETUP.PHONE
  [LAMBDA NIL                                                (* BBB " 8-Apr-85 10:06")
    (FLUSH.ESC.SEQ)                                          (* Flush out any old characters.)
    (SPEAK TTS.STOP)                                         (* Check if board is awake.)
    (READ.TTS)                                               (* Get Acknowledge.)
    (printout T " Response from TTS.STOP." T)
    (SPEAK PHONE.INIT)                                       (* Initialize Phone Interface.)
    (READ.PHONECONTROL)
    (printout T " Response from phone init." T)
    (SPEAK PHONE.AUTO.ANSWER)                                (* Send Auto-Answer message which sends the following: 
							     enable DTMF, two seconds of silence, finally a 
							     greeting.)
    (SPEAK PHONE.ARM)                                        (* Arm ring detect to answer pone on incoming calls.)
    (READ.PHONECONTROL)                                      (* Get acknowledge.)
    (printout T " Response from arming phone. " T])

(SPEAK
  [LAMBDA (BUFFER)                                           (* BBB "20-Mar-85 16:37")

          (* * Function: Sends text buffer to CallText 5050; It uses RS232WRITEBYTE to actually send the characters to the 
	  5050; If the character string ends in a period we will pad it with a blank in order to force the speaking of the 
	  last word. If a ↑ is encountered then we assume the next character is to be a nmemonic for a control character.
	  We convert the next character to a control char by anding off the high order three bits of the character.
	  For examle an ESCAPE char is specifed as ↑%[ This providesan easy way to insert non-printable control characters 
	  into string definitions.)



          (* * Arguments: Buffer is a character string.)



          (* * Returns: Nothing.)


    (PROG ((TEMPBUFFER (SUBSTRING BUFFER 1))
	   C)
          [while (SETQ C (GNC TEMPBUFFER)) do (if (EQ C (QUOTE ↑))
						  then       (* Convert the next character to control char.)
						       (RS232WRITEBYTE (LOGAND (CHCON1 (GNC 
										       TEMPBUFFER))
									       31))
						else (RS232WRITEBYTE (CHCON1 C]
          (if (STREQUAL (SUBSTRING BUFFER -1)
			".")
	      then (RS232WRITEBYTE (CHARCODE % )))
          (RS232FORCEOUTPUT T])

(FLUSH.ESC.SEQ
  [LAMBDA NIL                                                (* BBB "22-Mar-85 11:20")
    (RS232CLEARBUFFER (QUOTE INPUT])
)

(RPAQQ OFF.THE.HOOK NIL)

(RPAQQ PHONE.ARM "↑[*3L")

(RPAQQ PHONE.AUTO.ANSWER (
"↑[*%"↑[*1;0;61T↑[[200sThis is the Apr 2nd Interlisp-D mail reader. Please report problems to Becky Burwell. Please log in . %""
			   ))

(RPAQQ PHONE.DTMF "↑[*1;30;1T")

(RPAQQ PHONE.HANGUP "↑[*5L")

(RPAQQ PHONE.INIT "↑[*0L")

(RPAQQ PHONE.NO.DTMF "↑[*0T")

(RPAQQ TTS.STOP "↑[[S")

(RPAQQ REQUESTED.DATA R)

(RPAQQ UNREQUESTED.DATA U)
(PUTPROPS PROSE-PHONE COPYRIGHT ("Xerox Corporation" 1984 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (817 14393 (NO.WAIT.READ.TTS 827 . 1155) (START.OPERATOR.PROCESS 1157 . 1836) (
PROSE.OPERATOR 1838 . 3371) (START.CALLTEXT.MONITOR.PROCESS 3373 . 4390) (CALLTEXT.MONITOR.PROCESS 
4392 . 8273) (HAS.USER.TIMED.OUT? 8275 . 9209) (PHONEINPUT.MONITOR 9211 . 10564) (READ.TTS 10566 . 
10935) (READ.DTMF 10937 . 11310) (READ.PHONECONTROL 11312 . 11717) (SETUP.PHONE 11719 . 12833) (SPEAK 
12835 . 14235) (FLUSH.ESC.SEQ 14237 . 14391)))))
STOP