UART Module

The UART is used to simulate a telephone link to the outside world. When an alarm is triggered with the "send phone message" option enabled, a bit is set in one of the corresponding status bytes. The job of determining the highest priority message is done by U_next, which updates the pointer u_message. U_message points to the next byte to be sent, and is incremented by the interrupt after each send. The interrupt is triggered by the TxEmpty pin on the Uart, and so is called after each character is sent.

However, most of the time there is nothing to be sent, and so the interrupt will not do anything. This means that the TxEmpty pin does not make a high/low change (because nothing was sent so it stayed in the empty state), and so the interrupt stops being called. Therefore the kickstart procedure is required to force a call of the interrupt. The flag U_active determines whether or not a message is currently being sent, and hence whether the interrupt needs a forced call to begin retransmitting.

Download:
; /////////////////////////////////////////////////////////// ; // Security system Uart Module ; // (c) 1999 Geoff Knagge, Andrew Carr, Mark Lynn ; // last modified : 22/10/1999 ; // ; /////////////////////////////////////////////////////////// u_masks: .byte 01,02,04,08,10,20,40,80; ub_panic: .byte 0 ; These variables are flags to set which ub_smoke: .byte 0 ; doors, windows, etc have had alarms ub_windows: .byte 0 ; triggered but have not had their ub_doors: .byte 0 ; UART message sent. ub_edoors: .byte 0 ; edoors refers to doors connecting outside u_nomsg: .byte 0 ; a dummy message when there's nothing ; being sent. u_firemsg: .ascii '--------------- ' ; dashes replaced by phone number u_stime: .ascii 'xx:xx.xx Fire alarm triggered in the Virtual Office' .ascii ' Complex.' .byte 0D,0A,0 u_panicmsg: .ascii '--------------- ' u_ptime: .ascii 'xx:xx.xx Panic alarm triggered in the Virtual Office' .ascii ' Complex.' .byte 0D,0A,0 u_doormsg: .ascii '--------------- ' u_dtime: .ascii 'xx:xx.xx Internal door #' uid_dID: .ascii '?' .ascii ' violated in zone ' uid_zId: .ascii '?' .ascii ' of the Virtual Office Complex' .byte 0D,0A,0 u_edoormsg: .ascii '--------------- ' u_edtime: .ascii 'xx:xx.xx External door #' ued_dID: .ascii '?' .ascii ' opened and not disarmed during timeout in zone ' ued_zId: .ascii '?' .ascii ' of the Virtual Office Complex' .byte 0D,0A,0 u_winmsg: .ascii '--------------- ' u_wtime: .ascii 'xx:xx.xx Window #' uw_wID: .ascii '?' .ascii ' violated in zone ' uw_zId: .ascii '?' .ascii ' of the Virtual Office Complex' .byte 0D,0A,0 uartc= 21 uartd= 20 u_message: .word u_nomsg u_time: .byte 0 u_copytime: ; copies c_ascii to BC push af push de push hl push bc mvi a,0 sta u_time ; reset counter lxi de,c_ascii u_ctloop: cpi 2 jz nouw mov h,d mov l,e ; hl=de mov a,m mov h,b mov l,c ; hl=bc mov m,a nouw: inx bc inx de lda u_time inr a sta u_time cpi 8 jnz u_ctloop pop bc pop hl pop de pop af ret u_next: ; finds the highest priority alarm and ; sends a message for it lda ub_smoke cpi 0 jnz um_sm lda ub_panic cpi 0 jnz um_pa lda ub_windows cpi 0 jnz um_win lda ub_doors cpi 0 jnz um_idoor lda ub_edoors cpi 0 jnz um_edoor jmp un_j1 ;///////////////////////// external door message um_edoor: call firstbit ; find the first door alarmed - alarms.asm mov a,c adi 31 ; convert door number to ASCII sta ued_did ; save in message call SDgCtZone ; get controlling zone adi 31 ; convert to ASCII sta ued_zid ; save in message lxi hl,u_masks dad bc lda ub_edoors xri 0FF ; invert all bits ora m ; set the appropriate bit xri 0FF ; revert all bits - window is now cleared sta ub_edoors lxi hl,u_edoormsg shld u_message lxi bc,u_edtime call u_copytime lxi BC,ph_intrusion mov d,h mov e,l call ph_d2a; ; converts data at BC to ascii at DE, modes.asm ret ;///////////////////////// internal door message um_idoor: call firstbit ; find the first door alarmed mov a,c adi 31 ; convert door number to ASCII sta uid_did ; save in message call SDgCtZone ; get controlling zone adi 31 ; convert to ASCII sta uid_zid ; save in message lxi hl,u_masks dad bc lda ub_doors xri 0FF ; invert all bits ora m ; set the appropriate bit xri 0FF ; revert all bits - window is now cleared sta ub_doors lxi hl,u_doormsg shld u_message lxi bc,u_dtime call u_copytime lxi BC,ph_intrusion mov d,h mov e,l call ph_d2a; ; converts data at BC to ascii at DE, modes.asm ret ;///////////////////////// window message um_win: call firstbit ; find the first window alarmed mov a,c adi 31 ; convert window number to ASCII sta uw_wid ; save in message call SWgCtZone ; get controlling zone adi 31 ; convert to ASCII sta uw_zid ; save in message lxi hl,u_masks dad bc lda ub_windows xri 0FF ; invert all bits ora m ; set the appropriate bit xri 0FF ; revert all bits - window is now cleared sta ub_windows lxi hl,u_winmsg shld u_message lxi bc,u_wtime call u_copytime lxi BC,ph_intrusion mov d,h mov e,l call ph_d2a; ; converts data at BC to ascii at DE, modes.asm ret ;///////////////////////// smoke message um_sm: lxi hl,u_firemsg shld u_message lxi bc,u_stime call u_copytime lxi BC,ph_fire mov d,h mov e,l call ph_d2a; ; converts data at BC to ascii at DE, modes.asm mvi a,0 sta ub_smoke ret ;///////////////////////// panic message um_pa: lxi hl,u_panicmsg shld u_message lxi bc,u_ptime call u_copytime lxi BC,ph_panic mov d,h mov e,l call ph_d2a; ; converts data at BC to ascii at DE, modes.asm mvi a,0 sta ub_panic ret ;///////////////////////// jmp un_j1 un_j2: lxi hl,u_nomsg un_j1: shld u_message ret u_init: push af mvi a, 00010001# ; dummy mode out uartc mvi a, 01000000# ; reset command out uartc ; ensure it's reset mvi a, 01001001# ; 1 stop bit, 1* baud rate factor, no parity out uartc mvi a, 00010001# ; command word - turn tx on out uartc pop af ret u_kickstart: ; since the interrupt is called by the ; uart empty signal, when it runs out of things ; to send, the interrupt will stop being called ; Therefore, we need to kick start it when a ; new message comes through. lda u_active cpi 1 jz u_Kend call u_next di call u_interrupt U_kend: ret u_active: .byte 0; 1 = sending messages ; 0 = sent all messages, idle. u_interrupt: push af push bc push de push HL mvi a,63 ; enable interrupts out 80 mvi a,1 sta u_active lhld u_message ; put current message address in HL mov a,m ; put character into the accumulator cpi 00 jz uij1 ; jumps if no more characters u_send: out uartd ; send character to the uart data buffer inx HL ; increment pointer shld u_message ; store pointer jmp u_int_end ; end uij1: call u_next ; called when we're at the end of a msg lhld u_message mov a,m cpi 0 jnz u_send sta u_active ; set "uart waiting" flag jmp u_int_end ; end u_int_end: ei pop HL pop de pop bc pop af ret u_fire: push af mvi a,1 sta ub_smoke call u_kickstart; pop af ret u_panic: push af lda panicmode ani 2 ; check the UART message bit cpi 0 jz u_pj1 ; not set, so no message ;////////////// send the UART message here mvi a,1 sta ub_panic call u_kickstart ;////////////// u_pj1: pop af ret u_intrusion: ; e = type : 2=windows ; 3=internal door ; 4=timeout expired ; c = door/window number, 0=first push af lda intrusionmode ani 2 ; check the UART message bit cpi 0 jz u_ij1 ; not set, so no message ;////////////// send the UART message here mov a,e cpi 2 jz u_win cpi 3 jz u_ido push bc ; it's an external door! push hl mvi b,0 lxi hl,u_masks dad bc lda ub_edoors ora m ; set the bit sta ub_edoors pop hl pop bc jmp u_ij1 u_ido: push bc ; it's an internal door! push hl mvi b,0 lxi hl,u_masks dad bc lda ub_doors ora m ; set the bit sta ub_doors pop hl pop bc jmp u_ij1 u_win: push bc ; it's a window! push hl mvi b,0 lxi hl,u_masks dad bc lda ub_windows ora m ; set the bit sta ub_windows pop hl pop bc ;////////////// u_ij1: call u_kickstart pop af ret

This is page designed, maintained and
(C)opyright 1999 by Geoff Knagge