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
|