; REMOUSE3.ASM (c) A. Huitsing, The Bytewizards ; ; - ontvangen van IR-afstandsbedieningen dmv. timerinterrupt ; - vertalen serial mouse ; ; programma voor interfacing van PC muis naar MSX ; versie 2: communicatie met MSX via INT's (noodzakelijk voor snelheid) ; ; versie 2.1: verbetering MCCA emulatie detectie ; ; versie 3.0: REMOUSE PRO! ; nu ontvangen van MSX data waardoor veel ; extra opties mogelijk ; ; versie 3.1: I/O data aangepast voor simpeler communicatie ; ; zie onderaan voor meer uitleg .equ xtal,14328220 ; klokfrequentie (in Hz) .equ tosc,1000000/(xtal/1000) ; osc tijd (in nS) .equ tsamp,100 ; sample tijd (in uS) ; is zo gekozen dat Tsamp sowiezo niks aan de hand jb cycani,mai211 ; als cyclisch mag : geen probleem mov R5,0 ; R5 = tijd op oneindig sjmp mainlp mai211: orl A,R4 ; aan/uit gebied er weer bij mov R4,A ; R4 = pointer add A,#anidat ; base erbij mov R0,A mov A,@R0 ; haal animatiebyte acall prsani ; zet switches + haal tijd mov R5,A ; R5 = tijd sjmp mainlp main22: ; wacht e e n tijdseenheid (door misbruiken van samplemechanisme) mov sigcnt,#150d ; 150 * 100uS(=Tsamp) = 15 mS clr ovrrun mai22w: jnb ovrrun,mai22w ; wacht op overrun ajmp mainlp main3: mov A,lstsw ; in A opbouwen van switches jb repeat,repjmp ; nog repeteren ? orl P1,#0b00001111 ; deactiveer joystick mov C,ledlev ; zet led op normale level mov indled,C jb autfr1,repjm1 ; autofire -> afblijven setb ACC.5 ; deactivate SW1 repjm1: jb autfr2,repjmp setb ACC.4 ; deactivate SW2 repjmp: djnz R3,firjmp ; toe aan autofire wissel ? jnb autfr1,noaut1 cpl ACC.5 ; invert SW1 noaut1: jnb autfr2,noaut2 cpl ACC.4 ; invert SW2 noaut2: mov R3,firspd ; herladen met snelheid firjmp: acall set_sw ; update Switches mov A,#5d ; bepaalt de snelheid van autofire acall del_ms jb recvsw,fndkey ajmp mainlp fndkey: mov R0,#keytbl ; zoek toets op mov B,#12d fndkyl: mov A,@R0 inc R0 cjne A,irdat0,fndky2 jnb chkadr,keyfnd ; adres ook controleren ? fndky1: mov A,@R0 ; anders 2e byte ook vergelijken cjne A,irdat1,fndky2 ajmp keyfnd fndky2: inc R0 djnz B,fndkyl clr recvsw ; niks gevonden : ga weer wachten ajmp mainlp keyfnd: ; B bevat (12-toetsnr) clr recvsw mov C,ledlev ; inverteer led cpl C mov indled,C mov A,B add A,#(255d-4) ; 1<=B<=4 ? (tevens aanpassen) jnc chksw mov DPTR,#remap ; remap key naar up/dwn/lft/rght movc A,@A+DPTR anl A,#0b1111 ; alleen up/dwn/lft/rght mov B,P1 anl B,#0b11110000 orl B,A mov P1,B ajmp mainlp chksw: mov A,B ; controleer triggertoetsen mov B,lstsw ; actuele stand cjne A,#4,chksw1 ; autotrig 1 ? setb autfr1 ; zet aan ajmp chkswe chksw1: cjne A,#3,chksw2 ; trig 1 ? clr B.5 ; enable sw1 clr autfr1 ; geen autofire meer ajmp chkswe chksw2: cjne A,#2,chksw3 ; autotrig 2 ? setb autfr2 ; zet aan ajmp chkswe chksw3: cjne A,#1,chkswe clr B.4 ; enable sw2 clr autfr2 ; geen autofire meer chkswe: mov A,B acall set_sw ; update evt. switches ajmp mainlp prsani: ; parse animation byte ; - update switches ; - geef tijd ; INV A = animatie byte ; UIT A = counter ; REG A,R0,PSW mov R0,A ; R0 is nieuwe animatiebyte rr A ; 7,6 naar 5,4 rr A acall set_sw ; zet nieuwe switches mov A,R0 ; terug naar animatiebyte rrc A ; schuif tijdinfo op goede plek + maak C anl A,#31d ; filter tijd jnc prsanx add A,ACC ; x2 add A,ACC ; x4 add A,ACC ; x8 prsanx: ret ijkout: .BYTE 0b101111 ; AUTOFIRE 2 .BYTE 0b101110 ; FIRE 2 .BYTE 0b011111 ; AUTOFIRE 1 .BYTE 0b011110 ; FIRE 1 remap: .BYTE 0b111010 ; UPLEFT .BYTE 0b111011 ; LEFT .BYTE 0b111001 ; DOWNLEFT .BYTE 0b111101 ; DOWN .BYTE 0b110101 ; DOWNRIGHT .BYTE 0b110111 ; RIGHT .BYTE 0b110110 ; UPRIGHT .BYTE 0b111110 ; UP .equ t150,10*2 ; 150 ms .equ t225,15*2 ; 225 ms .equ t960,8*2+1 ; 960 ms .equ tinf,0 .equ pleft,0b01000000 ; alleen links .equ prght,0b10000000 ; ,, rechts .equ pboth,0b00000000 ; beide .equ pnone,0b11000000 ; geen deftbl: ; default parameter table .BYTE 2,0,3,0,6,0,9,0,8,0,7,0,4,0,1,0 ; 0..24 IR-keys .BYTE 32,0,33,0,16,0,17,0 .BYTE 0xff,0xff ; laatste IR-key .BYTE 0 ; default snelheid .BYTE pleft | t150 ; default switch animatie .BYTE pnone | t150 .BYTE pleft | t150 .BYTE pnone | tinf .BYTE 0,0,0,0 .BYTE 10d ; autofire speed ;==================================================================== ; MSX muis I/O ;==================================================================== trglh: ; interrupt handler ; maakt gebruik van registerbank #1 ; wordt aangeroepen bij opgaande flank TRG ingang ; zorgt voor voorbereiden van R5, R6 en R7: (als _DX geset) ;TRG +---+ +---+ ; ---+ +---+ +--- ; R5 R6 R7 ; R4 = mskp1 .equ rxexx,3*8 ; keuze registerbank .equ R0exx,rxexx+0 .equ R1exx,rxexx+1 .equ R2exx,rxexx+2 .equ R3exx,rxexx+3 .equ R4exx,rxexx+4 .equ R5exx,rxexx+5 .equ R6exx,rxexx+6 .equ R7exx,rxexx+7 jb _DX,trglh2 ; DX aan de beurt ? jb sel_ir,trglh1 ; niets aan P1 doen indien IR mov P1,R6exx ; zonder registerbank te wisselen ! trglh1: setb _trghi reti trglh2: push ACC mov A,lstdx swap A orl A,R4exx ; sw uit + geef laagste bit jb sel_ir,trglh3 ; niets aan P1 doen indien IR mov P1,A trglh3: push PSW orl PSW,#11000b ; kies registerbank 3 mov A,lstdx mov lstdx,#0 orl A,R4 ; sw uit + geef laagste bits mov R5,A mov A,lstdy ; altijd ophalen in paren swap A orl A,R4 ; sw uit + geef laagste bits mov R6,A mov A,lstdy mov lstdy,#0 orl A,R4 ; sw uit + geef laagste bits mov R7,A setb _trghi push B acall rcvmsx pop B pop PSW pop ACC reti trghl: ; wordt aangeroepen bij neergaande flank TRG ingang jbc _DX,trghl2 ; nog bezig met DX ? (auto clear!) jb sel_ir,trghl1 ; IR? -> skip P1 mov P1,R7exx ; zonder registerbank selectie trghl1: setb _DX ; volgende keer DX weer aan de beurt ajmp trghlx trghl2: mov synctl,#0 ; automatische synchronisatie jb sel_ir,trghlx ; IR? -> skip P1 mov P1,R5exx ; zonder registerbank selectie trghlx: push ACC mov A,lstsw ; switches erbij anl P1,A clr _trghi pop ACC reti ;------------------------------------------------- rcvmsx: ; kijk of de MSX iets te zenden heeft ; en ontvang het byte ; INV - ; UIT - ; REG ACC,B,R0,PSW orl P1,#mskp1 ; niet zelf naarbeneden trekken ! jnb swtch1,rcmsx2 ; switch 1 laag getrokken ? ret rcmsx2: clr EA ; alle int's uit push P1 acall rcvbyt ; haal byte op.. jc rcmsxe ; error ? acall prsbyt ; behandel ontvangen byte rcmsxe: ; clr _DX ; MOET ! (EXx FF zijn geset !!) mov synctl,#0 ; voor de veiligheid pop P1 setb EA ; int's weer aan ret prsbyt: ; behandel ontvangst van mode byte ; INV A = byte ; UIT - ; REG A,B,PSW ; evt. R0..R7 mov B,A ; B = nieuwe mode anl A,#mskmod nwmod1: cjne A,#md_set,nwmod2 ; mode = set parameter ? mov A,B anl A,#mskpar ; haal nummer jz nwmd1e ; parameter 0 ? add A,#-4 jc nwmd12 ; bitparam's 1..3 ? add A,#glbmd1-partbl+3 ; correctie voor bitvariabelen nwmd12: add A,#partbl mov R0,A ; R0 = pointer naar par. acall rcvbyt ; haal byte op jc nwmd1x mov @R0,A ; bewaar parameter nwmd1x: ajmp nwmodx nwmd1e: acall rcvbyt ; dummy byte ophalen bij param 0 sjmp nwmd1x ;------------------- nwmod2: cjne A,#md_get,nwmod3 ; mode = get parameter ? mov A,B anl A,#mskpar jnz nwmd21 mov A,#versie ; parameter 0 = versienummer sjmp nwmd2x nwmd21: add A,#-4 ; binnen parameters 1..3 ? jc nwmd22 add A,#glbmd1-partbl+3 ; correctie voor bitvariabelen nwmd22: add A,#partbl mov R0,A mov A,@R0 ; A = parameter nwmd2x: acall sndbyt ajmp nwmodx ;------------------- nwmod3: cjne A,#md_sub,nwmod3 ; alternative mode ? mov A,B anl A,#mskpar cjne A,#sb_mir,nwmd31 ; MCCA mode ? ajmp doalt nwmd31: cjne A,#sb_ijk,nwmd32 ; ijkmode ? setb reqijk ; geef request door sjmp nwmd3x nwmd32: cjne A,#sb_ser,nwmd33 ; seriele mode? ajmp sermod nwmd33: cjne A,#sb_res,nwmd34 ; reset ? ajmp reboot nwmd34: nwmd3x: ajmp nwmodx ;------------------- nwmod6: nwmodx: ret ;------------------- rcvbyt: ; receive MSX byte ; INV swtch1 is laaggetrokken door MSX ; swtch2 kan laag of hoog zijn.. ; TRG is laag OF hoog ! ; UIT C = geen correcte byte ontvangen (swtch1 is weer hoog) ; NC = A bevat ontvangen byte, TRG is laag ; REG A,B,PSW cpl indled ; indicate mov B,#4d ; B=teller clr A ; A=buffer rcvbtl: jb swtch1,rcvbte ; nog steeds 0 ? jnb trig,rcvbtl ; wacht op trig hoog rl A jnb swtch2,rcvbt1 inc A rcvbt1: jb swtch1,rcvbte ; nog wel 0 he? jb trig,rcvbt1 ; wacht op trig laag rl A jnb swtch2,rcvbt2 inc A rcvbt2: djnz B,rcvbtl cpl indled ; indicatie weer uit clr C ret rcvbte: cpl indled ; indicatie weer uit setb C ; error ret sndbyt: ; verstuur MSX byte ; INV swtch1 is laag ; swtch2 is laag ; TRG is laag ; A = data ; UIT C = mislukt ; NC = gelukt, TRG is laag ; REG A,B,PSW mov B,A ; data ook in B anl A,#0x0f ; laagste nibble 't eerst orl A,R4 ; beide switches inactief mov P1,A ; data voor flank aanbieden mov A,B swap A ; hoogste nibble voorbereiden anl A,#0x0f orl A,R4 sndby1: jb swtch1,sndbye ; wacht totdat trig actief wordt jnb trig,sndby1 mov P1,A ; high nibble op poort sndby2: jb swtch1,sndbye jb trig,sndby2 ; wacht totdat trig inactief wordt clr C ret sndbye: setb C ret ;==================================================================== ; serial Mouse I/O ;==================================================================== serint: ; serial interrupt service ; werkt met registerbank #2 ; zorgt voor binnenhalen muisdata + verwerken ; dus opbouwen van lstDX,lstDY en lstSW clr TI ; default: clear transmit interrupt jnb RI,serinx ; no Receiver interrupt -> exit clr RI ; reset receive flag (acknowledge interrupt) jb inh_ms,serinx ; mouse disabled ? clr sel_ir ; omschakelen naar muismode serin0: push PSW ; locale registers bewaren push ACC push B setb RS1 ; kies registerbank 2 clr RS0 mov B,SBUF ; ophalen seriele data acall domous ; verwerken pop B ; herstel registers pop ACC pop PSW serinx: reti ;------------------------------ domous: ; verwerken van muisdata ; wordt in interruptroutine aangeroepen ; en zorgt voor daadwerkelijk verwerken ; tevens autoswitch tussen Microsoft en Genius mode ; INV B bevat te verwerken byte ; UIT lstDX,lstDY en lstSW bijgewerkt ; REG A,B,PSW ; registergebruik R0 = alg gebruikt ; R1 = ; R2 = ; R3 = ; R4 = ; R5 = ; R6 = byte0 , geeft het eerst ontvangen byte ; R7 = sercnt, ,, aan welk byte er verwacht wordt jb genmod,gnmous ajmp msmous ;---------------------------------------- gnmous: ; protocol volgens geniusmode: gnmou0: cjne R7,#0,gnmou1 ; byte 0 : switches + sync mov A,B anl A,#0b11000000 ; bekijk bits 7 en 6 cjne A,#0b10000000,gnmo0e ; <>10 => geen genius acall leduit ; in ieder geval led uit mov R7,#1 ; volgende is byte 1 mov A,R6 ; byte0 xrl A,B ; bekijk welke knoppen er veranderd zijn mov R6,B jnb ACC.1,gnmo02 ; middelste knop veranderd ? jnb B.1,gnm011 ; bij indrukken knop altijd animatie jb swuani,gnm011 ; bij loslaten knop alleen bij swuani ret gnm011: mov A,anidat mov aniptr,#0 jnb B.1,gnmo01 ; middelste knop zojuist losgelaten ? mov A,anidat+4 ; bij loslaten beginnen in 2e helft mov aniptr,#4d gnmo01: acall prsani ; behandel eerste byte mov anictr,A ; set counter setb aniact ret gnmo02: jnb aniact,gnmo03 ; bezig met animatie ? anl A,#0b101 ; alleen als linker of rechterknop veranderd jnz gnmo03 ret gnmo03: mov A,B swap A mov C,ACC.6 ; copy A.6 naar A.5 mov ACC.5,C ajmp upd_sw ; doe de rest gnmo0e: cjne A,#0b11000000,gnm0ex ; <>11 => geen microsoft (syncfout) clr genmod ; overschakelen naar microsoft mode mov R7,#0 ajmp msmous gnm0ex: ret ; volgende byte afwachten gnmou1: cjne R7,#1,gnmou2 ; byte 1 : DX mov A,B mov R0,#dxbuf ; verwerk delta acall prsdlt ajmp gnmoux gnmou2: cjne R7,#2,gnmoux ; byte 2 : DY mov A,B cpl A inc A mov R0,#dybuf acall prsdlt acall pasdlt ; geef door acall ledaan ; indicatie aan gnmoux: inc R7 ; default: verhoog sercnt cjne R7,#5,gnmox2 mov R7,#0 gnmox2: ret ;---------------------------------------- msmous: ; protocol volgens microsoftmode: jb B.7,msmouj ; als bit7 van byte 0 geset is : OK setb genmod ; overschakelen op geniusmode mov R7,#0 ; sercnt = 0 mov R6,0xff ; byte0 = 0xff ajmp gnmous msmouj: msmou0: ; verwerk byte 0 cjne R7,#0,msmou1 jb B.6,msbyt0 ; als bit 6 geset -> OK ret msbyt0: mov A,B mov R6,A ; bewaar byte 0 in R6 cpl A ; voor MSX poort moet precies inverse komen! acall ledaan ; indicatie aan upd_sw: ; zie set_sw ; wordt door muis gebruikt (rekening houdend met swapsw!) ; + sercnt = 1 ; + clr aniact (disable animation) ; REG ACC,PSW clr aniact ; switch animatie disabled mov R7,#1 ; volgende is byte 1 jnb swapsw,set_sw ; swap switches ? mov C,ACC.4 rr A ; van bit 5 naar bit 4 mov ACC.5,C set_sw: ; zorg voor update lastsw ; INV A5/4 bevat geldige switches ; UIT lastsw gemaakt, poort updated ; REG ACC orl A,#0b11001111 ; zet bits buiten sw op 1 clr EA ; geen interrupts mov lstsw,A ; bewaren jb _trghi,setswe mov A,P1 orl A,#0b00110000 anl A,lstsw mov P1,A setswe: setb EA ret msmou1: ; verwerk byte 1..2 jb B.6,msbyt0 ; als bit 6 geset -> dit was byte 0 ! anl B,#0b00111111 ; alleen bits 0..5 zijn van belang cjne R7,#1,msmou2 ; byte 1 ? mov A,R6 ; opbouwen DX rr A ; roteer bit 1..0 naar bit 7..6 rr A anl A,#0b11000000 ; alleen bit 7 en 6 orl A,B ; in A nieuwe DX mov R0,#dxbuf ; verwerk deltawaarde acall prsdlt ; aanpassen deltawaarde mov R7,#2 ; volgende is byte 2 ajmp leduit ; indicatie uit msmou2: ; verwerk byte 2 mov A,R6 ; opbouwen DY rl A ; roteer bit 2..0 naar bit 7..6 rl A rl A rl A anl A,#0b11000000 ; alleen bits 7..6 orl A,B ; in A nieuwe DY mov R0,#dybuf ; verwerk deltawaarde acall prsdlt mov R7,#0 ; volgende is weer byte 0 acall leduit ; indicatie uit pasdlt: ; doorgeven van delta's ; INV A=delta Y clr EA mov lstdx,dxbuf+1 mov dxbuf+1,#0 mov lstdy,dybuf+1 mov dybuf+1,#0 setb EA ret prsdlt: ; verwerken van deltawaarde ; INV A=nieuwe delta ; R0 wijst naar 16 bits buffered delta ; REG A,B,PSW cpl A ; doe -A inc A mov B,A ; B = delta mov A,mouspd ; bekijk speedfactor anl A,#3 cjne A,#3,chksp0 ; spd=3(=verdubbelen) ? mov A,B subb A,#4 ; bij lage snelheid niet verdubbelen ! jc chks01 add A,#8 jc chks01 mov A,B add A,ACC mov C,B.7 ; bewaar oorspronkelijke sign in C mov B,#0 ; maak 16 bits jnb OV,chkspx ; ging 't mis ? mov A,#0x7f ; max pos. snelheid jnc chkspx ; als oorpsronkelijke positief was mov A,#0x81 ; anders max neg. snelheid sjmp chkspx chksp0: jnz chksp1 ; spd=0(=normal) ? chks01: mov A,B ; uitbreiden naar 16 bits mov B,#0 sjmp chkspx chkspc: rrc A ; schuif 16 bits signed naar rechts xch A,B rrc A xch A,B mov C,ACC.6 ; overnemen oude sign mov ACC.7,C ret chksp1: dec A ; spd=1(=slow 1)? jnz chksp2 mov A,B mov B,#0 sjmp chks21 chksp2: mov A,B ; spd=2(=very slow) mov B,#0 acall chkspc ; delen door 2 chks21: acall chkspc ; en nog een keer delen door 2 chkspx: ; na al dit gekloot staat in A,B een 16 bits offset xch A,B ; dus nu in B,A een 16 bits offset add A,@R0 ; uitvoeren van 16 bits optelling mov @R0,A inc R0 mov A,B addc A,@R0 ; C was blijven staan van vorige optelling mov @R0,A jnb OV,chksx1 ; is hierbij 'n overflow gekomen ? mov A,#7fh ; max. positief jnb B.7,chksx0 mov A,#81h ; max. negatief chksx0: mov @R0,A chksx1: dec R0 ret ;------------------------------------------------------------------- altmod: ; simuleer MCCA-ir ontvanger mov a,#5*4 ; vertraag +/- 5 sec acall delqrt ; (wacht op stabilisatie MSX power) setb repeat ; misbruik repeat switch mov repcnt,#75d ; natte vinger tijd (!!) chkmd2: jnb repeat,tonor jnb irsig,doalt ; naar alternatieve (MCCAbox-)mode? ajmp chkmd2 tonor: ajmp normod doalt: clr EA ; totaal geen interrupts meer mov P1,#0xff ; poort 1 inactief sim_ir: mov C,irsig mov indled,C cpl C ; in 't echt een BC547 :-) mov joy_up,C ajmp sim_ir ;------------------------------------------------------------------- ijken: ; invullen van KEYTBL (ijken) ; eerste toets is al ontvangen mov R0,#keytbl ; R0 als pointer naar keytable mov B,#12 ; 12 toetsen mov R2,#0xff ; vorige toets mov R3,#0xff mov DPTR,#ijkout-1 ; service output ijkenl: acall cplled ; led in knippertoestand mov A,B ; tabel staat al in omgekeerde volgorde! movc A,@A+DPTR mov P1,A mov A,#100d acall del_ms jnb recvsw,ijkenl mov A,R2 ; vergelijk met vorige cjne A,irdat0,ijken2 mov A,R3 cjne A,irdat1,ijken2 clr recvsw ; geef weer vrij ajmp ijkenl ijken2: mov A,irdat0 mov R2,A ; bewaar voor vergelijken mov @R0,A ; ,, in keytbl inc R0 mov A,irdat1 mov R3,A ; bewaar voor vergelijken mov @R0,A ; ,, in keytbl inc R0 acall ledaan mov A,#3 acall delqrt clr recvsw djnz B,ijkenl acall leduit setb chkadr ; geef aan dat ook naar adres moet kijken ret ;------------------------------------------------------------------- timhnd: ; timer interrupt handler ; wordt elke sampleperiode aangeroepen .flag irsig,P3.5 push ACC push PSW djnz synctl,timhn1 ; voor autosynchronisatie MSX muis protocol setb _DX timhn1: djnz sigcnt,timhn2 setb ovrrun ; geef aan dat teller overgelopen djnz repcnt,timhn2 clr repeat ; niet langer repeating timhn2: mov A,P3 ; ophalen data xrl A,lstsig ; kijk of veranderd is jb 0xE5,newsig pop PSW pop ACC reti newsig: ; overgang gedetecteerd; ; - in sigcnt staat gemeten tijd ; - op stack ligt A + PSW push DPH ; bewaar datapointer push DPL xrl lstsig,#0xff ; volgende keer andere flank mov DPH,nxtdph mov DPL,nxtdpl jb ovrrun,nwsig1 ; overrun ? jnb triggr,nwsig3 ; geen overrun & geen trigger : OK ajmp nwsig2 nwsig1: jb triggr,nwsig3 ; overrun & trigger : OK nwsig2: mov DPTR,#declop nwsig3: jb inh_ir,nwsig4 ; IR inhibitted ? acall nwsigc nwsig4: mov sigcnt,#0 ; reset teller clr ovrrun pop DPL pop DPH pop PSW pop ACC reti nwsigc: ; -op stack ligt RET adres ; -DPTR bevat hervat-adres ; -routine wordt ALTIJD verlaten door aanroep van GETTIM ; -waardoor dit returnadres weer hervat wordt clr A jmp @A+DPTR gettim: ; zorgt voor ophalen volgende tijd in sigcnt nogal getruuct: ; van SP wordt het RET adres bewaard als volgende waarde voor sprong ; indien er weer een tijd gemeten wordt pop nxtdph ; volgende keer verder met dit adres pop nxtdpl ret ; terugkeeradres van CALL nwsigc ;-------------------------------------------------------------------- ; decoderen IR-data: ; alleen ACC+PSW gebruiken ! declop: mov lstsig,0xff ; aktueel signaal is 1 setb triggr ; deze keer moet overrun acall gettim ; wacht op eerste hooglaagovergang clr triggr ; nu geen overrun meer toestaan decjp: acall gettim ; haal eerste bittijd mov A,sigcnt ; SONY ? add a,#snyt4m jnc no_sny subb A,#(2*snyt4a) jnc no_sny ajmp do_sny ; doe Sony no_sny: mov A,sigcnt ; JVC ? ; add a,#jvct4m ; jnc no_jvc ; subb A,#(2*jvct4a) ; jnc no_jvc ; ajmp declop no_jvc: ; ------------------------------- ; Philips (RC5) ; ------------------------------- .equ afw,4 ; 1/afw = afwijkings percentage .equ rc5t1,889 ; enkele periode tijd (in uS) .equ rc5t1c,rc5t1/tsamp ; uitgedrukt in tikken van timer .equ rc5t1a,rc5t1c/afw ; afwijking .equ rc5t1m,rc5t1c+rc5t1a ; max aantal tikken .equ rc5t2,2*rc5t1 ; dubbele periode tijd (in uS) .equ rc5t2c,rc5t2/tsamp .equ rc5t2a,rc5t2c/afw .equ rc5t2m,rc5t2c+rc5t2a do_rc5: ; behandelen RC5 code clr hulpsw ; init hulp vars setb bitlev mov bitcnt,#13d mov irbuf0,#0 mov irbuf1,#0 ajmp rc5skp ; eerste keer al opgehaald rc5lop: acall gettim ; haal volgende bittijd rc5skp: mov A,sigcnt add A,#rc5t2m ; lang ? jnc rc5krt subb A,#(2*rc5t2a) jnc rc5krt jb hulpsw,rc5err ; als deze kort moest zijn -> fout cpl bitlev ; omkeren bitlevel ajmp rc5nxt rc5krt: mov A,sigcnt add A,#rc5t1m ; kort ? jnc rc5err subb A,#(2*rc5t1a) jnc rc5err jbc hulpsw,rc5lop ; skip? -> clear sw & ga verder setb hulpsw ; volgende korte tijd skippen rc5nxt: mov C,bitlev ; zet bitlevel signaal in C acall shiftc ; schuif C in buffer djnz bitcnt,rc5lop ; was 't laatste bit ? mov A,irbuf1 rl A rl A mov irbuf1,A mov C,irbuf0.6 ; zet bit 0,1,6 en 7 van IRDAT1 mov irbuf1.0,C mov C,irbuf0.7 mov irbuf1.1,C mov C,irbuf1.5 ; Controle bit mov irbuf1.7,C mov C,irbuf1.6 ; zet bit 6 en 7 van IRBUF1 cpl C mov irbuf0.6,C anl irbuf0,#0b01111111 ; wis ongebruikte bits anl irbuf1,#0b00011111 ; (CONTROLE BIT OOK WEG !) recved: ; geef data door aan rest van programma jb recvsw,rcved1 ; nog in behandeling ? setb recvsw ; zo niet geef door mov irdat0,irbuf0 mov irdat1,irbuf1 rcved1: setb repeat ; set repeating mov repcnt,#reptim setb sel_ir ; nu IR aan de macht ajmp declop rc5err: ajmp declop ; overnieuw beginnen te decoderen shiftc: ; inschuiven van C in irbufx mov A,irbuf0 rlc A mov irbuf0,A mov A,irbuf1 rlc A mov irbuf1,A ret ; ------------------------------- ; Sony ; ------------------------------- .equ snyafw,3 .equ snyt1,550 ; enkele periode tijd (in uS) .equ snyt1c,snyt1/tsamp ; omgezet in aantal tikken .equ snyt1a,snyt1c/snyafw .equ snyt1m,snyt1c+snyt1a ; max T1 .equ snyt2,2*snyt1 ; dubbele periode tijd .equ snyt2c,snyt2/tsamp .equ snyt2a,snyt2c/snyafw .equ snyt2m,snyt2c+snyt2a ; max. aantal tikken .equ snyivl,snyt2m-(snyt1c-snyt1a) ; lengte interval [min(T1),max(T2)] .equ snybrd,snyivl/2 ; grens precies in het midden .equ snyt4,4*snyt1 ; viervoudige periode tijd (header) .equ snyt4c,snyt4/tsamp .equ snyt4a,snyt4c/4 .equ snyt4m,snyt4c+snyt4a .equ trgtim,(2*snyt4)/tsamp ; min trigger tijd .equ reptim,5 ; reload value voor repeat (natte vinger!) do_sny: mov bitcnt,#12 ; aantal bits mov irbuf0,#0 mov irbuf1,#0 snylop: acall gettim ; ophalen tijd mov A,sigcnt add A,#snyt1m ; 1T ? jnc snyerr subb A,#(2*snyt1a) jnc snyerr acall gettim ; ophalen tijd jb ovrrun,snyerr mov A,sigcnt add A,#snyt2m ; max 2T jnc snyerr subb A,#snyivl ; lengte interval[min(T),max(2T)] jnc snyerr add A,#snybrd ; bekijk grens (C = 1T, NC=2T) cpl C acall shrghc ; carry erin schuiven djnz bitcnt,snylop acall shrghc acall shrghc anl irbuf1,#0b00111111 ; adres mov A,irbuf0 rr A rr A anl A,#0b00111111 ; toets orl A,#0b10000000 ; voor onderscheid tussen Phil en Sony mov irbuf0,A ajmp recved snyerr: ajmp declop shrghc: mov A,irbuf1 rrc A mov irbuf1,A mov A,irbuf0 rrc A mov irbuf0,A ret ; ------------------------------- ; JVC ; ------------------------------- .equ jvct1,520 ; enkele periode tijd (in uS) .equ jvct1c,jvct1/tsamp .equ jvct1a,jvct1c/afw .equ jvct1m,jvct1c+jvct1a .equ jvct2,2*jvct1 ; dubbele periode tijd .equ jvct2c,jvct2/tsamp .equ jvct2a,jvct2c/afw .equ jvct2m,jvct2c+jvct2a .equ jvct4,4*jvct1 ; viervoudige periode tijd .equ jvct4c,jvct4/tsamp .equ jvct4a,jvct4c/afw .equ jvct4m,jvct4c+jvct4a .equ jvct8,8*jvct1 ; achtvoudige periode tijd .equ jvct8c,jvct8/tsamp .equ jvct8a,jvct8c/afw .equ jvct8m,jvct8c+jvct8a do_jvc: ajmp declop ;==================================================================== ; seriele mode: ;==================================================================== sermod: ; implementeer seriele mode ; ; opm. kan alleen verlaten worden door speciale break te versturen ; (waardoor controller reset !!!!) .equ serbuf,8 .equ bufend,serbuf+100d .equ serbsp,partbl ; parameter 4 = baudspeed .equ reg_0,0x00 ; direct ram address van registers .equ reg_1,0x01 .flag lsttrg,PSW.5 ; vorige toestand van trigger mov IE,#0 ; disable ALL ints mov PSW,#0 ; kies registerbank 0 mov SP,#bufend ; stack helemaal op 't einde van RAM mov P1,#0b00111111 ; switches + alle richtingen hoog mov P3,#0ffh ; P3 output disable, input enable mov A,serbsp ; bekijk snelheid (parameter 4) mov DPTR,#bsptbl movc A,@A + DPTR mov TH1,A ; zet baudspeed mov TMOD,#00100010b ; timer 0 & 1 8-bit auto-reload mov TCON,#01000000b ; start timer1 mov SCON,#01010000b ; serial port mode one + start receiver mov R0,#serbuf ; R0 = head mov R1,#serbuf ; R1 = tail clr lsttrg ; trigger is niet hoog setb TI ; geef aan dat SBUF ready is srmdlp: ; POLLING loop van serial mode jnb RI,srmd20 ; byte in serial register ? mov A,R0 ; inc (head) inc A cjne A,#bufend,srmd11 ; A = A MOD lengte mov A,#serbuf srmd11: cjne A,reg_1,srmd12 ; buffer full ? clr swtch2 ; geef error aan mov A,R0 ; en verhoog pointer niet srmd12: mov R0,A ; nieuwe putpointer mov @R0,SBUF ; bewaar data in buffer clr RI ; acknowledge receival ;-- trigger in hoge toestand -- srmd20: jnb trig,srmd30 ; trigger in low position ? jb lsttrg,srmd21 ; was trigger al hoog ? setb lsttrg ; trigger is nu hoog mov A,R2 ; ophalen actuele byte swap A anl A,#0x0f ; onderste helft orl A,#0b00110000 mov P1,A ; naar de poort setb indled ; led weer uit srmd21: mov C,TI ; op switch2 SBUF ready zetten cpl C mov swtch2,C setb swtch1 ; zelf in iedergeval switch 1 hoogmaken jb swtch1,srmd30 ; heeft MSX swtch1 activated ? setb swtch2 ; acknowledge begin serial transmission jnb swtch2,srmd30 ; probeert MSX seriele data te acknowledgen ? clr indled ; led aan mov B,#4d clr A srmdt1: jnb swtch2,srmdte ; reset controller ? jb trig,srmdt1 ; wacht op trigger laag mov C,swtch1 ; data in C rlc A ; binnenschuiven in buffer clr swtch2 ; acknowledge srmdt2: jb swtch2,srmdte ; reset controller ? jnb trig,srmdt2 ; wacht op trigger hoog mov C,swtch1 ; data in C rlc A ; binnenschuiven in buffer setb swtch2 ; acknowledge djnz B,srmdt1 clr TI ; reset TI mov SBUF,A ; ga verzenden srmdt3: jb trig,srmdt3 ; wacht op trigger laag setb indled ; led weer uit sjmp srmd31 srmdte: ajmp reboot ;-- trigger in lage toestand -- srmd30: jb trig,srmdlp ; is wel laag? jnb lsttrg,srmd40 ; was al laag ? srmd31: clr lsttrg ; hoog -> laag overgang gededecteerd orl P1,#00110000b ; zelf beide switches weer hoog jb swtch2,srmd40 ; acknowledge serial receival ? mov A,R1 ; increase tail indien mogelijk cjne A,reg_0,srmd32 ajmp srmd40 srmd32: inc A cjne A,#bufend,srmd33 mov A,#serbuf srmd33: mov R1,A srmd40: ; trigger is laag (misschien al een tijdje) jnb swtch1,srmdlp ; al/nog data op output aanwezig ? mov A,R1 cjne A,reg_0,srmd41 ; byte beschikbaar ? ajmp srmdlp srmd41: inc A ; verhoog tail cjne A,#bufend,srmd42 ; mod (lengte) mov A,#serbuf srmd42: mov R2,reg_1 ; oude R1 in R2 mov R1,A mov A,@R1 mov reg_1,R2 ; R1 weer herstellen mov R2,A ; R2 = actueel te versturen databyte anl A,#0fh ; alleen laagste bits orl A,#00110000b ; beide switches eerst maar inactief mov P1,A ; en weer op de poort clr swtch1 ; geef aan data aanwezig clr indled ; geef aan op led dat data beschikbaar ajmp srmdlp bsptbl: .byte BD0300,BD0600,BD1200,BD2400,BD4800,BD9600 ;==================================================================== ; algemene routines: ;==================================================================== ledaan: ; zet led aan clr C ajmp setled leduit: ; zet led uit setb C ajmp setled cplled: ; complement LEDlevel mov C,ledlev cpl C setled: ; INV C= nieuwe ledstatus mov ledlev,C mov indled,C ret ;---------------------------------------------------------------------------- delqrt: ; wacht aantal kwart sec ; INV A = aantal kwart sec ; UIT - ; REG PSW push ACC push B mov B,A ddd: mov A,#250d acall del_ms djnz B,ddd pop B pop ACC ret del_ms: ; wacht aantal ms ; INV A = aantal ms ; UIT - ; REG PSW push ACC push B mov B,#0 dd: djnz B,* ; +/- 500 uS djnz B,* ; +/- 500 uS djnz ACC,dd pop B pop ACC ret ;---------------------------------------------------------------------------- inictr: ; init controller registers mov PCON,#0 ; init power control register mov IE,#0 ; deactivate all interrupts mov A,#0ffh ; deactivate output ports mov P1,A mov P3,A mov SCON,#01000000b ; serial port mode one mov TMOD,#00100010b ; timer 0 & 1 8-bit auto-reload mov TH0,#tload ; T0 reload value mov TH1,#BD1200 ; T1 reload value mov TCON,#0b01010101 ; start timers (EX0/EX1: H>L transition) mov IP,#0b00000101 ; EX0 & EX1 : High priority mov IE,#0b10010111 ; enable +glob+T0+EX1+EX0 ints ret ; documentatie: ; ; voor muisprotocollen: zie mousprot.txt ; ; AT89C2051 is alsvolgt aangesloten: ; ; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; +---+---+---+---+---+----+---+---+ +---+---+---+---+---+---+---+---+ ; P3|LED|xxx|IR |DTR|TRG|*TRG|TxD|RxD| P1| | |FR2|FR1|RGH|LFT|DWN| UP| ; +-v-+---+---+---+---+----+---+---+ +---+---+---+---+---+---+---+---+ ; ints ; ; Opm. zoals te zien zijn INT0 en INT1 aangesloten op *TRG resp. TRG, die ; ervoor zorgen dat beide flanken van de MSXTRG pulse kunnen worden ; gedetecteerd ; ; in versie 3 (PRO) kunnen nu bytes verstuurd worden naar de ReMouse ; (vanuit de MSX) ; ; hiervoor geld het volgende protocol: ; TRG +-----------+ +---+ +---+ +---+ ; ----+ +---+ +---+ +---+ +------- ; SW1 ---+ ; +---------------------------------------------- ; SW2 ----\/----------\/--\/--\/--\/--\/--\/--\/--\/------ ; /\--bit 7---/\-6/\-5/\-4/\-3/\-2/\-1/\-0/ ; ; Dus SW1 moet laag zijn als TRG hoog gaat (vanuit MSX gezien!) ; en daarna laagblijven. Vervolgens wordt mbv. TRG de data die op SW2 ; staat geklokt. ; Zodoende kan er een byte verstuurd worden. De indeling van dit byte ; is alsvolgt: ; ; commando byte: 76543210 ; ||++++++-- parameter ; ++-------- mode 00 = get parameter ; 01 = set parameter ; 10 = set global mode ; 11 = not used ; per commandobyte kunnen er 6 bits parameter data meegegeven worden: ; ; (00) set parameter 43210 ; +++++-- parameter no. (0..63) ; ; let op!: daadwerkelijke data moet direct hierna verstuurd worden! ; dmv. zelfde protocol als ook het CMD byte verstuurd wordt ; ; (01) get parameter 43210 ; +++++-- parameter no. (0..63) ; ; nadat dit byte verstuurd is staat op up/dwn/lft/right ; meteen het low-nibble van de data ; bij opgaande flank van TRG verschijnt high-nibble ; ; TRG +-------------+ ; -----+ +------- ; ; ----\/------------\/----------- ; up/dwn/lft/rgh low-/\-high nibble/\undefined ; ; (10) set global mode 43210 ; 000|| ; ++---- submode 00 = MCCA IR-receiver mode ; 01 = trainer mode ; 10 = serial snoop mode ; 11 = not used ; ; ; MCCA IRBOX mode ; --------------- ; In deze mode gedraagd de ReMouse PRO interface zich als een volwaardige ; MCCA IR-receiver. Uit deze mode kan niet ontsnapt worden. Tevens is er ; vanaf dat moment geen mogelijkheid meer om te kijken of er een ReMouse ; interface aan de poort hangt !!! ; ; TRAINER mode ; ------------ ; In de trainer mode moeten de IR-toetsen in de vastgelegde volgorde ; getraind worden (zoals in de handleiding staat vermeld). Deze mode ; is niet voortijdig af te breken. ; ; SERIAL MODE ; ----------- ; In deze mode is het mogelijk de seriele poort van de ReMouse interface ; los te gebruiken. Dit kan bijvoorbeeld worden gebruikt om eenvoudige ; RS232 communicatie te verrichten. De parametertabel wordt hiervoor ; herbruikt. ; Bij het binnentreden van de seriele mode moeten in de parametertabel ; de volgende parameters klaarstaan : ; ; parameter 4 = baudrate 0 = 1200 (opm. dit is parameter 0 in partbl!) ; 1 = 2400 ; 2 = 4800 ; 3 = 9600 ; ; Vervolgens wordt de parametertabel gebruikt als seriele buffer ; hierdoor is het mogelijk zonder interrupts te werken (via de jostickpoort) ; ; de bytes die ontvangen worden kunnen alsvolgt opgehaald worden: ; ; SW1 (!dat.rdy) -----\ /------------- ; \------/ ; UP/DWN/LFT/RGHT ----\ /------\/------\ /----- ; \ d3..0 \ d7..4 \ ; ----/ \------/ \------/\---- ; TRG /--------\ ; ----------/ \------ ; ; - SW2 geeft overrun aan (interne buffer volgeraakt), clear dmv. TRG hoog ; ; - het versturen van bytes mbv. de ReMouse gaat hetzelfde als normale bytes ; versturen. ; ; - voor het afbreken van deze mode kan een speciaal RESET event verstuurd ; worden: ; ; TRG +----------+ ; ----+ +----- ; SW1 ----+ +---------- ; +-----+ ; ; hierdoor zal de controller volledig resetten !!