; ========================================================= ; Module: SonyIR ; ========================================================= ; Description: ; Read or write data using the Sony infrared controller ; protocol. ; Remarks: ; You must have 21 bytes of free RAM to store incoming ; data. Calculator must be running at 6MHz. ; See the manual for circuit information. ; ========================================================= .module SonyIR ; ......................................................... ; 21 bytes free RAM used to store pulse lengths. ; ......................................................... InputBuffer = OP1 ; ......................................................... ; Based on longest and shortest times left from tests on ; my calculator; what is the threshold between long and ; short pulses? ; ......................................................... PulseLong = 146 PulseShort = 40 PulseThreshold = (PulseLong + PulseShort) / 2 ; --------------------------------------------------------- ; Read -> Receives data from a Sony IR remote control. ; --------------------------------------------------------- ; Outputs: z on success, nz on failure. ; de = target device ID (variable bit length). ; c = command. ; a = length of command word (bits). ; Destroys: af, bc, de, hl. ; Remarks: Disables interrupts. ; --------------------------------------------------------- Read di ld hl,InputBuffer ; Maximum of 21 pulses (e will count the pulses found). ; We try to read one too many (and force timeout). ld de,22*256 GetBit ld b,0 - in a,(bport) rra jr nc,GotPulseLength djnz - ; Timeout! jr GotAllBits GotPulseLength ld b,0 - in a,(bport) rra jr c,GotBit djnz - ; Timeout! jr GotAllBits GotBit ld (hl),b inc hl inc e dec d jr nz,GetBit GotAllBits ld a,e ; How many bits did we *really* receive? cp 13 jr z,BitCountOK cp 16 jr z,BitCountOK cp 21 ret nz ; Not one of the allowed values... BitCountOK push af ; Save for later. ld de,0 ; DE = DEvice. :) ld c,0 ; C = read byte. ld hl,InputBuffer+1 ; Skip start bit. ld b,7 ; Always 7 data bits. - ld a,(hl) inc hl cp PulseThreshold rr c djnz - srl c pop af ; Received bits push af ; ie, 21 = 20 bits, 16 = 15 bits, 13 = 12 bits. sub 8 ld b,a ; Shift in the device ID - ld a,(hl) inc hl cp PulseThreshold rr d \ rr e djnz - ; At this point we need to align the data: pop af push af ld b,a ld a,24 sub b ld b,a - srl d \ rr e djnz - pop af dec a cp a ; Z ret ; ......................................................... ; 38kHz burst lengths (loops) ; ......................................................... CarrierFrequency = 40 .if CarrierFrequency == 38 PulseOut0 = 23 ; 0.6mS PulseOut1 = 46 ; 1.2mS PulseOutStart = 91 ; 2.4mS .elseif CarrierFrequency == 40 PulseOut0 = 24 ; 0.6mS PulseOut1 = 48 ; 1.2mS PulseOutStart = 97 ; 2.4mS .else .echoln "Carrier frequency must be 38kHz or 40kHz." .endif ; Assuming a 6MHz CPU speed and a 38kHz signal; ; To send a modulated signal you'd have to toggle the LED at 76kHz. ; That's 6E6 / 76E3 = 78.95 clock cycles. ; Each cycle is 26µS long. ; "Loops" correspond to how many times the LED is flashed on and off. ; To get a 0.6mS long pulse, you'd need 22.8 loops. ; To get a 1.2mS long pulse, you'd need 45.6 loops. ; To get a 2.4mS long pulse, you'd need 91.2 loops. ; Between pulses is a 0.6mS delay, which corresponds to 3600 clock cycles. ; --------------------------------------------------------- ; Write -> Send data using the Sony IR controller protocol. ; --------------------------------------------------------- ; Inputs: de = target device ID (variable bit length). ; c = command. ; a = length of command word (bits). ; Destroys: af, bc, de, hl. ; Remarks: Disables interrupts. Bits that are not to be ; sent should be reset (eg command should only ; be in the 0..127 range). Setting them can ; result in inaccurate timing. ; --------------------------------------------------------- Write di ; EHL = complete bitstream. ; D = bits. ; So here follows the usual bit packing nonsense). ld l,c sla l ld h,e ld e,d srl e rr h rr l ld d,a ld (InputBuffer+0),hl ld (InputBuffer+2),de ld b,PulseOutStart call IrPulseOut ; 10 ;(18*13+8)+(256*13+8)+7+10+7=3602 SendDataLoop rr e ; 8 rr h ; 8 rr l ; 8 jr c, Send1 Send0 ; At this point: total CCs = 7+8+8+8 ld b,PulseOut0 ; 7 jr PickedPulseLength ; 12 Send1 ; At this point: total CCs = 12+8+8+8 ld b,PulseOut1 ; 7 ld b,PulseOut1 ; 7 PickedPulseLength ; Total delay: 50 clocks. push bc ; 11 ; ; 50+11+10+27+6+12 = 108. ; 3600-108 = 3492 ; (3492-(8*2)-7)/13 = 266.8 ; 267-256 = 11 ld b,13 - djnz - - djnz - pop bc ; 10 call IrPulseOut ; 17+10=27 (call+ret overhead). dec d ; 6 jr nz,SendDataLoop ; 12 ret ; (Internal) output a pulse of modulated signal. ; In: b = length of burst. IrPulseOut -- ld c,b ld a,%11010010 out (bport),a .if CarrierFrequency == 38 ld b,4 - djnz - ld b,0 .else ld b,3 - nop djnz - nop .endif ld a,%11010000; 7 out (bport),a ; 11 .if CarrierFrequency == 38 ld b,2 ; 7 nop neg - djnz - ; (13*b)+8 .else ld b,2 neg - djnz - .endif ld b,c ; 4 djnz -- ; 13 ret ; 10 ; --------------------------------------------------------- ; WriteMultiple -> Send data multiple times. ; --------------------------------------------------------- ; Inputs: de = target device ID (variable bit length). ; c = command. ; a = length of command word (bits). ; b = number of times to send the data. ; Destroys: f, b, hl. ; Remarks: Disables interrupts. Bits that are not to be ; sent should be reset (eg command should only ; be in the 0..127 range). Setting them can ; result in inaccurate timing. ; --------------------------------------------------------- WriteMultiple push de push bc push af call Write ; Calculate the total length of the signal: ld a,0 ld b,16 ld hl,(InputBuffer+0) call CountCommandLength ld b,8 ld hl,(InputBuffer+2) call CountCommandLength ; Now, we didn't use ALL of that signal... ld b,a pop af push af ld c,a ld a,24 sub c add a,a ld c,a ld a,b sub c ld b,a ; B is the length of the pulse. ; Maximum length: 3*20 = 60. Add ten to pad out to ~45mS total. ld a,60+10 sub b ld b,a -- push bc ld b,19 - djnz - - djnz - pop bc djnz -- ; Last (but not least!) a little extra padding to bring us up to the full 45mS. ld b,115 - djnz - pop af pop bc pop de djnz WriteMultiple ret ; (Internal) Count the length of a command in 0.6mS steps. ; In: HL = bitstream. B = Number least significant bits to test. ; Out: A is incremented by (3*set bits)+(2*reset bits). CountCommandLength - rr h \ rr l jr c, Sent1 Sent0 ; We sent a zero (2) ld c,2 jr + Sent1 ; We sent a 1 (3). ld c,3 ld c,3 + add a,c djnz - ret .endmodule