; ; Program: HCSII Firmware w/ Z8S180 support ; ; Author: Ken Davidson ; Modified by Jeff Bachiochi (3.61/3.62) ; Modified by Mike Baptiste (3.63 -> ) ; ; Date: May 1, 2000 ; Version: 4.01 ; ; Copyright (c) 1999-2000 - Creative Control Concepts ; Copyright (c) 1992-1998 - Ken Davidson / Circuit Cellar ; ; All Rights Reserved ; ; Version 4.10 -- June 15, 2000 MSB ; -- Add support for Stat-Link interface ; ; Version 4.01 -- May 1, 2000 MSB ; -- Rewrote modem wtreply routine to handle any # of leading CRs ; -- Updated Modem Init String to handle more modems ; -- Updated CID code to handle MDMF format CID data ; -- Make CID Name data available for messages via %N ; -- Add flag %S for fixed size value displays with leading 0's ; -- Store incoming phone number in buffer for use in strings (%M) ; ; Version 4.00 -- January 5, 2000 MSB ; -- Add support for Z8S180 CPU w/faster clock & ASCI Tx/Rx FIFOs ; ; Version 3.63 -- December 25, 1999 MSB ; -- Fixed LCD Y2K problem - changed '19' to '20' ; -- Added deliberate DTMF ring latch reset during init ; ; Version 3.62 -- December 14, 1998 JLB ; -- Answer MAN bad checksum calculation ; @ totclr (add cr to end of string) ; @ pwmmsg (add cr to end of string) ; @ dirmsg (add cr to end of string) ; ; Version 3.61 -- October 19, 1998 JLB ; -- Answer MAN 8-bit ADC support bug fix (@ $AIN,$5) ; ; Version 3.60 -- March 9, 1998 ; -- Answer MAN support bug fixes ; -- Add timeout code to HCS-PLIX support ; ; Version 3.51 -- May 8, 1997 ; -- First pass at HCS-PLIX support ; ; Version 3.50 -- April 11, 1997 ; -- Final Answer MAN release ; ; Version 3.05 -- November 3, 1996 ; -- First pass at Answer MAN support ; -- Remove ADIO support ; ; Version 3.02 -- August 6, 1995 ; -- Fix ADIO netbit numbering ; -- Fix ADIO poll numbering on ADIO timeout ; ; Version 3.01 -- June 10, 1995 ; -- Fix bad storage of user-entered netbit value ; -- Fix PL-Link receive bug ; -- Fix final ELSE bug ; -- Modify network timing slightly ; ; Version 3.00 -- March 16, 1995 ; -- Release version ; ; Version 2.70 -- Interrupt disable at end of network transmission ; -- Fix DTMF LED polarity ; Version 2.69 -- Power fail with PLIX, PL-Link, hang bug fix attempt ; -- Program too big reply ; Version 2.68 -- Network module display, set netbit, set ADC, network string ; Version 2.67 -- Version check, LogSize, NetByte, MCIR netbit ; Version 2.66 -- ADC, DAC ; Version 2.65 -- Bugs, more HOST interface ; Version 2.64 -- Bugs, further modem support ; Version 2.63 -- Caller ID ; Version 2.62 -- Console message support ; Version 2.61 -- New network timeout code ; Version 2.60 -- First pass at PC-controlled status display ; ; Version 2.50 -- February 17, 1994 ; -- First pass at adding CS support ; ; Version 2.10 -- December 20, 1993 ; -- Release version ; ; Version 2.00 -- March 3, 1993 ; -- Release version ; ; Version 1.20 -- November 12, 1992 ; -- Add TV-Link support ; -- Add MCIR support ; -- Fix GIF reset bug ; ; Version 1.01 -- Fix BUFIO initialization ; -- Fix AllLightsOn/AllUnitsOff ; -- Fix ADC reset bug ; ; Version 1.0 -- March 17, 1992 ; -- Release version ; symbols globals on ; ver equ 4 subver equ 10 ; false equ 0 true equ .not.false ; test equ false ; procspd equ 12 ; 2:3.072, 3:4.608, 4:6.144, ; ; 6:9.216, 8:12.288 MHz. 12:18.423 ; include ports.lib ; Z180 on-chip ports include osmacro.asm ; RTOS macros ; ; Development memory map: ; 00000 - 07FFF: Bank Monitor ROM ; 08000 - 0FFFF: Bank SC executable code ; 10000 - 18000: Common 1 Log RAM ; 18000 - 1FFFF: Common 1 Battery-backed RAM ; ; Production memory map: ; 00000 - 07FFF: Bank EPROM ; 08000 - 0FFFF: Common 1 Log RAM ; 18000 - 1FFFF: Common 1 Battery-backed RAM ; if test cbarc equ 80h ; CBAR constant bbrc equ 08h ; BBR constant cbrl equ 08h ; CBR for logging cbrc equ 10h ; CBR constant else cbarc equ 80h ; CBAR constant bbrc equ 00h ; BBR constant cbrl equ 00h ; CBR for logging cbrc equ 10h ; CBR constant endif ; port1 equ 08000h ; RTC: on board port2 equ 0a000h ; RTC: BUFIO/50 port3 equ 0a010h ; RTC: BUFIO/50 port4 equ 0c800h ; BCC: on board port5 equ 0c900h ; BCC: on board port6o equ 0ef00h ; BCC: BCC54 port7o equ 0ee00h ; BCC: BCC54 port8o equ 0ed00h ; BCC: BCC54 port9o equ 0ec00h ; BCC: BCC54 port6i equ 0eb00h ; BCC: BCC54 port7i equ 0ea00h ; BCC: BCC54 port8i equ 0e900h ; BCC: BCC54 port9i equ 0e800h ; BCC: BCC54 port10 equ 0a020h ; RTC: BUFIO/50 port11 equ 0a030h ; RTC: BUFIO/50 ; pia1 equ 08000h ; CS: 6821 pia2 equ 08100h ; CS: 6821 pia3 equ 08200h ; CS: 6821 pia4 equ 08300h ; CS: 6821 clock equ 08400h ; CS: 6242 RTC phone equ 08500h ; CS: DTMF base port wdog equ 08600h ; CS: Watchdog trigger ; rtcadc equ 09000h ; RTC: ADC base port bcc13 equ 09000h ; BCC: BCC13 base port bcc30 equ 09800h ; BCC: BCC30 base port ; dtmf equ 0a040h ; RTC: DTMF base port dtmfctl equ dtmf ; Control port dtmfsts equ dtmf+10h ; Status port dtmfxcv equ dtmf+20h ; M8888 chip voice equ 0a080h ; RTC: Voice base port vdata equ voice ; Data port vstat equ voice+10h ; Status port vreset equ voice+20h ; Reset port ; pia5 equ 0a0c0h ; RTC: PLIX 6821 chip ; lf equ 10 cr equ 13 esc equ 27 alert equ '!' ack equ '^' reply equ '$' badver equ '#' toobig equ '@' curtime equ 80h x10stat equ 81h inpstat equ 82h outstat equ 83h adcstat equ 84h dacstat equ 85h modstat equ 86h netstat equ 87h msg equ 88h ; scrtc equ 1 ; RTC180 as SC scbcc equ 2 ; BCC180 as SC sccs equ 3 ; CS as SC ; alloff equ 1 ; X-10 function codes allon equ 2 on equ 3 off equ 4 dim equ 5 bright equ 6 ona equ 83h ; ifa equ 0f0h ; Event operators and operands ifn equ 0f1h elseop equ 0f2h ; oparen equ 70h cparen equ 71h andf equ 72h orf equ 73h notf equ 74h addf equ 75h subf equ 76h mulf equ 77h divf equ 78h stopm equ 0fch ; End of math equation stop equ 0fdh ; End of IF portion ; last equ 0feh ; End of actions in THEN portion ; endcont equ 0efh ; End of cont. section, start of seq. section endpgm equ 0eeh ; End of program endtbl equ 0ffh ; End of events table ; stksiz equ 128 ; Task stack size tbufsiz equ 96 rbufsiz equ 192 ; Must be <256! ; stmrs equ 64 ; Seconds timers (0-63) mtmrs equ 64 ; Minutes timers (64-127) tmrstor equ 0 ; ((stmrs + mtmrs) * 2) mod 256 ; modtyp equ 6 ; Six kinds of network modules supported modnum equ 8 ; Up to eight of each kind ; ntasks equ 14 ; inb macro reg,port ld bc,port in reg,(c) endm ; outb macro port,reg ld bc,port out (c),reg endm ; CODE ; start: di ld sp,t0sp ; if test ld a,0 ; Initialize MMU out0 (cbr),a ; Map 0000-7FFF and 8000-FFFF ld a,cbarc ; to same physical memory out0 (cbar),a ; (08000-0FFFF) ld a,bbrc out0 (bbr),a jp st ; Jump to low logical memory st: ld a,cbrc ; (same physical memory) out0 (cbr),a ; else ld a,cbarc ; Initialize MMU out0 (cbar),a ld a,bbrc out0 (bbr),a ld a,cbrc out0 (cbr),a endif ; jp $0 ; Skip over ident string ; db 'Creative Control Concepts Home Control System II--' db 'Supervisory Controller--Version ' db ver+'0','.',(subver/10)+'0',(subver.mod.10)+'0' db '--Copyright (c) 1992-1998, Circuit Cellar Inc.' db '--Copyright (c) 1999-2000 Creative Control Concepts' ; $0: call initchip ; Initialize rest of Z180 call initstor ; Clear local storage call initx10m ; Clear X-10 module state storage call clredge ; Clear input edge table call initints ; Set up interrupt stuff ; ld a,(verstor) ; Get stored version number cp ver ; Same as this one? jr nz,$1 ; Nope, clear storage ld a,(sverstor) ; Get stored subversion number cp subver ; Same as this one? jr nz,$1 ; Nope, clear storage ; call initevtbl ; Clear all done flags in events table call sumevents ; Sum event storage ld hl,power add a,(hl) ; Match correct checksum? jr z,$2 ; Yes, don't initialize tables $1: call clrtbl ; No, clear table and hardware defs call inittmrs ; Set all timer states to off call initvars ; Set all variables to zero call getsc ; Determine SC type $2: call inithard ; Set up on-board hardware ld a,0ffh ld (rstflg),a ; Flag that we just reset ld a,1 ; Default time display to every second ld (dtimem),a ld a,ver ; Store current version number ld (verstor),a ld a,subver ; Store current subversion number ld (sverstor),a ; rt_init ; rt_define task1,t1sp,0,33,1 ; Evaluater task rt_define task2,t2sp,0,33,2 ; Secondary eval task rt_define task3,t3sp,0,33,3 ; Read SmartWatch task rt_define task4,t4sp,0,33,4 ; Read inputs and ADC task rt_define task5,t5sp,0,33,5 ; Host interface task rt_define task6,t6sp,0,33,6 ; Spare task rt_define task7,t7sp,0,33,7 ; Network manager task rt_define task8,t8sp,0,33,8 ; PL-Link server task rt_define task9,t9sp,0,33,9 ; LCD-Link server task rt_define task10,t10sp,0,33,10 ; IR-Link server task rt_define task11,t11sp,0,33,11 ; DIO-Link server task rt_define task12,t12sp,0,33,12 ; MAN-Link server task rt_define task13,t13sp,0,33,13 ; DIO+-Link server task ; call ticsoff ; rt_run 1,1 ; Task 2 is run only when needed rt_run 3,100 rt_run 4,10 rt_run 5,10 ; rt_run 6,50 ; Spare rt_run 7,2 rt_run 8,48 rt_run 9,49 rt_run 10,51 rt_run 11,52 rt_run 12,53 rt_run 13,54 ; ld a,(sc) ; Check SC or a jr z,$9 ; Skip if not defined ld a,(numpl) ; PL-Link defined? or a jr nz,$9 ; Yes, skip rt_run 8,20 ; Assume PLIX, so run task more often ; $9: call ticson ; loop: jr loop ; page ; ;========================================================================= ; ; T A S K 1 ; ; Event Evaluation Routines ; ; ; Evaluate the event list starting at 'events'. ; task1: ld sp,t1sp top1: call copytbls ; Copy primary storage tables ; to secondary storage for testing ; call toggle1 ; Toggle output bit dolist: ld ix,events $0: ld a,(ix) ; Empty table? cp endtbl jp z,lstdone ; Yes, leave cp endcont ; Empty cont section? jr nz,lstloop ; No, continue inc ix ; Move past marker jr $0 ; Try starting again lstloop: ld b,(ix) ; Save IF/IFA opcode inc ix ; Skip over opcode call eval ; Evaluate condition jr z,skip ; Skip if equation is false ; ld c,(ix) ; Get "already done" flag ld (ix),0ffh ; Mark action done inc ix ; Point to offset ld a,b ; Check opcode cp ifa ; IF always? jr z,$1 ; If so, skip done flag test ld a,c ; Check done flag or a jr z,$1 ; Not done, so do it ld e,(ix) ; Was done, so skip over it inc ix ; Get low byte of offset ld d,(ix) ; Get high byte of offset inc ix add ix,de ; Skip over action ld a,(ix) ; Get LAST or ELSE inc ix ; Move past code cp elseop ; ELSE? jr nz,lst3 ; Nope inc ix ; Also skip the ELSE, so point to offset jr sk2 ; Skip the ELSE $1: inc ix ; Move past offset inc ix call action ; Do it jr lst3 ; Continue ; skip: ld (ix),0 ; Mark as not done inc ix ; Point to the offset ld e,(ix) ; Get low byte of offset inc ix ld d,(ix) ; Get high byte of offset inc ix add ix,de ; Skip over action lst2: ld a,(ix) ; Get LAST or ELSE inc ix ; Move past code cp elseop ; ELSE? jr nz,lst3 ; Nope ; ld c,(ix) ; Get "already done" flag ld (ix),0ffh ; Mark action done inc ix ; Point to offset ld a,b ; Check opcode cp ifa ; IF always? jr z,$1 ; If so, skip done flag test ld a,c ; Check done flag or a jr nz,sk2 ; Skip if normal IF and already done $1: inc ix ; Move past offset inc ix call action ; Do it jr lst3 ; Continue sk2: ld e,(ix) ; Get low byte of offset inc ix ld d,(ix) ; Get high byte of offset inc ix add ix,de ; Skip over action inc ix lst3: ld a,(ix) ; Check for end of list cp endtbl jr z,lstdone ; Yes, finish up this pass cp endcont ; End of cont section? jp nz,lstloop ; No, keep going inc ix ; Move past the marker jp lstloop ; Keep going lstdone: ld a,0 ld (rstflg),a ; No more reset state jp top1 ; ; Copy primary input and edge tables to secondary storage ; for use during pass through equation list. Do both local ; and netbit tables. ; copytbls: ld ix,input1 ; Primary ld iy,input2 ; Secondary ld hl,edge1 ; Primary ld de,edge2 ; Secondary ld b,0 $1: di ld a,(ix) ld (iy),a ld a,(hl) ; Clear primary during the ld (hl),0 ; copy ld (de),a ei inc ix inc iy inc hl inc de djnz $1 ; ; Now do netbit tables ; ld ix,netbit1 ; Primary ld iy,netbit2 ; Secondary ld hl,nedge1 ; Primary ld de,nedge2 ; Secondary ld bc,0002h ; Do 512 netbits $2: di ld a,(ix) ld (iy),a ld a,(hl) ; Clear primary during the ld (hl),0 ; copy ld (de),a ei inc ix inc iy inc hl inc de djnz $2 dec c jr nz,$2 ret ; savetbls: ld ix,input2 ; Secondary ld iy,input3 ; Storage ld hl,edge2 ; Secondary ld de,edge3 ; Storage ld b,0 $1: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $1 ; ; Now do netbit tables ; ld ix,netbit2 ; Secondary ld iy,netbit3 ; Storage ld hl,nedge2 ; Secondary ld de,nedge3 ; Storage ld bc,0002h ; Do 512 netbits $2: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $2 dec c jr nz,$2 ret ; resttbls: ld ix,input3 ; Storage ld iy,input2 ; Secondary ld hl,edge3 ; Storage ld de,edge2 ; Secondary ld b,0 $1: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $1 ; ; Now do netbit tables ; ld ix,netbit3 ; Storage ld iy,netbit2 ; Secondary ld hl,nedge3 ; Storage ld de,nedge2 ; Secondary ld bc,0002h ; Do 512 netbits $2: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $2 dec c jr nz,$2 ret ; ; Toggle an output bit to allow time testing and to ; show task 1 activity ; toggle1: push bc ld bc,pia4+3 in a,(c) xor 08h out (c),a pop bc ret ; ; Toggle an output bit to allow time testing and to ; show task 2 activity ; toggle2: push bc ld bc,pia4+1 in a,(c) xor 08h out (c),a pop bc ret ; ; action: push bc push de push hl act1: ld a,(ix) cp last jp z,actdone cp 80h ; If <80h, then X-10 command jp c,x10cmd cp 0a0h ; If >=80h and =A0h and =16? jr nc,$8 ; Yes, do it cp 8 ; =8? jr z,$41 ; RTC-DTMF LED3 cp 9 ; =9? jr z,$42 ; RTC-DTMF LED4 ld bc,pia3+3 ; SS LED6 cp 10 ; =10? jr z,$5 ld bc,pia4+1 ; SS LED7 cp 11 ; =11? jr z,$5 ld bc,pia4+3 ; SS LED8 cp 12 ; =12? jr z,$5 jr $9 ; No match, not supported by hardware ; ; Do RTC-DTMF LEDs ; $41: ld a,(dtmfo) ; Get current settings bit 0,d ; On or off? set 5,a ; Turn LED3 on (bit on) jr nz,$41a res 5,a ; Turn LED3 off (bit off) $41a: ld (dtmfo),a outb dtmfctl,a jr $9 ; $42: ld a,(dtmfo) ; Get current settings bit 0,d ; On or off? set 4,a ; Turn LED4 on (bit on) jr nz,$42a res 4,a ; Turn LED4 off (bit off) $42a: ld (dtmfo),a outb dtmfctl,a jr $9 ; ; Do SpectraSense LEDs ; $5: ld a,(sc) ; Make sure we're a SpectraSense cp sccs jr nz,$99 ; Nope, skip in a,(c) bit 0,d ; On or off? res 3,a ; Turn LED on (bit off) jr nz,$6 set 3,a ; Turn LED off (bit on) $6: out (c),a jr $9 ; $8: out (c),e ; Send out to port $9: ld (hl),e ; and save for later use ; ld hl,output ; Point to local storage ld c,(ix+1) ; Get output number ld b,0 add hl,bc ld (hl),d ; Save new state ; $99: inc ix inc ix jp act1 ; outtbl: dw port1+2 ; 0-7 dw port3+0 ; 8-15 (on-board LEDs) dw port3+0 ; 16-23 dw port3+1 ; 24-31 dw port3+2 ; 32-39 dw port5+0 ; 40-47 dw port5+1 ; 48-55 dw port5+2 ; 56-63 dw port6o+0 ; 64-71 dw port6o+1 ; 72-79 dw port6o+2 ; 80-87 dw port7o+0 ; 88-95 dw port7o+1 ; 96-103 dw port7o+2 ; 104-111 dw port8o+0 ; 112-119 dw port8o+1 ; 120-127 dw port8o+2 ; 128-135 dw port9o+0 ; 136-143 dw port9o+1 ; 144-151 dw port9o+2 ; 152-159 dw pia4 ; 160-167 dw pia4+2 ; 168-175 dw pia3+2 ; 176-183 dw port11+0 ; 184-191 dw port11+1 ; 192-199 dw port11+2 ; 200-207 ; ; ; Turn a timer on or off ; ontmr: ld a,80h ; High byte of new timer value (timer on) jr tmrcom offtmr: ld a,0 ; Timer is off tmrcom: ld hl,timers ; Now clear timer in either case ld e,(ix+1) sla e ld d,0 add hl,de ; Offset to timer ld (hl),0 ; Low byte to 0 inc hl ld (hl),a ; High byte to 0 or 80 inc ix inc ix jp act1 ; ; Turn a netbit on or off ; onnetb: ld a,1 jr nbcom offnetb:ld a,0 nbcom: ld (nbval),a ; Save new value ld a,0ffh ld (t1netbf),a ; Set our flag ld a,(t5netbf) ; Check if other task sending netbit or a jr z,$2 ; Nope, continue ld a,0 ld (t1netbf),a ; Clear our flag $1: ld a,(t5netbf) ; Check other task again or a jr nz,$1 ; Wait for it to finish jr nbcom ; Try again to grab netbit routines $2: ld a,(ix+1) ; Get low byte of netbit number ld (nbstor),a ld a,(ix+2) ; High byte of netbit number ld (nbstor+1),a call donetb ; Turn netbit on or off ; ld a,0 ld (t1netbf),a ; Turn our flag off ; inc ix inc ix inc ix jp act1 ; ; Send a network command to turn a netbit on or off. ; Enter with 16-bit netbit number at nbstor and ; new value at nbval. ; donetb: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld a,(nbstor+1) ; Get high byte of bit number or a ; 0? jp nz,$20 ; No, so must be DIO+ ld a,(nbstor) ; Get bit number cp 64 ; 0-63? jp c,$10 ; Yes, DIO cp 96 ; 64-95? jp c,$99 ; Yes, LCD so skip cp 224 ; 96-223? jr c,$01 ; Yes, AMAN ; ; Send message to MCIR ; ld de,t1tbuf ld hl,netmcir ld bc,15 ldir ; Copy command frame to buffer ; ld a,(nbstor) ; Get bit number rrca ; Calculate link number and 07h ; Ensure 0-7 add a,'0' ; Convert to ASCII ld (t1tbuf+7),a ; Put in buffer ; ld a,(nbstor) ; Get bit number again and 01h ; Ensure 0 or 1 add a,'A' ; Convert to ASCII A or B ld (t1tbuf+10),a ; Put in buffer ld a,(nbval) ld d,a ; Save for later add a,'0' ; Convert to ASCII ld (t1tbuf+12),a ; Put in buffer ; ld hl,netbit1 ; Point to local storage ld iy,nedge1 ld a,(nbstor) ; Get netbit number ld c,a ld b,0 add hl,bc add iy,bc ld a,(hl) ; Get old state ld (hl),d ; Save new state cp d ; Change? jr z,$02 ; No, skip edge ld (iy),0ffh ; Flag edge $02: ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum jp $90 ; ; Send message to AMAN ; $01: ld de,t1tbuf ld hl,netaman ld bc,17 ldir ; Copy command frame to buffer ; ld a,(nbstor) ; Get bit number (96-223) sub 96 ; 0-127 ld b,a ; Save it rra rra rra rra and 0fh ; Link number add a,'0' ; Convert to ASCII ld (t1tbuf+8),a ; Put in buffer ld a,(nbval) ld d,a ; Save for later ; ld hl,netbit1 ; Point to local storage ld iy,nedge1 ld a,(nbstor) ; Get netbit number ld c,a ld b,0 add hl,bc add iy,bc ld a,(hl) ; Get old state ld (hl),d ; Save new state cp d ; Change? jr z,$2 ; No, skip edge ld (iy),0ffh ; Flag edge $2: ld hl,netbit1 ; Point to local storage ld a,(nbstor) ; Get netbit number and 0f8h ; Point to first bit of that module ld c,a ld b,0 add hl,bc ld b,8 ; Do 8 bits ld c,0 $loop: xor a ; Clear carry ld a,(hl) ; Get next bit or a ; Test bit and clear carry jr z,$clr scf ; Set carry $clr: rr c ; Rotate carry into C inc hl djnz $loop ld a,c ; Get result call hto2a ; Convert to two ASCII digits ld a,b ld (t1tbuf+13),a ld a,c ld (t1tbuf+14),a ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum jp $90 ; ; Send message to DIO ; $10: ld de,t1tbuf ld hl,netdio ld bc,19 ldir ; Copy command frame to buffer ; ld a,(nbstor) ; Get bit number rrca ; Calculate link number rrca rrca and 07h ; Ensure 0-7 add a,'0' ; Convert to ASCII ld (t1tbuf+8),a ; Put in buffer ; ld a,(nbstor) ; Get bit number again and 07h ; Ensure 0-7 add a,'0' ; Convert to ASCII ld (t1tbuf+14),a ; Put in buffer ld a,(nbval) ld d,a ; Save for later add a,'0' ; Convert to ASCII ld (t1tbuf+16),a ; Put in buffer ; ld hl,netbit1 ; Point to local storage ld iy,nedge1 ld a,(nbstor) ; Get netbit number ld c,a ld b,0 add hl,bc add iy,bc ld a,(hl) ; Get old state ld (hl),d ; Save new state cp d ; Change? jr z,$12 ; No, skip edge ld (iy),0ffh ; Flag edge $12: ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum jr $90 ; ; Send message to DIO+ ; $20: ld de,t1tbuf ld hl,netdiop ld bc,19 ldir ; Copy command frame to buffer ; ld a,(nbstor) ; Get bit number rrca ; Calculate link number rrca rrca and 07h ; Ensure 0-7 add a,'0' ; Convert to ASCII ld (t1tbuf+8),a ; Put in buffer ; ld a,(nbstor) ; Get bit number again and 03h ; Ensure 0-3 add a,'0' ; Convert to ASCII ld (t1tbuf+14),a ; Put in buffer ld a,(nbval) ld d,a ; Save for later add a,'0' ; Convert to ASCII ld (t1tbuf+16),a ; Put in buffer ; ld hl,netbit1 ; Point to local storage ld iy,nedge1 ld a,(nbstor) ; Get netbit number ld c,a ld b,1 add hl,bc add iy,bc ld a,(hl) ; Get old state ld (hl),d ; Save new state cp d ; Change? jr z,$22 ; No, skip edge ld (iy),0ffh ; Flag edge $22: ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; $90: ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send $99: ret ; netmcir db cr,'#00 IR0 OA=0',cr,0 netaman db cr,'#00 MAN0 SO 00',cr,0 netdio db cr,'#00 DIO0 SDP.0=0',cr,0 netdiop db cr,'#00 ADP0 SDO.0=0',cr,0 ; ; ; Send a text string to an LCD-Link ; lcdmsg: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; ld de,t1tbuf ld hl,lcdhdr ld bc,13 ldir ; Copy command header to buffer ; inc ix ld a,(ix) ; Get link number inc ix add a,'0' ; Make into ASCII ld (t1tbuf+9),a ; Put into buffer ; ld hl,t1tbuf+13 call msgout ; Put the message into the packet ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; jp act1 ; lcdhdr db cr,'#00 TERM0 S=',0 ; ; ; Send a text string to a DIO-Link ; diomsg: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; ld de,t1tbuf ld hl,diohdr ld bc,14 ldir ; Copy command header to buffer ; inc ix ld a,(ix) ; Get link number ld e,a ; Save it push de inc ix add a,'0' ; Make into ASCII ld (t1tbuf+8),a ; Put into buffer ; ld hl,t1tbuf+14 call msgout ; Put the message into the packet ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; pop de ld hl,nettmrs+24 ; Start of DIO timers ld d,0 add hl,de ; Offset to timer for this module ld (hl),3 ; Don't query for 3 seconds ; ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; jp act1 ; diohdr db cr,'#00 DIO0 TDP=',0 ; ; ; Send a text string to a TV-Link ; tvmsg: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; ld de,t1tbuf ld hl,tvhdr ld bc,9 ldir ; Copy command header to buffer ; inc ix ld a,(ix) ; Get link number inc ix add a,'0' ; Make into ASCII ld (t1tbuf+5),a ; Put into buffer ; ld hl,t1tbuf+9 call msgout ; Put the message into the packet ; ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; jp act1 ; tvhdr db cr,'! TV0 S=',0 ; ; ; Send a text string to the console ; conmsg: $1: ld a,(msgflg) ; Buffer already full? or a jr nz,$1 ; inc ix ; Point to message ld hl,cmsgbuf call msgout ; Put the message into buffer ld (hl),lf ; Add lf after cr inc hl ld (hl),0 ; Zero terminated ld a,0ffh ld (msgflg),a ; Ready to send ; jp act1 ; ; ; Send a text string to the network ; netmsg: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; ld de,t1tbuf ld hl,nethdr ld bc,5 ldir ; Copy command header to buffer ; inc ix ; Point to string ld hl,t1tbuf+5 call msgout ; Put the message into the packet ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; jp act1 ; nethdr db cr,'#00 ',0 ; ; ; Get the raw message string from memory starting at IX and ; put into buffer memory at HL to be sent to network. ; msgout: push af push de $1: ld a,(ix) ; Copy message to buffer inc ix cp 80h ; Display time without seconds? jr nz,$10 ; No, keep going ld a,(time+3) ; Yes, get hours call pbcdm ; Print it to the buffer ld (hl),':' inc hl ld a,(time+2) ; Get minutes call pbcdm jr $1 ; Do next character $10: cp 81h ; Display time with seconds? jr nz,$11 ; No, keep going ld a,(time+3) ; Yes, get hours call pbcdm ; Print it to the buffer ld (hl),':' inc hl ld a,(time+2) ; Get minutes call pbcdm ld (hl),':' inc hl ld a,(time+1) ; Get seconds call pbcdm jr $1 ; Do next character $11: cp 82h ; Display day of week? jr nz,$12 ; No, keep going ld a,(time+4) ; Yes, get day of week dec a ld iy,dow ; Point to string table sla a sla a ld c,a ld b,0 add iy,bc ; Offset within table ld b,3 ; Do three characters $111: ld a,(iy) ld (hl),a inc iy inc hl djnz $111 jr $1 ; Do next character $12: cp 83h ; Display date? jr nz,$13 ; No, keep going ld a,(time+6) ; Yes, get month call pbcdm ; Print it to the buffer ld (hl),'/' inc hl ld a,(time+5) ; Yes, get day call pbcdm ; Print it to the buffer ld (hl),'/' inc hl ld a,(time+7) ; Get year call pbcdm jr $1 ; Do next character $13: cp 84h ; Display full date? jr nz,$14 ; No, keep going ld a,(time+6) ; Yes, get month call bcd2dec ; Convert from BCD to decimal dec a ld iy,mon ; Point to string table sla a sla a ld c,a ld b,0 add iy,bc ; Offset within table ld b,4 ; Do three characters $131: ld a,(iy) ld (hl),a inc iy inc hl djnz $131 ld a,(time+5) ; Get day call pbcdm ld (hl),',' inc hl ld (hl),' ' inc hl ld (hl),'2' ; MSB 991225 - Changed for Y2K from 19 inc hl ld (hl),'0' inc hl ld a,(time+7) ; Get year call pbcdm jp $1 ; Do next character $14: cp 85h ; Display CID Number? jr nz,$141 ; No, keep trying ld iy,cndnum ; Point to CID Num Buffer jr $142 $141 cp 86h ; Display CID Name? jr nz,$15 ; No, try next ld iy,cndbuf ; Point to CID Num Buffer $142 ld a,(iy) ; Grab character from buffer or a jp z,$1 ; End of string (0) ld (hl),a ; Store in msg buffer inc hl ; Point to next buffer spot inc iy ; Get next char jr $142 $15: cp 90h ; Display variable w/no leading spaces/zeros? jr nz,$16 ; No, keep going ld c,(ix) ; Get number of decimal places inc ix ld b,2 ; Remove leading zeros and spaces ld e,(ix) ; Get variable number sla e ; Multiply by 2 ld d,0 inc ix push hl ld hl,vars add hl,de ld e,(hl) ; Put variable value into DE inc hl ld d,(hl) pop hl ; Restore memory pointer call pde5dcm ; Print variable to memory jp $1 ; Do next character $16: cp 91h ; Display variable with leading spaces? jr nz,$17 ; No, keep going ld c,(ix) ; Get number of decimal places inc ix ld b,1 ; Replace leading zeros with spaces ld e,(ix) ; Get variable number sla e ; Multiply by 2 ld d,0 inc ix push hl ld hl,vars add hl,de ld e,(hl) ; Put variable value into DE inc hl ld d,(hl) pop hl ; Restore memory pointer call pde5dcm ; Print variable to memory jp $1 ; Do next character $17: cp 92h ; Display variable with leading zeros? jr nz,$18 ; No, keep going ld c,(ix) ; Get number of decimal places inc ix ld b,0 ; Leave leading zeros ld e,(ix) ; Get variable number sla e ; Multiply by 2 ld d,0 inc ix push hl ld hl,vars add hl,de ld e,(hl) ; Put variable value into DE inc hl ld d,(hl) pop hl ; Restore memory pointer call pde5dcm ; Print variable to memory jp $1 ; Do next character $18: cp 93h ; Display variable with set # of digits? jr nz,$19 ; No, keep going ld c,(ix) ; Get number of digits places inc ix ld e,(ix) ; Get variable number sla e ; Multiply by 2 ld d,0 inc ix push hl ld hl,vars add hl,de ld e,(hl) ; Put variable value into DE inc hl ld d,(hl) pop hl ; Restore memory pointer call pdeadcm ; Print variable to memory jp $1 ; Do next character $19: ld (hl),a inc hl cp cr ; End of string? jp nz,$1 ; No, keep going ; ld (hl),lf ; Add linefeed ; inc hl ld (hl),0 ; Terminate packet ; pop de pop af ret ; ; ; Reset all 8255s ; rstio: call initppis inc ix jp act1 ; ; Clear all system variables ; clrvar: call initvars inc ix jp act1 ; ; Clear all system timers ; clrtmr: call inittmrs inc ix jp act1 ; ; Clear log storage ; clrlogm:ld hl,logstrt ld (logptrh),hl ld (logptrt),hl inc ix jp act1 ; ; Clear the totalizer on the selected AMAN module ; clrtot: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t1tbuf ld hl,totclr ld bc,14 ; MSB - change to 14 to match string len ldir ; Copy command frame to buffer ld a,(ix+1) ; Link number and 07h add a,'0' ; Convert to ASCII ld (t1tbuf+8),a ; Put in buffer ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; inc ix inc ix jp act1 ; totclr db cr,'#00 MAN0 RT',cr,0 ; ; HVAC/Stat-Link network command support ; hvacled: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t1tbuf ld hl,hlednc ; Point to skeleton command ld bc,18 ; Length of string ldir ; Copy command frame to buffer ; ld a,(ix+1) ; Stat number (00-32) call hto2a ld a,b ld (t1tbuf+11),a ld a,c ld (t1tbuf+12),a ; LED # is upper nybble, Mode is lower nybble ld a,(ix+2) ; Grab LED # from upper nybble call hto2a ld a,b ld (t1tbuf+14),a ld a,c ld (t1tbuf+15),a ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; inc ix inc ix inc ix jp act1 ; hlednc db cr,'#00 SL0 SL00 00',cr,0 ; hvacfan: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t1tbuf ld hl,hfannc ; Point to skeleton command ld bc,17 ; Length of string ldir ; Copy command frame to buffer ; ld a,(ix+1) ; Stat number (00-32) call hto2a ld a,b ld (t1tbuf+11),a ld a,c ld (t1tbuf+12),a ; ld a,(ix+2) ; Grab mode letter (already in ASCII) ld (t1tbuf+14),a ; Put in buffer ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; inc ix inc ix inc ix jp act1 ; hfannc db cr,'#00 SL0 SF00 0',cr,0 ; hvacnet: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t1tbuf ld hl,hnetnc ; Point to skeleton command ld bc,11 ; Length of string ldir ; Copy command frame to buffer ; inc ix ; Point to msg ld hl,t1tbuf+11 call msgout ; Put message into buffer ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Calc Checksum ; ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; jp act1 ; hnetnc db cr,'#00 SL0 N=',0 ; hvacmod: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t1tbuf ld hl,hmodnc ; Point to skeleton command ld bc,17 ; Length of string ldir ; Copy command frame to buffer ; ld a,(ix+1) ; Stat number (00-32) call hto2a ld a,b ld (t1tbuf+11),a ld a,c ld (t1tbuf+12),a ; ld a,(ix+2) ; Grab mode letter (already in ASCII) ld (t1tbuf+14),a ; Put in buffer ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; inc ix inc ix inc ix jp act1 ; hmodnc db cr,'#00 SL0 SM00 0',cr,0 ; ; Wait 0.1-25.5 seconds ; wait: ld a,(ix+1) ld (dtmfto),a ; Set up delay time $0: push ix rt_run 2,2 ; Start secondary eval pop ix ld a,0ffh ; Flag task 2 as running ld (t2flag),a $1: ld a,(dtmfto) or a jr z,$2 ; Timed out, finish up ld a,(t2flag) ; Task 2 running? or a jr nz,$1 ; Yes, keep waiting jr $0 ; No, so start it again $2: ld a,(t2flag) ; Task 2 running? or a jr nz,$2 ; Yes, keep waiting ; inc ix inc ix jp act1 ; ; Take the phone off hook and enforce 2-second ; billing delay ; offhk: ld a,(sc) cp sccs ; CS? jr nz,$00 ; Nope, RTC or BCC ; ld bc,pia2+3 in a,(c) ; Get current settings set 3,a ; Set voice mode out (c),a ld bc,pia2+1 in a,(c) set 3,a ; Take phone off hook out (c),a jr $01 $00: ld a,(dtmfo) ; Get current settings set 7,a ; Set voice mode set 6,a ; and take the phone off hook outb dtmfctl,a ld (dtmfo),a ; $01: ld a,20 ; Delay 2 seconds ld (dtmfto),a $0: push ix rt_run 2,2 ; Start secondary eval pop ix ld a,0ffh ; Flag task 2 as running ld (t2flag),a $1: ld a,(dtmfto) or a jr z,$2 ; Timed out, so finish up ld a,(t2flag) ; Task 2 running? or a jr nz,$1 ; Yes, keep waiting jr $0 ; No, so start it again $2: ld a,(t2flag) ; Task 2 running? or a jr nz,$2 ; Yes, keep waiting ; ld bc,(ctrl88) in a,(c) ; Clear DTMF input buffer inc ix jp act1 ; ; Put the phone on hook ; onhk: ld a,(sc) cp sccs ; CS? jr nz,$00 ; Nope, RTC or BCC ; ld bc,pia2+1 in a,(c) res 3,a ; Put phone on hook out (c),a jr $01 $00: ld a,(dtmfo) ; Get current settings res 6,a ; Put on hook outb dtmfctl,a ld (dtmfo),a $01: ld bc,(ctrl88) in a,(c) ; Clear DTMF input buffer inc ix jp act1 ; ; Dial the DTMF string ; dials: ld bc,(data88) ; Get M8888 port address push bc ; Save port address inc ix ; Point to start of string $1: ld a,(ix) ; Get next character or a ; 0? jr z,$99 ; Yes, done cp ',' ; Delay? jr z,$7 ; Yes, do it ld hl,dialtbl ; Point to lookup table ld b,16 ; 16 entries in table $2: cp (hl) ; Compare char with table entry jr z,$3 ; Match, so handle it inc hl ; Skip to next entry djnz $2 jr $9 $3: dec b ; Make B the dial code ld a,b ; Save it pop bc ; Get chip port address out (c),a ; Send tone inc bc ; Point at status port $4: in a,(c) ; Get status bit 1,a ; Check TDRE jr z,$4 ; Keep waiting dec bc ; Point at data port again push bc ; Save it again jr $9 $7: ld hl,dtmfto ld (hl),20 ; Delay 2 seconds $8: ld a,(hl) or a jr nz,$8 $9: inc ix ; Point to next character (ignore this one) jr $1 ; Do next character $99: pop bc ; Fix stack inc ix jp act1 ; dialtbl:db 'CBA#*0987654321D' ; ; Dial the DTMF digit in the specified variable ; diald: ld hl,vars ld e,(ix+1) sla e ; Multiply by 2 ld d,0 add hl,de ld a,(hl) ; Get low byte (ignore high byte) call ddig ; Dial the single digit inc ix inc ix jp act1 ; ; Dial the DTMF number in the specified variable ; dialn: ld hl,vars ld e,(ix+1) sla e ; Multiply by 2 ld d,0 add hl,de ld e,(hl) ; Get low byte inc hl ld d,(hl) ; Get high byte ld b,(ix+2) ; Get number of digits ; ex de,hl ; Put number in HL push hl ; Save it for later ld de,1000 call unspd ; HL/1000 ld a,l ; Get result ld (digit1),a ; Save it call unspm ; (HL/1000)*1000 ex de,hl pop hl xor a ; Clear carry sbc hl,de ; HL=num-((num/1000)*1000) ; push hl ; Save number for later ld de,100 call unspd ; HL/100 ld a,l ; Get result ld (digit2),a ; Save it call unspm ; (HL/100)*100 ex de,hl pop hl xor a ; Clear carry sbc hl,de ; HL=num-((num/100)*100) ; push hl ; Save number for later ld de,10 call unspd ; HL/10 ld a,l ; Get result ld (digit3),a ; Save it call unspm ; (HL/10)*10 ex de,hl pop hl xor a ; Clear carry sbc hl,de ; HL=num-((num/10)*10) ; ld a,l ; Get last place ld (digit4),a ; Save it ; ld hl,digit1 ; Point to first digit ld a,5 sub b ; Make 1-4 digits into 4-1 increments $1: dec a jr z,$2 ; If zero, start putting out digits inc hl ; Otherwise, point to next digit jr $1 $2: ld a,(hl) ; Get next digit call ddig ; Dial the digit inc hl djnz $2 ; Do them all ; inc ix inc ix inc ix jp act1 ; ; Dial the binary digit contained in A ; ddig: push af push bc push de push hl and 0fh ; Make sure A is 0-F ld hl,dtbl ; Point to lookup table ld e,a ld d,0 add hl,de ; Offset into table ld a,(hl) ; Get MT8888 value ld bc,(data88) ; Point to M8888 data port out (c),a ; Send tone inc bc ; Point to status port $4: in a,(c) ; Get status bit 1,a ; Check TDRE jr z,$4 ; Keep waiting pop hl pop de pop bc pop af ret ; dtbl: db 10,1,2,3,4,5,6,7,8,9,11,12,13,14,15,0 ; ; ; Send the speech string to the voice board ; say: $0: ld a,0ffh ld (t1sayf),a ; Set our flag ld a,(t5sayf) ; Check if other task speaking or a jr z,$2 ; Nope, continue ld a,0 ld (t1sayf),a ; Clear our flag $1: ld a,(t5sayf) ; Check other task again or a jr nz,$1 ; Wait for it to finish jr $0 ; Try again to grab speech routines $2: inc ix ; Point to voice string ld hl,vbuf ; Point to voice buffer call msgout ; Convert string to text ld hl,vbuf $3: ld a,(hl) ; Get next character cp '~' ; Substitute command char? jr nz,$4 ; No, continue ld a,01h $4: cp '|' ; Substitute speech interrupt? jr nz,$5 ; No, continue ld a,18h $5: call vout ; Send character to voice board inc hl or a ; End of string? jr nz,$3 ; ld a,0 ld (t1sayf),a ; Turn our flag off jp act1 ; ; ; Send the speech string to the voice board and wait for ; it to finish ; sayw: $0: ld a,0ffh ld (t1sayf),a ; Set our flag ld a,(t5sayf) ; Check if other task speaking or a jr z,$2 ; Nope, continue ld a,0 ld (t1sayf),a ; Clear our flag $1: ld a,(t5sayf) ; Check other task again or a jr nz,$1 ; Wait for it to finish jr $0 ; Try again to grab speech routines $2: inc ix ; Point to voice string ld hl,vbuf ; Point to voice buffer call msgout ; Convert string to text ld hl,vbuf $3: ld a,(hl) ; Get next character cp '~' ; Substitute command char? jr nz,$4 ; No, continue ld a,01h $4: cp '|' ; Substitute speech interrupt? jr nz,$5 ; No, continue ld a,18h $5: call vout ; Send character to voice board inc hl or a ; End of string? jr nz,$3 ; ld a,0 ld (t1sayf),a ; Turn our flag off call vwait ; Wait for speech to finish jp act1 ; ; vout: push af push bc push de push hl ld d,a ; Save character ld bc,vstat ; ld hl,10000 ; Timeout constant ld hl,20000 ; Double for S180 processor MSB 011900 $1: in e,(c) bit 4,e ; Test RDY bit jr nz,$2 ; Wait for RDY to go high dec hl ; Decrement timeout ld a,h or l jr nz,$1 jr $4 ; Timeout, so abort $2: ld bc,vdata out (c),d ; Send the character ; ld bc,vstat ; ld hl,10000 ; Timeout constant ld hl,20000 ; Double for S180 processor MSB 011900 $3: in e,(c) bit 4,e ; Test RDY bit jr z,$4 ; Wait for RDY to go low dec hl ; Decrement timeout ld a,h or l jr nz,$3 $4: pop hl pop de pop bc pop af ret ; vwait: push af push bc push ix ; ; First, wait up to 10 seconds for the speech to start ; ld a,100 ; 10-second timeout ld (saytmr),a ld bc,vstat $0: rt_run 2,2 ; Start secondary eval ld a,0ffh ; Flag task 2 as running ld (t2flag),a $1: in a,(c) bit 6,a ; Wait for speech to start jr nz,$2 ; It's started, so wait for Task 2 to finish ld a,(saytmr) ; Check timeout or a jr z,$5 ; The voice board has gone south, abort ld a,(t2flag) ; Task 2 running? or a jr nz,$1 ; Yes, keep waiting jr $0 ; No, so start it again $2: ld a,(t2flag) ; Task 2 running? or a jr nz,$2 ; Yes, keep waiting ; ; Now wait up to 25 seconds for speech to finish ; ld a,250 ; 25-second timeout ld (saytmr),a $3: rt_run 2,2 ; Start secondary eval ld a,0ffh ; Flag task 2 as running ld (t2flag),a $4: in a,(c) bit 6,a ; Wait for speech to end jr z,$5 ; It's done, so wait for Task 2 to finish ld a,(saytmr) ; Check timeout or a jr z,$5 ; The voice board has gone south, abort ld a,(t2flag) ; Task 2 running? or a jr nz,$4 ; Yes, keep waiting jr $3 ; No, so start it again $5: ld a,(t2flag) ; Task 2 running? or a jr nz,$5 ; Yes, keep waiting pop ix pop bc pop af ret ; ; ; Store new modem init string from user ; setinit: inc ix ; Point to first character ld hl,mdminit ; String storage $1: ld a,(ix) ld (hl),a inc ix inc hl or a jr nz,$1 ; Copy until zero encountered ld a,0ffh ld (initmdm),a ; Flag that modem needs initializing jp act1 ; ; ; Action is a flexible type, so use flexible routines ; act3: sub 0a0h ; Make into 0-4 sla a ; Multiply by 2 ld hl,acttbl3 ; Point to action table ld e,a ld d,0 add hl,de ; Offset to proper routine ld e,(hl) inc hl ld d,(hl) ; Get routine start address ex de,hl jp (hl) ; Do it ; acttbl3:dw setvr,setdaco,setref,setmcir,logdat ; 0xA0-0xA4 dw rcrings,cidenb,setnetb,pwmtot,pwmhi ; 0xA5-0xA9 dw bitdir,keypto,hvacssp ; 0xAA-0xAC ; ; ; Routines to support acttbl3 ; ; Set variable to a new value ; setvr: ld hl,vars ; Point to variable in question ld e,(ix+1) sla e ; Multiply by 2 ld d,0 add hl,de inc ix ; Move past opcode inc ix ; Move past variable number ex de,hl ; Save HL call domath ; Calculate new value for variable ex de,hl ; Put storage pointer back into HL ld (hl),e ; Save low byte inc hl ld (hl),d ; Save high byte jp act1 ; ; Set a D/A converter channel ; setdaco: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t1tbuf ld hl,dacmsg ld bc,24 ldir ; Copy command frame to buffer ; ld a,(ix+1) ; Get channel number ld c,a ; Save it for later rrca ; Calculate link number rrca and 07h ; Ensure 0-7 add a,'0' ; Convert to ASCII ld (t1tbuf+8),a ; Put in buffer ; inc ix ; Move past opcode inc ix ; Move past channel number call domath ; Calculate new value for DAC ; ex de,hl ; Save result in DE ld hl,dacvals ; Save value in local storage ld b,0 sla c ; Multiply channel by 2 add hl,bc ; Offset into storage ld (hl),e ; Save it inc hl ld (hl),d ; ; Answer MAN needs both DAC channels in one command, so retrieve both values ; for this module from memory. ; ld a,0fch and c ; Point to even channel offset ld c,a ld hl,dacvals add hl,bc ; push iy ld iy,t1tbuf ld a,(hl) inc hl call hto2a ; Convert to two ASCII digits ld (iy+15),b ld (iy+16),c ld a,(hl) inc hl call hto2a ld (iy+13),b ld (iy+14),c ld a,(hl) inc hl call hto2a ld (iy+20),b ld (iy+21),c ld a,(hl) inc hl call hto2a ld (iy+18),b ld (iy+19),c pop iy ; ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send ; $9: jp act1 ; dacmsg db cr,'#00 MAN0 SD 0000 0000',cr,0 ; ; ; Tell MCIR-Link to send an IR command ; setmcir: $1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$1 ; ld de,t1tbuf ld hl,mcirhdr ld bc,17 ldir ; Copy command header to buffer ; inc ix ; Skip over opcode ld a,(ix) ; Get link number ld e,a ; Save it push de inc ix ; Skip over link number add a,'0' ; Make into ASCII ld (t1tbuf+7),a ; Put into buffer ; call domath ; Calculate new MCIR value ld a,h cp 7 ; Is high byte <7? jr c,$4 ; Yes, so value under 700h (1792) jr nz,$3 ; If not =7, must be too big ld a,l ; If =7, check low byte cp 0d0h ; Is low byte 0, Z=0 if module is on. ; chkon: push de push hl ld a,b ; Get housecode sub 'A' rla rla rla rla and 0f0h add a,c dec a ld e,a ld d,0 ld hl,modules add hl,de ld a,(hl) and 01h ; Return just low bit pop hl pop de ret ; ; Flag module as on ; seton: push af push de push hl ld a,b ; Get housecode sub 'A' rla rla rla rla and 0f0h add a,c dec a ld e,a ld d,0 ld hl,modules add hl,de ld a,0a1h ; Module on, set locally ld (hl),a ld (dx10f),a ; Flag to display modules pop hl pop de pop af ret ; ; Flag module as off ; setoff: push af push de push hl ld a,b ; Get housecode sub 'A' rla rla rla rla and 0f0h add a,c dec a ld e,a ld d,0 ld hl,modules add hl,de ld a,a0h ; Module off, set locally ld (hl),a ld a,0ffh ld (dx10f),a ; Flag to display modules pop hl pop de pop af ret ; ; Flag all modules in housecode as off ; setaoff: push af push bc push de push hl ld a,b ; Get housecode sub 'A' rla rla rla rla and 0f0h ld e,a ld d,0 ld hl,modules add hl,de ld b,16 ; Do all 16 modules ld a,a0h ; Module off, set locally $1: ld (hl),a inc hl djnz $1 ld a,0ffh ld (dx10f),a ; Flag to display modules pop hl pop de pop bc pop af ret ; ; Convert decimal value (00-99) in A to two ASCII digits and ; place in BC. ; atoc: push af ld bc,0 $1: sub 10 jr c,$2 inc b jr $1 $2: add a,10 add a,'0' ld c,a ld a,b add a,'0' ld b,a pop af ret ; ; Put HL as four decimal characters into memory starting at IY ; phl4dcm: push af push bc push de push hl ld a,0 ld (neg),a ; Number not negative ld b,0 ; Keep leading zeros ld de,1000 ; Place 1000s call pd1 ld de,100 ; Place 100s call pd1 ld de,10 ; Place 10s call pd1 ld a,l ; Do 1s add a,'0' ld (iy),a inc iy pop hl pop de pop bc pop af ret ; ; Put DE as five decimal characters (with sign) into ; memory starting at HL. Number of places to print ; after decimal point is in C. ; ; If B=0, leave leading zeros ; B=1, replace leading zeros with spaces ; B=2, remove leading zeros ; pde5dcm: push af push bc push de push iy push hl ; Transfer memory pointer to IY pop iy ex de,hl ; Put number into HL ld a,5 ; Make C 5-0 sub c ld c,a ld a,0 bit 7,h ; Check sign jr z,$1 ; If positive, skip ld a,0ffh ; Flag as negative $1: ld (neg),a ; Save sign bit 7,h ; Check sign again call nz,comphl ; Make number positive ; ld a,c cp 1 jr z,$11 or a jr nz,$2 ld (iy),'.' inc iy $11: ld b,0 $2: ld de,10000 ; Place 10000s call pd1 dec c ; ld a,c cp 1 jr z,$21 or a jr nz,$3 ld (iy),'.' inc iy $21: ld b,0 $3: ld de,1000 ; Place 1000s call pd1 dec c ; ld a,c cp 1 jr z,$31 or a jr nz,$4 ld (iy),'.' inc iy $31: ld b,0 $4: ld de,100 ; Place 100s call pd1 dec c ; ld a,c cp 1 jr z,$41 or a jr nz,$5 ld (iy),'.' inc iy $41: ld b,0 $5: ld de,10 ; Place 10s call pd1 dec c ; ld a,c or a jr nz,$6 ld (iy),'.' inc iy $6: ld b,0 ; Always display 0 if in last place ld de,1 ; Do 1s call pd1 push iy ; Put final pointer back into HL pop hl pop iy pop de pop bc pop af ret ; ; Put DE as up to 5 decimal characters with remaining ; leading chars set to '0'. Size of value displayed is ; loaded into c. So if c is 4 and value is 2 digits, ; include 4-2 zeros in front. If c < # of digits, ; simply output the value. Value is stored in HL ; pdeadcm: push af push bc push de push iy push hl ; Transfer memory pointer to IY pop iy ex de,hl ; Put number into HL ; Subtract c from 5 to count how many digits to output ; with 'Leading Zero's Off (B=2)' set and then once ; we hit that spot, flip B=0 for leading zeros ld a,5 ; Make C 5-0 sub c ld c,a ; C=# of digits that should NOT be zeros ld b,2 ; Default to no 0's ; Check sign of number and convert positive if necessary ld a,0 bit 7,h ; Check sign jr z,$1 ; If positive, skip ld a,0ffh ; Flag as negative $1: ld (neg),a ; Save sign bit 7,h ; Check sign again call nz,comphl ; Make number positive ; ; ld a,c ; Check if we should flip B flag to 0 or a jr nz,$2 $11: ld b,0 ; Tell pd1 to output a leading 0 inc c ; Will dec later to stay at 0 $2: ld de,10000 ; Place 10000s call pd1 dec c ; ld a,c or a jr nz,$3 $21: ld b,0 inc c $3: ld de,1000 ; Place 1000s call pd1 dec c ; ld a,c or a jr nz,$4 $31: ld b,0 inc c $4: ld de,100 ; Place 100s call pd1 dec c ; ld a,c or a jr nz,$5 $41: ld b,0 $5: ld de,10 ; Place 10s call pd1 dec c ; $6: ld b,0 ; Always display 0 if in last place ld de,1 ; Do 1s call pd1 push iy ; Put final pointer back into HL pop hl pop iy pop de pop bc pop af ret ; ; Divide HL by DE and place the quotient in memory at IY. ; If B=0, leave leading zeros ; B=1, replace leading zeros with spaces ; B=2, remove leading zeros ; Leaves remainder in HL. ; pd1: push bc ld c,0 ; Set count $2: ld a,l ; Sub E from L sub e ld l,a ; Result in L ld a,h ; Sub D from H w/borrow sbc a,d ld h,a ; Result in H jr c,$3 ; Done if carry set (further borrow) inc c ; Inc count jr $2 $3: ld a,l ; Add E to L add a,e ld l,a ; Result in L ld a,h ; Add D to H w/carry adc a,d ld h,a ; Result in H ld a,c ; Get result or a ; Check for zero jr nz,$4 or b ; Done with leading zeros? jr z,$4 ; Yes, leave them in cp 2 ; Remove zeros and space? jr z,$99 ; Yes, skip character ld a,' ' ; Replace zero with space jr $98 $4: ld b,0 ; No more leading zeros ld a,(neg) ; Check if negative number or a jr z,$5 ld (iy),'-' ; If so, place leading negative sign inc iy xor a ; Turn off negative so no more leading ld (neg),a ; signs are placed $5: ld a,c ; Get final value add a,'0' ; Convert to ASCII $98: ld (iy),a ; Place in memory inc iy $99: ld a,b ; Return a modified register B pop bc ; But restore C ld b,a ret ; ;-------------------------------------------------------------------- ; ; Math Support Routines ; ; ; Signed single-precision multiply ; ; Multiply DE by HL with result in HL and ; carry flag set if overflow ; spmul: push af bit 7,h ; Check if negative ld a,0 jr z,$1 call comphl ; Yes, complement and set sign flag ld a,0ffh $1: ld (sign1),a ; Save sign ex de,hl ; Swap contents bit 7,h ; Check if negative ld a,0 jr z,$2 call comphl ; Yes, complement and set sign flag ld a,0ffh $2: ld (sign2),a ; Save sign ex de,hl ; Swap again call unspm ; Do multiply on two positive operands jr c,$3 ; Overflow? bit 7,h ; Overflow? jr z,$4 ; No, continue $3: ld hl,7fffh ; Force max value on overflow $4: push hl ld hl,sign2 ; Calculate sign of result ld a,(sign1) xor (hl) pop hl jr z,okret ; Positive, return call comphl ; Negative, complement jr okret ; ; ; Signed single-precision divide ; ; Divide HL by DE with result in HL and ; carry flag set if overflow ; spdiv: push af bit 7,h ; Check if negative ld a,0 jr z,$1 call comphl ; Yes, complement and set sign flag ld a,0ffh $1: ld (sign1),a ; Save sign ex de,hl ; Swap contents bit 7,h ; Check if negative ld a,0 jr z,$2 call comphl ; Yes, complement and set sign flag ld a,0ffh $2: ld (sign2),a ; Save sign ex de,hl ; Swap again call unspd ; Do divide on two positive operands jr c,$3 ; Overflow? bit 7,h ; Overflow? jr z,$4 ; No, continue $3: ld hl,7fffh ; Force max value on overflow $4: push hl ld hl,sign2 ; Calculate sign of result ld a,(sign1) xor (hl) pop hl jr z,okret ; Positive, return call comphl ; Negative, complement jr okret ; ovflret: pop af scf ; Set carry ret okret: pop af or a ; Clear carry ret ; ; ; Unsigned single-precision multiply ; ; Multiply DE by HL with result in HL and ; carry flag set if overflow ; unspm: push af push bc push de xor a ; Clear overflow ld (ovfl),a push hl ld hl,0 ; Zero long accumulator ld (acc),hl pop hl ld b,16 ; Do 16 loops $1: srl h ; Rotate multiplier right rr l jr nc,$3 ; Don't add if LSB is zero push hl ; Save value ld hl,(acc) add hl,de ; Add in multiplicand ld (acc),hl ; New accumulated value jr nc,$2 ld a,0ffh ; Set overflow flag ld (ovfl),a $2: pop hl $3: sla e ; Rotate multiplicand left rl d djnz $1 pop de pop bc ld hl,(acc) ; Get result ld a,(ovfl) ; Check for overflow or a jr z,okret jr ovflret ; ; ; Unsigned single-precision divide ; ; Divide HL by DE with result in HL and ; carry flag set if overflow ; unspd: push af push bc push hl ld hl,0 ; Zero long accumulator ld (acc),hl pop hl ld a,h cp d ; Is H>D? jr c,$99 ; Result is zero if HE? jr c,$99 ; Result is zero if HL=0.4 s? jr nc,$mid ; Yes, go to common code ld a,(cpnoise) ; No, count it as noise inc a ld (cpnoise),a cp 2 ; Noise count >=2? jr c,$top ; No, continue to listen ld e,2 ; Yes, we probably hear voice, so flag connect jr $99 $again: ld a,65 ; Wait for up to 6.5 seconds call docp ; Do call progress ld e,2 ; Assume connect or a ; Check for no tone jr z,$99 ; Nothing heard, must be connected cp 4 ; >=0.4 s? jr nc,$mid ; Yes, go to common code ld a,(cpnoise) ; No, count it as noise inc a ld (cpnoise),a cp 2 ; Noise count >=2? jr c,$again ; No, continue to listen ld e,2 ; Yes, we probably hear voice, so flag connect jr $99 $mid: ld l,a ; Save A xor a ; Get a zero ld (cpnoise),a ; Zero noise counter ld a,l ; Restore A cp 7 ; Is tone <0.7 seconds? jr c,$busy ; Yes, check further for busy cp 23 ; Is tone <2.3 seconds? jr c,$ring ; Yes, assume a ring ld e,2 ; Sound heard >=2.3 seconds, so assume answer jr $99 $busy: ld e,1 ; Prepare for it to be a busy ld a,30 ; Wait for up to 3 seconds call docp ; Do call progress cp 4 ; >=0.4 s? jr nc,$bsy1 ; Yes, continue ld a,(cpnoise) ; No, count it as noise inc a ld (cpnoise),a cp 2 ; Noise count >=2? jr c,$again ; No, continue to listen ld e,2 ; Yes, we probably hear voice, so flag connect jr $99 $bsy1: cp 7 ; Is tone <0.7 seconds? jr c,$99 ; Yes, we have a busy jr $again ; No match, so start again $ring: ld e,0 ; Assume no answer dec d ; Decrement ring counter jr nz,$again ; Keep waiting (no answer if no jump) $99: xor a ; Get a zero ld (cpchk),a ; Tell task 4 to stop checking ld a,01h ; Enable tones, DTMF, no IRQ (reg A) ld bc,(ctrl88) out (c),a ld (iy),e ; Store value ld (iy+1),0 ; inc ix ld a,0 ; TRUE was not last operand jp goend ; ; Do call progress. Enter with A containing maximum time (in tenths of ; seconds) to wait for a tone. Returns with A containing length of ; tone heard (in tenths of seconds). Filters bursts shorter than 0.4 s. ; ; First wait for tone to start, then wait for it to end. Returns either ; when the maximum time has been reached or when the tone has started ; and stopped. ; docp: push de push ix ld e,0 ; Assume no tone at all for now ld (cpto),a ; Set up timeout $00: push de rt_run 2,2 ; Start secondary eval pop de ld a,0ffh ; Flag task 2 as running ld (t2flag),a $01: ld a,(cpontmr) ; Get how long CP has been on or a ; Still 0? jr nz,$11 ; Nope, tone has started ld a,(cpto) ; Waited long enough? or a jr z,$90 ; Yes, return ld a,(t2flag) ; Task 2 running? or a jr nz,$01 ; Yes, keep waiting jr $00 ; No, so start it again $10: push de rt_run 2,2 ; Start secondary eval pop de ld a,0ffh ; Flag task 2 as running ld (t2flag),a $11: ld a,(cpontmr) ; Get how long CP has been on or a ; Gone to 0? jr z,$90 ; Yes, tone has finished ld e,a ; Save new value ld a,(cpto) ; Waited long enough? or a jr z,$90 ; Yes, return ld a,(t2flag) ; Task 2 running? or a jr nz,$11 ; Yes, keep waiting jr $10 ; No, so start it again $90: ld a,(t2flag) ; Task 2 running? or a jr nz,$90 ; Yes, keep waiting ld a,e pop ix pop de ret ; ; New caller ID data flag ; cidnew: ld a,(newcid) ; New CID data flag ld (iy),a ; Store value ld (iy+1),0 ld a,0 ; TRUE was not last operand ld (newcid),a ; CIDnew false on next pass jp goend ; ; Caller ID month ; cidmon: ld hl,(ciddata) ; CID month ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Caller ID day ; cidday: ld hl,(ciddata+2) ; CID day ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Caller ID hour ; cidhour:ld hl,(ciddata+4) ; CID hour ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Caller ID minute ; cidmin: ld hl,(ciddata+6) ; CID minute ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Caller ID area code ; cidarea:ld hl,(ciddata+8) ; CID area code ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Caller ID exchange ; cidexch:ld hl,(ciddata+10) ; CID exchange ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Caller ID number ; cidnum: ld hl,(ciddata+12) ; CID number ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Get log size ; logsize: ld hl,(logptrt) ; Start of data ex de,hl ; Put head in DE ld hl,(logptrh) ; End of data xor a ; Clear carry sbc hl,de ; Figure size ld a,h and 07fh ; Clear high bit ld h,a srl h ; Divide by 8 rr l srl h rr l srl h rr l ld (iy),l ; Store value ld (iy+1),h ld a,0 ; TRUE was not last operand jp goend ; ; Netbyte ; netbyte:ld hl,netbit2 ; Point to netbits ld d,0 ld e,(ix) sla e ; Multiply by 8 rl d sla e rl d sla e rl d add hl,de ; Offset to first bit ld c,0 ; Initial value ld b,8 ; Do 8 bits $1: ld a,(hl) ; Get bit value rr a ; Shift bit into carry rr c ; Shift into composite value inc hl djnz $1 ; Do 8 bits ; ld (iy),c ; Save final value ld (iy+1),0 inc ix ld a,0 ; TRUE was not last operand jp goend ; ; Current AC power status ; acp: ld a,(acpwr) ; Current status ld (iy),a ; Store value ld (iy+1),0 ld a,0 ; TRUE was not last operand jp goend ; ; Has AC power failed since last test? ; acf: ld a,(acfail) ; Power failed flag ld (iy),a ; Store value ld (iy+1),0 ld a,(acpwr) ; Check if power is on or a jr z,$1 ; If not, don't touch value of ACfailed ld a,0 ; Power is back, so clear ld (acfail),a ; ACfailed for next pass $1: ld a,0 ; TRUE was not last operand jp goend ; ; Frequency inputs ; freq: ld hl,freqs ld e,(ix) ld d,0 sla e ; Multiply DE by 2 rl d add hl,de ; Offset to desired value ld e,(hl) ; Get frequency value (low byte) inc hl ld d,(hl) ; High byte ld (iy),e ; Save it ld (iy+1),d inc ix ld a,0 ; TRUE was not last operand jp goend ; ; Totalizer inputs ; total: ld hl,totals ld e,(ix) ld d,0 sla e ; Multiply DE by 2 rl d add hl,de ; Offset to desired value ld e,(hl) ; Get totalizer value (low byte) inc hl ld d,(hl) ; High byte ld (iy),e ; Save it ld (iy+1),d inc ix ld a,0 ; TRUE was not last operand jp goend ; ; Get a single keypad press ; getkey: ld e,(ix) ; Get module number call gkdig ; Get a digit cp 0ffh ; Timed out? jr z,$1 ; Yes, store -1 ld (iy),a ; Save value ld (iy+1),0 jr $2 $1: ld (iy),0efh ; Timed out, return -1 ld (iy+1),0ffh $2: inc ix ld a,0 ; TRUE was not last operand jp goend ; ; Get up to four keypad presses and return a single value. ; Pressing * or # terminates the number if shorter than ; four digits. ; getknum: ld b,4 ; Get four digits ld hl,0 ; Clear accumulator $1: ld e,(ix) ; Get module number call gkdig ; Get a digit cp 0ffh ; Timed out? jr z,$2 ; Yes, store -1 cp 10 ; Digit <= 9? jr nc,$15 ; No, so must be # or *; return ld de,10 call spmul ; HL = HL * 10 ld d,0 ld e,a add hl,de ; Add new digit djnz $1 $15: ld (iy),l ; Save final value ld (iy+1),h jr $3 $2: ld (iy),0efh ; Store -1 for timeout ld (iy+1),0ffh $3: inc ix ld a,0 ; TRUE was not last operand jp goend ; ; Get a single keypad press. Enter with AMAN module number in E. ; The timeout (in tenths of seconds) is in keyto. ; Returns with value in A (-1 is timed out). ; gkdig: push bc push de push hl push ix ld d,0 ld hl,ktime add hl,de ld a,(hl) ; Get timeout ld (keyto),a ; Set it up $0: push de rt_run 2,2 ; Start secondary eval pop de ld a,0ffh ; Flag task 2 as running ld (t2flag),a $1: ld c,e ; Get module number sla c ; Multiply by 4 sla c ld ix,khead0 ; First head pointer ld b,0 add ix,bc ; Offset to proper head pointer ld l,(ix) ; Low byte of head ld h,(ix+1) ; High byte of head ld c,(ix+2) ; Low byte of tail ld b,(ix+3) ; High byte of tail xor a ; Clear carry sbc hl,bc ; Compare the pointers jr nz,$2 ; Different, so key is ready ld a,(keyto) ; Check for timeout or a jr z,$15 ; Yes, take care of it ld a,(t2flag) ; Task 2 running? or a jr nz,$1 ; Yes, keep waiting jr $0 ; No, so start it again $15: ld a,0ffh ; Timed out, return -1 push af ; Save value jr $9 $2: ld l,(ix+2) ; Get the tail pointer ld h,(ix+3) ld c,(hl) ; Get the key ld b,16 ; Don't allow to go past 16 loops ld hl,keycvt ; Point to conversion table $3: ld a,(hl) ; Get next ASCII value sub c ; Compare it jr z,$4 ; If a match, get corresponding binary value inc hl ; If not, point to next one inc hl djnz $3 $4: inc hl ld a,(hl) ; Get binary value push af ; Save it ld l,(ix+2) ; Get tail pointer again ld h,(ix+3) inc hl ; Next buffer location push de ; Save module number (E) ld a,e ; Get module number again and 07h ; Ensure 0-7 inc a ld c,a ld b,8 mlt bc ex de,hl ; Put pointer in DE ld hl,kbuf0 ; Start of buffers add hl,bc ; End of this link's buffer (carry is cleared) sbc hl,de pop bc ; Restore module number (C) jr nz,$5 ; If result of subtract not zero, not end of buffer ld a,c ; Wrap around in buffer and 07h ; Ensure 0-7 ld c,a ld b,8 mlt bc ld hl,kbuf0 add hl,bc ex de,hl ; Put buffer start in DE $5: ld (ix+2),e ; Save tail pointer ld (ix+3),d $9: ld a,(t2flag) ; Task 2 running? or a jr nz,$9 ; Yes, keep waiting pop af ; Restore key to A pop ix pop hl pop de pop bc ret ; keycvt: db '0',0,'1',1,'2',2,'3',3,'4',4,'5',5,'6',6,'7',7 db '8',8,'9',9,'E',10,'F',11,'A',12,'B',13,'C',14,'D',15 db 0,0 ; ; goend: ld (trueop),a pop hl pop de pop bc pop af ret ; ; Convert BCD number in A to decimal and leave in A ; bcd2dec: push bc ld b,a srl b ; Move high nybble to low srl b srl b srl b ld c,10 mlt bc ; Multiply by 10 and 0fh ; Take off high nybble add a,c ; Add in low nybble pop bc ; All done ret ; ; ; Operation is a fixed type, so use dedicated routines. ; eva3: sub 10h ; Make into 0-13h sla a ; Multiply by 2 ld hl,optbl3 ; Point to operation table ld e,a ld d,0 add hl,de ; Offset to proper routine ld e,(hl) inc hl ld d,(hl) ; Get routine start address ex de,hl jp (hl) ; Do it ; optbl3: dw todeq,todne,todgt,todlt,todge,todle dw rset,inon,inoff,inedg dw neton,netoff,netedg,outon,outoff dw x10on,x10off,tmron,tmroff,buteq ; ; ; Routines to support optbl3 ; ; Time of Day ; todeq: ld iy,time+2 ; Point to minutes storage ld a,(ix+0) ; Minutes cp (iy+0) ; Current minutes jp nz,false3 ld a,(ix+1) ; Hours cp (iy+1) ; Current hours jp nz,false3 ld a,(ix+2) ; Day of week or a ; If day=0, every day jp z,true3 cp 8 ; Weekday? jr nz,$1 ld a,(weekday) or a jp nz,true3 jp false3 $1: cp 9 ; Weekend? jr nz,$2 ld a,(weekend) or a jp nz,true3 jp false3 $2: cp (iy+2) ; Current DOW jp nz,false3 jp true3 ; todne: ld iy,time+2 ; Point to minutes storage ld a,(ix+0) ; Minutes cp (iy+0) ; Current minutes jp nz,true3 ld a,(ix+1) ; Hours cp (iy+1) ; Current hours jp nz,true3 ld a,(ix+2) ; Day of week or a ; If day=0, every day jp z,false3 cp 8 ; Weekday? jr nz,$1 ld a,(weekday) or a jp nz,false3 jp true3 $1: cp 9 ; Weekend? jr nz,$2 ld a,(weekend) or a jp nz,false3 jp true3 $2: cp (iy+2) ; Current DOW jp nz,true3 jp false3 ; todgt: ld iy,time+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$3 cp 8 ; Weekday? jr nz,$1 ld a,(weekday) or a jr nz,$3 jp false3 $1: cp 9 ; Weekend? jr nz,$2 ld a,(weekend) or a jr nz,$3 jp false3 $2: cp (iy+2) jp nz,false3 $3: ld a,(iy+1) ; Time hour cp (ix+1) ; Event hour jp c,false3 jp nz,true3 ld a,(ix+0) ; Event minute cp (iy+0) ; Time minute jp nc,false3 jp true3 ; todlt: ld iy,time+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$3 cp 8 ; Weekday? jr nz,$1 ld a,(weekday) or a jr nz,$3 jp false3 $1: cp 9 ; Weekend? jr nz,$2 ld a,(weekend) or a jr nz,$3 jp false3 $2: cp (iy+2) jp nz,false3 $3: ld a,(ix+1) ; Event hour cp (iy+1) ; Time hour jp c,false3 jp nz,true3 ld a,(iy+0) ; Time minute cp (ix+0) ; Event minute jp nc,false3 jp true3 ; todge: ld iy,time+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$3 cp 8 ; Weekday? jr nz,$1 ld a,(weekday) or a jr nz,$3 jp false3 $1: cp 9 ; Weekend? jr nz,$2 ld a,(weekend) or a jr nz,$3 jp false3 $2: cp (iy+2) jp nz,false3 $3: ld a,(iy+1) ; Time hour cp (ix+1) ; Event hour jp c,false3 jp nz,true3 ld a,(iy+0) ; Time minute cp (ix+0) ; Event minute jp c,false3 jp true3 ; todle: ld iy,time+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$3 cp 8 ; Weekday? jr nz,$1 ld a,(weekday) or a jr nz,$3 jp false3 $1: cp 9 ; Weekend? jr nz,$2 ld a,(weekend) or a jr nz,$3 jp false3 $2: cp (iy+2) jp nz,false3 $3: ld a,(ix+1) ; Event hour cp (iy+1) ; Time hour jp c,false3 jp nz,true3 ld a,(ix+0) ; Event minute cp (iy+0) ; Time minute jp c,false3 jp true3 ; ; System Reset ; rset: ld a,(rstflg) jp argdone ; ; Direct Inputs ; inon: ld hl,input2 ld e,(ix) ld d,(ix+1) add hl,de bit 0,(hl) jp z,false2 jp true2 ; inoff: ld hl,input2 ld e,(ix) ld d,(ix+1) add hl,de bit 0,(hl) jp nz,false2 jp true2 ; inedg: ld hl,edge2 ld e,(ix) ld d,(ix+1) add hl,de bit 0,(hl) jp z,false2 jp true2 ; ; Netbits ; neton: ld hl,netbit2 ld e,(ix) ld d,(ix+1) add hl,de bit 0,(hl) jp z,false2 jp true2 ; netoff: ld hl,netbit2 ld e,(ix) ld d,(ix+1) add hl,de bit 0,(hl) jp nz,false2 jp true2 ; netedg: ld hl,nedge2 ld e,(ix) ld d,(ix+1) add hl,de bit 0,(hl) jp z,false2 jp true2 ; ; Direct Outputs ; outon: ld hl,output ld e,(ix) ld d,0 add hl,de bit 0,(hl) jp z,false1 jp true1 ; outoff: ld hl,output ld e,(ix) ld d,0 add hl,de bit 0,(hl) jp nz,false1 jp true1 ; ; X-10 Modules ; x10on: ld a,(ix) ; Get housecode sub 'A' rla rla rla rla and 0f0h add a,(ix+1) dec a ld e,a ld d,0 ld hl,modules add hl,de bit 0,(hl) jp z,false2 jp true2 ; x10off: ld a,(ix) ; Get housecode sub 'A' rla rla rla rla and 0f0h add a,(ix+1) dec a ld e,a ld d,0 ld hl,modules add hl,de bit 0,(hl) jp nz,false2 jp true2 ; ; Timers ; tmron: ld hl,timers ld e,(ix) ; Point to timer value sla e ld d,0 add hl,de ; Offset to desired timer inc hl bit 7,(hl) ; Check high bit of high byte jr z,false1 jr true1 ; tmroff: ld hl,timers ld e,(ix) ; Point to timer value sla e ld d,0 add hl,de ; Offset to desired timer inc hl bit 7,(hl) ; Check high bit of high byte jr nz,false1 jr true1 ; ; iButton ; buteq: ld a,(ix) ; Get module number inc ix and 07h ; Ensure 0-7 ld d,0 ld e,a sla e ; Multiply by 8 sla e sla e ld iy,cbutton ; Button storage add iy,de ; Offset to proper module ld b,8 ; Check up to 8 bytes $butlp: inc ix ; Skip over byte flag ld a,(ix) ; Get next byte of compare code cp (iy) ; Compare with read code inc ix ; (Incs don't affect Z flag) inc iy jr nz,$nope ; If not the same, no match djnz $butlp jr true0 ; Match complete, good $nope: dec b jr z,false0 inc ix ; Finish adjusting pointer inc ix jr $nope ; ; false0: ld a,00h jr argdone ; true0: ld a,0ffh jr argdone ; false1: ld a,00h jr f1 true1: ld a,0ffh f1: inc ix jr argdone ; false2: ld a,00h jr f2 true2: ld a,0ffh f2: inc ix inc ix jr argdone ; false3: ld a,00h jr f3 true3: ld a,0ffh f3: inc ix inc ix inc ix jr argdone ; false4: ld a,00h jr f4 true4: ld a,0ffh f4: inc ix inc ix inc ix inc ix ; argdone: xor b pop hl pop de pop bc ret ; page ; ;========================================================================= ; ; T A S K 2 ; ; Secondary Event Evaluation Routine ; ; Evaluate the event list starting at 'events'. ; task2: ld sp,t2sp ld a,0ffh ld (t2flag),a ; Flag us as running ; ld hl,(op1) ; Save eval operand storage push hl ld hl,(op2) push hl ; call savetbls ; Save secondary tables for Task 1 call copytbls ; Copy primary storage tables ; to secondary storage for testing ; call toggle2 ; Toggle output bit ; ld ix,events ld a,(ix) ; Empty table? cp endtbl jp z,$8 ; Yes, leave cp endcont ; End of continuous section? jp z,$8 ; Yes, skip sequential $1: ld b,(ix) ; Save IF/IFA opcode inc ix ; Skip over opcode call eval ; Evaluate condition jr z,$3 ; Skip if equation is false ; ld c,(ix) ; Get "already done" flag ld (ix),0ffh ; Mark action done inc ix ; Point to offset ld a,b ; Check opcode cp ifa ; IF always? jr z,$2 ; If so, skip done flag test ld a,c ; Check done flag or a jr z,$2 ; Not done, so do it ld e,(ix) ; Was done, so skip over it inc ix ; Get low byte of offset ld d,(ix) ; Get high byte of offset inc ix add ix,de ; Skip over action ld a,(ix) ; Get LAST or ELSE inc ix ; Move past code cp elseop ; ELSE? jr nz,$7 ; Nope inc ix ; Also skip the ELSE, so point to offset jr $6 ; Skip the ELSE $2: inc ix ; Move past offset inc ix call action ; Do it jr $7 ; Continue $3: ld (ix),0 ; Mark as not done inc ix ; Point to the offset $4: ld e,(ix) ; Get low byte of offset inc ix ld d,(ix) ; Get high byte of offset inc ix add ix,de ; Skip over action ; ld a,(ix) ; Get LAST or ELSE inc ix ; Move past code cp elseop ; ELSE? jr nz,$7 ; Nope ; ld c,(ix) ; Get "already done" flag ld (ix),0ffh ; Mark action done inc ix ; Point to offset ld a,b ; Check opcode cp ifa ; IF always? jr z,$5 ; If so, skip done flag test ld a,c ; Check done flag or a jr nz,$6 ; Skip if normal IF and already done $5: inc ix ; Move past offset inc ix call action ; Do it jr $7 ; Continue $6: ld e,(ix) ; Get low byte of offset inc ix ld d,(ix) ; Get high byte of offset inc ix add ix,de ; Skip over action inc ix $7: ld a,(ix) ; Check for end cp endcont ; End of continuous section? jr z,$8 ; Yes, finish up cp endtbl ; End of table? jp nz,$1 ; No, do next event $8: pop hl ; Restore eval operand storage ld (op2),hl pop hl ld (op1),hl ; call resttbls ; Put tables back for Task 1 ; rt_cancel 2 ; Cancel after one pass through list ; ld a,0 ld (rstflg),a ; No more reset state ld (t2flag),a ; We're no longer running ; rt_exit ; page ; ;========================================================================= ; ; T A S K 3 ; ; Read the SmartWatch or CS real-time clock and place the time starting ; at "time." SmartWatch code uses only registers during watch access. ; Also uses alternate registers which aren't saved by the RTOS, so ; interrupts *must* be off when running code between the dotted lines. ; task3: ld sp,t3sp ; ld a,(time+1) ; Get current seconds ld e,a ld a,(time+2) ; Get current minutes ld d,a ; Save them for timer update check push de ; ld a,(sc) ; Check processor type cp sccs jr nz,sw ; If RTC or BCC, do SmartWatch ; ; Read the clock contents and save them in eight bytes starting at ; TIME. Stored in SmartWatch format. ; ld bc,clock+0dh $0: ld a,5 ; Set hold out (c),a in a,(c) ; Get status bit 1,a ; Busy? jr z,$1 ; Nope, continue ld a,4 ; Yes, clear hold out (c),a jr $0 ; Check again $1: di ld bc,clock ld hl,time ld (hl),0 ; Fractional seconds inc hl call $rdbyte ; Get seconds call $rdbyte ; Get minutes call $rdbyte ; Get hours inc hl ; Skip over DOW storage call $rdbyte ; Get day call $rdbyte ; Get month call $rdbyte ; Get year in a,(c) ; Get DOW and 07h ; Kill upper bits inc a ; Make 0-6 into 1-7 ld (time+4),a ; Save DOW ; ld bc,clock+0dh ld a,4 ; Clear hold out (c),a ; jp t3cont ; ; Read a byte from the RTC a nybble at a time starting at port BC ; and save it at HL. On exit, BC and HL point to next port and ; storage location. E is corrupted. ; $rdbyte: in a,(c) ; Get low nybble inc bc ; Point to next and 0fh ; Kill upper bits ld e,a ; Save it in a,(c) ; Get high nybble inc bc ; Point to next and 0fh ; Kill upper bits rlca ; Put into upper nybble rlca rlca rlca or e ; Combine with lower half ld (hl),a ; Save it inc hl ret ; ;.................................................................... ; sw: di ld b,8 $0: ld a,(swram) ; Prepare for key djnz $0 ; ld hl,key ; Point to key ld c,8 ; 8 bytes $1: ld b,8 ; 8 bits/byte ld a,(hl) $2: ld (swram),a ; Send bit of key (D0) rrca ; Rotate next bit into D0 djnz $2 ; Do 8 bits inc hl ; Do next byte dec c jr nz,$1 ; ld b,8 ; Tenths of seconds $3: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $3 ; Do 8 bits ld a,c exx ; Alternate ld b,a exx ; Primary ; ld b,8 ; Seconds $4: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $4 ; Do 8 bits ld a,c exx ; Alternate ld c,a exx ; Primary ; ld b,8 ; Minutes $5: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $5 ; Do 8 bits ld a,c exx ; Alternate ld d,a exx ; Primary ; ld b,8 ; Hours $6: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $6 ; Do 8 bits ld a,c exx ; Alternate ld e,a exx ; Primary ; ld b,8 ; Day of week $7: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $7 ; Do 8 bits ld a,c and 0fh ; Clear extra bits exx ; Alternate ld h,a exx ; Primary ; ld b,8 ; Day of month $8: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $8 ; Do 8 bits ld a,c exx ; Alternate ld l,a exx ; Primary ; ld b,8 ; Month $9: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $9 ; Do 8 bits ld d,c ; ld b,8 ; Year $10: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $10 ; Do 8 bits ld e,c ; ld ix,time ld (ix+6),d ld (ix+7),e exx ; Alternate ld (ix+0),b ld (ix+1),c ld (ix+2),d ld (ix+3),e ld (ix+4),h ld (ix+5),l exx ; Primary ; ;.................................................................... ; t3cont: ei pop de ld a,(time+2) ; Get current minutes cp d ; Update minutes timers if call nz,updmtmrs ; minutes have changed ; ld a,(time+1) ; Get current seconds cp e ; Have seconds changed? jr z,$11 ; Nope, done cp 30h ; Yes, are we on the half minute? jr nz,$10 ; Nope, continue ld a,0ffh ; Flag to check AC power ld (acchk),a ; status if using PL-Link ld hl,mancfgf ; Flags to get Answer MAN configurations ld b,8 $man: ld (hl),0ffh inc hl djnz $man $10: call updstmrs ; Update seconds timers on change ; ld a,(time+4) ; Get day of week cp 1 ; Sunday? jr z,$12 ; Yes, mark weekend cp 7 ; Saturday? jr nz,$13 ; No, weekday $12: ld a,0ffh ; Flag weekend ld (weekend),a ld a,0 ld (weekday),a jr $14 $13: ld a,0ffh ; Flag weekday ld (weekday),a ld a,0 ld (weekend),a $14: ld a,0ffh ld (dtimef),a ; Flag to display time ld (dinpf),a ; Flag to display inputs ld (doutf),a ; Flag to display outputs ld (dadcf),a ; Flag to display ADC channels ld (ddacf),a ; Flag to display DAC channels ld (dnetf),a ; Flag to display network modules ld (dbitf),a ; Flag to display netbits $11: rt_exit ; ; updstmrs: ld ix,timers ; Timer values ld b,stmrs ; Number of seconds timers $1: ld a,(ix+1) ; Get high byte bit 7,a ; Timer on? jr z,$2 ; No, skip ld e,(ix) ld d,(ix+1) inc de ; 16-bit increment ld a,d or e jr z,$2 ; Don't allow to wrap ld (ix),e ; Save new value ld (ix+1),d $2: inc ix inc ix djnz $1 ; ; Also decrement all network module status timers ; ld hl,nettmrs ld b,modtyp*modnum xor a ; Zero A $3: cp (hl) ; Timer=0? jr z,$4 ; Yes, skip decrement dec (hl) $4: inc hl djnz $3 ; Do all timers ret ; ; updmtmrs: ld ix,timers+(stmrs*2) ; Timer values (skip seconds timers) ld b,mtmrs ; Number of minutes timers $1: ld a,(ix+1) ; Get high byte bit 7,a ; Timer on? jr z,$2 ; No, skip ld e,(ix) ld d,(ix+1) inc de ; 16-bit increment ld a,d or e jr z,$2 ; Don't allow to wrap ld (ix),e ; Save new value ld (ix+1),d $2: inc ix inc ix djnz $1 ; ; We also need to check if there have been any recent PL-Link ; transmissions and flag an X-10 table update if not. ; ld a,(plsent) or a ; PL-Link tranmission in the last minute? jr z,$3 ; Nope, flag to update table xor a ld (plsent),a ; Clear flag for next minute ld (uptbl),a ; Make sure table isn't updated jr $4 $3: ld a,0ffh ; Flag to update table ld (uptbl),a $4: ret ; page ; ;========================================================================= ; ; T A S K 4 ; ; Get inputs and place them in memory. Also increments and decrements ; time-out timers used by other tasks that might ordinarily ; get stuck in infinite loops. Also process the RTC-DTMF ring ; detect and call progress timeouts plus speech timeout. ; task4: ld sp,t4sp ld hl,input1 ld iy,edge1 ld ix,inptbl ; Input port table $1: ld c,(ix) ld b,(ix+1) ld a,b or c jr z,$99 ; If port addr=0, done ; ld e,8 ; Do 8 bits in d,(c) ; Get input byte $2: ld a,07fh ; Set up for off bit srl d ; Rotate bit 0 to carry jr c,$3 ; No inversion ld a,0 ; Really an on bit $3: push bc ld b,(hl) ; Get previous value bit 7,b ; Manually set? jr nz,$5 ; Yes, so ignore physical input cp b ; Same as new? jr z,$4 ; Yes, no edge ld (iy),0ffh ; Flag edge $4: ld (hl),a ; Save bit state $5: pop bc inc hl ; Point to next storage inc iy ; Point to next edge flag dec e ; Do all bits jr nz,$2 inc ix ; Point to next table entry inc ix jr $1 ; Do next port ; ; Read the ADC channel we started last time, then start the ; next channel ; $99: ld a,(sc) ; Check hardware or a jp z,$39 ; Not configured yet, skip cp sccs ; CS? jp z,$60 ; Yes, do it cp scrtc ; RTC180? jr z,$20 ; Yes, do it ld a,(adcres) ; BCC180, so check resolution cp 12 ; 12 bits (BCC30)? jr z,$35 ; Yes, do it jr $25 ; Must be BCC13 (8 bits) ; ; Do ADC on RTC180 ; $20: ld bc,rtcadc ld a,(channel) ; Get current ADC channel add a,c ; Add offset to ADC base address ld c,a in e,(c) ; Get conversion value low byte ld d,0 ; Start with high byte zero ld a,(adcres) ; Check resolution cp 8 jr z,$21 ; Only 8 bits, so done reading in a,(c) ; It's 10 bits, so get other 2 rla ; Rotate them into final number rl e rl d rla rl e rl d $21: ld hl,adcvals ; Point to storage ld a,(channel) ; Get channel number again ld b,0 ld c,a sla c ; Multiply BC by 2 rl b add hl,bc ; Offset to correct locations inc hl ; Point at high byte bit 7,(hl) ; Forced value? jr nz,$21a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $21a: inc a ; Next channel cp 8 ; Too far? jr c,$22 ; No, save it ld a,0 ; Start again at 0 $22: ld (channel),a ; Save it ld bc,rtcadc add a,c ; Point to next channel port ld c,a out (c),a ; Start conversion jp $39 ; Exit ; ; Do BCC13 ; $25: ld bc,bcc13 ld a,(channel) ; Get current ADC channel add a,c ; Add offset to ADC base address ld c,a in e,(c) ; Get conversion value low byte ld d,0 ; High byte always zero ld hl,adcvals+16 ; Point to storage ld a,(channel) ; Get channel number again ld b,0 ld c,a sla c ; Multiply BC by 2 rl b add hl,bc ; Offset to correct locations inc hl ; Point at high byte bit 7,(hl) ; Forced value? jr nz,$25a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $25a: inc a ; Next channel cp 8 ; Too far? jr c,$26 ; No, save it ld a,0 ; Start again at 0 $26: ld (channel),a ; Save it jr $39 ; ; Do BCC30 ; $35: ld bc,bcc30 in d,(c) ; Get conversion value high byte in e,(c) ; Get low byte bit 4,d ; Check sign bit jr z,$36 ; If positive, it's OK ld de,0 ; Force to 0 if negative $36: ld hl,adcvals+192 ; Point to storage ld a,(channel) ; Get channel number ld b,0 ld c,a sla c ; Multiply BC by 2 rl b add hl,bc ; Offset to correct locations inc hl ; Point at high byte bit 7,(hl) ; Forced value? jr nz,$36a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $36a: inc a ; Next channel cp 16 ; Too far? jr c,$38 ; No, save it ld a,0 ; Start again at 0 $38: ld (channel),a ; Save it ld bc,bcc30 set 4,a out (c),a ; Select channel and reset ADC res 4,a out (c),a ; Now start conversion jr $39 ; ; Do CS serial ADC ; $60: call rdadc ; Do conversion ex de,hl ; Put result in DE ld hl,adcvals+256 ; Point to storage ld a,(channel) ; Get channel number again ld b,0 ld c,a sla c ; Multiply BC by 2 rl b add hl,bc ; Offset to correct locations inc hl ; Point at high byte bit 7,(hl) ; Forced value? jr nz,$60a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $60a: inc a ; Next channel cp 8 ; Too far? jr c,$61 ; No, save it ld a,0 ; Start again at 0 $61: ld (channel),a ; Save it call setchan ; Set up mux for next read ld hl,adcgain ; Point to gain storage ld e,a ld d,0 add hl,de ; Offset to correct channel ld a,(hl) ; Get gain call setgain ; Set it ; ; Process timers ; $39: ld hl,totmr inc (hl) ; Increment time-out timer ld a,(dtmfto) dec a ; Decrement timer used by DTMF stuff cp 0ffh jr z,$39a ; Don't let wrap around ld (dtmfto),a $39a: ld a,(keyto) dec a ; Decrement timer used by keypad stuff cp 0ffh jr z,$39b ; Don't let wrap around ld (keyto),a $39b: ld a,(cpto) dec a ; Decrement timer used by CP stuff cp 0ffh jr z,$39c ; Don't let wrap around ld (cpto),a $39c: ld a,(saytmr) dec a ; Decrement speech timer cp 0ffh jr z,$40 ; Don't let wrap around ld (saytmr),a ; ; Process ring detect signal ; $40: ld a,(ringtmr) inc a ; Increment time since last ring jr z,$41 ; Don't let wrap around ld (ringtmr),a $41: ld a,(ringtmr) ; Get time since last ring started cp 30 ; <3 seconds? jr c,$49 ; Yes, don't do anything jr nz,$42 ; Jump if not exactly 3 seconds ld hl,ringctr inc (hl) ; Increment number of rings detected inb a,dtmfsts ; Read status to clear ring interrupt in0 a,(itc) set 1,a ; Reenable INT1 out0 (itc),a jr $49 $42: cp 60 ; <6 seconds? jr c,$49 ; Yes, between rings ld a,0 ld (ringctr),a ; Clear ring counter ; ; Process call progress signal ; $49: ld a,(cpchk) ; Checking call progress? or a jr z,$59 ; Nope, skip CP check ld a,(sc) cp sccs ; CS? jr nz,$53 ; No, do RTC/BCC ; ld bc,pia1+2 ; CP status port ; MSB - 991226 v3.63s - Z8S180 change for faster system clock (18.432 MHz) ; ld de,1125 ; Num of loops for 5 ms ld de,2248 ; Num of loops for 5 ms $50: in a,(c) ; Check CP status (9 T states) bit 6,a ; (6) jr nz,$57 ; Found, inc on time (6) dec de ; Decrement timeout (4) ld a,d ; (4) or e ; (4) jr nz,$50 ; Keep checking (8) jr $55 $53: ld bc,dtmfsts ; DTMF board status port ; MSB - 991226 v3.63s - Z8S180 change for faster system clock (18.432 MHz) ; ld de,1125 ; Num of loops for 5 ms ld de,2248 ; Num of loops for 5 ms $54: in a,(c) ; Check CP status (9 T states) bit 2,a ; (6) jr nz,$57 ; Found, inc on time (6) dec de ; Decrement timeout (4) ld a,d ; (4) or e ; (4) jr nz,$54 ; Keep checking (8) ; $55: ld a,(cpofftmr) ; Nothing in 5 ms, so count off time inc a ; Increment off time jr z,$56 ; Don't let wrap around ld (cpofftmr),a $56: xor a ; Get a zero ld (cpontmr),a ; Clear on timer jr $59 $57: ld a,(cpontmr) ; Yes, count on time inc a ; Increment on time jr z,$58 ; Don't let wrap around ld (cpontmr),a $58: xor a ; Get a zero ld (cpofftmr),a ; Clear off timer $59: rt_exit ; inptbl: dw port1+0 ; 0-7 dw port1+1 ; 8-15 dw port2+0 ; 16-23 dw port2+1 ; 24-31 dw port2+2 ; 32-39 dw port4+0 ; 40-47 dw port4+1 ; 48-55 dw port4+2 ; 56-63 dw port6i+0 ; 64-71 dw port6i+1 ; 72-79 dw port6i+2 ; 80-87 dw port7i+0 ; 88-95 dw port7i+1 ; 96-103 dw port7i+2 ; 104-111 dw port8i+0 ; 112-119 dw port8i+1 ; 120-127 dw port8i+2 ; 128-135 dw port9i+0 ; 136-143 dw port9i+1 ; 144-151 dw port9i+2 ; 152-159 dw pia2 ; 160-167 dw pia2+2 ; 168-175 dw pia3 ; 176-183 dw port10+0 ; 184-191 dw port10+1 ; 192-199 dw port10+2 ; 200-207 dw 0 ; ; Set CS analog mux channel. Channel number (0-7) in A on entry. ; setchan: push af push bc push de and a,07h ; Ensure 0-7 ld e,a ; Save it ld a,0 ; Gain 1 call setgain ld bc,pia1+2 in a,(c) ; Get current port and 0f8h ; Mask off lower three bits or e ; Insert new channel out (c),a ; Select it pop de pop bc pop af ret ; ; Set CS ADC gain. A contains gain value on entry. ; 0 = 1, 1 = 2, 2 = 4, 3 = 8 ; setgain: push af push bc push de di ld e,a ld bc,pia1+1 in a,(c) ; Do bit 0 of gain or a,34h res 3,a ; Assume a 0 bit 0,e ; Check what it should be jr z,$1 ; If zero, we were correct set 3,a ; One, so set bit $1: out (c),a ld bc,pia1+3 in a,(c) ; Do bit 1 of gain or a,34h res 3,a ; Assume a 0 bit 1,e ; Check what it should be jr z,$2 ; If zero, we were correct set 3,a ; One, so set bit $2: out (c),a ei pop de pop bc pop af ret ; ; Read the CS serial ADC. Channel and gain must have been set already. ; Returns with conversion value in HL. ; rdadc: push af push bc push de call cson call inbyte ; Get high byte ld d,a call inbyte ; Get low byte ld e,a ; ; Now reverse the bit order and clean up by rotating into HL ; ld hl,0 ; Clear workspace rr d ; Skip over two junk bits rr d ld b,6 ; Do remaining six bits $1: rr d ; Rotate into carry rl l ; Rotate into L (reverse bit order) djnz $1 ; Do all six bits ld a,(adcres) ; Get ADC resolution sub 6 ; Already done first six bits ld b,a $2: rr e rl l rl h djnz $2 call csoff pop de pop bc pop af ret ; ; Turn on CS ADC chip select ; cson: push af push bc di ld bc,pia1+2 in a,(c) res 3,a ; Turn chip select on out (c),a ei pop bc pop af ret ; ; Turn off CS ADC chip select ; csoff: push af push bc di ld bc,pia1+2 in a,(c) set 3,a ; Turn chip select off out (c),a ei pop bc pop af ret ; ; Get a serial byte from the CS ADC using the CSIO ; inbyte: in0 a,(cntr) ; Get CSIO status bit 5,a ; Already receiving? jr nz,inbyte ; Yes, wait set 5,a out0 (cntr),a ; Start receiving in1: in0 a,(cntr) ; Get CSIO status bit 5,a ; Done receiving? jr nz,in1 ; No, wait in0 a,(trdr) ; Get byte ret ; ;========================================================================= ; ; T A S K 5 ; ; Host computer interface handler ; task5: ld sp,t5sp ld a,(modemf) ; Check if modem is present ld b,a ld a,(initmdm) ; and needs initializing again and b jp nz,setmodem ; If so, do it ; call cstat ; Anything from PC? jp z,chkdisp ; No, see if anything to be displayed call cin ; Yes, get next character cp reply ; Are we getting an echo? jp z,setmodem ; Yes, must be modem cp '0' ; Start of SDMF caller ID response? jp z,callerid ; Yes, parse string cp '8' ; Start of MDMF caller ID response? jp z,callerid ; Yes, parse string cp alert ; Lead-in alert character? jp nz,chkdisp ; No, check for status display ; call cin ; Get command byte jp c,t5done ; Abort on timeout cp 32h ; <32h? jp nc,t5done ; Abort if out of range sla a ; Multiply by 2 ld e,a ld d,0 ; Create an offset ld hl,cmdtbl ; Start of command table add hl,de ; Point to proper routine ld e,(hl) inc hl ld d,(hl) ex de,hl jp (hl) ; Go to proper routine ; cmdtbl: dw sysrst,pause,updat,seltim,gettim,settim,newprg,clrlog dw logsiz,getlog,setlog,fill,fill,fill,fill,fill dw selx10,getx10,setx10,selinp,getinp,setinp dw selout,getout,setout,seladc,getadc,setadc dw seldac,getdac,setdac,selmod,getmod dw selnet,getnet,setnet,getvar,setvar dw fill,fill,fill,fill,fill,fill,fill,fill,fill,fill dw netstr,saystr ; fill: jp t5done ; ;------------------------------------------------------------------------- ; ; Initialize modem ; setmodem: ld a,0ffh ld (modemf),a ; Flag modem present ld a,0 ld (initmdm),a ; Don't need to initialize again ; ld a,cr ; Lets terminate the garbage in the modem call cout $0: call cin ; Flush input buffer and let modem get ready for ATZ jr nc,$0 ; (Timeout allows modem to finish sending) ; ld hl,mreset ; Reset modem $1: ld a,(hl) or a jr z,$2 call cout inc hl jr $1 $2: call wtreply jp c,t5done ; If no reply, abort ; ld hl,mdminit ; Send basic init string $3: ld a,(hl) or a jr z,$4 call cout inc hl jr $3 $4: ld hl,rinit ; Add number of rings to string $5: ld a,(hl) or a jr z,$6 call cout inc hl jr $5 $6: ld a,(mrings) ; Get number of rings add a,'0' ; Make into ASCII call cout ; ld a,(icidf) ; Should we include CID string? or a jr z,$99 ; Nope, so finish up ld hl,cidinit ; Set up caller ID $7: ld a,(hl) or a jr z,$8 call cout inc hl jr $7 $8: ld a,(cidon) ; Get on/off status or a ld a,'2' ; Turn it on jr nz,$9 ld a,'0' ; Turn it off $9: call cout $99: ld a,cr ; Send cr for end of init command call cout call wtreply jp c,t5done ; If no reply, abort jp t5exit ; All done ; mreset db 'ATZ',cr,0 ; cr/lf flushes modem line buffer ;minit db 'AT&FMV&D&K&Q5',0 ; Newer modem init string minit db 'AT&F0E1L2M1Q0V1',0 rinit db 'S0=',0 cidinit db '#CID=',0 ; ; ; Process Caller ID inSDMF or MDMF ; ; SDMF is the older style of Caller ID used for Calling Number Delivery ; It is being phased out by Bellcore, but some telcos still use it if ; customers do not subscribe to calling name delivery ; ; The format for the message from the modem will be as follows: ; ; Character Decimal ASCII Actual ; Description Value Value Bits (LSB) ; ------------------- ------- ----- --------------- ; Message Type (SDMF) 4 0 0 0 0 0 1 0 0 ; Message Length (18) 18 0 0 0 1 0 0 1 0 ; Month (December) 49 1 0 0 1 1 0 0 0 1 ; 50 2 0 0 1 1 0 0 1 0 ; Day (25) 50 2 0 0 1 1 0 0 1 0 ; 53 5 0 0 1 1 0 1 0 1 ; Hour (3pm) 49 1 0 0 1 1 0 0 0 1 ; 53 5 0 0 1 1 0 1 0 1 ; Minutes (30) 51 3 0 0 1 1 0 0 1 1 ; 48 0 0 0 1 1 0 0 0 0 ; Number (6061234567) 54 6 0 0 1 1 0 1 1 0 ; 48 0 0 0 1 1 0 0 0 0 ; 54 6 0 0 1 1 0 1 1 0 ; 49 1 0 0 1 1 0 0 0 1 ; 50 2 0 0 1 1 0 0 1 0 ; 51 3 0 0 1 1 0 0 1 1 ; 52 4 0 0 1 1 0 1 0 0 ; 53 5 0 0 1 1 0 1 0 1 ; 54 6 0 0 1 1 0 1 1 0 ; 55 7 0 0 1 1 0 1 1 1 ; Checksum 79 0 1 0 0 1 1 1 1 ; ; If the number is not sent due to Out of Area or Private, ; the number field (Byte 11) will be O or P in ASCII and the ; message length will be 9 instead of 18 ; ; MDMF is the newer data format used when customers have Calling ; Name Delivery (CNAM) and also by a growing number of telcos for ; simple Calling NUmber Delivery (CND) as Bellcore phases out SDMF ; ; The format of MDMF is as follows: ; ; Character Decimal ASCII Actual ; Description Value Value Bits (LSB) ; -------------------------- ------- ----- --------------- ; Message Type (MDMF) 128 1 0 0 0 0 0 0 0 ; Message Length (33) 33 0 0 1 0 0 0 0 1 ; Parameter Type (Date/Time) 1 0 0 0 0 0 0 0 1 ; Parameter Length (8) 8 0 0 0 0 1 0 0 0 ; Month (November) 49 1 0 0 1 1 0 0 0 1 ; 49 1 0 0 1 1 0 0 0 1 ; Day (28) 50 2 0 0 1 1 0 0 1 0 ; 56 8 0 0 1 1 1 0 0 0 ; Hour (3pm) 49 1 0 0 1 1 0 0 0 1 ; 53 5 0 0 1 1 0 1 0 1 ; Minutes (43) 52 4 0 0 1 1 0 1 0 0 ; 51 3 0 0 1 1 0 0 1 1 ; Parameter Type (Number) 2 0 0 0 0 0 0 1 0 ; Parameter Length (10) 10 0 0 0 0 1 0 1 0 ; Number (6062241359) 54 6 0 0 1 1 0 1 1 0 ; 48 0 0 0 1 1 0 0 0 0 ; 54 6 0 0 1 1 0 1 1 0 ; 50 2 0 0 1 1 0 0 1 0 ; 50 2 0 0 1 1 0 0 1 0 ; 52 4 0 0 1 1 0 1 0 0 ; 49 1 0 0 1 1 0 0 0 1 ; 51 3 0 0 1 1 0 0 1 1 ; 53 5 0 0 1 1 0 1 0 1 ; 57 9 0 0 1 1 1 0 0 1 ; Parameter Type (Name) 7 0 0 0 0 0 1 1 1 ; Parameter Length (9) 9 0 0 0 0 1 0 0 1 ; Name (Joe Smith) 74 J 0 1 0 0 1 0 1 0 ; 111 o 0 1 1 0 1 1 1 1 ; 101 e 0 1 1 0 0 1 0 1 ; 32 0 0 1 0 0 0 0 0 ; 83 S 0 1 0 1 0 0 1 1 ; 109 m 0 1 1 0 1 1 0 1 ; 105 i 0 1 1 0 1 0 0 1 ; 116 t 0 1 1 1 0 1 0 0 ; 104 h 0 1 1 0 1 0 0 0 ; Checksum 88 0 1 0 1 1 0 0 0 ; ; The time/date section is the same as SDMF which will allow us to use the ; same code for it. The number and name sections are identified by their ; Parameter Type. An actual Phone Number section is prefixed with 0x02. ; The name is prefixed with a 0x07. If the number is not present due to ; Private or Out of Area, the Number Parm Type will be 0x04 and the name ; parm type will be 0x08. The length of both parms will be 0x01. Their ; data byte will both be 'P' for Private and 'O' for out of area. ; callerid: ld hl,cndbuf ld (hl),0 ; Clear Name Buffer on each call ld hl,cidbuf ld (hl),a ; Store first data byte which flags SDMF or MDMF inc hl $0: call cin jp c,t5exit ; Unexpected end of data ld (hl),a ; Put in buffer inc hl cp a,cr ; End of string? jr nz,$0 ; Nope, keep going ; Need to skip proper # of bytes for SDMF or MDMF ld a,(cidbuf) ; Grab first byte 0=SDMF 8=MDMF cp a,'0' ; SDMF? jr nz,$1 ; Nope, MDMF ld ix,cidbuf+5 ; Skip to lower nibble of 1st data byte (SDMF) jr $2 $1: ld ix,cidbuf+9 ; Skip to lower nibble of 1st data byte (MDMF) $2: ld iy,ciddata ; Point to XPRESS data buffer ld b,2 call cidpars ; Parse month ld b,2 call cidpars ; Parse day ld b,2 call cidpars ; Parse hour ld b,2 call cidpars ; Parse minute ; At this point, we are pointing to the lower nibble of the next data byte ; We may need to skip ahead for MDMF (+4 bytes) ld a,(cidbuf) ; Grab SDMF/MDMF flag cp a,'8' ; Is it MDMF? jr nz,$3 ; Nope - its SDMF ld ix,cidbuf+29 ; Skip to lower nibble of 1st MDMF data byte $3: dec ix ; Point to upper nybble of first data byte ld a,(ix) ; Check for out of area or private cp '4' ; Out of area? (ASCII O = 4F) jr nz,$5 ; Nope ld a,0 ; Put 000 in area code, exch, and number ld b,6 $4: ld (iy),a inc iy djnz $4 ; Lets store 'Out of Area' in %N & %M buffer even if they don't have CNAMD ld ix,cndbuf ; Point to CND buffer ld iy,cndnum ; Point to Num Buffer ld hl,cndouta ; Point to OOA String $41 ld a,(hl) ; Grab string character ld (ix),a ; Store the character ld (iy),a or a ; Done yet? jp z,$9 ; Yes, lets do the string inc ix inc iy inc hl jr $41 ; Next char $5: cp '5' ; Private? (ASCII P = 50) jr nz,$6 ; Nope, must be real number ld hl,999 ; Put 999 in area code and exch ld (iy),l ld (iy+1),h ld (iy+2),l ld (iy+3),h ld hl,9999 ; Put 9999 in number ld (iy+4),l ld (iy+5),h ; Lets store 'Private' in %N & %M buffer even if they don't have CNAMD ld ix,cndbuf ; Point to CND buffer ld iy,cndnum ; Point to Number Buffer ld hl,cndpriv ; Point to Private String $51 ld a,(hl) ; Grab string character ld (ix),a ; Store the character ld (iy),a or a ; Done yet? (0 at end) jp z,$9 ; Yes, lets quit inc ix inc iy inc hl jr $51 ; Next char ; Process the phone number ; If we have a real number, lets store it in the %N buffer as well. $6: push ix ; Save the pointer to the number inc ix ; Point back at low nybble ld b,3 call cidpars ; Parse area code ld b,3 call cidpars ; Parse exchange ld b,3 call cidpars ; Parse first three digs of number dec iy ; Get result dec iy ld l,(iy) ld h,(iy+1) ld de,10 ; Multiply it by 10 call mult ld a,(ix) ; Get fourth digit and 0fh ld d,0 ld e,a add hl,de ld (iy),l ; Save final result ld (iy+1),h ; Now lets go back and store the number in the text buffer pop ix ; Grab old pointer (pointing to upper nibble) ld iy,cndnum ; Point to number buffer ld b,3 ; Process each part call numpars ld (iy),'-' ; Save - between Area Code & Exchange inc iy ld b,3 call numpars ld (iy),'-' ; Save - between Exchange & Number inc iy ld b,4 call numpars ld (iy),0 ; End of data flag ; If we had a real number, lets see if we have a name too ld a,(cidbuf) ; Grab SDMF/MDMF flag cp '8' ; Is it MDMF? jr nz,$9 ; Nope - its SDMF, so no name inc ix ; Point to field type ld a,(ix) cp '7' ; 7 is Name Packet Type, just to be safe jr nz,$9 ; No name, lets bail ; We have a name. Lets store it in the buffer ; We'll use iy since we are done with it. inc ix ; Now we point to first upper nibble ld iy,cndbuf ; Set this here. numpars call saves val we don't need ld b,1 call numpars ; Convert two bytes into actual ASCII value cp 32 ; set to 31 if > 31 jr c,$7 ld a,31 ; Max # of chars allowed $7: ld b,a ; Use length in dec counter dec iy ; Will overwite val numpars put here call numpars ; Numpars will take care of the rest! ; Here we trim off any trailing spaces in the data $81 dec iy ; Point to the last character stored ld a,(iy) ; Grab last char cp ' ' ; Space? jr z,$81 ; Yup, lets try previous char ld (iy+1),0 ; Store end of string ; $9: ld a,0ffh ld (newcid),a ; Flag new data ; jp t5exit cndpriv db 'Private',0 cndouta db 'Out Of Area',0 ; ; ; Read the raw CID data starting at IX, combine B bytes, ; and store at IY. Good for up to three bytes. ; cidpars: ld hl,0 ; Clear acc $0: ld a,(ix) ; Raw byte and 0fh ; Convert ASCII to actual value inc ix inc ix ld h,10 mlt hl ; Shift acc left base 10 ld d,0 ld e,a add hl,de ; Combine djnz $0 ; Do all pieces ; ld (iy),l ; Store final value inc iy ld (iy),h inc iy ret ; ; Simple routine to join to ASCII byte into the actual ASCII value ; The process is repeated for b bytes ; ix points to the upper nibble byte in a buffer and the result is ; returned in a. e is used as a scratch register. The buffer to ; store the data in is pointed to by iy and iy is incremented ; AFTER each loop so iy always points to the next available spot ; numpars: $0: ld a,(ix) ; Do upper nybble sub '0' cp 0ah jr c,$1 sub 7 $1: rlca rlca rlca rlca ld e,a ; Save upper nibble in e inc ix ld a,(ix) ; Do lower nybble sub '0' cp 0ah ; Is it 0-9? jr c,$2 ; Yes, skip subtraction sub 7 $2: or e ; Combine them into a ld (iy),a inc iy inc ix ; Point to next upper nibble djnz $0 ret ; ; ; Wait for an OK reply from the modem. The modem may take several ; seconds, so we must do multiple calls to cin. ; wtreply: ; Since we flush the leading before ATZ, all other s indicate ; the end of a command $0: call cin ; Flush echoed AT command from buffer jr c,$1 ; Buffer is empty cp cr ; Look for trailing cr on modem command jr nz,$0 ; Jump if no cr found ; $1: ld b,10 ; Ten calls is about 4.0 seconds on S180 $2: call cin jr nc,$3 ; Got something (clears carry/err flag) djnz $2 ; Try again scf ; Nothing, so flag error jr $4 $3: ; Lets make this more robust by specifically looking for an ; 'E'rror or '4', otherwise, receive chars until there are no ; more. Before, anything other than a 'O', '0', or cr/lf would ; cause an error with some modems. cp cr ; Ignore CR and LF jr z,$1 cp lf jr z,$1 cp 'O' ; OK result? (Word reply) jr z,$5 ; Yes, return no error (carry clear) cp '0' ; OK result? (Numeric reply) jr z,$5 ; Yes, return no error (carry clear) cp 'E' ; ERROR returned jr z,$4 cp '4' ; Numeric error code jr nz,$2 ; Loop until timeout $4: scf ; Flag error (carry set) $5: push af ; Save carry flag $6: call cin ; Flush rest of reply jr nc,$6 ; Wait for timeout pop af ; Restore carry flag ret ; ; Unsigned single-precision multiply ; ; Multiply DE by HL with result in HL ; Ignores overflow. ; mult: push af push bc push de push hl ld hl,0 ; Zero long accumulator ld (t5acc),hl pop hl ld b,16 ; Do 16 loops $1: srl h ; Rotate multiplier right rr l jr nc,$3 ; Don't add if LSB is zero push hl ; Save value ld hl,(t5acc) add hl,de ; Add in multiplicand ld (t5acc),hl ; New accumulated value pop hl $3: sla e ; Rotate multiplicand left rl d djnz $1 pop de pop bc pop af ld hl,(t5acc) ; Get result ret ; ; ;------------------------------------------------------------------------- ; ; Reset system and clear memory ; sysrst: ld a,0 ld (ver),a ; Force memory clear jp start ; Restart system ;--- ; ; Pause all output until next command ; pause: ld a,0ffh ; Flag the pause ld (pausef),a ld a,reply ; Send the acknowledge call cout ld a,01h call cout jp t5exit ;--- ; ; Request that current status information be sent to HOST immediately ; updat: ld a,0ffh ld (dtimef),a ; Flag to display time ld (dx10f),a ; Flag to display X-10 ld (dinpf),a ; Flag to display inputs ld (doutf),a ; Flag to display outputs ld (dadcf),a ; Flag to display ADC channels ld (ddacf),a ; Flag to display DAC channels ld (dnetf),a ; Flag to display network modules ld (dbitf),a ; Flag to display netbits xor a ld (modemf),a ; No modem present ld (pausef),a ; Turn off pause jp chkdisp ;--- ; ; Select time display mode ; seltim: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (dtimem),a ; Save mode ld a,03h jp acknldg ;--- ; ; Get time once ; gettim: ld a,reply call cout ld a,04h call cout ld hl,time ld b,8 $1: ld a,(hl) call cout inc hl djnz $1 jp t5done ;--- ; ; Set new time ; settim: call ticsoff ld hl,ntbuf ; Point to new time buffer ld b,8 ; 8 bytes $1: call cin ; Get next character jr nc,$2 ; If no timeout, continue call ticson jp t5done ; Timeout, abort command $2: ld (hl),a ; Save it inc hl djnz $1 ; Get all information call settime ; Set the SmartWatch call ticson ld a,05h jp acknldg ;--- ; ; Load a new program ; newprg: call ticsoff ld a,ack call cout ; rt_cancel 1 ; ld hl,hardware ; Point to hardware configuration storage ld b,47 ; 47 bytes of info $0: call cin jp c,$err ; Abort on timeout ld (hl),a inc hl djnz $0 ; ld e,0 ; Clear number of endpgms received ld d,0 ; Clear number of endtbls received ld c,0 ; Clear too big flag ld b,0 ; Clear sum ld hl,events ; Point to table $gcloop: call cin ; Get next character jr c,$err ; Abort on timeout ld (hl),a ; Save it add a,b ; Add to sum ld b,a ; Save it ld a,(hl) ; Get character back cp endpgm ; End of program byte? jr nz,$5 ; Nope, continue inc e ; Count number received ld a,e cp 3 jr nc,$1 ; If received three or more, done jr $7 $5: ld e,0 ; Zero endpgms received cp endtbl ; End of table byte? jr nz,$6 ; Nope, continue inc d ; Count number received ld a,d cp 3 jr nc,$8 ; If received three or more, mark start of ptrs jr $7 $6: ld d,0 ; Zero endtbls received $7: inc hl ld a,h ; Check for overflow or l jr nz,$gcloop ; If none, keep going dec hl ; Keep HL at FFFF ld c,0ffh ; Flag program too big jr $gcloop ; Keep going to flush rest of program $8: ld d,0 ; Zero endtbls received inc hl ld (doneptr),hl ; Save the pointer jr $gcloop $1: call cin ; Get checksum from host jr c,$err ; Abort on timeout ld (power),a ; Save it as power-up integrity flag add a,b ; Result should be zero jr nz,$err ; Nope, error ld a,c ; Check for too big or a jr nz,$berr ; Too big ld a,(compver) ; Check compiler version cp ver jr nz,$verr ; Error if different ld a,(compsver) cp subver jr z,$2 ; Continue if it matches jr $verr ; Nope, error ; ; Program too big for memory ; $berr: ld a,toobig ; Signal too big call cout jr $err ; ; Compiler version different from firmware version ; $verr: ld a,badver ; Signal bad version call cout ; ; Error in transmission, so clear table ; $err: call clrtbl ; Clear event table and hardware defs call inittmrs ; Set all timer states to off call initvars ; Set all variables to zero call getsc ; Figure out SC type jr $3 $2: ld a,ack ; Signal OK call cout ; ; Now set up hardware for new configuration ; $3: call inithard ; Set up on-board hardware ld a,0ffh ld (rstflg),a ; Flag reset condition ld a,(numpl) ; PL-Link defined? jr z,$31 ; No, assume PLIX rt_run 8,48 ; Set task frequency for PL-Link jr $32 $31: rt_run 8,20 ; Using PLIX, so run task more often $32: rt_run 1,1 call ticson jp t5done ;--- ; ; Clear the log ; clrlog: ld hl,logstrt ld (logptrh),hl ld (logptrt),hl ld a,07h jp acknldg ;--- ; ; Get log size ; logsiz: ld a,reply ; Send start of response call cout ld a,08h call cout ld hl,(logptrt) ; Start of data ex de,hl ; Put head in DE ld hl,(logptrh) ; End of data xor a ; Clear carry sbc hl,de ; Figure size ld a,h and 07fh ; Clear high bit ld h,a srl h ; Divide by 8 rr l srl h rr l srl h rr l ld a,l ; Send data call cout ld a,h call cout jp t5done ;--- ; ; Send log data ; getlog: ld a,reply ; Send start of response call cout ld a,09h call cout ld hl,(logptrh) ; End of data ex de,hl ; Put head in DE ld hl,(logptrt) ; Start of data $1: push hl xor a ; Clear carry sbc hl,de ; Head = tail? pop hl jr z,$9 ; Yes, done call getlbyt ; Get byte from log memory call cout inc hl ld a,h ; Check for end of memory or l jr nz,$1 ld hl,logstrt ; Wrap around jr $1 $9: ld a,0ffh ; Flag end of data call cout call cout call cout jp t5done ; ; Get data from log memory at HL and return in A ; getlbyt: push bc ld b,cbrl ; CBR for log memory ld c,cbrc ; CBR for regular memory ; di out0 (cbr),b ; Point to log memory ld a,(hl) ; Get byte out0 (cbr),c ; Restore memory map ei ; pop bc ret ;--- ; ; Put data into log memory. ; ; Use the t1logf and t5logf semaphores to have exclusive use of ; logging memory during operation. Because Task 1 is locked out ; from doing logging during this operation, it's OK to use the ; putlog function here. ; setlog: $0: ld a,0ffh ld (t5logf),a ; Set our flag ld a,(t1logf) ; Check if other task doing logging or a jr z,$2 ; Nope, continue ld a,0 ld (t5logf),a ; Clear our flag $1: ld a,(t1logf) ; Check other task again or a jr nz,$1 ; Wait for it to finish jr $0 ; Try again to grab log $2: call cin ; Get reference number jp c,$err ; If timeout, abort command ld hl,(logptrh) ; Point to next available spot call putlog ; Store it inc hl ; call cin ; Get low byte of data jp c,$err ; If timeout, abort command call putlog ; Save it inc hl call cin ; Get high byte of data jp c,$err ; If timeout, abort command call putlog ; Save it inc hl ; ld a,(time+6) ; Get month call bcd2dec ; Convert to decimal call putlog ; Save it inc hl ld a,(time+5) ; Get day call bcd2dec ; Convert to decimal call putlog ; Save it inc hl ld a,(time+3) ; Get hour call bcd2dec ; Convert to decimal call putlog ; Save it inc hl ld a,(time+2) ; Get minute call bcd2dec ; Convert to decimal call putlog ; Save it inc hl ld a,(time+1) ; Get second call bcd2dec ; Convert to decimal call putlog ; Save it inc hl ; ld a,h or l ; Is HL=0? jr nz,$3 ; No, save new pointer ld hl,logstrt ; Yes, wrap around $3: ld (logptrh),hl ex de,hl ; Put head in DE ld hl,(logptrt) ; Get tail ex de,hl ; Put tail in DE xor a ; Clear carry sbc hl,de ; Compare the two jr nz,$99 ; If not equal, done ex de,hl ; Put tail in HL ld de,8 ; Move up one record add hl,de ld a,h ; Check for wrap around or l jr nz,$4 ; None, just save it ld hl,logstrt $4: ld (logptrt),hl ; Save tail $99: ld a,0 ld (t5logf),a ; Turn our flag off ld a,0ah jp acknldg $err: ld a,0 ld (t5logf),a ; Turn our flag off jp t5done ;--- ; ; Select X-10 modules to display ; selx10: ld hl,mdisp ; Point to display bitmaps ld b,2 ; Do two bytes $1: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (hl),a ; Save new bitmap inc hl djnz $1 ld a,10h jp acknldg ;--- ; ; Get X-10 module status ; getx10: ld hl,modules call cin ; Get next character jp c,t5done ; If timeout, abort command ld e,a ld d,0 add hl,de ld d,(hl) ; ld a,reply ; Start of response call cout ld a,11h ; Opcode call cout ld a,e ; House/mod call cout ld a,d ; Status and 01h ; Return 0 for off, 1 for on call cout jp t5done ;--- ; ; Set X-10 modules on or off ; ; Use the t1x10f and t5x10f semaphores to have exclusive use of ; X-10 transmit routine. Because Task 1 is locked out from ; sending X-10 commands during this operation, it's OK to use ; the transmit function here. ; setx10: call cin ; Get house/mod jr c,$err ; If timeout, abort command ld c,a ; Save it srl a ; Move upper nybble low srl a srl a srl a add a,'A' ; Make house code into ASCII ld b,a ; Save it ld a,c and a,0fh ; Keep unit number inc a ; Make 1-16 ld c,a ; Save it ; call cin ; Get function jr c,$err ; If timeout, abort command cp 6 ; 0-5? jr nc,$err ; No, out of range inc a ; Make 1-6 ld d,a ; Save it ; call cin ; Get repeat jr c,$err ; If timeout, abort command cp 32 ; 0-31? jr nc,$err ; No, out of range ld e,a ; Save it ; $0: ld a,0ffh ld (t5x10f),a ; Set our flag ld a,(t1x10f) ; Check if other task doing X-10 or a jr z,$2 ; Nope, continue ld a,0 ld (t5x10f),a ; Clear our flag $1: ld a,(t1x10f) ; Check other task again or a jr nz,$1 ; Wait for it to finish jr $0 ; Try again to grab X-10 routines $2: call transmit ; Send X-10 command ; ld a,0 ld (t5x10f),a ; Turn our flag off ld a,12h jp acknldg $err: ld a,0 ld (t5x10f),a ; Turn our flag off jp t5done ;--- ; ; Select inputs to display ; selinp: ld hl,digin ; Point to display bitmaps ld b,4 ; Do four bytes $1: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (hl),a ; Save new bitmap inc hl djnz $1 ld a,13h jp acknldg ;--- ; ; Get input status ; getinp: ld hl,input1 call cin ; Get next character jp c,t5done ; If timeout, abort command ld e,a ld d,0 add hl,de ld d,(hl) ; ld a,reply ; Start of response call cout ld a,14h ; Opcode call cout ld a,e ; Input number call cout ld a,d ; Status and 01h ; Return 0 for off, 1 for on call cout jp t5done ;--- ; ; Set input on or off ; setinp: call cin ; Get input number jp c,t5done ; If timeout, abort command ld hl,input1 ld e,a ld d,0 add hl,de call cin ; Get new value jp c,t5done ; If timeout, abort command cp 2 ; Make input transparent? jr nz,$1 ; Nope, force new state res 7,(hl) ; Yes, clear the high bit jr $9 ; Done $1: ld b,00h ; Assume off for now and 01h ; Make sure it's 0 or 1 jr z,$2 ; Skip if off ld b,7fh ; Really on $2: ld a,(hl) ; Get old value and 7fh cp b jr z,$3 ; If no change, no edge push hl ld hl,edge1 ; Set the edge add hl,de ld (hl),0ffh pop hl $3: set 7,b ; Flag a forced input ld (hl),b ; Save new value $9: ld a,15h jp acknldg ;--- ; ; Select outputs to display ; selout: ld hl,digout ; Point to display bitmaps ld b,4 ; Do four bytes $1: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (hl),a ; Save new bitmap inc hl djnz $1 ld a,16h jp acknldg ;--- ; ; Get output status ; getout: ld hl,output call cin ; Get next character jp c,t5done ; If timeout, abort command ld e,a ld d,0 add hl,de ld d,(hl) ; ld a,reply ; Start of response call cout ld a,17h ; Opcode call cout ld a,e ; Output number call cout ld a,d ; Status and 01h ; Return 0 for off, 1 for on call cout jp t5done ;--- ; ; Set output on or off ; setout: ld ix,t5store ; Temporary storage call cin ; Get output number jp c,t5done ; If timeout, abort command ld (ix),a ; Save output number call cin ; Get new value jp c,t5done ; If timeout, abort command or a ld d,0ffh ; Assume on jr nz,$1 ; Assumed correct ld d,00h ; Really want off $1: ld hl,outtbl ; Point to table of output ports ld a,(ix) srl a ; Divide by 8 and multiply by 2 srl a ; to get table offset srl a ; Done like this to provide integer sla a ; divide with no remainder ld b,0 ld c,a add hl,bc ; Point to correct table entry ld c,(hl) ; Get port address inc hl ld b,(hl) push bc ; Save it ; ld a,(ix) and 07h ; A = 0-7 inc a ; A = 1-8 ld b,a xor a ; Load A with 0 scf ; Start with bit 0 $2: rla djnz $2 ; Shift bit to proper position ; (A now has bit mask) ld c,(ix) ; Get output number again srl c ; Divide by 8 srl c srl c ld b,0 ld hl,outport ; Point to 8-bit port values add hl,bc ; Offset to proper port ld e,(hl) ; Get current port value pop bc ; Restore port address bit 0,d ; Turning on or off? jr z,$3 ; Turning off or e ; Turn proper bit on jr $4 $3: cpl a and e ; Turn proper bit off $4: ld e,a ; Save new value for a moment ld a,(ix) ; Get output number again cp 8 ; 0-7? jr c,$8 ; Yes, do it cp 16 ; >=16? jr nc,$8 ; Yes, do it cp 8 ; =8? jr z,$41 ; RTC-DTMF LED3 cp 9 ; =9? jr z,$42 ; RTC-DTMF LED4 ld bc,pia3+3 ; SS LED6 cp 10 ; =10? jr z,$5 ld bc,pia4+1 ; SS LED7 cp 11 ; =11? jr z,$5 ld bc,pia4+3 ; SS LED8 cp 12 ; =12? jr z,$5 jr $9 ; No match, not supported by hardware ; ; Do RTC-DTMF LEDs ; $41: ld a,(dtmfo) ; Get current settings bit 0,d ; On or off? set 5,a ; Turn LED3 on (bit on) jr nz,$41a res 5,a ; Turn LED3 off (bit off) $41a: ld (dtmfo),a outb dtmfctl,a jr $9 ; $42: ld a,(dtmfo) ; Get current settings bit 0,d ; On or off? set 4,a ; Turn LED4 on (bit on) jr nz,$42a res 4,a ; Turn LED4 off (bit off) $42a: ld (dtmfo),a outb dtmfctl,a jr $9 ; ; Do SpectraSense LEDs ; $5: ld a,(sc) ; Make sure we're a SpectraSense cp sccs jr nz,$99 ; Nope, skip in a,(c) bit 0,d ; On or off? res 3,a ; Turn LED on (bit off) jr nz,$6 set 3,a ; Turn LED off (bit on) $6: out (c),a jr $9 ; $8: out (c),e ; Send out to port $9: ld (hl),e ; and save for later use ; ld hl,output ; Point to local storage ld c,(ix) ; Get output number ld b,0 add hl,bc ld (hl),d ; Save new state ; $99: ld a,18h jp acknldg ;--- ; ; Select ADC channels to display ; seladc: ld hl,anain ; Point to display bitmaps ld b,3 ; Do three bytes $1: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (hl),a ; Save new bitmap inc hl djnz $1 ld a,19h jp acknldg ;--- ; ; Get ADC input value ; getadc: ld hl,adcvals ; Point to ADCs call cin ; Get channel number jp c,t5done ; If timeout, abort command ld b,a ; Save number ld e,a ld d,0 sla e ; Multiply by 2 rl d add hl,de ; Offset to desired value ld a,reply ; Start of response call cout ld a,1ah ; Opcode call cout ld a,b ; Channel number call cout ld a,(hl) ; Get low byte of ADC value call cout inc hl ld a,(hl) ; Get high byte and 7fh ; Mask off high bit call cout jp t5done ;--- ; ; Set ADC input value ; setadc: ld hl,adcvals ; Point to ADCs call cin ; Get channel number jp c,t5done ; If timeout, abort command ld e,a ld d,0 sla e ; Multiply by 2 rl d add hl,de ; Offset to desired value call cin ; Get low byte of new value jp c,t5done ; If timeout, abort command ld c,a ; Save it call cin ; Get high byte of new value jp c,t5done ; If timeout, abort command ld b,a cp 10h ; >=4096? jr c,$1 ; Nope, save it inc hl ; Point at high byte of current value res 7,(hl) ; Make transparent jr $9 $1: set 7,b ; Flag forced value ld (hl),c ; Save new value inc hl ld (hl),b $9: ld a,1bh jp acknldg ;--- ; ; Select DAC channels to display ; seldac: ld hl,anaout ; Point to display bitmaps ld b,1 ; Do one byte $1: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (hl),a ; Save new bitmap inc hl djnz $1 ld a,1ch jp acknldg ;--- ; ; Get DAC value ; getdac: ld hl,dacvals ; Point to DACs call cin ; Get channel number jp c,t5done ; If timeout, abort command ld b,a ; Save number ld e,a ld d,0 add hl,de ; Offset to desired value ld a,reply ; Start of response call cout ld a,1dh ; Opcode call cout ld a,b ; Channel number call cout ld a,(hl) ; Get low byte of DAC value call cout inc hl ld a,(hl) ; Get high byte and 7fh ; Mask off high bit call cout jp t5done ;--- ; ; Set DAC output value ; setdac: $1: ld a,(t5trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t5tbuf ld hl,dacmsg ld bc,24 ldir ; Copy command frame to buffer ; call cin ; Get channel number jp c,t5done ; If timeout, abort command ld e,a ; Save it for later rrca ; Calculate link number rrca and 07h ; Ensure 0-7 add a,'0' ; Convert to ASCII ld (t5tbuf+8),a ; Put in buffer ; ld a,e ; Get channel number again and 03h ; Ensure 0-3 add a,'0' ; Convert to ASCII ld (t5tbuf+16),a ; Put in buffer ; call cin ; Get DAC value low jp c,t5done ; If timeout, abort command ld c,a ; Save it for later call cin ; Get DAC value high jp c,t5done ; If timeout, abort command ld b,a ; Save it for later ; ld hl,dacvals ; Save value in local storage ld d,0 sla e ; Multiply channel by 2 add hl,de ; Offset into storage ld (hl),c ; Save it inc hl ld (hl),b ; ; Answer MAN needs both DAC channels in one command, so retrieve both values ; for this module from memory. ; ld a,0fch and e ; Point to even channel offset ld e,a ld hl,dacvals add hl,de ; push iy ld iy,t5tbuf ld a,(hl) inc hl call hto2a ; Convert to two ASCII digits ld (iy+15),b ld (iy+16),c ld a,(hl) inc hl call hto2a ld (iy+13),b ld (iy+14),c ld a,(hl) inc hl call hto2a ld (iy+20),b ld (iy+21),c ld a,(hl) inc hl call hto2a ld (iy+18),b ld (iy+19),c pop iy ; ld hl,t5tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; ld a,0 ld (t5wait),a ; Don't wait for response ld a,0ffh ld (t5trdy),a ; Ready to send ; ld a,1eh jp acknldg ;--- ; ; Select network modules to display ; selmod: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (netmod),a ; Save new bitmap ld a,1fh jp acknldg ;--- ; ; Get network module status ; getmod: ld hl,lnkresp call cin ; Get network module type/num jp c,t5done ; If timeout, abort command ld c,a ; Save raw value and 0f0h ; Get just upper nybble srl a ; Shift it right one ld d,a ; Save it ld a,c ; Get raw value and 07h ; Save module number or d ; Add in type ld e,a ; Use for offset ld d,0 add hl,de ld b,(hl) ; Get status ; ld a,reply ; Start of response call cout ld a,20h ; Opcode call cout ld a,c ; Network module type/num call cout ld a,b ; Status and 03h ; 0:timeout, 1:active, 2:err call cout jp t5done ;--- ; ; Select netbits to display ; selnet: ld hl,netbits ; Point to display bitmaps ld b,5 ; Do five bytes $1: call cin ; Get next character jp c,t5done ; If timeout, abort command ld (hl),a ; Save new bitmap inc hl djnz $1 ld a,21h jp acknldg ;--- ; ; Get netbit status ; getnet: ld hl,netbit1 call cin ; Get netbit number low jp c,t5done ; If timeout, abort command ld e,a call cin ; Get netbit number high jp c,t5done ; If timeout, abort command ld d,a add hl,de ld b,(hl) ; Get status ; ld a,reply ; Start of response call cout ld a,22h ; Opcode call cout ld a,e ; Netbit number low call cout ld a,d ; Netbit number high call cout ld a,b ; Status and 01h ; Return 0 for off, 1 for on call cout jp t5done ;--- ; ; Set netbit on or off ; setnet: $0: ld a,0ffh ld (t5netbf),a ; Set our flag ld a,(t1netbf) ; Check if other task sending netbit or a jr z,$2 ; Nope, continue ld a,0 ld (t5netbf),a ; Clear our flag $1: ld a,(t1netbf) ; Check other task again or a jr nz,$1 ; Wait for it to finish jr $0 ; Try again to grab netbit routines $2: call cin ; Get netbit number low jp c,t5done ; If timeout, abort command ld (nbstor),a call cin ; Get netbit number high jp c,t5done ; If timeout, abort command ld (nbstor+1),a call cin ; Get new netbit value jp c,t5done ; If timeout, abort command and 01h ; Make sure it's 0 or 1 ld (nbval),a call donetb ; Turn netbit on or off ; ld a,0 ld (t5netbf),a ; Turn our flag off ; ld a,23h jp acknldg ;--- ; ; Get variable value ; getvar: ld hl,vars ; Point to variables call cin ; Get variable number jp c,t5done ; If timeout, abort command ld b,a ; Save number ld e,a sla e ; Multiply by 2 ld d,0 add hl,de ; Offset to desired value ld a,reply ; Start of response call cout ld a,24h ; Opcode call cout ld a,b ; Variable number call cout ld a,(hl) ; Get low byte of variable value call cout inc hl ld a,(hl) ; Get high byte call cout jp t5done ;--- ; ; Set variable value ; setvar: ld hl,vars ; Point to variables call cin ; Get variable number jp c,t5done ; If timeout, abort command ld e,a sla e ; Multiply by 2 ld d,0 add hl,de ; Offset to desired value call cin ; Get low byte jp c,t5done ; If timeout, abort command ld (hl),a ; Save it inc hl call cin ; Get high byte jp c,t5done ; If timeout, abort command ld (hl),a ; Save it ld a,25h jp acknldg ;--- ; ; Send command string to network ; netstr: $1: ld a,(t5trdy) ; Buffer already full? or a jr nz,$1 ; Yes, wait ; ld de,t5tbuf ld hl,usrcmd ld bc,5 ldir ; Copy command frame to buffer ex de,hl ; Move buffer address into HL ; $2: call cin ; Get next character jp c,t5done ; If timeout, abort command or a ; Zero terminated? jr z,$3 ; Yes, end of string ld (hl),a ; Save it inc hl jr $2 $3: ld (hl),cr ; Terminate command in buffer inc hl ; ld (hl),lf ; with a LF ; inc hl ld (hl),0 ; ld hl,t5tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; ld a,0 ld (t5wait),a ; Don't wait for response ld a,0ffh ld (t5trdy),a ; Ready to send ; ld a,30h jp acknldg ; usrcmd db cr,'#00 ' ; ;--- ; ; Send string to voice board ; saystr: $0: ld a,0ffh ld (t5sayf),a ; Set our flag ld a,(t1sayf) ; Check if other task speaking or a jr z,$2 ; Nope, continue ld a,0 ld (t5sayf),a ; Clear our flag $1: ld a,(t1sayf) ; Check other task again or a jr nz,$1 ; Wait for it to finish jr $0 ; Try again to grab speech routines $2: ld hl,vbuf $25: call cin ; Get next character jp c,t5done ; If timeout, abort command or a ; Zero terminated? jr z,$29 ; Yes, found end ld (hl),a ; Save it inc hl jr $25 $29: ld (hl),cr ; Add cr,lf inc hl ld (hl),lf inc hl ld (hl),0 ; Terminate string ld hl,vbuf $3: ld a,(hl) ; Get next character cp '~' ; Substitute command char? jr nz,$4 ; No, continue ld a,01h $4: cp '|' ; Substitute speech interrupt? jr nz,$5 ; No, continue ld a,18h $5: call vout ; Send character to voice board inc hl or a ; End of string? jr nz,$3 ; ld a,0 ld (t5sayf),a ; Turn our flag off ld a,31h jp acknldg $err: ld a,0 ld (t5sayf),a ; Turn our flag off jp t5done ; ;------------------------------------------------------------------------- ; ; Display routines ; chkdisp: ld a,(modemf) ; Is modem connected? or a jr z,$1 ; No, keep checking xor a ; Yes, so skip displays ld (msgflg),a ; Throw away any console messages jp t5exit ; $1: ld a,(pausef) ; Is the display paused? or a jr z,$2 ; No, go ahead and display things xor a ; Yes, so skip displays ld (msgflg),a ; Throw away any console messages jp t5exit ; $2: ld a,(dtimef) or a call nz,disptime ld a,0 ld (dtimef),a ; ld a,(dinpf) or a call nz,dispinp ld a,0 ld (dinpf),a ; ld a,(doutf) or a call nz,dispout ld a,0 ld (doutf),a ; ld a,(dadcf) or a call nz,dispadc ld a,0 ld (dadcf),a ; ld a,(ddacf) or a call nz,dispdac ld a,0 ld (ddacf),a ; ld a,(dx10f) or a call nz,dispx10 ld a,0 ld (dx10f),a ; ld a,(dnetf) or a call nz,dispnet ld a,0 ld (dnetf),a ; ld a,(dbitf) or a call nz,dispbit ld a,0 ld (dbitf),a ; ld a,(msgflg) or a call nz,dispmsg ld a,0 ld (msgflg),a ; jp t5done ; ; ; Display the current time and date ; disptime: ld a,(dtimem) ; Check mode or a jr z,$9 ; If zero, time display off cp 2 ; Minute display? jr nz,$0 ; Nope, assume seconds ld a,(time+1) ; Check current seconds or a jr nz,$9 ; If not exactly on minute, skip display $0: ld a,reply call cout ld a,curtime call cout ld hl,time ld b,8 $1: ld a,(hl) call cout inc hl djnz $1 $9: ret ; ; ; Display state of inputs ; dispinp: ld hl,input1 ; Point to input storage ld ix,digin ; Point to bitmap of what's being used ld e,4 ; Do four bitmapped bytes ld d,0 ; Input byte number $1: ld b,8 ; Do 8 bits of bitmap ld c,(ix) ; Get bitmap inc ix $2: rrc c ; Put next bit into carry jr nc,$3 ; Skip if not used ld a,reply call cout ld a,inpstat call cout ; Tell HOST what's coming ld a,d call cout ; Tell it which 8 bits call dispbits jr $4 $3: push de ; Skip 8 inputs ld de,8 add hl,de pop de $4: inc d djnz $2 ; Do all 8 bits of bitmap dec e jr nz,$1 ; Do all four bitmaps ret ; ; ; Display state of outputs ; dispout: ld hl,output ; Point to output storage ld ix,digout ; Point to bitmap of what's being used ld e,4 ; Do four bitmapped bytes ld d,0 ; Output byte number $1: ld b,8 ; Do 8 bits of bitmap ld c,(ix) ; Get bitmap inc ix $2: rrc c ; Put next bit into carry jr nc,$3 ; Skip if not used ld a,reply call cout ld a,outstat call cout ; Tell HOST what's coming ld a,d call cout ; Tell it which 8 bits call dispbits jr $4 $3: push de ; Skip 8 outputs ld de,8 add hl,de pop de $4: inc d djnz $2 ; Do all 8 bits of bitmap dec e jr nz,$1 ; Do all four bitmaps ret ; ; ; Display state of netbits ; dispbit: ld hl,netbit1 ; Point to netbit storage ld ix,netbits ; Point to bitmap of what's being used ld e,5 ; Do five bitmapped bytes ld d,0 ; Netbit byte number $1: ld b,8 ; Do 8 bits of bitmap ld c,(ix) ; Get bitmap inc ix $2: rrc c ; Put next bit into carry jr nc,$3 ; Skip if not used ld a,reply call cout ld a,netstat call cout ; Tell HOST what's coming ld a,d call cout ; Tell it which 8 bits call dispbits jr $4 $3: push de ; Skip 8 netbits ld de,8 add hl,de pop de $4: inc d djnz $2 ; Do all 8 bits of bitmap dec e jr nz,$1 ; Do all five bitmaps ret ; ; ; Display eight input or output bits. Enter with starting ; storage address in HL. Returns with HL pointing at next ; undisplayed input location. ; dispbits: push af push bc ld c,0 ld b,8 $2: ld a,(hl) rra rr c inc hl djnz $2 ld a,c call cout pop bc pop af ret ; ; ; Display ADC channel ; dispadc: ld hl,adcvals ; Point to ADC storage ld ix,anain ; Point to bitmap of what's being used ld e,3 ; Do three bitmapped bytes ld d,0 ; Group number $1: ld b,8 ; Do 8 bits of bitmap ld c,(ix) ; Get bitmap inc ix $2: rrc c ; Put next bit into carry jr nc,$3 ; Skip if not used ld a,reply call cout ld a,adcstat call cout ; Tell HOST what's coming ld a,d call cout ; Tell it which group push bc ld b,8 ; Do 8 channels $25: ld a,(hl) ; Get value low call cout inc hl ld a,(hl) ; Get value high and 7fh ; Make sure high bit off call cout inc hl djnz $25 pop bc jr $4 $3: push de ; Skip 8 channels ld de,16 add hl,de pop de $4: inc d djnz $2 ; Do all 8 bits of bitmap dec e jr nz,$1 ; Do all bitmaps ret ; ; ; Display DAC channel ; dispdac: ld hl,dacvals ; Point to DAC storage ld ix,anaout ; Point to bitmap of what's being used ld e,1 ; Do one bitmapped byte ld d,0 ; Group number $1: ld b,8 ; Do 8 bits of bitmap ld c,(ix) ; Get bitmap inc ix $2: rrc c ; Put next bit into carry jr nc,$3 ; Skip if not used ld a,reply call cout ld a,dacstat call cout ; Tell HOST what's coming ld a,d call cout ; Tell it which group push bc ld b,4 ; Do 2 channels $25: ld a,(hl) ; Get value call cout inc hl djnz $25 pop bc jr $4 $3: push de ; Skip first 2 channels ld de,4 add hl,de pop de $4: push de ; Skip second 2 channels ld de,4 add hl,de pop de inc d djnz $2 ; Do all 8 bits of bitmap dec e jr nz,$1 ; Do all bitmaps ret ; ; ; Display status of modules ; dispx10: ld hl,(mdisp) ; Which modules to display ld b,16 ; Do 16 modules ld c,'A' ; Start with A $0: srl h ; Do 16-bit rotate right into carry rr l jr nc,$1 ; If bit zero, don't display ld a,reply call cout ld a,x10stat ; Display current module call cout ld a,c call dx10 $1: inc c djnz $0 ret ; ; ; Send to host status of all modules with housecode found in A. Calling ; routine must have already sent prefix to host. ; dx10: push bc push de push hl call cout ; Display housecode letter sub a,'A' ld c,a ld b,10h mlt bc ld hl,modules add hl,bc ld de,0 ld b,10h ; Do 16 modules dm1: ld a,(hl) ; Get module state rra ; Rotate into carry rr d ; Rotate into DE rr e inc hl djnz dm1 ld a,e ; Send low byte call cout ld a,d ; Send high byte call cout pop hl pop de pop bc ret ; ; ; Display status of network modules ; dispnet: ld ix,numlnks ld hl,lnkresp ld a,(netmod) ; Get display bitmap ld e,a ; Save it ld b,6 ; Six kinds of links $1: ld c,8 ; Up to eight of each rr e ; Move next bit into carry push de ; Save bitmap jr nc,$3 ; If no display, skip type ld d,(ix) ; Get actual number ld e,0 ; Start with 0 $2: ld a,d ; How many left? or a jr z,$3 ; None, do next ld a,reply call cout ld a,modstat call cout ld a,6 sub a,b ; Make up link ID sla a sla a sla a sla a or e ; Link number call cout ; Send link ID ld a,(hl) ; Get latest response call cout ; Send response inc hl inc e dec c dec d jr nz,$2 $3: pop de $3a: ld a,c or a jr z,$4 inc hl dec c jr $3a $4: inc ix djnz $1 $9: ret ; ; ; Display console message ; dispmsg: ld a,reply call cout ld a,msg call cout ld hl,cmsgbuf ; Point at message buffer $0: ld a,(hl) ; Get next character call cout inc hl or a ; Zero terminated. Done? jr nz,$0 ; Nope, do next ret ; ; acknldg: ld b,a ; Save command value ld a,reply call cout ld a,b call cout t5done: xor a ; Get a zero ld (modemf),a ; Modem not present ld (pausef),a ; Reenable display t5exit: rt_exit ; ; ; Turn off multitasking tics ; ticsoff: di in0 a,(tcr) res 0,a out0 (tcr),a ei ret ; ; Turn multitasking tics back on ; ticson: di in0 a,(tcr) set 0,a out0 (tcr),a ei ret ; ; Set the SmartWatch or CS clock to the time stored starting at "ntbuf." ; SmartWatch code uses only registers during watch access. Also uses ; alternate registers which aren't saved by the RTOS, so interrupts ; *must* be off when running the code. ; settime: di push bc push de push hl ld a,(sc) cp sccs ; CS? jp z,setclk ; Yes exx ; Alternate push bc push de push hl ld ix,ntbuf ld b,(ix+0) ld c,(ix+1) ld d,(ix+2) ld e,(ix+3) ld h,(ix+4) ld l,(ix+5) exx ; Primary ld d,(ix+6) ld e,(ix+7) ; ld b,8 $0: ld a,(swram) ; Prepare for key djnz $0 ; ld hl,key ; Point to key ld c,8 ; 8 bytes $1: ld b,8 ; 8 bits/byte ld a,(hl) $2: ld (swram),a ; Send bit of key (D0) rrca ; Rotate next bit into D0 djnz $2 ; Do 8 bits inc hl ; Do next byte dec c jr nz,$1 ; exx ; Alternate ld a,b ; Tenths of seconds exx ; Primary ld b,8 ; 8 bits/byte $3: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $3 ; Do 8 bits ; exx ; Alternate ld a,c ; Seconds exx ; Primary ld b,8 ; 8 bits/byte $4: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $4 ; Do 8 bits ; exx ; Alternate ld a,d ; Minutes exx ; Primary ld b,8 ; 8 bits/byte $5: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $5 ; Do 8 bits ; exx ; Alternate ld a,e ; Hours exx ; Primary ld b,8 ; 8 bits/byte $6: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $6 ; Do 8 bits ; exx ; Alternate ld a,h ; Day of week exx ; Primary res 5,a ; Make sure oscillator is on set 4,a ; Make sure we ignore reset ld b,8 ; 8 bits/byte $7: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $7 ; Do 8 bits ; exx ; Alternate ld a,l ; Day of month exx ; Primary ld b,8 ; 8 bits/byte $8: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $8 ; Do 8 bits ; ld a,d ; Month ld b,8 ; 8 bits/byte $9: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $9 ; Do 8 bits ; ld a,e ; Year ld b,8 ; 8 bits/byte $10: ld (swram),a ; Send bit of data (D0) rrca ; Rotate next bit into D0 djnz $10 ; Do 8 bits ; exx ; Alternate pop hl pop de pop bc exx ; Primary jr t5end ; ; Write new values to the RTC. Values are stored at NTBUF ; in SmartWatch format. ; setclk: ld bc,clock+0dh $0: ld a,5 ; Set hold out (c),a in a,(c) ; Get status bit 1,a ; Busy? jr z,$1 ; Nope, continue ld a,4 ; Yes, clear hold out (c),a jr $0 ; Check again $1: ld bc,clock ld a,(ntbuf+1) ; Seconds call $wrbyte ld a,(ntbuf+2) ; Minutes call $wrbyte ld a,(ntbuf+3) ; Hours call $wrbyte ld a,(ntbuf+5) ; Day call $wrbyte ld a,(ntbuf+6) ; Month call $wrbyte ld a,(ntbuf+7) ; Year call $wrbyte ld a,(ntbuf+4) ; DOW dec a ; Make 1-7 into 0-6 out (c),a ld bc,clock+0fh ld a,1 ; Set reset out (c),a ld a,5 ; Set 24-hour mode and reset out (c),a ld a,4 ; Clear reset out (c),a ; ld bc,clock+0dh ld a,4 ; Clear hold out (c),a jr t5end ; ; Write the byte in A to the RTC a nybble at a time starting at ; port BC. On exit, BC points to the next port. E is corrupted. ; $wrbyte: ld e,a ; Save original and 0fh ; Kill upper bits out (c),a ; Set low nybble inc bc ld a,e ; Get original rrca ; Move upper into lower rrca rrca rrca and 0fh ; Kill upper bits out (c),a ; Set high nybble inc bc ret ; t5end: pop hl pop de pop bc ei ret ; key: db 0c5h,3ah,0a3h,5ch,0c5h,3ah,0a3h,5ch ; ; ; Print the BCD number in A with leading zero. ; pbcd: push af rra rra rra rra and 0fh cp 0ah jr c,$1 add a,7 $1: add a,'0' call cout pop af push af and 0fh cp 0ah jr c,$2 add a,7 $2: add a,'0' call cout pop af ret ; ; ; Print the BCD number in A with leading zero, but to memory. ; Places characters starting at (HL). Exits with HL pointing ; to location after last character of BCD number. ; pbcdm: push af rra rra rra rra and 0fh cp 0ah jr c,$1 add a,7 $1: add a,'0' ld (hl),a inc hl pop af push af and 0fh cp 0ah jr c,$2 add a,7 $2: add a,'0' ld (hl),a inc hl pop af ret ; ; ; Print A as a 3-digit decimal number. ; pa3dc: push af push bc push de ld bc,0 ld d,0 $0: sub 100 jr c,$1 inc b jr $0 $1: add a,100 $2: sub 10 jr c,$3 inc c jr $2 $3: add a,10 ld d,a ld a,b add a,'0' call cout ld a,c add a,'0' call cout ld a,d add a,'0' call cout pop de pop bc pop af ret ; ; Print CR/LF pair ; crlf: push af ld a,cr call cout ld a,lf call cout pop af ret ; ; Print the string found immediately ; following the CALL instruction. ; print: ex (sp),hl push af call pstr pop af ex (sp),hl ret ; ; ; Print the string pointed to by HL. ; pstr: ld a,(hl) inc hl or a ret z call cout jr pstr ; cout: push af $1: in0 a,(stat1) bit 1,a jr z,$1 pop af out0 (tdr1),a ret ; ; ;cstat: ; in0 a,(stat1) ; and 80h ; ret ; ; Check whether host input buffer has anything new. Returns ; with A=0, Z=1 if nothing, else A<>0, Z=0. ; cstat: push de ; (11 T states) push hl ; (11) ld hl,(hinbuft) ; (18) Get both buffer pointers ex de,hl ; ( 3) ld hl,(hinbufb) ; (18) ld a,l ; ( 4) sub e ; ( 4) Zero if nothing new pop hl ; ( 9) pop de ; ( 9) ret ; ( 9) ; (96) ; ;cin: ; call cstat ; jr z,cin ; in0 a,(rdr1) ; ret ; ; Get a character from the host input buffer. ; Return with carry set if timeout, else clear. ; Timeout is ~0.8 seconds at 9.216 MHz. ; Timeout is ~0.4 seconds at 18.432 MHz cin: push hl ld hl,0 ; Timeout counter $1: call cstat ; (112 T states) jr nz,$2 ; Character ready dec hl ; Decrement timer ld a,h ; Check for zero or l jr nz,$1 ; Keep waiting scf ; Flag timeout error jr $3 $2: ld hl,(hinbufb) ; Point to character ld a,(hl) ; Get it inc l ld (hinbufb),hl or a ; Clear carry for no timeout $3: pop hl ret ; page ; ;========================================================================= ; ; T A S K 6 ; ; Not used ; task6: rt_exit ; page ; ;========================================================================= ; ; T A S K 7 ; ; Network serial port output manager. ; task7: ld sp,t7sp $1: ld a,(rstflg) ; Is this the first pass after a program or a ; load or reset? ;*** jr z,$15 ; Nope, start with task0 ld ix,t3trdy ; Yes, so skip task0, task1, and task2 on ld hl,t3rbuf ; the first pass ld (rbuf),hl ld hl,t3tbuf ld (tbuf),hl ld b,ntasks-3 jr $3 $15: ld ix,t0trdy ld hl,t0rbuf ld (rbuf),hl ld hl,t0tbuf ld (tbuf),hl ld b,ntasks $2: ld a,(rstflg) ; Still in first pass? or a ;*** jr nz,$3 ; Yes, so keep ignoring task1 ld a,(t1trdy) ; Does task1 have something to say? or a jr z,$3 ; Nope, continue round robin push ix ; Yes, give task1 priority ld ix,t1trdy ld hl,(rbuf) push hl ld hl,t1rbuf ld (rbuf),hl ld hl,(tbuf) push hl ld hl,t1tbuf ld (tbuf),hl call netsend ; Send packet ld a,(ix+1) ; Wait for response? or a jr z,$4 ; No, continue with next ; call netrec ; Wait for a response $4: ld (ix),0 ; Buffer now empty pop hl ; Restore old pointers ld (tbuf),hl pop hl ld (rbuf),hl pop ix jr $2 ; Continue with round robin ; $3: ld a,(ix) or a ; Ready to send? jr z,$9 ; No, do next call netsend ; Yes, do it ld a,(ix+1) ; Wait for response? or a jr z,$8 ; No, continue with next ; call netrec ; Wait for a response $8: ld (ix),0 ; Buffer now empty $9: inc ix ; Point to next task block inc ix inc ix inc ix ; ld hl,(rbuf) ld de,rbufsiz add hl,de ld (rbuf),hl ; ld hl,(tbuf) ld de,tbufsiz add hl,de ld (tbuf),hl ; dec b jp nz,$2 jp $1 ; netsend: push bc push hl ld hl,(tbuf) call xmiton ; Enable RS-485 transmitter ld b,tbufsiz $1: ld a,(hl) or a jr z,$2 call netout ; Send character to net inc hl djnz $1 $2: call xmitoff ; Disable transmitter pop hl pop bc ret ; xmiton: push bc in0 b,(cntla0) res 4,b ; Enable RS-485 transmitter out0 (cntla0),b ld b,50 $1: djnz $1 ; Allow line to settle pop bc ret ; netout: push af $1: in0 a,(stat0) bit 1,a ; Check TDRE jr z,$1 ; Wait for previous character pop af out0 (tdr0),a ; Send character ret ; xmitoff: push bc $1: in0 b,(stat0) bit 1,b ; Check TDRE jr z,$1 ; Wait for last character to be put in sh reg di ; Make sure delay isn't interrupted ; MSB - 991226 v3.63s update ; Updated serial stop bit timing for 18.432MHz ; @ 9.216MHz: ((37*9) + 12 - 2) + (((256 * 9) + 12 - 2) * 4) - 2 = 9597 ticks = 1.04134 ms ; @ 18.432MHz: We need 19169 ticks for 1.04ms so we use 8 and 72 and get 19170 for 1.04004 ms ; ; The S180 docs don't really make it clear. They say the transmit buffer has a 2x FIFO, but ; the status flags say nothing about it nor do the diagrams. We seem to be trampling the last ; character as if the RS-485 driver is being tri-stated too soon. If there really IS a 2 deep ; FIFO on the transmit register AND the FIFO doesn't affect TDRE (i.e. TDRE only reflects the ; the state of the write register, not the FIFO register between the TDR and TSR if such a thing ; exists) then we need to wait for 2.08 ms. Bummer to stall the RTOS for that long on each ; character. ; So anyway, lets try 38339 ticks for 2.08 ms. This gives us 16 and 145. ; This fixed the problem of the trailing CR being trashed. Wish there was ; a way to avoid stalling for 2ms everytime a network packet is sent. Could be worse though. ; ; ld c,4 ; Wait exactly 10 bit times (1.04 ms) for ; ld b,37 ; character to be sent ld c,16 ld b,145 $2: djnz $2 ; 9 T states (on branch) 7 on fall through dec c ; 4 T states jr nz,$2 ; 8 T states (on branch) 6 on fall through in0 b,(cntla0) set 4,b ; Disable transmitter out0 (cntla0),b ei pop bc ret ; ; netrec: push bc push de push hl ld a,0 ld (totmr),a ; Initialize timeout counter ld hl,(rbuf) ld (rptr),hl ; Initialize receiver buffer pointer ld a,0 ld (rcntr),a ; Init character counter $1: ld hl,(ninbuft) ; Get both buffer pointers ex de,hl ld hl,(ninbufb) ld a,l cp e ; Anything in buffer? jr z,$8 ; No, check for timeout ; ld a,(hl) ; Yes, get it ld b,a ; Save it inc l ld (ninbufb),hl cp lf ; End of string? jr z,$9 ; Yes, flag ready cp cr ; End of string? jr z,$9 ; Yes, flag ready ld a,(rcntr) ; Check for full buffer cp rbufsiz ; Counter >= bufsize? jr nc,$2 ; Yes, buffer full, flush buffer ; ld hl,(rptr) ld a,b cp '$' ; Start of string? jr nz,$3 ; No, save char in buffer $2: ld hl,(rbuf) ; Yes, reset pointer (flush buffer) ld a,0 ; Reset counter ld (rcntr),a $3: ld (hl),b ; Put character in buffer inc hl ld (rptr),hl ld hl,rcntr inc (hl) ; Increment character counter ; $8: ld a,(totmr) ; Check for timeout cp 7 jr c,$1 ; If <7, keep going ld a,0 ld (ix+2),a ; Not ready ld a,0ffh ld (ix+3),a ; Timed out jr $99 $9: ld a,(rcntr) ; Check packet length or a jr z,$1 ; If 0, ignore CR or LF and keep waiting ld hl,(rptr) ; If >0, then we have a real finished packet ld (hl),0 ; Mark end of packet inc hl ld (rptr),hl ld hl,rcntr inc (hl) ; Increment character counter ; MSB - 991226 v3.63s changes for Z8S180 ; Need to double the counter for this timeout ; ld c,40 ; Wait after last character received ld c,80 ; Wait after last character received ld b,0 ; (about 10 ms) $90: djnz $90 ; 9 T States on branch, 7 on pass through dec c ; 4 T States jr nz,$90 ; 8 T States on branch, 6 on pass through ld a,0 ld (ix+3),a ; No timeout ld a,0ffh ld (ix+2),a ; String ready $99: ld a,0 ld (ix+1),a ; Stop waiting for response pop hl pop de pop bc ret ; page ; ;========================================================================= ; ; T A S K 8 ; ; Poll X-10 network module and update local module state table ; with result. ; task8: ld sp,t8sp ld a,(numpl) or a jp nz,pl ; If a PL-Link defined, always use it ; ; Use PLIX. Update power fail flags, check for ; anything new received, then check for outgoing traffic. ; ld bc,pia1+2 ; Assume SS ld a,(sc) ; Get SC type cp scbcc+1 ; BCC or RTC? jr nc,$ss ; Nope, stick with SS ld bc,pia5+2 ; Yup, redirect to HCS-PLIX port $ss: in a,(c) ; Get current status bit 7,a ; Power on? ld a,0ffh ; Prepare for AC on jr nz,$00 ; Power is on ld (acfail),a ; Indicate power has failed ld a,0 ; Power is off $00: ld (acpwr),a ; Save current state ; $0: call recx10 or a jr z,$xmit ; Nothing new ; ; Get received code and act on it ; ld hl,houstbl ; Convert housecode into offset into storage ld e,b ld d,0 add hl,de ; Point to offset value ld e,(hl) ld hl,modules add hl,de ; Point HL to start of housecode bit 4,c ; Is this a command or a module select? jr nz,$cmd ; Jump if command ; ; A module has been selected. Set bit 6 in this module (to select it) ; and clear bit 5 in all modules in this housecode (to deselect all ; those from the previous command). ; push hl ; Save pointer to start of housecode ld b,16 ; Do all 16 modules $1: res 5,(hl) inc hl djnz $1 ld hl,seltbl ; Convert module number into real offset ld b,0 add hl,bc ld c,(hl) pop hl add hl,bc ; Now go to individual module set 6,(hl) jr $0 ; Check for more ; ; A command has been issued. Set bit 5 and clear bit 6 on any module ; in housecode that has bit 6 set (no more may be selected), then ; apply command to any module in housecode with bit 5 set. ; $cmd: push hl ; Save pointer to start of housecode ld b,16 ; Do all 16 modules $2: bit 6,(hl) ; Has module been selected? jr z,$3 ; Nope, skip res 6,(hl) set 5,(hl) $3: inc hl djnz $2 pop hl ; ld a,c ; Check command cp 18h ; All lights on? jr z,$0 ; Yes, ignore it cp 10h ; All units off? jr nz,$5 ; Nope, must be on/off/dim/bright ; ; For all units off, clear all modules in housecode ; ld b,16 $4: ld (hl),80h ; Turn module off and deselect it inc hl djnz $4 jr $99 ; ; For on/off/dim/bright, apply the command to selected modules ; $5: cp 1ch ; Off? jr z,$8 ; Yes, do it ld b,16 ; Set on/dim/bright to on $6: bit 5,(hl) ; Selected? jr z,$7 ; Nope, skip set 0,(hl) ; Flag module as on $7: inc hl djnz $6 jr $99 ; $8: ld b,16 $9: bit 5,(hl) ; Selected? jr z,$10 ; Nope, skip res 0,(hl) ; Flag module as off $10: inc hl djnz $9 ; $99: ld a,0ffh ; Flag to display module status ld (dx10f),a jr $0 ; ; Check transmit buffer and send any commands found to PLIX ; $xmit: ld hl,(plixoh) ; Head pointer ld de,(plixot) ; Tail pointer xor a ; Clear carry sbc hl,de ; Pointers the same? jp z,t8exit ; Yes, done ld hl,(plixot) ; Get tail again ld b,(hl) ; Get housecode inc l ld c,(hl) ; Get function inc l ld d,(hl) ; Get repeats inc l ld (plixot),hl ; Save new tail call sendx10 ; Give it to PLIX ld a,0ffh ; Flag to display module status ld (dx10f),a jr $xmit ; Check for more ; houstbl:db 0c0h,0d0h,0e0h,0f0h,020h,030h,000h,010h db 040h,050h,060h,070h,0a0h,0b0h,080h,090h seltbl: db 0ch,0dh,0eh,0fh,02h,03h,00h,01h db 04h,05h,06h,07h,0ah,0bh,08h,09h ; ; ; Use the PL-Link to talk X-10 ; pl: ld a,(nettmrs) ; Check if we should delay query or a jp nz,t8exit ; Yes, skip query this time ld a,(acchk) ; Ask for AC power status instead of or a ; X-10 modules on half minute jp z,plx10 ; Not half minute, ask for X-10 status ; ld a,0 ; Clear flag ld (acchk),a ld de,t8tbuf ld hl,ACqury ld bc,12 ldir ; Copy header to buffer ld hl,t8tbuf+1 call setcheck ; Fill in checksum ld a,0ffh ld (t8wait),a ; Flag wait for response ld (t8trdy),a ; Flag buffer as full $1: ld a,(t8rrdy) ; Wait for response or a jr nz,$5 ; Go process response ld a,(t8rto) ; Check for timeout or a jr nz,$11 ; If so, flag it and exit rt_wait 1 ; Give up control for one tick jr $1 ; Check again $11: ld a,0 ; Flag timeout ld (plresp),a jp t8exit ; $5: ld hl,t8rbuf call vercheck ; Verify correct checksum jr z,$0 ; If OK, continue ld a,02h ; Flag error ld (plresp),a jp t8exit ; and abort $0: ld a,01h ; Flag response ld (plresp),a ; ld a,(t8rbuf+4) ; Make sure this is for us cp 'X' jp nz,t8exit ; Nope, ignore response ; ld hl,t8rbuf+13 ; Skip over header ld a,(hl) ; Current AC status cp '0' ; On? jr z,$6 ; Yes ld a,0 ; Nope, off ld (acpwr),a ; Save power status ld a,0ffh ld (acfail),a ; Always failed when power off jp t8exit ; All done $6: ld a,0ffh ; Flag power as on ld (acpwr),a ; Save status inc hl inc hl ld a,(hl) ; Failed reply cp '0' ; Power failed? jr z,$7 ; No failure ld a,0ffh ; Yes, power failed since last query ld (acfail),a ; Save status $7: jp t8exit ; All done ; plx10: ld de,t8tbuf ld hl,x10qury ld bc,13 ldir ; Copy header to buffer ld hl,t8tbuf+1 call setcheck ; Fill in checksum ld a,0ffh ld (t8wait),a ; Flag wait for response ld (t8trdy),a ; Flag buffer as full $1: ld a,(t8rrdy) ; Wait for response or a jr nz,$5 ; Go process response ld a,(t8rto) ; Check for timeout or a jr nz,$11 ; If so, flag it and exit rt_wait 1 ; Give up control for one tick jr $1 ; Check again $11: ld a,0 ; Flag timeout ld (plresp),a jr t8exit ; $5: ld hl,t8rbuf call vercheck ; Verify correct checksum jr z,$0 ; If OK, continue ld a,02h ; Flag error ld (plresp),a jr t8exit ; and abort $0: ld a,01h ; Flag response ld (plresp),a ; ld a,(t8rbuf+4) ; Make sure this is for us cp 'X' jr nz,t8exit ; Nope, ignore response ; ld hl,t8rbuf+8 ; Skip over header ld ix,modules ; Point to module state storage ld b,16 ; 16 house codes $2: ld a,(hl) ; Do upper nybble call atoh rlca rlca rlca rlca ld d,a inc hl ld a,(hl) ; Do lower nybble call atoh or d ; Combine them ld d,a ; Save modules 8-16 inc hl ; ld a,(hl) ; Do upper nybble call atoh rlca rlca rlca rlca ld e,a inc hl ld a,(hl) ; Do lower nybble call atoh or e ; Combine them ld e,a ; Save modules 0-7 inc hl ; push bc ; Now put them into the state table ld b,16 ; Do 16 modules $3: ld c,01h srl d ; 16-bit shift right into carry rr e jr c,$4 ld c,00h $4: ld a,(ix) ; Get current value and 01h ; Look at only low bit cp c ; Current = new? jr z,$6 ; Yes, save new and continue ld a,(uptbl) ; Are we believing everything? or a jr nz,$6 ; Yes, so save value ld a,(ix) ; No, get current value again bit 7,a ; Was it set locally? jr nz,$7 ; Yes, don't touch it $6: ld (ix),c ; Save new value $7: inc ix djnz $3 ; Next module pop bc djnz $2 ; Next house code ; ld a,0ffh ld (dx10f),a t8exit: ld a,0 ld (t8rrdy),a ld (t8rto),a ld (uptbl),a rt_exit ; x10qury db cr,'#00 X10 QS',cr,0 ACqury db cr,'#00 X10 P',cr,0 ; ; Convert ASCII "0"-"F" to hex 0-F ; atoh: sub '0' cp 0ah ret c sub 7 ret ; ; Convert hex 0-F to ASCII "0"-"F" ; htoa: add a,'0' cp ':' ret c add a,7 ret ; ; Convert hex 00-FF in A to ASCII "00"-"FF" ; and return in BC ; hto2a: push af push af and 0fh call htoa ld c,a pop af rra rra rra rra and 0fh call htoa ld b,a pop af ret ; ; Send an X-10 message to the power line using PLIX. Enter with ; housecode in B, function in C, and repeats in D. Repeats should ; always equal 2 unless a dim or bright command is being sent. ; sendx10: call syncplix ld a,b ; Send housecode call sendplix ld a,c ; Function call sendplix ld a,d ; Repeats call sendplix ret ; ; ; Receive X-10 message from power line. If no new message received, ; returns with A=0. If message ready, returns with A<>0, housecode ; in B, and function in C. ; recx10: call recplix ; Get housecode ld b,a call recplix ; Get function ld c,a ld a,0 ; Assume no new code bit 4,b ; Check for new code jr z,$1 ; Correct assumption, nothing new ld a,0ffh ; Code is new $1: res 4,b ; Clear bit ret ; ; syncplix: push af ld a,0 ; Clear PIC write buffer call sendplix call sendplix call sendplix ld a,31 ; End of sync cycle call sendplix pop af ret ; ; sendplix: push af push bc push de push hl ld bc,pia1 ; Assume SS push af ld a,(sc) ; Get SC type cp scbcc+1 ; BCC or RTC? jr nc,$0 ; Nope, stick with SS ld bc,pia5 ; Yup, redirect to HCS-PLIX port $0: pop af ld de,0 ; Timeout counters ld l,10 ; Double timeout counter for S180 MSB 011900 set 5,a ; Set select line set 6,a ; Set direction line out (c),a ; Send to PIC $1: dec e jr nz,$1a ; No timeout, continue dec d jr nz,$1a dec l jr z,$9 ; Return if timed out $1a: in a,(c) ; Wait for acknowledgement bit 7,a jr z,$1 ; ld de,0 ; Timeout counters ld l,10 ; Double timeout counter for S180 MSB 011900 ld a,0 ; Finish write cycle out (c),a $2: dec e jr nz,$2a ; No timeout, continue dec d jr nz,$2a dec l jr z,$9 ; Return if timed out $2a: in a,(c) ; Wait for end of cycle bit 7,a jr nz,$2 ; $9: pop hl pop de pop bc pop af ret ; ; recplix: push bc push de call plixrd ; Set up PIA for read ld bc,pia1 ; Assume SS push af ld a,(sc) ; Get SC type cp scbcc+1 ; BCC or RTC? jr nc,$0 ; Nope, stick with SS ld bc,pia5 ; Yup, redirect to HCS-PLIX port $0: pop af ld de,0 ; Timeout counters ld l,10 ; Double timeout counter for S180 MSB 011900 ld a,20h ; Set select and direction lines out (c),a ; Send to PIC $1: dec e jr nz,$1a ; No timeout, continue dec d jr nz,$1a dec l jr z,$9 ; Return if timed out $1a: in a,(c) ; Wait for data ready bit 7,a jr z,$1 ; and a,1fh ; Mask data push af ld de,0 ; Timeout counters ld l,10 ; Double timeout counter for S180 MSB 011900 ld a,0 ; Acknowledge data read out (c),a $2: dec e jr nz,$2a ; No timeout, continue dec d jr nz,$2a dec l jr z,$9 ; Return if timed out $2a: in a,(c) ; Wait for end of read cycle bit 7,a jr nz,$2 ; $9: call plixwr ; Put PIA back to write mode pop af pop de pop bc ret ; ; ; Set up PIA for write cycle ; plixwr: push af push bc ld bc,pia1+1 ; Assume SS push af ld a,(sc) ; Get SC type cp scbcc+1 ; BCC or RTC? jr nc,$0 ; Nope, stick with SS ld bc,pia5+1 ; Yup, redirect to HCS-PLIX port $0: pop af di in a,(c) res 2,a ; Select data direction out (c),a dec bc ld a,01111111b ; IOOOOOOO out (c),a inc bc in a,(c) set 2,a ; Select data out (c),a ei pop bc pop af ret ; ; ; Set up PIA for read cycle ; plixrd: push af ld bc,pia1+1 ; Assume SS push af ld a,(sc) ; Get SC type cp scbcc+1 ; BCC or RTC? jr nc,$0 ; Nope, stick with SS ld bc,pia5+1 ; Yup, redirect to HCS-PLIX port $0: pop af push bc di in a,(c) res 2,a ; Select data direction out (c),a dec bc ld a,01100000b ; IOOIIIII out (c),a inc bc in a,(c) set 2,a ; Select data out (c),a ei pop bc pop af ret ; page ; ;========================================================================= ; ; T A S K 9 ; ; LCD-Link server. ; task9: ld sp,t9sp ld a,(numlcd) or a jp z,$99 ; Skip if no LCD-Links ; ld b,a ; Save total ld a,(nextlcd) ; Get number of link to be polled cp b ; Too big? jr c,$0 ; No, continue ld a,0 ; Yes, so go back to first ld (nextlcd),a $0: ld hl,nettmrs+8 ; Start of LCD timers ld e,a ; Get offset ld d,0 add hl,de ld a,(hl) ; Check if we should delay query or a jp nz,$98 ; Yes, skip query this time ; ld de,t9tbuf ld hl,LCDqury ld bc,14 ldir ; Copy header to buffer ld a,(nextlcd) add a,'0' ; Make link number into ASCII ld (t9tbuf+9),a ; Put into packet ld hl,t9tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0ffh ld (t9wait),a ; Flag wait for response ld (t9trdy),a ; Flag buffer as full ld hl,lcdresp ; Point to response table ld a,(nextlcd) ; Get current link number ld e,a ld d,0 add hl,de $1: ld a,(t9rrdy) ; Wait for response or a jr nz,$5 ; Go process response ld a,(t9rto) ; Check for timeout or a jr nz,$11 ; If so, flag it and exit push hl rt_wait 1 ; Give up control for one tick pop hl jr $1 ; Check again $11: ld (hl),0 ; Flag timeout jp $98 ; $5: push hl ld hl,t9rbuf call vercheck ; Verify correct checksum pop hl jr z,$9 ; If OK, continue ld (hl),2 ; Flag error jp $99 ; and abort $9: ld (hl),1 ; Flag response ; ld a,(t9rbuf+4) ; Make sure this is for us cp 'T' jp nz,$98 ; Nope, ignore response ; ; Handle four push buttons ; ld hl,t9rbuf+10 ; Skip over header ld a,(hl) ; Do upper nybble call atoh rlca rlca rlca rlca ld c,a inc hl ld a,(hl) ; Do lower nybble call atoh or c ; Combine them ld c,a ; ld a,(nextlcd) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 4 rlca ld hl,netbit1+64 ; Point to storage ld iy,nedge1+64 ld e,a ld d,0 add hl,de ; Offset to start of link add iy,de ; ld b,4 ; Do 4 bits srl c ; Skip low-order 4 bits srl c srl c srl c $3: ld a,0 ; Assume 0 srl c ; 8-bit shift right into carry jr nc,$4 ; It is 0, so save it ld a,1 ; It's a 1 $4: ld d,(hl) ; Get old value ld (hl),a ; Save new value cp d ; Change? jr z,$6 ; No, skip edge ld (iy),0ffh ; Flag edge $6: inc hl inc iy djnz $3 ; Next bit ; ; Handle keypad presses ; ld hl,t9rbuf+12 ; Skip over header and buttons ld a,(hl) ; Do upper nybble or a ; Set flags jr z,$98 ; No keypresses, exit inc hl ld a,(nextlcd) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 4 rlca ld iy,khead0 ; Start of head/tail storage ld e,a ld d,0 add iy,de ; Offset to proper pair $nxtkey: ld a,(hl) ; Get next keypress or a ; Set flags jr z,$98 ; Done if no more push hl ld e,(iy) ; Get head pointer ld d,(iy+1) ld (de),a ; Save keypress inc de ; Next buffer location ld a,(nextlcd) ; Get current link again and 07h ; Ensure 0-7 inc a ld c,a ld b,8 mlt bc ld hl,kbuf0 ; Start of buffers add hl,bc ; End of this link's buffer (carry is cleared) sbc hl,de jr nz,$bufok ; If not zero, not end of buffer ld a,(nextlcd) ; Wrap around in buffer and 07h ; Ensure 0-7 ld c,a ld b,8 mlt bc ld hl,kbuf0 add hl,bc ex de,hl ; Put buffer start in DE $bufok: ld (iy),e ; Save it ld (iy+1),d pop hl inc hl jr $nxtkey ; $98: ld hl,nextlcd inc (hl) ; Do next link on next pass $99: ld a,0 ld (t9rrdy),a ld (t9rto),a rt_exit ; LCDqury db cr,'#00 TERM0 Q',cr,0 ; page ; ;========================================================================= ; ; T A S K 10 ; ; Poll MC/IR-Link network modules and update local input state table ; with result. ; task10: ld sp,t10sp ld a,(numir) or a jp z,$99 ; Skip if no MC/IR-Links ; ld b,a ; Save total ld a,(nextir) ; Get number of link to be polled cp b ; Too big? jr c,$0 ; No, continue ld a,0 ; Yes, so go back to first ld (nextir),a $0: ld hl,nettmrs+16 ; Start of MC/IR timers ld e,a ; Get offset ld d,0 add hl,de ld a,(hl) ; Check if we should delay query or a jp nz,$98 ; Yes, skip query this time ; ld de,t10tbuf ld hl,IRqury ld bc,17 ldir ; Copy message to buffer ld a,(nextir) add a,'0' ; Make link number into ASCII ld (t10tbuf+7),a ; Put into message in buffer ld hl,t10tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0ffh ld (t10wait),a ; Flag wait for response ld (t10trdy),a ; Flag buffer as full ld hl,irresp ; Point to response table ld a,(nextir) ; Get current link number ld e,a ld d,0 add hl,de ; Point to proper response entry $1: ld a,(t10rrdy) ; Wait for response or a jr nz,$5 ; Go process response ld a,(t10rto) ; Check for timeout or a jr nz,$11 ; If so, flag it and exit push hl rt_wait 1 ; Give up control for one tick pop hl jr $1 ; Check again $11: ld (hl),0 ; Flag timeout jr $98 ; $5: push hl ld hl,t10rbuf call vercheck ; Verify correct checksum pop hl jr z,$9 ; If OK, continue ld (hl),2 ; Flag error jr $99 ; and abort $9: ld (hl),1 ; Flag response ; ld a,(t10rbuf+4) ; Make sure this is for us cp 'I' jr nz,$98 ; Nope, ignore response ; ld a,(nextir) ; Get current link number set 7,a ; Set high bit to indicate presence ld e,a ; Save it for later ld hl,t10rbuf+17 ; Skip over header ld ix,irvals ; Point to room code storage ld b,32 ; Do 32 blocks of 8 $2: ld a,(hl) ; Do upper nybble call atoh rlca rlca rlca rlca ld c,a inc hl ld a,(hl) ; Do lower nybble call atoh or c ; Combine them ld c,a ; Save bits 0-7 inc hl ; push bc ; Now put them into storage ld b,8 ; Do 8 bits $3: srl c ; 8-bit shift right into carry jr nc,$4 ; Not present, skip store ld (ix),e ; Save link number $4: inc ix djnz $3 ; Next bit pop bc djnz $2 ; Next set of 8 ; $98: ld hl,nextir inc (hl) ; Do next link on next pass $99: ld a,0 ld (t10rrdy),a ld (t10rto),a rt_exit ; IRqury db cr,'#00 IR0 Q0-255',cr,0 ; page ; ;========================================================================= ; ; T A S K 11 ; ; Poll DIO-Link network modules and update local input state table ; with result. ; task11: ld sp,t11sp ld a,(numdio) or a jp z,$99 ; Skip if no DIO-Links ; ld b,a ; Save total ld a,(nextdio) ; Get number of link to be polled cp b ; Too big? jr c,$0 ; No, continue ld a,0 ; Yes, so go back to first ld (nextdio),a $0: ld hl,nettmrs+24 ; Start of DIO timers ld e,a ; Get offset ld d,0 add hl,de ld a,(hl) ; Check if we should delay query or a jp nz,$98 ; Yes, skip query this time ; ld de,t11tbuf ld hl,DIOqury ld bc,15 ldir ; Copy message to buffer ld a,(nextdio) add a,'0' ; Make link number into ASCII ld (t11tbuf+8),a ; Put into message in buffer ld hl,t11tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0ffh ld (t11wait),a ; Flag wait for response ld (t11trdy),a ; Flag buffer as full ld hl,dioresp ; Point to response table ld a,(nextdio) ; Get current link number ld e,a ld d,0 add hl,de ; Point to proper response entry $1: ld a,(t11rrdy) ; Wait for response or a jr nz,$5 ; Go process response ld a,(t11rto) ; Check for timeout or a jr nz,$11 ; If so, flag it and exit push hl rt_wait 1 ; Give up control for one tick pop hl jr $1 ; Check again $11: ld (hl),0 ; Flag timeout jr $98 ; $5: push hl ld hl,t11rbuf call vercheck ; Verify correct checksum pop hl jr z,$9 ; If OK, continue ld (hl),2 ; Flag error jr $99 ; and abort $9: ld (hl),1 ; Flag response ; ld a,(t11rbuf+4) ; Make sure this is for us cp 'D' jr nz,$98 ; Nope, ignore response ; ld hl,t11rbuf+12 ; Skip over header ld a,(hl) ; Do upper nybble call atoh rlca rlca rlca rlca ld c,a inc hl ld a,(hl) ; Do lower nybble call atoh or c ; Combine them ld c,a ; Save bits 0-7 ; ld a,(nextdio) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 8 rlca rlca ld hl,netbit1 ; Point to storage ld iy,nedge1 ld e,a ld d,0 add hl,de ; Offset to start of link add iy,de ; ld b,8 ; Do 8 bits $3: ld a,0 ; Assume 0 srl c ; 8-bit shift right into carry jr nc,$4 ; It is 0, so save it ld a,1 ; It's a 1 $4: ld d,(hl) ; Get old value ld (hl),a ; Save new value cp d ; Any change? jr z,$6 ; No, skip edge ld (iy),0ffh ; Flag edge $6: inc hl inc iy djnz $3 ; Next bit ; $98: ld hl,nextdio inc (hl) ; Do next link on next pass $99: ld a,0 ld (t11rrdy),a ld (t11rto),a rt_exit ; DIOqury db cr,'#00 DIO0 QDP',cr,0 ; page ; ;========================================================================= ; ; T A S K 12 ; ; Poll MAN-Link network modules and update local input state table ; and ADC tables with results. ; task12: ld sp,t12sp ld a,(numman) or a jp z,$99 ; Skip if no MAN-Links ; ld b,a ; Save total ld a,(nextman) ; Get number of link to be polled cp b ; Too big? jr c,$11 ; No, continue ld a,0 ; Yes, so go back to first ld (nextman),a $11: ld hl,mancfgf ; Point to flag storage ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 ld e,a ld d,0 add hl,de ; Point to correct flag ld a,(hl) ; Ask for configuration word on half or a ; minute jr z,$12 ; Not half minute, continue push hl ld hl,MANqc ; Query configuration call askman ; Send query and process reply pop hl ld (hl),0 $12: ld hl,mancfg ; Configuration word storage ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 2 ld e,a ld d,0 add hl,de ; Point to correct word ld e,(hl) ; Get it and save it in DE inc hl ld d,(hl) ; ld hl,MANqe ; Always ask for digital and analog I/O call askman ; Send query and process reply ; ld hl,MANqf ; Frequency input bit 3,e call nz,askman ld hl,MANqt ; Totalizer input bit 1,d call nz,askman ; ld hl,MANqs ; iButton input bit 0,d call nz,askman ; ld hl,nextman inc (hl) ; Do next link on next pass $99: ld a,0 ld (t12rrdy),a ld (t12rto),a rt_exit ; MANqc db 14,cr,'#00 MAN0 QC',cr,0 MANqe db 14,cr,'#00 MAN0 QE',cr,0 MANqf db 14,cr,'#00 MAN0 QF',cr,0 MANqt db 14,cr,'#00 MAN0 QT',cr,0 MANqs db 14,cr,'#00 MAN0 QS',cr,0 ; ; ; Send a query to the Answer MAN and process the reply. ; Enter with start of query string in HL. ; askman: push bc push de $1: ld a,(t12trdy) ; Wait for buffer to be empty or a jr nz,$1 ; ld de,t12tbuf ld b,0 ld c,(hl) ; Get string length inc hl ldir ; Copy header to buffer ld a,(nextman) add a,'0' ; Make link number into ASCII ld (t12tbuf+8),a ; Put into message in buffer ld hl,t12tbuf+1 call setcheck ; Fill in checksum ld a,0ffh ld (t12wait),a ; Flag wait for response ld (t12trdy),a ; Flag buffer as full ld hl,manresp ; Point to response table ld a,(nextman) ; Get current link number ld e,a ld d,0 add hl,de ; Point to proper response entry $2: ld a,(t12rrdy) ; Wait for response or a jr nz,$4 ; Go process response ld a,(t12rto) ; Check for timeout or a jr nz,$3 ; If so, flag it and exit push hl rt_wait 1 ; Give up control for one tick pop hl jr $2 ; Check again $3: ld (hl),0 ; Flag timeout jr $9 ; $4: push hl ld hl,t12rbuf call vercheck ; Verify correct checksum pop hl jr z,$5 ; If OK, continue ld (hl),2 ; Flag error jr $9 ; and abort $5: ld (hl),1 ; Flag response ; ld a,(t12rbuf+4) ; Make sure this is for us cp 'M' jr nz,$9 ; Nope, ignore response ; call scanman ; Parse reply $9: ld a,0 ld (t12rrdy),a ld (t12rto),a pop de pop bc ret ; All done ; ; ; Scan Answer MAN reply looking for data headers ; scanman: ld hl,t12rbuf+8 ; Point to start of reply data $loop: ld a,(hl) ; Get next character inc hl or a ; End of reply? ret z ; Yes, stop cp 'I' ; Digital inputs? jr z,$din cp 'O' ; Digital outputs? jr z,$dout cp 'A' ; Analog inputs? jr z,$ain cp 'D' ; Analog outputs? jr z,$aout cp 'F' ; Frequency input? jr z,$freq cp 'T' ; Totalizer input? jp z,$total cp 'S' ; iButton input? jp z,$button cp 'C' ; Configuration word? jp z,$cfg jr $loop ; None of the above, so keep scanning ; ; Handle digital inputs ; $din: inc hl ; Skip over : call tobin ; Convert to binary push hl ; Save reply pointer ld hl,netbit1+96 ; Point to storage ld iy,nedge1+96 call tostor ; Put status in storage pop hl inc hl ; Skip over value inc hl jp $loop ; Do next data ; ; Handle digital outputs ; $dout: inc hl ; Skip over : call tobin ; Convert to binary push hl ; Save reply pointer ld hl,netbit1+104 ; Point to storage ld iy,nedge1+104 call tostor ; Put status in storage pop hl inc hl ; Skip over value inc hl jp $loop ; Do next data ; ; Analog inputs ; $ain: ld a,(hl) ; Get channel number inc hl inc hl ; Skip over : sub '0' ; Convert ASCII to binary ld b,a ; Save it ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 8 rlca rlca add a,b ; Add channel offset ld e,a ld d,0 sla e ; Multiply DE by 2 rl d push hl ld hl,adcvals+32 ; Point to start of storage add hl,de ; Offset to start of link ex de,hl ; DE = storage pop hl ; HL = buffer $5 bit 2,b ; test for channel4/5 ld b,0 ; clear B (preclear high nybble for 8-bit'rs) jr z,$10 ; jump if not (must be channel 0-3 8-bit'rs) $8 ld a,(hl) ; Get high nybble inc hl call atoh ; Convert to binary ld b,a ; Save it $10 call tobin ; Convert next two nybbles to binary inc hl inc hl ex de,hl ; HL = storage inc hl ; Point at high byte bit 7,(hl) ; Forced value? jr nz,$15 ; Yes, skip save dec hl ld (hl),a ; Save conversion value low byte inc hl ld (hl),b ; Save high nybble $15: ex de,hl ; HL = buffer jp $loop ; $aout: inc hl ; Just ignore data for now inc hl inc hl inc hl inc hl jp $loop ; ; Frequency input ; $freq: inc hl ; Skip over : ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 2 ld e,a ld d,0 push hl ld hl,freqs ; Point to start of storage add hl,de ; Offset to start of link ex de,hl ; DE = storage pop hl ; HL = buffer call tobin ; Convert high byte to binary and 7fh ; Throw away high bit ld b,a ; Save it inc hl inc hl call tobin ; Convert low byte inc hl inc hl ex de,hl ; HL = storage ld (hl),a ; Save frequency low byte inc hl ld (hl),b ; Save high byte ex de,hl ; HL = buffer jp $loop ; ; Totalizer input ; $total: inc hl ; Skip over : inc hl ; Skip over high byte inc hl ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 2 ld e,a ld d,0 push hl ld hl,totals ; Point to start of storage add hl,de ; Offset to start of link ex de,hl ; DE = storage pop hl ; HL = buffer call tobin ; Convert high byte to binary ld b,a ; Save it inc hl inc hl call tobin ; Convert low byte inc hl inc hl ex de,hl ; HL = storage ld (hl),a ; Save frequency low byte inc hl ld (hl),b ; Save high byte ex de,hl ; HL = buffer jp $loop ; ; iButton input ; $button: inc hl ; Skip over : ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 ld d,0 ld e,a sla e ; Multiply by 8 sla e sla e ld ix,cbutton ; Point to button storage add ix,de ; Offset to this module ld b,8 ; Do 8 bytes $b1: call tobin ; Convert byte to binary ld (ix),a ; Save it inc hl ; Point to next ASCII inc hl inc hl ; Skip space inc ix djnz $b1 ; Do all 8 bytes jp $loop ; ; Configuration word ; $cfg: inc hl ; Skip over : ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 2 ld e,a ld d,0 push hl ld hl,mancfg ; Point to start of storage add hl,de ; Offset to start of link ex de,hl ; DE = storage pop hl ; HL = buffer call tobin ; Convert high byte to binary ld b,a ; Save it inc hl inc hl call tobin ; Convert low byte inc hl inc hl ex de,hl ; HL = storage ld (hl),a ; Save configuration low byte inc hl ld (hl),b ; Save high byte ex de,hl ; HL = buffer jp $loop ; ; ; Convert ASCII response to binary number. Enter with HL ; pointing at two-byte ASCII value and exit with binary ; version in A. ; tobin: push bc push hl ld a,(hl) ; Do upper nybble call atoh ld c,a sla c sla c sla c sla c inc hl ld a,(hl) ; Do lower nybble call atoh or c ; Combine them pop hl pop bc ret ; ; Put 8-bit status byte into storage one bit to a byte. Enter ; with HL pointing at starting storage location, IY pointing at ; starting edge table location, and status byte in A. Automatically ; offsets into storage and edge table depending on what link is ; being accessed. ; tostor: ld c,a ld a,(nextman) ; Get current link number and 07h ; Ensure 0-7 ld e,a ld d,16 mlt de ; Multiply by 16 add hl,de ; Offset to start of link add iy,de ; ld b,8 ; Do 8 bits $3: ld a,0 ; Assume 0 srl c ; 8-bit shift right into carry jr nc,$4 ; It is 0, so save it ld a,1 ; It's a 1 $4: ld d,(hl) ; Get old value ld (hl),a ; Save new value cp d ; Change? jr z,$5 ; No, skip edge ld (iy),0ffh ; Flag edge $5: inc hl inc iy djnz $3 ; Next bit ret ; page ; ;========================================================================= ; ; T A S K 13 ; ; Poll DIO+-Link network modules and update local input state table ; and ADC tables with results. ; task13: ld sp,t13sp ld a,(numdiop) or a jp z,$99 ; Skip if no DIO+-Links ; ld b,a ; Save total ld a,(nextdiop) ; Get number of link to be polled cp b ; Too big? jr c,$0 ; No, continue ld a,0 ; Yes, so go back to first ld (nextdiop),a ; ; Ask for netbits and analog channel ; $0: ld hl,nettmrs+40 ; Start of DIO+ timers ld e,a ; Get offset ld d,0 add hl,de ld a,(hl) ; Check if we should delay query or a jp nz,$98 ; Yes, skip query this time ; ld de,t13tbuf ld hl,DIOPq ld bc,18 ldir ; Copy message to buffer ld a,(nextdiop) add a,'0' ; Make link number into ASCII ld (t13tbuf+8),a ; Put into message in buffer ld hl,t13tbuf+1 ; Point to packet call setcheck ; Fill in checksum ld a,0ffh ld (t13wait),a ; Flag wait for response ld (t13trdy),a ; Flag buffer as full ld hl,diopresp ; Point to response table ld a,(nextdiop) ; Get current link number ld e,a ld d,0 add hl,de ; Point to proper response entry $1: ld a,(t13rrdy) ; Wait for response or a jr nz,$2 ; Go process response ld a,(t13rto) ; Check for timeout or a jr nz,$11 ; If so, flag it and exit push hl rt_wait 1 ; Give up control for one tick pop hl jr $1 ; Check again $11: ld (hl),0 ; Flag timeout jp $98 ; $2: push hl ld hl,t13rbuf call vercheck ; Verify correct checksum pop hl jr z,$3 ; If OK, continue ld (hl),2 ; Flag error jr $99 $3: ld (hl),1 ; Flag response ; ld a,(t13rbuf+6) ; Make sure this is for us cp 'P' jr nz,$98 ; Nope, ignore response ; ld hl,t13rbuf+12 ; Point to input status call tobin ; Convert to binary ld c,a ; ld a,(nextdiop) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 8 rlca rlca ld hl,netbit1+256 ; Point to storage ld iy,nedge1+256 ld e,a ld d,0 add hl,de ; Offset to start of link add iy,de ; ld b,4 ; Do 4 bits $4: ld a,0 ; Assume 0 srl c ; 8-bit shift right into carry jr nc,$5 ; It is 0, so save it ld a,1 ; It's a 1 $5: ld d,(hl) ; Get old value ld (hl),a ; Save new value cp d ; Change? jr z,$6 ; No, skip edge ld (iy),0ffh ; Flag edge $6: inc hl inc iy djnz $4 ; Next bit ; ; Now process the analog response ; ld hl,t13rbuf+18 ; Point to first channel status call tobin ; Convert to binary ld b,a ; High byte inc hl ; Point to low byte inc hl call tobin ld c,a ; Low byte ; ld a,(nextdiop) ; Get current link number and 07h ; Ensure 0-7 rlca ; Multiply by 8 rlca rlca ld hl,adcvals+224 ; Point to start of storage ld e,a ld d,0 sla e ; Multiply DE by 2 rl d add hl,de ; Offset to start of link inc hl ; Point to high byte bit 7,(hl) ; Forced value? jr nz,$98 ; Yes, skip save dec hl ld (hl),c ; Save conversion value low byte inc hl ld (hl),b ; Save high byte ; $98: ld hl,nextdiop inc (hl) ; Do next link on next pass $99: ld a,0 ld (t13rrdy),a ld (t13rto),a rt_exit ; DIOPq db cr,'#00 ADP0 QDI,AI',cr,0 ; page ; ;========================================================================= ; ; General-Purpose Support Routines ; ; ; Initialize on-board hardware. ; inithard: call initppis ; Set up 8255s call initpias ; Set up CS 6821s call initx10 ; Send X-10 setup strings call initclock ; Set up 6242 (CS) call initdtmf ; Set up DTMF and voice boards call initadc ; Start ADC timer ; ld hl,minit ; Default modem init string ld de,mdminit ; Storage for it $0: ld a,(hl) ld (de),a inc hl inc de or a jr nz,$0 ; ret ; ; ; Figure out SC type. We can tell the difference between RTC/BCC and ; CS, but not between RTC and BCC. Assuming BCC is safer because ; ADC clock is turned off. This is really only so we know which clock ; is being used so the time can be displayed before an XPRESS program ; has been loaded. ; Since this routine corrupts the control register for the 8255/6821, ; it *must* be followed immediately by calls to initppis and initpias. ; getsc: push bc ld bc,port1+2 in a,(c) ; If 6821, this clears high bit of ctrl reg ld bc,port1+3 ld a,92h ; Sets 8255 for in/in/out and is out (c),a ; harmless to a 6821 in a,(c) ; If 6821, we'll read back 12h cp 12h ; (high bit is read only and cleared above) jr nz,$1 ; Assume BCC ld a,sccs ; Must be CS jr $2 $1: ld a,scbcc $2: ld (sc),a ; Save what we found pop bc ret ; ; ; Fill in checksum for network message. Enter with HL pointing ; to start of packet (should point to "#" character). Fills in ; checksum in buffer and packet is ready to send. ; setcheck: push bc push hl ld c,0 ; Clear sum $1: ld a,(hl) inc hl cp cr ; End of packet? jr z,$9 ; Yes, done cp lf ; End of packet? jr z,$9 ; Yes, done add a,c ; Add to sum ld c,a ; Save it jr $1 $9: ld a,c cpl ; Take 2's complement inc a ld c,a pop hl ; Restore packet start inc hl ; Point to checksum slot rra ; Move upper nybble to lower rra rra rra and 0fh call htoa ; Convert to ASCII ld (hl),a ; Save upper nybble inc hl ld a,c ; Do lower nybble and 0fh call htoa ld (hl),a ; Save lower nybble pop bc ret ; ; ; Verify checksum in received network message. Enter with HL pointing ; to start of packet (should point to "$" character). Returns with ; A=0, Z=1 if OK, otherwise A<>0, Z=0. ; vercheck: push bc inc hl ld a,(hl) ; Get high nybble of checksum call atoh ; Convert from ASCII rla rla rla rla and 0f0h ld b,a inc hl ld a,(hl) ; Get lower nybble call atoh or b ; Combine ld b,a ; Save ld (hl),'0' ; Replace checksum with "00" dec hl ld (hl),'0' dec hl ld c,0 ; Clear sum $1: ld a,(hl) inc hl or a ; End of packet? jr z,$9 ; Yes, done add a,c ; Add to sum ld c,a ; Save it jr $1 $9: ld a,c add a,b ; Add sum sent by node pop bc ret ; ; ; Initialize Z180 chip ; initchip: push bc push de push hl ld hl,inttbl ; Point to the interrupt vector table out0 (il),l ld a,h ld i,a ld b,9 ; Fill table with error vector ld de,interr ic1: ld (hl),e inc hl ld (hl),d inc hl djnz ic1 ld a,0 ld hl,sertbl ; Point to serial init table ld bc,0600h ; Start at port 0 and do 6 ports otimr ; Init on-board serial in0 a,(rdr0) ; Clear receiver in0 a,(rdr1) ; Clear receiver ld a,cr out0 (tdr0),a out0 (tdr1),a ; New Z8S180 CPU Control Registers ld a,3Fh ; 1x Clock multiply, Regular crystal out0 (clkmult),a ld a,80h ; Full drive with div 1 CPU clock out0 (ccr),a ld a,60h ; Disable the CTS0 and DCD0 functionality in the Z8S180 out0 (asext0),a ld a,08h ; Ensure TOUT pin is activated in the Z8S180 for ADC out0 (iar1b),a ; MSB 3.63s/Z8S180 0 memory wait states and 4 I/O wait states @ 18MHz ld a,30h ; Should be 60h for Z80180 (1 memory, 3 I/O wait states) out0 (dcntl),a ld a,0 out0 (itc),a ; Disable INT0, INT1, and INT2 out0 (rcr),a ; Disable RAM refresh out0 (tcr),a in0 a,(stat1) res 2,a ; Select RXS out0 (stat1),a ld a,01h out0 (cntr),a ; Select 230-kbps data rate pop hl pop de pop bc ret ; sertbl: db 74h ; Enable Tx & Rx, 8 data, 1 stop, no parity db 74h ; Enable Tx & Rx, 8 data, 1 stop, no parity ; Z8S180 Change - MSB 991225 Need to update baud rate for new clock rate db 22h ; 9600 bps (with clock at 18.432MHz & divide by 1) db 22h ; 9600 bps ; db 21h ; 9600 bps (with clock at 18.432MHz & divide by 2) ; db 21h ; 9600 bps db 00h ; No interrupts db 00h ; No interrupts ; ; ; Clear event table storage, hardware configuration byte, ; and number of link storage. ; clrtbl: push af push bc push hl ld a,03h ; Checksum for cleared memory ld (power),a ld a,endtbl ld (events),a ; Clear event table ld (events+1),a ld (events+2),a ; ld hl,hardware ; Clear rest of storage ld b,hardend-hardware $1: ld (hl),0 inc hl djnz $1 pop hl pop bc pop af ret ; ; ; Sum the event table to check for integrity after ; power failure. Return sum in A. When added to ; correct checksum, the result should be 0. ; sumevents: push bc push hl ld hl,events ; Point to table ld b,0 ; Clear sum ld e,0 ; Clear number of endpgm bytes encountered $1: ld a,(hl) ; Get next byte add a,b ; Add to checksum ld b,a ld a,(hl) ; Get it again cp endpgm ; End of program byte? jr nz,$2 ; Nope, continue inc e ; Count number encountered ld a,e cp 3 jr nc,$4 ; If encounter three or more in a row, done jr $3 $2: ld e,0 ; Zero endpgms encountered $3: inc hl ld a,h ; Check for wrap around or l jr nz,$1 ; If not, continue; otherwise, abort $4: ld a,b ; Get sum pop hl pop bc ret ; ; ; Clear all "done" flags in event table to zero. Done to ; ensure table integrity after power failure. ; initevtbl: push hl push ix ld a,(events) ; Check for empty table cp endtbl jr z,$9 ; If so, just return ; ld ix,(doneptr) $1: ld hl,events ; Point to table ld e,(ix) ; Get offset into program ld d,(ix+1) ld a,d ; Check for end of program (high byte > 7F) rla ; Put high bit into carry jr c,$9 ; If set, assume done add hl,de ld (hl),0 ; Zero done flag inc ix inc ix jr $1 $9: pop ix pop hl ret ; ; ; Initialize all interrupts besides RTOS stuff ; initints: push de push hl ; ld hl,ninbuf ; Network input buffer ld (ninbuft),hl ld (ninbufb),hl ld hl,asci0 ld (inttbl+0eh),hl in0 a,(stat0) set 3,a ; Enable receive interrupt out0 (stat0),a ; ld hl,hinbuf ; Host input buffer ld (hinbuft),hl ld (hinbufb),hl ld hl,asci1 ld (inttbl+10h),hl in0 a,(stat1) set 3,a ; Enable receive interrupt out0 (stat1),a ; ld a,0 ; Clear ring counter ld (ringctr),a ld hl,ringint ; Ring detect ISR ld (inttbl),hl ; Set up INT1 in0 a,(itc) set 1,a ; Enable INT1 out0 (itc),a ; pop hl pop de ret ; ; ; Clear input edge storage tables ; clredge: push bc push hl push ix ld hl,edge1 ld ix,nedge1 ld b,0 ld a,0 $1: ld (hl),a ld (ix),a inc hl inc ix djnz $1 pop ix pop hl pop bc ret ; ; ; Initialize local storage to all zeros ; initstor: push bc push hl ld hl,storage ld bc,storend-storage $1: ld a,0 ld (hl),a inc hl dec bc ld a,b or c jr nz,$1 ; ld a,0ffh ld (acpwr),a ; Default power to on state ; ld hl,kbuf0 ; Initialize the keypad buffers ld (khead0),hl ld (ktail0),hl ld hl,kbuf1 ld (khead1),hl ld (ktail1),hl ld hl,kbuf2 ld (khead2),hl ld (ktail2),hl ld hl,kbuf3 ld (khead3),hl ld (ktail3),hl ld hl,kbuf4 ld (khead4),hl ld (ktail4),hl ld hl,kbuf5 ld (khead5),hl ld (ktail5),hl ld hl,kbuf6 ld (khead6),hl ld (ktail6),hl ld hl,kbuf7 ld (khead7),hl ld (ktail7),hl ; pop hl pop bc ret ; ; ; Initialize module storage to all zeros ; initx10m: push bc push hl ld hl,modules ld b,0 ld a,0 $1: ld (hl),a inc hl djnz $1 pop hl pop bc ret ; ; ; Initialize 8255s ; initppis: push bc push de push hl push ix ld hl,inittbl ; Initialization table ld a,(sc) cp sccs ; CS? jr nz,$1 ; Nope, RTC/BCC ld hl,inittbl+3 ; Yes, so skip RTC180's 8255 $1: ld c,(hl) ; Get port address inc hl ld b,(hl) inc hl ld a,b ; If zero, done or c jr z,$2 ld a,(hl) ; Get init value inc hl out (c),a ; Init port jr $1 ; Do next port ; ; Now set all outputs to what we have in storage ; $2: ld hl,outtbl ; Point to table of output ports ld ix,outport ; Local output storage ld e,23 ; Do 23 8-bit ports $3: ld a,(ix) ; Get 8-bit port value inc ix ld c,(hl) ; Get low byte of port address inc hl ld b,(hl) ; Get high byte inc hl out (c),a ; Set port dec e jr nz,$3 ; Do next port ; pop ix pop hl pop de pop bc ret ; inittbl:dw port1+3 db 92h dw port2+3 db 9bh dw port3+3 db 80h dw port4+3 db 9bh dw port5+3 db 80h dw port6i+3 db 9bh dw port7i+3 db 9bh dw port8i+3 db 9bh dw port9i+3 db 9bh dw port6o+3 db 80h dw port7o+3 db 80h dw port8o+3 db 80h dw port9o+3 db 80h dw port10+3 db 9bh dw port11+3 db 80h dw 0 db 0 ; ; ; Initialize the CS 6821s ; initpias: push bc push hl ld a,(sc) cp sccs ; CS? jr nz,$2 ; Nope, no PIAs present ld hl,piatbl ; Initialization table $1: ld c,(hl) ; Get port address inc hl ld b,(hl) inc hl ld a,b ; If zero, done or c jr z,$2 ld a,30h ; Initial ctrl reg value with DDR selected out (c),a dec bc ; Point to DDR ld a,(hl) ; Get I/O config inc hl out (c),a inc bc ; Point to CRx in a,(c) set 2,a ; Select data port out (c),a jr $1 ; ld bc,pia3+1 in a,(c) set 3,a ; Enable RS-422 console driver out (c),a ld bc,pia3+3 in a,(c) res 3,a ; LED6 off out (c),a ld bc,pia4+1 in a,(c) res 3,a ; LED7 off out (c),a ld bc,pia4+3 in a,(c) res 3,a ; LED8 off out (c),a jr $9 $2: cp scbcc+1 ; BCC or RTC? jr nc,$9 ; Nope, exit ld bc,pia5+1 ld a,01111111b out (c),a ld bc,pia5+3 ld a,00001111b out (c),a $9: pop hl pop bc ret ; piatbl: dw pia1+1 db 01111111b dw pia1+3 db 00001111b dw pia2+1 db 00000000b dw pia2+3 db 00000000b dw pia3+1 db 00000000b dw pia3+3 db 11111111b dw pia4+1 db 11111111b dw pia4+3 db 11111111b dw 0 db 0 ; ; ; Initialize CS 6242 real-time clock ; initclock: ld a,(sc) cp sccs ; CS? jr nz,$9 ; Nope, this isn't needed push bc ld a,04h ; No hold ld bc,clock+0dh out (c),a inc bc ld a,01h ; No interrupt out (c),a inc bc ld a,0 ; No reset, no test out (c),a pop bc $9: ret ; ; ; Start timer 1 for ADC ; initadc: push af push bc ld a,(sc) ; What kind of SC? or a jr z,$1 ; Not defined, so make sure clock is off cp scbcc ; Is it BCC180? jr z,$1 ; Yes, so make sure clock is off in0 a,(tcr) ; Must be RTC180 or CS, so set up clock and 0d1h ; Disable timer 1 out0 (tcr),a ; MSB - 991226 v3.63s Z8S180 change ; We may be able to stick with the fast clock, but lets double the ; prescale since we doubled the clock speed ; ld a,01h ; Set up fastest clock ld a,02h ; Set up fastest clock out0 (tmdr1l),a out0 (rldr1l),a ld a,00h out0 (tmdr1h),a out0 (rldr1h),a in0 a,(tcr) or 06h ; Start timer 1 with clock output out0 (tcr),a ld bc,rtcadc in a,(c) ; Dummy reads in a,(c) out (c),a ; Start a conversion jr $9 $1: in0 a,(tcr) and 0d1h ; Disable timer 1 out0 (tcr),a $9: pop bc pop af ret ; ; ; Initialize the DTMF and voice boards ; initdtmf: push af push bc inb a,vreset ; Reset voice board ld a,(sc) or a ; 0? jr z,$99 ; Yes, undefined cp sccs ; CS? jr nz,$1 ; No, RTC/BCC ; ld bc,phone ; Point to CS M8888 data reg ld (data88),bc ; Save it inc bc ; Point to CS M8888 ctrl reg ld (ctrl88),bc ; Save it ; ld bc,pia2+1 in a,(c) res 3,a ; Set voice mode out (c),a ld bc,pia2+3 in a,(c) res 3,a ; Put phone on hook out (c),a jr $9 ; $1: ld bc,dtmfxcv ; Point to RTC M8888 data reg ld (data88),bc ; Save it inc bc ; Point to RTC M8888 ctrl reg ld (ctrl88),bc ; Save it ; Ring latch may power up undefined which leads to detect problems ; Here we can read from the register to ensure it is cleared ; MSB 991225 - v3.63 inb a,dtmfsts ; Read status to clear ring interrupt ; ld a,80h ; DAA voice mode, on hook, status LEDs ld (dtmfo),a ; Save it outb dtmfctl,a ; $9: ld bc,(ctrl88) ld a,00h ; Send out some zeros to clear the registers out (c),a out (c),a ld a,08h ; Select register B out (c),a ld a,00h ; Burst, no test, dual tones (register B) out (c),a ld a,01h ; Enable tones, DTMF, no IRQ (register A) out (c),a ; $99: ld a,0ffh ; Max out ring detect timer ld (ringtmr),a pop bc pop af ret ; ; ; Set all timer states to off and clear values ; inittmrs: push bc push hl ld hl,timers ld a,0 ld b,tmrstor $1: ld (hl),a inc hl djnz $1 pop hl pop bc ret ; ; ; Initialize variable storage to all zeros ; initvars: push bc push hl ld hl,vars ld a,0 ld b,0 $1: ld (hl),a inc hl djnz $1 pop hl pop bc ret ; ;==================================================================== ; initx10: push bc push de push hl ld a,(numpl) ; Is there a PL-Link? or a jr nz,$1 ; Yes, use it ;*** ld a,(sc) ;*** cp sccs ; CS? ;*** jr nz,$1 ; Nope, assume PL-Link present ; ld hl,plixout ; Set up PLIX output buffer ld (plixoh),hl ; Head pointer ld (plixot),hl ; Tail pointer ld hl,plixin ; PLIX input buffer ld (plixih),hl ; Head pointer ld (plixit),hl ; Tail pointer call plixwr ; Put PIA in write mode call syncplix ; Flush the PLIX internal buffers ; $1: ld hl,x10istr ; Turn off refresh ld de,t0tbuf ld bc,12 ldir ld a,0 ld (t0wait),a ; Don't wait for response ld a,0ffh ; Buffer ready to send ld (t0trdy),a pop hl pop de pop bc ret ; x10istr db cr,'! X10 R00',cr,0 ; page ; ;========================================================================= ; ; Interrupt Service Routines ; ; ; Receive a character on serial port 0 (network) ; asci0: push af push hl ; MSB 991217 - v3.63s Z8S180 changes ; Lets make sure we get all the characters in the FIFO (Z8S180) ; We can simply loop until RDRF is 0 $1: in0 a,(stat0) ; Did char generate int? bit 7,a jr z,$2 ; No, probably error (or no more FIFO data) in0 a,(rdr0) ; Yes, get and save it ld hl,(ninbuft) ld (hl),a inc l ld (ninbuft),hl jr $1 ; MSB v3.63 $2: in0 a,(cntla0) res 3,a ; Clear error flags out0 (cntla0),a pop hl pop af ei ret ; ; ; Receive a character on serial port 1 (host) ; asci1: push af push hl ; MSB 991217 - v3.63s Z8S180 changes ; Lets make sure we get all the characters in the FIFO (Z8S180) ; We can simply loop until RDRF is 0 $1: in0 a,(stat1) ; Did char generate int? bit 7,a jr z,$2 ; No, probably error (or no more FIFO data) in0 a,(rdr1) ; Yes, get and save it ld hl,(hinbuft) ld (hl),a inc l ld (hinbuft),hl jr $1 $2: in0 a,(cntla1) res 3,a ; Clear error flags out0 (cntla1),a pop hl pop af ei ret ; ; ; INT1: Ring detect on RTC-DTMF board ; ; For each ring, clear the ring timer. After 3 seconds, Task 4 ; increments the ring counter, clears the interrupt, and ; reenables INT1. After 6 seconds, Task 4 clears the ring ; counter. ; ringint: push af ld a,0 ld (ringtmr),a ; Clear ring timer in0 a,(itc) res 1,a ; Disable INT1 out0 (itc),a pop af ei ret ; ; ; Interrupt error ; interr: push af push bc push de push hl call print db cr,lf,'HCS: Interrupt Error!',cr,lf,0 pop hl pop de pop bc pop af ei ret ; ; ; String storage ; dow: db 'Sun Mon Tue Wed Thu Fri Sat ' mon: db 'Jan Feb Mar Apr May Jun ' db 'Jul Aug Sep Oct Nov Dec ' ; ;========================================================================= ; ; RAM Storage ; DATA ; time ds 8 ; 0:1/10sec, 1:sec, 2:min, 3:hour (8 bytes) ; 4:dow, 5:day, 6:mon, 7:yr ntbuf ds 10 ; Buffer for setting new time ds 12 ; Space between time stuff and RTOS stuff ; ; NVRAM section offset 08180h ; storage equ $ ; cidbuf ds 128 ; Caller ID packet buffer ; 8180h + 128 puts us on 256-byte boundary ninbuf ds 256 ; Must be 256 on 256-byte boundary! hinbuf ds 256 ; Must be 256 on 256-byte boundary! plixout ds 256 ; PLIX output buffer (must be 256 on boundary!) plixin ds 256 ; PLIX input buffer (must be 256 on boundary!) cmsgbuf ds 256 ; Message destined for console ; modules ds 256 ; Primary module state storage input1 ds 256 ; Primary input state storage input2 ds 256 ; Secondary input3 ds 256 edge1 ds 256 ; Primary input edge storage edge2 ds 256 ; Secondary edge3 ds 256 netbit1 ds 512 ; Primary netbit I/O storage netbit2 ds 512 ; Secondary netbit3 ds 512 nedge1 ds 512 ; Primary netbit edge storage nedge2 ds 512 ; Secondary nedge3 ds 512 output ds 256 ; Output state storage adcvals ds 272 ; ADC input values dacvals ds 32 ; DAC output values irvals ds 256 ; IR code storage vbuf ds 256 ; Voice string output buffer outport ds 32 ; Output ports packed into 8-bit bytes t5vbuf ds 96 ; Buffer for task 5 voice support freqs ds 16 ; Frequency read on Answer MAN totals ds 16 ; Totalizer on Answer MAN mancfg ds 16 ; Configuration words for all Answer MANs cndbuf ds 32 ; CID Name Buffer cndnum ds 13 ; CID Number Buffer ; t0tbuf ds tbufsiz ; Task 0 transmit buffer t1tbuf ds tbufsiz ; X-10 transmit buffer t2tbuf ds tbufsiz t3tbuf ds tbufsiz t4tbuf ds tbufsiz t5tbuf ds tbufsiz t6tbuf ds tbufsiz t7tbuf ds tbufsiz t8tbuf ds tbufsiz t9tbuf ds tbufsiz t10tbuf ds tbufsiz t11tbuf ds tbufsiz t12tbuf ds tbufsiz t13tbuf ds tbufsiz ; t0rbuf ds rbufsiz t1rbuf ds rbufsiz t2rbuf ds rbufsiz t3rbuf ds rbufsiz t4rbuf ds rbufsiz t5rbuf ds rbufsiz t6rbuf ds rbufsiz t7rbuf ds rbufsiz t8rbuf ds rbufsiz t9rbuf ds rbufsiz t10rbuf ds rbufsiz t11rbuf ds rbufsiz t12rbuf ds rbufsiz t13rbuf ds rbufsiz ; khead0 ds 2 ; Keypad buffer head and tail storage ktail0 ds 2 khead1 ds 2 ktail1 ds 2 khead2 ds 2 ktail2 ds 2 khead3 ds 2 ktail3 ds 2 khead4 ds 2 ktail4 ds 2 khead5 ds 2 ktail5 ds 2 khead6 ds 2 ktail6 ds 2 khead7 ds 2 ktail7 ds 2 ; kbuf0 ds 8 ; Keypad buffers kbuf1 ds 8 kbuf2 ds 8 kbuf3 ds 8 kbuf4 ds 8 kbuf5 ds 8 kbuf6 ds 8 kbuf7 ds 8 ; ninbuft ds 2 ; Network buffer top pointer ninbufb ds 2 ; Network buffer bottom pointer hinbuft ds 2 ; Host buffer top pointer hinbufb ds 2 ; Host buffer bottom pointer ; plixoh ds 2 ; PLIX output head pointer plixot ds 2 ; PLIX output tail pointer plixih ds 2 ; PLIX input head pointer plixit ds 2 ; PLIX input tail pointer ; tbuf ds 2 ; Pointer to base of current xmit buf rbuf ds 2 ; Pointer to base of current recv buf rptr ds 2 ; Pointer to current receive buffer rcntr ds 1 ; Count of number of received characters ; totmr ds 1 ; Timeout timer (incr by input task) dtmfto ds 1 ; Timeout timer for DTMF keyto ds 1 ; Timeout timer for keypad ktime ds 8 ; Keypad timeout constants cpto ds 1 ; Timeout timer for CP ringtmr ds 1 ; DTMF ring detect timer saytmr ds 1 ; Speech wait timer plsent ds 1 ; Flag to indicate recent PL-Link xmit uptbl ds 1 ; Flag to indicate PL-Link table update ; rstflg ds 1 ; Reset flag adtogl ds 1 ; Flag to indicate ana or dig on next poll t1logf ds 1 ; Flag to indicate task 1 is logging something t5logf ds 1 ; Flag to indicate task 5 is logging something t1x10f ds 1 ; Flag to indicate task 1 is sending X-10 t5x10f ds 1 ; Flag to indicate task 5 is sending X-10 t1sayf ds 1 ; Flag to indicate task 1 is speaking t5sayf ds 1 ; Flag to indicate task 5 is speaking t1netbf ds 1 ; Flag to indicate task 1 is sending netbit t5netbf ds 1 ; Flag to indicate task 5 is sending netbit ; channel ds 1 ; Current working channel of local ADC op1 ds 2 ; Storage for operand 1 in evarg and domath op2 ds 2 ; Storage for operand 2 in evarg and domath op3 ds 2 ; Storage for final assignment value in action neg ds 1 ; Negative flag for decimal print routines forcef ds 1 ; Flag to force a false result trueop ds 1 ; Flag to indicate last operand was TRUE sign1 ds 1 ; Math routines storage sign2 ds 1 ovfl ds 1 acc ds 2 t5acc ds 2 ; Accumulator for multiply routine in task 5 t2flag ds 1 ; Flag to indicate task 2 is running dtmfo ds 1 ; DTMF board output port storage ringctr ds 1 ; DTMF ring detect counter digit1 ds 1 ; Dial digit storage (must be 4 digit2 ds 1 ; consecutive locations!) digit3 ds 1 digit4 ds 1 cpchk ds 1 ; Call progress check flag cpnoise ds 1 ; Call progress noise counter cpontmr ds 1 ; Call progress tone on timer cpofftmr ds 1 ; Call progress tone off timer ctrl88 ds 2 ; Storage for address of M8888 control reg data88 ds 2 ; Storage for address of M8888 data reg t5store ds 1 ; Temporary storage nbstor ds 2 ; Storage for netbit routines nbval ds 1 acchk ds 1 ; Flag to poll PL-Link for AC status mancfgf ds 8 ; Flags to poll all Answer MANs for configuration ptotal ds 2 ; PWM total period storage phigh ds 2 ; PWM high period storage cbutton ds 64 ; Current iButton storage ; mdminit ds 80 ; Modem init string mrings ds 1 ; Number of rings until modem answer cidon ds 1 ; Flag to indicate whether CID is enabled newcid ds 1 ; Flag to indicate new CID data ciddata ds 14 ; Caller ID data storage acpwr ds 1 ; Flag to indicate current AC status acfail ds 1 ; Flag to indicate whether power has failed ; weekday ds 1 weekend ds 1 ; lnkresp equ $ plresp ds 8 ; Response history of network mods irresp ds 8 lcdresp ds 8 dioresp ds 8 manresp ds 8 diopresp ds 8 ; nextpl ds 1 ; Next module to be polled nextir ds 1 nextlcd ds 1 nextdio ds 1 nextman ds 1 nextdiop ds 1 ; nettmrs ds modtyp*modnum ; Timers for status queries ; pausef ds 1 ; Flag to indicate display is paused dtimef ds 1 ; Display time flag dinpf ds 1 ; Display inputs flag doutf ds 1 ; Display outputs flag dbitf ds 1 ; Display netbits flag dadcf ds 1 ; Display ADC channels flag ddacf ds 1 ; Display DAC channels flag dx10f ds 1 ; Display modules flag dnetf ds 1 ; Display network flag modemf ds 1 ; Modem present flag initmdm ds 1 ; Flag to indicate modem needs initializing icidf ds 1 ; Flag to include CID init string msgflg ds 1 ; Flag to indicate message ready for display ; dtimem ds 1 ; Time display mode dnetm ds 1 ; Network display mode ; ; Flags for each task that indicate transmit buffer full, whether a ; response is expected, receive buffer full, and when a timeout ; has occurred waiting for a response. ; t0trdy ds 1 ; Task 0 transmit buffer full flag t0wait ds 1 ; Task 0 wait for response flag t0rrdy ds 1 ; Task 0 receive buffer full flag t0rto ds 1 ; Task 0 receiver timeout flag ; t1trdy ds 1 t1wait ds 1 t1rrdy ds 1 t1rto ds 1 ; t2trdy ds 1 t2wait ds 1 t2rrdy ds 1 t2rto ds 1 ; t3trdy ds 1 t3wait ds 1 t3rrdy ds 1 t3rto ds 1 ; t4trdy ds 1 t4wait ds 1 t4rrdy ds 1 t4rto ds 1 ; t5trdy ds 1 t5wait ds 1 t5rrdy ds 1 t5rto ds 1 ; t6trdy ds 1 t6wait ds 1 t6rrdy ds 1 t6rto ds 1 ; t7trdy ds 1 t7wait ds 1 t7rrdy ds 1 t7rto ds 1 ; t8trdy ds 1 t8wait ds 1 t8rrdy ds 1 t8rto ds 1 ; t9trdy ds 1 t9wait ds 1 t9rrdy ds 1 t9rto ds 1 ; t10trdy ds 1 t10wait ds 1 t10rrdy ds 1 t10rto ds 1 ; t11trdy ds 1 t11wait ds 1 t11rrdy ds 1 t11rto ds 1 ; t12trdy ds 1 t12wait ds 1 t12rrdy ds 1 t12rto ds 1 ; t13trdy ds 1 t13wait ds 1 t13rrdy ds 1 t13rto ds 1 ; storend equ $ ; End of storage that is cleared on reset ; timers ds (stmrs+mtmrs)*2 ; General-purpose timers vars ds 256 ; 128 16-bit variables logptrh ds 2 ; Log pointer head logptrt ds 2 ; Log pointer tail doneptr ds 2 ; Pointer to done flag pointer table ; hardware equ $ ; Start of hardware configuration storage compver ds 1 ; Compiler major version compsver ds 1 ; Compiler minor version sc ds 1 ; 1=RTC180, 2=BCC180, 3=CS adcres ds 1 ; 8,10,12 adcgain ds 16 ; 0,1,2,3 = 1,2,4,8 adcchan ds 1 ; 8,16 digin ds 4 ; Bitmapped digout ds 4 ; Bitmapped anain ds 3 ; Bitmapped anaout ds 1 ; Bitmapped netbits ds 5 ; Bitmapped netmod ds 1 ; Bitmapped ; numlnks equ $ numpl ds 1 ; Number of PL-Link modules in system numir ds 1 numlcd ds 1 numdio ds 1 numman ds 1 numdiop ds 1 mdisp ds 2 ; Which X-10 modules to display hardend equ $ ; verstor ds 1 ; Current firmware version sverstor ds 1 ; Current firmware subversion power ds 1 ; Power-up integrity (table checksum) ; swram ds 1 ; Location at which to access SmartWatch ; ds 32-(($-storage).and.31) ; ; Interrupt Vector Table ; inttbl: ds 2 ; INT1 ds 2 ; INT2 ds 2 ; PRT0 ds 2 ; PRT1 ds 2 ; DMAC0 ds 2 ; DMAC1 ds 2 ; CSI/O ds 2 ; ASCI0 ds 2 ; ASCI1 ; ds stksiz t0sp ds stksiz t1sp ds stksiz t2sp ds stksiz t3sp ds stksiz t4sp ds stksiz t5sp ds stksiz t6sp ds stksiz t7sp ds stksiz t8sp ds stksiz t9sp ds stksiz t10sp ds stksiz t11sp ds stksiz t12sp ds stksiz t13sp ds stksiz ; events equ $ ; logstrt equ 08000h ; end