; Copyright (C) 2001 Circuit Cellar Incorporated ; 4 Park St. ; Vernon, CT 06066 ; ; steve@circuitcellar.com; ; ; This program is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version 2 ; of the License, or (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ; ; cpu z380 extmode off page 0 relaxed on ; ; Program: HCSII ; Author: Ken Davidson ; Date: March 9, 1998 ; Version: 3.60 ; ; Copyright (c) 1992-1998 ; Ken Davidson ; All Rights Reserved ; ; 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 3 subver equ 60 ; ifndef true false equ 0 true equ 1 endif ; test equ false ; procspd equ 6 ; 2:3.072, 3:4.608, 4:6.144, ; ; 6:9.216, 8:12.288 MHz ; 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 numtsk equ 16 ; max number of tasks-1 allowed ; ROMEND EQU 0x7FFF ; 32K ROM ; **************************************************************************** ; V3.60 had tics at 0x1200 V 4.01 doubles them to 0x2400 ; **************************************************************************** ;tic equ 4608 ; timer divisor to get 100 tics/sec tic equ 0x1200 ; timer divisor to get 100 tics/sec ;cbar_data equ 84h ; RTOS CBAR value ; **************************************************************************** ; ; Task state definitions ; waiting equ 1 ; task is in a WAIT mode suspend equ 2 ; task has been interrupted so another can be serviced active equ 4 ; task currently has control of the CPU ready equ 8 ; task was started by a RUN & is ready to execute none equ 10h ; task not defined dormant equ 20h ; task is defined but has nothing to do ; tcb_size equ 16 ; size of each TCB entry ; ; Offsets into each TCB entry to get specific values ; t_state equ 0 ; task state t_cancel equ 1 ; cancel flag t_bank equ 2 ; task's MMU bank t_priority equ 3 ; task's priority t_rsi equ 4 ; task's reschedule interval t_rsc equ 6 ; task's reschedule count t_wait equ 8 ; task's wait count t_start equ 10 ; task's start address t_sp equ 12 ; task's stack pointer during timer int ;t_istate equ 14 ; task's state when suspended ; *[ ASCII ]****************************************************************** ZERO equ '0' ; ASCII Zero (0x30) OH equ 'O' ; ASCII o (Uppercase) ; inb macro reg,port ld bc,port in reg,(c) endm ; outb macro port,reg ld bc,port out (c),reg endm ; ; CODE ; **************************************************************************** title "Open Source HCS ROM code effort, using assembler AS" ; **************************************************************************** ; ; segment code ORG 0x0000 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 $$L0 ; Skip over ident string ; db "Circuit Cellar Home Control System II" db "--" db "Supervisory Controller" db "--" db "Version ", ver+0x30, ".", (subver/10)+0x30, (subver#10)+0x30 db "--" db "Copyright (c) 1992-1998, Circuit Cellar Inc." ; $$L0: 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,$$L1 ; Nope, clear storage ld a,(sverstor) ; Get stored subversion number cp subver ; Same as this one? jr nz,$$L1 ; 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,$$L2 ; Yes, don't initialize tables $$L1: 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 $$L2: 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,$$L9 ; Skip if not defined ld a,(numpl) ; PL-Link defined? or a jr nz,$$L9 ; Yes, skip rt_run 8,20 ; Assume PLIX, so run task more often ; $$L9: 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 $$L0: 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 $$L0 ; 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,$$L1 ; If so, skip done flag test ld a,c ; Check done flag or a jr z,$$L1 ; 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 $$L1: 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,$$L1 ; If so, skip done flag test ld a,c ; Check done flag or a jr nz,sk2 ; Skip if normal IF and already done $$L1: 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 $$L1: 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 $$L1 ; ; 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 $$L2: 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 $$L2 dec c jr nz,$$L2 ret ; savetbls: ld ix,input2 ; Secondary ld iy,input3 ; Storage ld hl,edge2 ; Secondary ld de,edge3 ; Storage ld b,0 $$L1: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $$L1 ; ; 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 $$L2: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $$L2 dec c jr nz,$$L2 ret ; resttbls: ld ix,input3 ; Storage ld iy,input2 ; Secondary ld hl,edge3 ; Storage ld de,edge2 ; Secondary ld b,0 $$L1: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $$L1 ; ; 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 $$L2: di ld a,(ix) ld (iy),a ld a,(hl) ld (de),a ei inc ix inc iy inc hl inc de djnz $$L2 dec c jr nz,$$L2 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 0x0A ; If >=80h and <0xA0, fixed action cp 0xA0 ; If >=80h and <0x0A, fixed action jp c,act2 cp 0ach ; If >=0xA0 and =16? jr nc,$$L8 ; Yes, do it cp 8 ; =8? jr z,$$L41 ; RTC-DTMF LED3 cp 9 ; =9? jr z,$$L42 ; RTC-DTMF LED4 ld bc,pia3+3 ; SS LED6 cp 10 ; =10? jr z,$$L5 ld bc,pia4+1 ; SS LED7 cp 11 ; =11? jr z,$$L5 ld bc,pia4+3 ; SS LED8 cp 12 ; =12? jr z,$$L5 jr $$L9 ; No match, not supported by hardware ; ; Do RTC-DTMF LEDs ; $$L41: ld a,(dtmfo) ; Get current settings bit 0,d ; On or off? set 5,a ; Turn LED3 on (bit on) jr nz,$$L41a res 5,a ; Turn LED3 off (bit off) $$L41a: ld (dtmfo),a outb dtmfctl,a jr $$L9 ; $$L42: ld a,(dtmfo) ; Get current settings bit 0,d ; On or off? set 4,a ; Turn LED4 on (bit on) jr nz,$$L42a res 4,a ; Turn LED4 off (bit off) $$L42a: ld (dtmfo),a outb dtmfctl,a jr $$L9 ; ; Do SpectraSense LEDs ; $$L5: ld a,(sc) ; Make sure we're a SpectraSense cp sccs jr nz,$$L99 ; Nope, skip in a,(c) bit 0,d ; On or off? res 3,a ; Turn LED on (bit off) jr nz,$$L6 set 3,a ; Turn LED off (bit on) $$L6: out (c),a jr $$L9 ; $$L8: out (c),e ; Send out to port $$L9: 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 ; $$L99: 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 (mytimer 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,$$L2 ; Nope, continue ld a,0 ld (t1netbf),a ; Clear our flag $$L1: ld a,(t5netbf) ; Check other task again or a jr nz,$$L1 ; Wait for it to finish jr nbcom ; Try again to grab netbit routines $$L2: 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: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; Yes, wait ; ld a,(nbstor+1) ; Get high byte of bit number or a ; 0? jp nz,$$L20 ; No, so must be DIO+ ld a,(nbstor) ; Get bit number cp 64 ; 0-63? jp c,$$L10 ; Yes, DIO cp 96 ; 64-95? jp c,$$L99 ; Yes, LCD so skip cp 224 ; 96-223? jr c,$$L01 ; 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,$$L02 ; No, skip edge ld (iy),0ffh ; Flag edge $$L02: ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum jp $$L90 ; ; Send message to AMAN ; $$L01: 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,$$L2 ; No, skip edge ld (iy),0ffh ; Flag edge $$L2: 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 $$Lloop: xor a ; Clear carry ld a,(hl) ; Get next bit or a ; Test bit and clear carry jr z,$$Lclr scf ; Set carry $$Lclr: rr c ; Rotate carry into C inc hl djnz $$Lloop 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 $$L90 ; ; Send message to DIO ; $$L10: 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,$$L12 ; No, skip edge ld (iy),0ffh ; Flag edge $$L12: ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum jr $$L90 ; ; Send message to DIO+ ; $$L20: 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,$$L22 ; No, skip edge ld (iy),0ffh ; Flag edge $$L22: ld hl,t1tbuf+1 ; Point to packet call setcheck ; Fill in checksum ; $$L90: ld a,0 ld (t1wait),a ; Don't wait for response ld a,0ffh ld (t1trdy),a ; Ready to send $$L99: 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: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; 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: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; 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: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; 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: $$L1: ld a,(msgflg) ; Buffer already full? or a jr nz,$$L1 ; 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: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; 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 $$L1: ld a,(ix) ; Copy message to buffer inc ix cp 80h ; Display time without seconds? jr nz,$$L10 ; No, keep going ld a,(mytime+3) ; Yes, get hours call pbcdm ; Print it to the buffer ld (hl),':' inc hl ld a,(mytime+2) ; Get minutes call pbcdm jr $$L1 ; Do next character $$L10: cp 81h ; Display time with seconds? jr nz,$$L11 ; No, keep going ld a,(mytime+3) ; Yes, get hours call pbcdm ; Print it to the buffer ld (hl),':' inc hl ld a,(mytime+2) ; Get minutes call pbcdm ld (hl),':' inc hl ld a,(mytime+1) ; Get seconds call pbcdm jr $$L1 ; Do next character $$L11: cp 82h ; Display day of week? jr nz,$$L12 ; No, keep going ld a,(mytime+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 $$L111: ld a,(iy) ld (hl),a inc iy inc hl djnz $$L111 jr $$L1 ; Do next character $$L12: cp 83h ; Display date? jr nz,$$L13 ; No, keep going ld a,(mytime+6) ; Yes, get month call pbcdm ; Print it to the buffer ld (hl),'/' inc hl ld a,(mytime+5) ; Yes, get day call pbcdm ; Print it to the buffer ld (hl),'/' inc hl ld a,(mytime+7) ; Get year call pbcdm jr $$L1 ; Do next character $$L13: cp 84h ; Display full date? jr nz,$$L14 ; No, keep going ld a,(mytime+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 $$L131: ld a,(iy) ld (hl),a inc iy inc hl djnz $$L131 ld a,(mytime+5) ; Get day call pbcdm ld (hl),',' inc hl ld (hl),' ' inc hl ld (hl),'1' inc hl ld (hl),'9' inc hl ld a,(mytime+7) ; Get year call pbcdm jp $$L1 ; Do next character $$L14: cp 90h ; Display variable? jr nz,$$L15 ; 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 $$L1 ; Do next character $$L15: cp 91h ; Display variable? jr nz,$$L16 ; 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 $$L1 ; Do next character $$L16: cp 92h ; Display variable? jr nz,$$L17 ; 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 $$L1 ; Do next character $$L17: ld (hl),a inc hl cp cr ; End of string? jp nz,$$L1 ; 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: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; Yes, wait ; ld de,t1tbuf ld hl,totclr ld bc,13 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",0 ; ; Wait 0.1-25.5 seconds ; wait: ld a,(ix+1) ld (dtmfto),a ; Set up delay time $$L0: push ix rt_run 2,2 ; Start secondary eval pop ix ld a,0ffh ; Flag task 2 as running ld (t2flag),a $$L1: ld a,(dtmfto) or a jr z,$$L2 ; Timed out, finish up ld a,(t2flag) ; Task 2 running? or a jr nz,$$L1 ; Yes, keep waiting jr $$L0 ; No, so start it again $$L2: ld a,(t2flag) ; Task 2 running? or a jr nz,$$L2 ; 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,$$L00 ; 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 $$L01 $$L00: 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 ; $$L01: ld a,20 ; Delay 2 seconds ld (dtmfto),a $$L0: push ix rt_run 2,2 ; Start secondary eval pop ix ld a,0ffh ; Flag task 2 as running ld (t2flag),a $$L1: ld a,(dtmfto) or a jr z,$$L2 ; Timed out, so finish up ld a,(t2flag) ; Task 2 running? or a jr nz,$$L1 ; Yes, keep waiting jr $$L0 ; No, so start it again $$L2: ld a,(t2flag) ; Task 2 running? or a jr nz,$$L2 ; 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,$$L00 ; Nope, RTC or BCC ; ld bc,pia2+1 in a,(c) res 3,a ; Put phone on hook out (c),a jr $$L01 $$L00: ld a,(dtmfo) ; Get current settings res 6,a ; Put on hook outb dtmfctl,a ld (dtmfo),a $$L01: 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 $$L1: ld a,(ix) ; Get next character or a ; 0? jr z,$$L99 ; Yes, done cp ',' ; Delay? jr z,$$L7 ; Yes, do it ld hl,dialtbl ; Point to lookup table ld b,16 ; 16 entries in table $$L2: cp (hl) ; Compare char with table entry jr z,$$L3 ; Match, so handle it inc hl ; Skip to next entry djnz $$L2 jr $$L9 $$L3: 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 $$L4: in a,(c) ; Get status bit 1,a ; Check TDRE jr z,$$L4 ; Keep waiting dec bc ; Point at data port again push bc ; Save it again jr $$L9 $$L7: ld hl,dtmfto ld (hl),20 ; Delay 2 seconds $$L8: ld a,(hl) or a jr nz,$$L8 $$L9: inc ix ; Point to next character (ignore this one) jr $$L1 ; Do next character $$L99: 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 $$L1: dec a jr z,$$L2 ; If zero, start putting out digits inc hl ; Otherwise, point to next digit jr $$L1 $$L2: ld a,(hl) ; Get next digit call ddig ; Dial the digit inc hl djnz $$L2 ; 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 $$L4: in a,(c) ; Get status bit 1,a ; Check TDRE jr z,$$L4 ; 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: $$L0: ld a,0ffh ld (t1sayf),a ; Set our flag ld a,(t5sayf) ; Check if other task speaking or a jr z,$$L2 ; Nope, continue ld a,0 ld (t1sayf),a ; Clear our flag $$L1: ld a,(t5sayf) ; Check other task again or a jr nz,$$L1 ; Wait for it to finish jr $$L0 ; Try again to grab speech routines $$L2: inc ix ; Point to voice string ld hl,vbuf ; Point to voice buffer call msgout ; Convert string to text ld hl,vbuf $$L3: ld a,(hl) ; Get next character cp '~' ; Substitute command char? jr nz,$$L4 ; No, continue ld a,01h $$L4: cp '|' ; Substitute speech interrupt? jr nz,$$L5 ; No, continue ld a,18h $$L5: call vout ; Send character to voice board inc hl or a ; End of string? jr nz,$$L3 ; 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: $$L0: ld a,0ffh ld (t1sayf),a ; Set our flag ld a,(t5sayf) ; Check if other task speaking or a jr z,$$L2 ; Nope, continue ld a,0 ld (t1sayf),a ; Clear our flag $$L1: ld a,(t5sayf) ; Check other task again or a jr nz,$$L1 ; Wait for it to finish jr $$L0 ; Try again to grab speech routines $$L2: inc ix ; Point to voice string ld hl,vbuf ; Point to voice buffer call msgout ; Convert string to text ld hl,vbuf $$L3: ld a,(hl) ; Get next character cp '~' ; Substitute command char? jr nz,$$L4 ; No, continue ld a,01h $$L4: cp '|' ; Substitute speech interrupt? jr nz,$$L5 ; No, continue ld a,18h $$L5: call vout ; Send character to voice board inc hl or a ; End of string? jr nz,$$L3 ; 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 $$L1: in e,(c) bit 4,e ; Test RDY bit jr nz,$$L2 ; Wait for RDY to go high dec hl ; Decrement timeout ld a,h or l jr nz,$$L1 jr $$L4 ; Timeout, so abort $$L2: ld bc,vdata out (c),d ; Send the character ; ld bc,vstat ld hl,10000 ; Timeout constant $$L3: in e,(c) bit 4,e ; Test RDY bit jr z,$$L4 ; Wait for RDY to go low dec hl ; Decrement timeout ld a,h or l jr nz,$$L3 $$L4: 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 $$L0: rt_run 2,2 ; Start secondary eval ld a,0ffh ; Flag task 2 as running ld (t2flag),a $$L1: in a,(c) bit 6,a ; Wait for speech to start jr nz,$$L2 ; It's started, so wait for Task 2 to finish ld a,(saytmr) ; Check timeout or a jr z,$$L5 ; The voice board has gone south, abort ld a,(t2flag) ; Task 2 running? or a jr nz,$$L1 ; Yes, keep waiting jr $$L0 ; No, so start it again $$L2: ld a,(t2flag) ; Task 2 running? or a jr nz,$$L2 ; Yes, keep waiting ; ; Now wait up to 25 seconds for speech to finish ; ld a,250 ; 25-second timeout ld (saytmr),a $$L3: rt_run 2,2 ; Start secondary eval ld a,0ffh ; Flag task 2 as running ld (t2flag),a $$L4: in a,(c) bit 6,a ; Wait for speech to end jr z,$$L5 ; It's done, so wait for Task 2 to finish ld a,(saytmr) ; Check timeout or a jr z,$$L5 ; The voice board has gone south, abort ld a,(t2flag) ; Task 2 running? or a jr nz,$$L4 ; Yes, keep waiting jr $$L3 ; No, so start it again $$L5: ld a,(t2flag) ; Task 2 running? or a jr nz,$$L5 ; 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 $$L1: ld a,(ix) ld (hl),a inc ix inc hl or a jr nz,$$L1 ; 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 0x0A ; Make into 0-4 sub 0xA0 ; 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 dw rcrings,cidenb,setnetb,pwmtot,pwmhi dw bitdir,keypto ; ; ; 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: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; 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 ; $$L9: jp act1 ; dacmsg db cr,"#00 MAN0 SD 0000 0000",cr,0 ; ; ; Tell MCIR-Link to send an IR command ; setmcir: $$L1: ld a,(t1trdy) ; Buffer already full? or a jr nz,$$L1 ; 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,$$L4 ; Yes, so value under 700h (1792) jr nz,$$L3 ; 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,0x0A ; Module off, set locally ld a,0xA0 ; 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,0xA0 ; Module off, set locally ;*** ld a,0x0A ; Module off, set locally $$L1: ld (hl),a inc hl djnz $$L1 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 $$L1: sub 10 jr c,$$L2 inc b jr $$L1 $$L2: 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,$$L1 ; If positive, skip ld a,0ffh ; Flag as negative $$L1: ld (neg),a ; Save sign bit 7,h ; Check sign again call nz,comphl ; Make number positive ; ld a,c cp 1 jr z,$$L11 or a jr nz,$$L2 ld (iy),'.' inc iy $$L11: ld b,0 $$L2: ld de,10000 ; Place 10000s call pd1 dec c ; ld a,c cp 1 jr z,$$L21 or a jr nz,$$L3 ld (iy),'.' inc iy $$L21: ld b,0 $$L3: ld de,1000 ; Place 1000s call pd1 dec c ; ld a,c cp 1 jr z,$$L31 or a jr nz,$$L4 ld (iy),'.' inc iy $$L31: ld b,0 $$L4: ld de,100 ; Place 100s call pd1 dec c ; ld a,c cp 1 jr z,$$L41 or a jr nz,$$L5 ld (iy),'.' inc iy $$L41: ld b,0 $$L5: ld de,10 ; Place 10s call pd1 dec c ; ld a,c or a jr nz,$$L6 ld (iy),'.' inc iy $$L6: 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 $$L2: 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,$$L3 ; Done if carry set (further borrow) inc c ; Inc count jr $$L2 $$L3: 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,$$L4 or b ; Done with leading zeros? jr z,$$L4 ; Yes, leave them in cp 2 ; Remove zeros and space? jr z,$$L99 ; Yes, skip character ld a,' ' ; Replace zero with space jr $$L98 $$L4: ld b,0 ; No more leading zeros ld a,(neg) ; Check if negative number or a jr z,$$L5 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 $$L5: ld a,c ; Get final value add a,'0' ; Convert to ASCII $$L98: ld (iy),a ; Place in memory inc iy $$L99: 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,$$L1 call comphl ; Yes, complement and set sign flag ld a,0ffh $$L1: ld (sign1),a ; Save sign ex de,hl ; Swap contents bit 7,h ; Check if negative ld a,0 jr z,$$L2 call comphl ; Yes, complement and set sign flag ld a,0ffh $$L2: ld (sign2),a ; Save sign ex de,hl ; Swap again call unspm ; Do multiply on two positive operands jr c,$$L3 ; Overflow? bit 7,h ; Overflow? jr z,$$L4 ; No, continue $$L3: ld hl,7fffh ; Force max value on overflow $$L4: 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,$$L1 call comphl ; Yes, complement and set sign flag ld a,0ffh $$L1: ld (sign1),a ; Save sign ex de,hl ; Swap contents bit 7,h ; Check if negative ld a,0 jr z,$$L2 call comphl ; Yes, complement and set sign flag ld a,0ffh $$L2: ld (sign2),a ; Save sign ex de,hl ; Swap again call unspd ; Do divide on two positive operands jr c,$$L3 ; Overflow? bit 7,h ; Overflow? jr z,$$L4 ; No, continue $$L3: ld hl,7fffh ; Force max value on overflow $$L4: 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 $$L1: srl h ; Rotate multiplier right rr l jr nc,$$L3 ; 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,$$L2 ld a,0ffh ; Set overflow flag ld (ovfl),a $$L2: pop hl $$L3: sla e ; Rotate multiplicand left rl d djnz $$L1 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,$$L99 ; Result is zero if HE? jr c,$$L99 ; Result is zero if HL=0.4 s? jr nc,$$Lmid ; 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,$$Ltop ; No, continue to listen ld e,2 ; Yes, we probably hear voice, so flag connect jr $$L99 $$Lagain: 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,$$L99 ; Nothing heard, must be connected cp 4 ; >=0.4 s? jr nc,$$Lmid ; 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,$$Lagain ; No, continue to listen ld e,2 ; Yes, we probably hear voice, so flag connect jr $$L99 $$Lmid: 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,$$Lbusy ; Yes, check further for busy cp 23 ; Is tone <2.3 seconds? jr c,$$Lring ; Yes, assume a ring ld e,2 ; Sound heard >=2.3 seconds, so assume answer jr $$L99 $$Lbusy: 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,$$Lbsy1 ; Yes, continue ld a,(cpnoise) ; No, count it as noise inc a ld (cpnoise),a cp 2 ; Noise count >=2? jr c,$$Lagain ; No, continue to listen ld e,2 ; Yes, we probably hear voice, so flag connect jr $$L99 $$Lbsy1: cp 7 ; Is tone <0.7 seconds? jr c,$$L99 ; Yes, we have a busy jr $$Lagain ; No match, so start again $$Lring: ld e,0 ; Assume no answer dec d ; Decrement ring counter jr nz,$$Lagain ; Keep waiting (no answer if no jump) $$L99: 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 $$L00: push de rt_run 2,2 ; Start secondary eval pop de ld a,0ffh ; Flag task 2 as running ld (t2flag),a $$L01: ld a,(cpontmr) ; Get how long CP has been on or a ; Still 0? jr nz,$$L11 ; Nope, tone has started ld a,(cpto) ; Waited long enough? or a jr z,$$L90 ; Yes, return ld a,(t2flag) ; Task 2 running? or a jr nz,$$L01 ; Yes, keep waiting jr $$L00 ; No, so start it again $$L10: push de rt_run 2,2 ; Start secondary eval pop de ld a,0ffh ; Flag task 2 as running ld (t2flag),a $$L11: ld a,(cpontmr) ; Get how long CP has been on or a ; Gone to 0? jr z,$$L90 ; Yes, tone has finished ld e,a ; Save new value ld a,(cpto) ; Waited long enough? or a jr z,$$L90 ; Yes, return ld a,(t2flag) ; Task 2 running? or a jr nz,$$L11 ; Yes, keep waiting jr $$L10 ; No, so start it again $$L90: ld a,(t2flag) ; Task 2 running? or a jr nz,$$L90 ; 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 $$L1: ld a,(hl) ; Get bit value rr a ; Shift bit into carry rr c ; Shift into composite value inc hl djnz $$L1 ; 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,$$L1 ; If not, don't touch value of ACfailed ld a,0 ; Power is back, so clear ld (acfail),a ; ACfailed for next pass $$L1: 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,$$L1 ; Yes, store -1 ld (iy),a ; Save value ld (iy+1),0 jr $$L2 $$L1: ld (iy),0efh ; Timed out, return -1 ld (iy+1),0ffh $$L2: 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 $$L1: ld e,(ix) ; Get module number call gkdig ; Get a digit cp 0ffh ; Timed out? jr z,$$L2 ; Yes, store -1 cp 10 ; Digit <= 9? jr nc,$$L15 ; 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 $$L1 $$L15: ld (iy),l ; Save final value ld (iy+1),h jr $$L3 $$L2: ld (iy),0efh ; Store -1 for timeout ld (iy+1),0ffh $$L3: 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 $$L0: push de rt_run 2,2 ; Start secondary eval pop de ld a,0ffh ; Flag task 2 as running ld (t2flag),a $$L1: 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,$$L2 ; Different, so key is ready ld a,(keyto) ; Check for timeout or a jr z,$$L15 ; Yes, take care of it ld a,(t2flag) ; Task 2 running? or a jr nz,$$L1 ; Yes, keep waiting jr $$L0 ; No, so start it again $$L15: ld a,0ffh ; Timed out, return -1 push af ; Save value jr $$L9 $$L2: 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 $$L3: ld a,(hl) ; Get next ASCII value sub c ; Compare it jr z,$$L4 ; If a match, get corresponding binary value inc hl ; If not, point to next one inc hl djnz $$L3 $$L4: 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,$$L5 ; 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 $$L5: ld (ix+2),e ; Save tail pointer ld (ix+3),d $$L9: ld a,(t2flag) ; Task 2 running? or a jr nz,$$L9 ; 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,mytime+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,$$L1 ld a,(weekday) or a jp nz,true3 jp false3 $$L1: cp 9 ; Weekend? jr nz,$$L2 ld a,(weekend) or a jp nz,true3 jp false3 $$L2: cp (iy+2) ; Current DOW jp nz,false3 jp true3 ; todne: ld iy,mytime+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,$$L1 ld a,(weekday) or a jp nz,false3 jp true3 $$L1: cp 9 ; Weekend? jr nz,$$L2 ld a,(weekend) or a jp nz,false3 jp true3 $$L2: cp (iy+2) ; Current DOW jp nz,true3 jp false3 ; todgt: ld iy,mytime+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$$L3 cp 8 ; Weekday? jr nz,$$L1 ld a,(weekday) or a jr nz,$$L3 jp false3 $$L1: cp 9 ; Weekend? jr nz,$$L2 ld a,(weekend) or a jr nz,$$L3 jp false3 $$L2: cp (iy+2) jp nz,false3 $$L3: 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,mytime+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$$L3 cp 8 ; Weekday? jr nz,$$L1 ld a,(weekday) or a jr nz,$$L3 jp false3 $$L1: cp 9 ; Weekend? jr nz,$$L2 ld a,(weekend) or a jr nz,$$L3 jp false3 $$L2: cp (iy+2) jp nz,false3 $$L3: 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,mytime+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$$L3 cp 8 ; Weekday? jr nz,$$L1 ld a,(weekday) or a jr nz,$$L3 jp false3 $$L1: cp 9 ; Weekend? jr nz,$$L2 ld a,(weekend) or a jr nz,$$L3 jp false3 $$L2: cp (iy+2) jp nz,false3 $$L3: 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,mytime+2 ; Point to minutes storage ld a,(ix+2) or a ; If day=0, every day jr z,$$L3 cp 8 ; Weekday? jr nz,$$L1 ld a,(weekday) or a jr nz,$$L3 jp false3 $$L1: cp 9 ; Weekend? jr nz,$$L2 ld a,(weekend) or a jr nz,$$L3 jp false3 $$L2: cp (iy+2) jp nz,false3 $$L3: 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 $$Lbutlp: 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,$$Lnope ; If not the same, no match djnz $$Lbutlp jr true0 ; Match complete, good $$Lnope: dec b jr z,false0 inc ix ; Finish adjusting pointer inc ix jr $$Lnope ; ; 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,$$L8 ; Yes, leave cp endcont ; End of continuous section? jp z,$$L8 ; Yes, skip sequential $$L1: ld b,(ix) ; Save IF/IFA opcode inc ix ; Skip over opcode call eval ; Evaluate condition jr z,$$L3 ; 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,$$L2 ; If so, skip done flag test ld a,c ; Check done flag or a jr z,$$L2 ; 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,$$L7 ; Nope inc ix ; Also skip the ELSE, so point to offset jr $$L6 ; Skip the ELSE $$L2: inc ix ; Move past offset inc ix call action ; Do it jr $$L7 ; Continue $$L3: ld (ix),0 ; Mark as not done inc ix ; Point to the offset $$L4: 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,$$L7 ; 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,$$L5 ; If so, skip done flag test ld a,c ; Check done flag or a jr nz,$$L6 ; Skip if normal IF and already done $$L5: inc ix ; Move past offset inc ix call action ; Do it jr $$L7 ; Continue $$L6: 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 $$L7: ld a,(ix) ; Check for end cp endcont ; End of continuous section? jr z,$$L8 ; Yes, finish up cp endtbl ; End of table? jp nz,$$L1 ; No, do next event $$L8: 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,(mytime+1) ; Get current seconds ld e,a ld a,(mytime+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 $$L0: ld a,5 ; Set hold out (c),a in a,(c) ; Get status bit 1,a ; Busy? jr z,$$L1 ; Nope, continue ld a,4 ; Yes, clear hold out (c),a jr $$L0 ; Check again $$L1: di ld bc,clock ld hl,mytime ld (hl),0 ; Fractional seconds inc hl call $$Lrdbyte ; Get seconds call $$Lrdbyte ; Get minutes call $$Lrdbyte ; Get hours inc hl ; Skip over DOW storage call $$Lrdbyte ; Get day call $$Lrdbyte ; Get month call $$Lrdbyte ; Get year in a,(c) ; Get DOW and 07h ; Kill upper bits inc a ; Make 0-6 into 1-7 ld (mytime+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. ; $$Lrdbyte: 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 $$L0: ld a,(swram) ; Prepare for key djnz $$L0 ; ld hl,key ; Point to key ld c,8 ; 8 bytes $$L1: ld b,8 ; 8 bits/byte ld a,(hl) $$L2: ld (swram),a ; Send bit of key (D0) rrca ; Rotate next bit into D0 djnz $$L2 ; Do 8 bits inc hl ; Do next byte dec c jr nz,$$L1 ; ld b,8 ; Tenths of seconds $$L3: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L3 ; Do 8 bits ld a,c exx ; Alternate ld b,a exx ; Primary ; ld b,8 ; Seconds $$L4: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L4 ; Do 8 bits ld a,c exx ; Alternate ld c,a exx ; Primary ; ld b,8 ; Minutes $$L5: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L5 ; Do 8 bits ld a,c exx ; Alternate ld d,a exx ; Primary ; ld b,8 ; Hours $$L6: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L6 ; Do 8 bits ld a,c exx ; Alternate ld e,a exx ; Primary ; ld b,8 ; Day of week $$L7: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L7 ; Do 8 bits ld a,c and 0fh ; Clear extra bits exx ; Alternate ld h,a exx ; Primary ; ld b,8 ; Day of month $$L8: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L8 ; Do 8 bits ld a,c exx ; Alternate ld l,a exx ; Primary ; ld b,8 ; Month $$L9: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L9 ; Do 8 bits ld d,c ; ld b,8 ; Year $$L10: ld a,(swram) ; Get bit of data (D0) rra ; Rotate it into carry rr c ; Rotate carry into storage djnz $$L10 ; Do 8 bits ld e,c ; ld ix,mytime 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,(mytime+2) ; Get current minutes cp d ; Update minutes timers if call nz,updmtmrs ; minutes have changed ; ld a,(mytime+1) ; Get current seconds cp e ; Have seconds changed? jr z,$$L11 ; Nope, done cp 30h ; Yes, are we on the half minute? jr nz,$$L10 ; 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 $$Lman: ld (hl),0ffh inc hl djnz $$Lman $$L10: call updstmrs ; Update seconds timers on change ; ld a,(mytime+4) ; Get day of week cp 1 ; Sunday? jr z,$$L12 ; Yes, mark weekend cp 7 ; Saturday? jr nz,$$L13 ; No, weekday $$L12: ld a,0ffh ; Flag weekend ld (weekend),a ld a,0 ld (weekday),a jr $$L14 $$L13: ld a,0ffh ; Flag weekday ld (weekday),a ld a,0 ld (weekend),a $$L14: 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 $$L11: rt_exit ; ; updstmrs: ld ix,timers ; Timer values ld b,stmrs ; Number of seconds timers $$L1: ld a,(ix+1) ; Get high byte bit 7,a ; Timer on? jr z,$$L2 ; No, skip ld e,(ix) ld d,(ix+1) inc de ; 16-bit increment ld a,d or e jr z,$$L2 ; Don't allow to wrap ld (ix),e ; Save new value ld (ix+1),d $$L2: inc ix inc ix djnz $$L1 ; ; Also decrement all network module status timers ; ld hl,nettmrs ld b,modtyp*modnum xor a ; Zero A $$L3: cp (hl) ; Timer=0? jr z,$$L4 ; Yes, skip decrement dec (hl) $$L4: inc hl djnz $$L3 ; Do all timers ret ; ; updmtmrs: ld ix,timers+(stmrs*2) ; Timer values (skip seconds timers) ld b,mtmrs ; Number of minutes timers $$L1: ld a,(ix+1) ; Get high byte bit 7,a ; Timer on? jr z,$$L2 ; No, skip ld e,(ix) ld d,(ix+1) inc de ; 16-bit increment ld a,d or e jr z,$$L2 ; Don't allow to wrap ld (ix),e ; Save new value ld (ix+1),d $$L2: inc ix inc ix djnz $$L1 ; ; 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,$$L3 ; 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 $$L4 $$L3: ld a,0ffh ; Flag to update table ld (uptbl),a $$L4: 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 $$L1: ld c,(ix) ld b,(ix+1) ld a,b or c jr z,$$L99 ; If port addr=0, done ; ld e,8 ; Do 8 bits in d,(c) ; Get input byte $$L2: ld a,07fh ; Set up for off bit srl d ; Rotate bit 0 to carry jr c,$$L3 ; No inversion ld a,0 ; Really an on bit $$L3: push bc ld b,(hl) ; Get previous value bit 7,b ; Manually set? jr nz,$$L5 ; Yes, so ignore physical input cp b ; Same as new? jr z,$$L4 ; Yes, no edge ld (iy),0ffh ; Flag edge $$L4: ld (hl),a ; Save bit state $$L5: pop bc inc hl ; Point to next storage inc iy ; Point to next edge flag dec e ; Do all bits jr nz,$$L2 inc ix ; Point to next table entry inc ix jr $$L1 ; Do next port ; ; Read the ADC channel we started last time, then start the ; next channel ; $$L99: ld a,(sc) ; Check hardware or a jp z,$$L39 ; Not configured yet, skip cp sccs ; CS? jp z,$$L60 ; Yes, do it cp scrtc ; RTC180? jr z,$$L20 ; Yes, do it ld a,(adcres) ; BCC180, so check resolution cp 12 ; 12 bits (BCC30)? jr z,$$L35 ; Yes, do it jr $$L25 ; Must be BCC13 (8 bits) ; ; Do ADC on RTC180 ; $$L20: 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,$$L21 ; 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 $$L21: 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,$$L21a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $$L21a: inc a ; Next channel cp 8 ; Too far? jr c,$$L22 ; No, save it ld a,0 ; Start again at 0 $$L22: 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 $$L39 ; Exit ; ; Do BCC13 ; $$L25: 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,$$L25a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $$L25a: inc a ; Next channel cp 8 ; Too far? jr c,$$L26 ; No, save it ld a,0 ; Start again at 0 $$L26: ld (channel),a ; Save it jr $$L39 ; ; Do BCC30 ; $$L35: 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,$$L36 ; If positive, it's OK ld de,0 ; Force to 0 if negative $$L36: 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,$$L36a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $$L36a: inc a ; Next channel cp 16 ; Too far? jr c,$$L38 ; No, save it ld a,0 ; Start again at 0 $$L38: 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 $$L39 ; ; Do CS serial ADC ; $$L60: 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,$$L60a ; Yes, skip save dec hl ld (hl),e ; Save conversion inc hl ld (hl),d $$L60a: inc a ; Next channel cp 8 ; Too far? jr c,$$L61 ; No, save it ld a,0 ; Start again at 0 $$L61: 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 ; $$L39: ld hl,totmr inc (hl) ; Increment time-out timer ld a,(dtmfto) dec a ; Decrement timer used by DTMF stuff cp 0ffh jr z,$$L39a ; Don't let wrap around ld (dtmfto),a $$L39a: ld a,(keyto) dec a ; Decrement timer used by keypad stuff cp 0ffh jr z,$$L39b ; Don't let wrap around ld (keyto),a $$L39b: ld a,(cpto) dec a ; Decrement timer used by CP stuff cp 0ffh jr z,$$L39c ; Don't let wrap around ld (cpto),a $$L39c: ld a,(saytmr) dec a ; Decrement speech timer cp 0ffh jr z,$$L40 ; Don't let wrap around ld (saytmr),a ; ; Process ring detect signal ; $$L40: ld a,(ringtmr) inc a ; Increment time since last ring jr z,$$L41 ; Don't let wrap around ld (ringtmr),a $$L41: ld a,(ringtmr) ; Get time since last ring started cp 30 ; <3 seconds? jr c,$$L49 ; Yes, don't do anything jr nz,$$L42 ; 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 $$L49 $$L42: cp 60 ; <6 seconds? jr c,$$L49 ; Yes, between rings ld a,0 ld (ringctr),a ; Clear ring counter ; ; Process call progress signal ; $$L49: ld a,(cpchk) ; Checking call progress? or a jr z,$$L59 ; Nope, skip CP check ld a,(sc) cp sccs ; CS? jr nz,$$L53 ; No, do RTC/BCC ; ld bc,pia1+2 ; CP status port ld de,1125 ; Num of loops for 5 ms $$L50: in a,(c) ; Check CP status (9 T states) bit 6,a ; (6) jr nz,$$L57 ; Found, inc on time (6) dec de ; Decrement timeout (4) ld a,d ; (4) or e ; (4) jr nz,$$L50 ; Keep checking (8) jr $$L55 $$L53: ld bc,dtmfsts ; DTMF board status port ld de,1125 ; Num of loops for 5 ms $$L54: in a,(c) ; Check CP status (9 T states) bit 2,a ; (6) jr nz,$$L57 ; Found, inc on time (6) dec de ; Decrement timeout (4) ld a,d ; (4) or e ; (4) jr nz,$$L54 ; Keep checking (8) ; $$L55: ld a,(cpofftmr) ; Nothing in 5 ms, so count off time inc a ; Increment off time jr z,$$L56 ; Don't let wrap around ld (cpofftmr),a $$L56: xor a ; Get a zero ld (cpontmr),a ; Clear on timer jr $$L59 $$L57: ld a,(cpontmr) ; Yes, count on time inc a ; Increment on time jr z,$$L58 ; Don't let wrap around ld (cpontmr),a $$L58: xor a ; Get a zero ld (cpofftmr),a ; Clear off timer $$L59: 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,$$L1 ; If zero, we were correct set 3,a ; One, so set bit $$L1: 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,$$L2 ; If zero, we were correct set 3,a ; One, so set bit $$L2: 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 $$L1: rr d ; Rotate into carry rl l ; Rotate into L (reverse bit order) djnz $$L1 ; Do all six bits ld a,(adcres) ; Get ADC resolution sub 6 ; Already done first six bits ld b,a $$L2: rr e rl l rl h djnz $$L2 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 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 ; $$L0: call cin ; Flush input buffer jr nc,$$L0 ; ld hl,mreset ; Reset modem ld a,cr call cout $$L1: ld a,(hl) or a jr z,$$L2 call cout inc hl jr $$L1 $$L2: call wtreply jp c,t5done ; If no reply, abort ; ld hl,mdminit ; Send basic init string ld a,cr call cout $$L3: ld a,(hl) or a jr z,$$L4 call cout inc hl jr $$L3 $$L4: ld hl,rinit ; Add number of rings to string $$L5: ld a,(hl) or a jr z,$$L6 call cout inc hl jr $$L5 $$L6: 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,$$L99 ; Nope, so finish up ld hl,cidinit ; Set up caller ID $$L7: ld a,(hl) or a jr z,$$L8 call cout inc hl jr $$L7 $$L8: ld a,(cidon) ; Get on/off status or a ld a,'2' ; Turn it on jr nz,$$L9 ld a,'0' ; Turn it off $$L9: call cout $$L99: ld a,cr call cout call wtreply jp c,t5done ; If no reply, abort jp t5exit ; All done ; mreset db "ATZ",cr,0 minit db "AT&FMV&D&K&Q5",0 rinit db "S0=",0 cidinit db "#CID=",0 ; ; ; Parse Caller ID data string ; callerid: ld hl,cidbuf $$L0: 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,$$L0 ; Nope, keep going ; ld ix,cidbuf+4 ld iy,ciddata 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 ; 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,$$L2 ; Nope ld a,0 ; Put 000 in area code, exch, and number ld b,6 $$L1: ld (iy),a inc iy djnz $$L1 jr $$L9 $$L2: cp '5' ; Private? (ASCII P = 50) jr nz,$$L3 ; 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 jr $$L9 $$L3: 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 ; $$L9: ld a,0ffh ld (newcid),a ; Flag new data ; jp t5exit ; ; 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 $$L0: ld a,(ix) ; Raw byte and 0fh 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 $$L0 ; Do all pieces ; ld (iy),l ; Store final value inc iy ld (iy),h inc iy ret ; ; ; Wait for an OK reply from the modem. The modem may take several ; seconds, so we must do multiple calls to cin. ; wtreply: call cin ; Assume leading CR $$L0: call cin ; Flush input buffer jr c,$$L1 ; No more in buffer cp cr ; Wait for trailing CR jr nz,$$L0 ; $$L1: ld b,5 ; Five calls is about 4.0 seconds $$L2: call cin jr nc,$$L3 ; Got something djnz $$L2 ; Try again scf ; Nothing, so flag error jr $$L4 $$L3: cp cr ; Ignore CR and LF jr z,$$L1 cp lf jr z,$$L1 cp 'O' ; OK result? jr z,$$L4 ; Yes, return no error (carry clear) cp '0' ; OK result? jr z,$$L4 ; Yes, return no error (carry clear) scf ; Flag error (carry set) $$L4: push af ; Save carry flag $$L5: call cin ; Flush rest of reply jr nc,$$L5 ; 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 $$L1: srl h ; Rotate multiplier right rr l jr nc,$$L3 ; 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 $$L3: sla e ; Rotate multiplicand left rl d djnz $$L1 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,mytime ld b,8 $$L1: ld a,(hl) call cout inc hl djnz $$L1 jp t5done ;--- ; ; Set new time ; settim: call ticsoff ld hl,ntbuf ; Point to new time buffer ld b,8 ; 8 bytes $$L1: call cin ; Get next character jr nc,$$L2 ; If no timeout, continue call ticson jp t5done ; Timeout, abort command $$L2: ld (hl),a ; Save it inc hl djnz $$L1 ; 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 $$L0: call cin jp c,$$Lerr ; Abort on timeout ld (hl),a inc hl djnz $$L0 ; 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 $$Lgcloop: call cin ; Get next character jr c,$$Lerr ; 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,$$L5 ; Nope, continue inc e ; Count number received ld a,e cp 3 jr nc,$$L1 ; If received three or more, done jr $$L7 $$L5: ld e,0 ; Zero endpgms received cp endtbl ; End of table byte? jr nz,$$L6 ; Nope, continue inc d ; Count number received ld a,d cp 3 jr nc,$$L8 ; If received three or more, mark start of ptrs jr $$L7 $$L6: ld d,0 ; Zero endtbls received $$L7: inc hl ld a,h ; Check for overflow or l jr nz,$$Lgcloop ; If none, keep going dec hl ; Keep HL at FFFF ld c,0ffh ; Flag program too big jr $$Lgcloop ; Keep going to flush rest of program $$L8: ld d,0 ; Zero endtbls received inc hl ld (doneptr),hl ; Save the pointer jr $$Lgcloop $$L1: call cin ; Get checksum from host jr c,$$Lerr ; Abort on timeout ld (power),a ; Save it as power-up integrity flag add a,b ; Result should be zero jr nz,$$Lerr ; Nope, error ld a,c ; Check for too big or a jr nz,$$Lberr ; Too big ld a,(compver) ; Check compiler version cp ver jr nz,$$Lverr ; Error if different ld a,(compsver) cp subver jr z,$$L2 ; Continue if it matches jr $$Lverr ; Nope, error ; ; Program too big for memory ; $$Lberr: ld a,toobig ; Signal too big call cout jr $$Lerr ; ; Compiler version different from firmware version ; $$Lverr: ld a,badver ; Signal bad version call cout ; ; Error in transmission, so clear table ; $$Lerr: 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 $$L3 $$L2: ld a,ack ; Signal OK call cout ; ; Now set up hardware for new configuration ; $$L3: call inithard ; Set up on-board hardware ld a,0ffh ld (rstflg),a ; Flag reset condition ld a,(numpl) ; PL-Link defined? jr z,$$L31 ; No, assume PLIX rt_run 8,48 ; Set task frequency for PL-Link jr $$L32 $$L31: rt_run 8,20 ; Using PLIX, so run task more often $$L32: 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