From: pshuprs@prism.gatech.EDU (Howlin' Bob)
Newsgroups: comp.sys.hp48
Subject: Re: Syseval to check rx pin state?
Keywords: syseval serial i/o port
Date: 9 Oct 92 19:56:09 GMT
Organization: Georgia Institute of Technology

In article <2ad48043.1862.2comp.sys.hp48.1@hpcvbbs.cv.hp.com> akcs.n2kyw@hpcvbbs.cv.hp.com (Paul Smith) writes:
>As a followup to my earlier posting:
>
>>>Is there a simple syseval or other way to check the state
>>>of the serial port's receive pin from a program?  I want to 
>>>avoid any ml type overhead stuff, so a single syseval would
>>>be ideal.
>>>Thanks
>>>Paul Smith
>>>smit3223@nova.gmi.edu
>
>To which Robert Sanders (pshuprs@prism.gatech.edu) kindly responded:
>
>>Well, Paul, I'm not sure what sort of "overhead" you mean, 
>>except maybe typing...
>
>This particular application does not really need that much speed, 
>though.  The program's purpose is to take morse code input (once
>externally converted to logic "on" and "off") which would be supplied
>to the rx pin as a ttl level (what is it, 0V and -5V ?) and decode
>it to ascii, perhaps putting it on the screen as well.  I can handle
>all the programming required for the decoding (I've fabricated a chip
>before which does this sort of thing), I'm just missing the program
>access to the pin state.

Speed probably isn't important for this, but with long delays
you might miss transitions (i.e. you'll see 1-0-1 as 1).

>
>Any further info would be appreciated, even some ML stuff
>(I guess now's as good a time as any to dive in  :)  )
>

Start diving!
>Thanks
>Paul Smith  (N2KYW)
>smit3223@nova.gmi.edu


[This whole post is about reading the RX pin on the HP48's serial
 port.  If you don't care, then skip it. It's a long one.]

First of all, there are two VERY important locations for doing this.
No, first of all, I need to thank Joe Ervin for the information
I used to do this.  This entire post is basically a paraphrasing of
his work.  Thanks.

Second are the V.I.A.'s (very imp. addresses)
  0x110  (110 hexadecimal)   is  the UART control register
  0x111                      is the serial receive control/status

They are nibble-long memory-mapped IO registers.  When you twiddle
these, you're twiddling hardware.

UART_CONTROL at 0x110:   [SON ETBE ERBF ERBZ]
                       msb                  least significant bit.
   SON=Serial ON. set it to allow the UART to work
       the rest are interrupt control registers explained in the source
       below

SERIAL_STATUS at 0x111:  [RX RER RBZ RBF]
   
   RX corresponds to the state of the receive (RX) line
      (read only - you can hardly change someone else's TX by writing here)
      the rest are explained in the source below.

To read the state of the RX pin, simply set bit 3 of the UART_CONTROL
register and then read bit 3 of the SERIAL_STATUS register. very simple.

This sort of thing is all but useless for real serial IO, as you'd have
to do all sort of timing, jamming bits together in a makeshift shift
register, etc. That's what the hardware boys are for (and, of course, the
UART - Universal Asynchronous Rabbit Tamer...sorry I forgot the last two
letters. Basically, a serial line->Byte device)

A program follows which does some neat stuff for monitoring the RX pin
THe poster (Paul) who asked about this plans on using the RX pin for
morse code applications. This would be simple. Sort of. I guess
you'd have to debounce.

I don't remember the CSHP48EX format (sorry), but here's the program in 
asc-> format:

----------------CUT HERE----------------------------------
%%HP: T(1)A(R)F(.); @ tasc v2.52 file
"D9D20EA431C2A203200014C41425D402D2D2D2D2D2D2022585B5421C2A209200
0C435A302252464020202022535A3022524A5B7421C2A203100014A302022554
25B8421CCD20651008FB97601BCD40780820F1580808F80821081B9760715801
F0110030815D01701BB01001581840841340000010815F0808B39315A0808736
116080820815801806B1016080820A1580180110E410015C0808A2F287051850
8082485200D86810CD8AD011B311001580840808A0C2871218513485200D7681
0CF8AF011B4110015A18411B9760715E090ED01BB01006D3F1BCD40780820015
8080801F0110030015D08F2D7608DF7530FBD81B2130B722"
@ BYTES: #227Bh 246
----------------CUT HERE----------------------------------


And here's the source code for it.
This is also the documentation. :-)
I wrote this using the HP tools, and in HP mnemonics.
They're really kind of aesthetic once you're accustomed to them.

save this file as "chkrx.s"
----------------CUT HERE----------------------------------
******************************************************************
** CHKRX  
**
** -Sample program that checks RX pin of serial port
**  I show all the UART status bits on these annunciators:
**
**  LowBat	bRX	( rx pin high, i hope )
**  RightShift	bRBZ	( receiver busy )
**  LeftShift	bRBF	( receive buffer full )
**  Alpha	bRER	( receive error??? )
**  IO			( last 0 was a one->zero transition )
**
** - press ON (ATTN) to exit
** 
**  INPUT:   none
**
**  OUTPUT:  1: zeroes%	    ( number of zeroes on RX )
**	- this number refers to how many one->zero transitions occurred
**
**
** COMMENTS:  try typing quickly to watch the error (alpha) come on
**            is you run this with normal serial IO, the RX 
**	      annunciator ((*)) never seems to go off. i don't
**	      know much about serial IO, but that tells me that
**            RX=1 is an idle condition
**
** 10/9/92 - Robert Sanders
**           any questions, comments, etc. e-mail to
**   pshuprs@prism.gatech.edu      or   gt8134b@prism.gatech.edu
******************************************************************

ASSEMBLE
    NIBASC \HPHP48-E\

** misc UART addresses
CRER 	EQU	#113	( write here to clear RER )
RBF	EQU	#114	( 2-nibble, receive buffer )

** STATUS SERVICE DELAY CONSTANTS
**
** these allow the RER and RBF annunciators and status bits to
** stay set for a while, then be cleared.  the numbers are
** #'s of iterations before clearing, and the translation of
** loops->clock cycles->milliseconds will vary slightly with
** your HP48, and also with which bits get set 
**
** there is no hardware reason to do this, but you need this
** to see any results.
** the side effect is, a character received isn't taken out of
** the receive buffer for 600 loop iterations (it can easily
** choke at 9600 baud.)

RERCOUNT EQU 600
RBFCOUNT EQU 600	

**  UART status bits (at addr #111)
bRBF	EQU	0	( receive buffer full	)
bRBZ	EQU	1	( receiver busy		)
bRER	EQU	2	( receive error?	)
bRX	EQU	3	( rx pin high????	)

** UART control bits
bERBZ	EQU	0	( enable interrupt for RBZ?  )
bERBF	EQU	1	( enable interrupt for RBF?  )
bETBE	EQU	2	( I'd say TransmitBufferEmpty, but dunno )
bSON	EQU	3	( enable UART I/O - SerialON )

** ST bits used
sRER	EQU	0
sRBF	EQU	1
RPL

*============================================================*
*                 RPL STARTS HERE                            *
*============================================================*
::
   CLEARVDISP
   $ "ALARM ------ RX"		DISPROW1
   $ "LS: RBF    RS: RBZ"	DISPROW3
   $ "A:  RER"			DISPROW4 

   CODE
	gosbvl	=SAVPTR		* save regs
	d0=(5)	=DISABLE_KBD
	la(1)	#F
	dat0=a	1		* disable keyboard polling (flag)
	INTOFF			* shut off keyboard interrupts

	la(2)	#80
	d0=(5)	=ATTNFLG
	dat0=a	1		* init to 0 ON key presses

************************************************************
***********************  ROM INFO  *************************
************************************************************
* here's what OpenUartClr at #3161e (PMC) does to setup
* it sets ERBF (enable receive buffer full interrupt?)
*         ERBZ (enable receiver busy interrupt?)
*	  SON  (SerialON - enable UART I/O)
*
*	d1=(5)	#110
*	lc(1)	#b		* sets SON, ERBF, ERBZ 
*	dat1=c	4
************************************************************

* the following is iffy
	d1=(5)	=IOC		* IOControl register (UART control) 
	lc(1)	2^bSON		* set bSON bit
	dat1=c	1

	d1=d1+	1		* serial receive control/status at #111h

	d0=(5)	=ANNCTRL	* annunciator contol (bit 2=ALPHA)
	dat0=a	2		* turn all annunciators off, but leave
				* enabled (a should be 80 here)

	st=0	sRER		* no RER condition yet
	st=0	sRBF		* no RBF condition yet

	lc(5)	0
	r0=c	a
	
** in this loop, D1 points to the RX status mibble
**               D0 points to the annunciator control nibble upon
**		    entry (and loop), but changes
**	         R0 counts zeroes on RX
**               ST<0> indicates RER condition unserviced
**	         ST<1> indicates RBF condition unserviced
**		  B holds counter for clearing RER. at b=0, clears
**		  D holds counter for clearing RBF. at b=0, clears
**

mloop	c=dat1	1		* get RX status nibble
	?cbit=1	bRX
	goyes	postzero	* after zero processing

** this code does "zero processing"
**   if RX=0 last time, the IO annunciator is cleared
**   if RX=1 last time, the IO annunciator is set and the zero counter
**			is incremented. this flags a one->zero transition
**
** the zero counter is kept in R0
**
	a=dat0	1		* get old annunciators
	?abit=1	bRX		* RX ann was set, so transition occurred
	goyes	trans	
notrans				* comes here if RX is zero,
				* but RX was zero before
	d0=d0+	1		* point to ANN2
	la(1)	8		* ANN_ON=8, IO_ANN=2
	dat0=a	1
	d0=d0-	1		* point back to ANNCTRL (ANN1)
	goto	postzero

trans
	d0=d0+	1		* point to ANN2
	la(1)	10		* ANN_ON=8, IO_ANN=2
	dat0=a	1
	d0=d0-	1		* point back to ANNCTRL (ANN1)
	a=r0	a		* increment 0 counter
	a=a+1	a		* ..
	r0=a	a		* ..

** post "zero processing"
postzero			
	dat0=c	1		* drive RX status onto annun.

	?cbit#1	bRER		* if no RER condition, check RBF
	goyes	chkrbf

*************** service RER **************
chkrer	?st=1	sRER
	goyes	cntrer
	st=1	sRER		* flag the new RER
	la(5)	RERCOUNT	* times to countdown before clearing
	b=a	a
	goto	chkrbf
cntrer	b=b-1	a 		* service old RER
	?b#0	a
	goyes	chkrbf		* not displayed long enough yet
	d0=(5)	CRER		* address to clear RER
	dat0=a	1		* any value will clear
	st=0	sRER		* mark old RER condition gone

*************** service RBF **************
chkrbf	?cbit#1	bRBF		* no RBF condition
	goyes	chkattn	
	?st=1	sRBF
	goyes	cntrbf
	st=1	sRBF		* flag the new RBF
	lc(5)	RBFCOUNT	* times to countdown before clearing
	d=c	a
	goto	chkattn
cntrbf	d=d-1	a 		* service old RBF
	?d#0	a
	goyes	chkattn		* not displayed long enough yet
	d0=(5)	RBF		* address of receive buffer
	a=dat0	2		* get buffered byte
	st=0	sRBF		* mark old RBF condition gone

chkattn
	d0=(5)	=ATTNFLG
	c=dat0	1		* get annctrl nibble
	?c#0	p		* ON pressed yet?
	goyes	done		* exit program
	d0=(5)	=ANNCTRL
	goto	mloop

** get us back to the normal system state
done	d0=(5)	=DISABLE_KBD
	la(1)	0
	dat0=a	1		* enable keyboard polling
	INTON
	d1=(5)	=IOC		* IOControl register (UART control) 
	lc(1)	0		* clear all, especially bSON 
	dat1=c	1 		* (turn serial I/O off)

	gosbvl	=GETPTR		* restore RPL registers
	govlng	=PUSH#LOOP	* pushes R0 as sysbin and reenter
				* RPL main loop
   ENDCODE


   UNCOERCE			( turn # into real )
;
 
----------------CUT HERE----------------------------------



WE'RE BACK!!!
and this is the loader control file.
save it as "chkrx.m"

----------------CUT HERE----------------------------------
SUpress XRef LXref
OUtput chkrx
OPtion COde 
LIst  UNresolved 
SEarch entries.o
RElocate chkrx.o
----------------CUT HERE----------------------------------


From then on, follow the standard procecure for compiling.
I hope this helps someone!


Robert


-- 
Robert Sanders 
Georgia Institute of Technology
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!pshuprs
Internet: pshuprs@prism.gatech.edu     OR  gt8134b@prism.gatech.edu
Newsgroups: comp.sys.hp48