diff options
Diffstat (limited to 'src/engine/link/ir_core.asm')
-rw-r--r-- | src/engine/link/ir_core.asm | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/src/engine/link/ir_core.asm b/src/engine/link/ir_core.asm new file mode 100644 index 0000000..ab9eaae --- /dev/null +++ b/src/engine/link/ir_core.asm @@ -0,0 +1,531 @@ +; if carry flag is set, only delays +; if carry not set: +; - set rRP to $c1, wait; +; - set rRP to $c0, wait; +; - return +Func_19674: + jr c, .delay_once + ld [hl], $c1 + ld a, 5 + jr .loop_delay_1 ; jump to possibly to add more cycles? +.loop_delay_1 + dec a + jr nz, .loop_delay_1 + ld [hl], $c0 + ld a, 14 + jr .loop_delay_2 ; jump to possibly to add more cycles? +.loop_delay_2 + dec a + jr nz, .loop_delay_2 + ret + +.delay_once + ld a, 21 + jr .loop_delay_3 ; jump to possibly to add more cycles? +.loop_delay_3 + dec a + jr nz, .loop_delay_3 + nop + ret + +; input a = byte to transmit through IR +TransmitByteThroughIR: + push hl + ld hl, rRP + push de + push bc + ld b, a + scf ; carry set + call Func_19674 + or a ; carry not set + call Func_19674 + ld c, 8 + ld c, 8 ; number of input bits +.loop + ld a, $00 + rr b + call Func_19674 + dec c + jr nz, .loop + pop bc + pop de + pop hl + ldh a, [rJOYP] + bit 1, a ; P11 + jr z, ReturnZFlagUnsetAndCarryFlagSet + xor a ; return z set + ret + +; same as ReceiveByteThroughIR but +; returns $0 in a if there's an error in IR +ReceiveByteThroughIR_ZeroIfUnsuccessful: + call ReceiveByteThroughIR + ret nc + xor a + ret + +; returns carry if there's some time out +; and output in register a of $ff +; otherwise returns in a some sequence of bits +; related to how rRP sets/unsets bit 1 +ReceiveByteThroughIR: + push de + push bc + push hl + +; waits for bit 1 in rRP to be unset +; up to $100 loops + ld b, 0 + ld hl, rRP +.wait_ir + bit 1, [hl] + jr z, .ok + dec b + jr nz, .wait_ir + ; looped around $100 times + ; return $ff and carry set + pop hl + pop bc + pop de + scf + ld a, $ff + ret + +.ok +; delay for some cycles + ld a, 15 +.loop_delay + dec a + jr nz, .loop_delay + +; loop for each bit + ld e, 8 +.loop + ld a, $01 + ; possibly delay cycles? + ld b, 9 + ld b, 9 + ld b, 9 + ld b, 9 + +; checks for bit 1 in rRP +; if in any of the checks it is unset, +; then a is set to 0 +; this is done a total of 9 times + bit 1, [hl] + jr nz, .asm_196ec + xor a +.asm_196ec + bit 1, [hl] + jr nz, .asm_196f1 + xor a +.asm_196f1 + dec b + jr nz, .asm_196ec + ; one bit received + rrca + rr d + dec e + jr nz, .loop + ld a, d ; has bits set for each "cycle" that bit 1 was not unset + pop hl + pop bc + pop de + or a + ret + +ReturnZFlagUnsetAndCarryFlagSet: + ld a, $ff + or a ; z not set + scf ; carry set + ret + +; called when expecting to transmit data +Func_19705: + ld hl, rRP +.asm_19708 + ldh a, [rJOYP] + bit 1, a + jr z, ReturnZFlagUnsetAndCarryFlagSet + ld a, $aa ; request + call TransmitByteThroughIR + push hl + pop hl + call ReceiveByteThroughIR_ZeroIfUnsuccessful + cp $33 ; acknowledge + jr nz, .asm_19708 + xor a + ret + +; called when expecting to receive data +Func_1971e: + ld hl, rRP +.asm_19721 + ldh a, [rJOYP] + bit 1, a + jr z, ReturnZFlagUnsetAndCarryFlagSet + call ReceiveByteThroughIR_ZeroIfUnsuccessful + cp $aa ; request + jr nz, .asm_19721 + ld a, $33 ; acknowledge + call TransmitByteThroughIR + xor a + ret + +ReturnZFlagUnsetAndCarryFlagSet2: + jp ReturnZFlagUnsetAndCarryFlagSet + +TransmitIRDataBuffer: + call Func_19705 + jr c, ReturnZFlagUnsetAndCarryFlagSet2 + ld a, $49 + call TransmitByteThroughIR + ld a, $52 + call TransmitByteThroughIR + ld hl, wIRDataBuffer + ld c, 8 + jr TransmitNBytesFromHLThroughIR + +ReceiveIRDataBuffer: + call Func_1971e + jr c, ReturnZFlagUnsetAndCarryFlagSet2 + call ReceiveByteThroughIR + cp $49 + jr nz, ReceiveIRDataBuffer + call ReceiveByteThroughIR + cp $52 + jr nz, ReceiveIRDataBuffer + ld hl, wIRDataBuffer + ld c, 8 + jr ReceiveNBytesToHLThroughIR + +; hl = start of data to transmit +; c = number of bytes to transmit +TransmitNBytesFromHLThroughIR: + ld b, $0 +.loop_data_bytes + ld a, b + add [hl] + ld b, a + ld a, [hli] + call TransmitByteThroughIR + jr c, .asm_1977c + dec c + jr nz, .loop_data_bytes + ld a, b + cpl + inc a + call TransmitByteThroughIR +.asm_1977c + ret + +; hl = address to write received data +; c = number of bytes to be received +ReceiveNBytesToHLThroughIR: + ld b, 0 +.loop_data_bytes + call ReceiveByteThroughIR + jr c, ReturnZFlagUnsetAndCarryFlagSet2 + ld [hli], a + add b + ld b, a + dec c + jr nz, .loop_data_bytes + call ReceiveByteThroughIR + add b + or a + jr nz, ReturnZFlagUnsetAndCarryFlagSet2 + ret + +; disables interrupts, and sets joypad and IR communication port +; switches to CGB normal speed +StartIRCommunications: + di + call SwitchToCGBNormalSpeed + ld a, P14 + ldh [rJOYP], a + ld a, $c0 + ldh [rRP], a + ret + +; reenables interrupts, and switches CGB back to double speed +CloseIRCommunications: + ld a, P14 | P15 + ldh [rJOYP], a +.wait_vblank_on + ldh a, [rSTAT] + and STAT_LCDC_STATUS + cp STAT_ON_VBLANK + jr z, .wait_vblank_on +.wait_vblank_off + ldh a, [rSTAT] + and STAT_LCDC_STATUS + cp STAT_ON_VBLANK + jr nz, .wait_vblank_off + call SwitchToCGBDoubleSpeed + ei + ret + +; set rRP to 0 +ClearRP: + ld a, $00 + ldh [rRP], a + ret + +; expects to receive a command (IRCMD_* constant) +; in wIRDataBuffer + 1, then calls the subroutine +; corresponding to that command +ExecuteReceivedIRCommands: + call StartIRCommunications +.loop_commands + call ReceiveIRDataBuffer + jr c, .error + jr nz, .loop_commands + ld hl, wIRDataBuffer + 1 + ld a, [hl] + ld hl, .CmdPointerTable + cp NUM_IR_COMMANDS + jr nc, .loop_commands ; invalid command + call .JumpToCmdPointer ; execute command + jr .loop_commands +.error + call CloseIRCommunications + xor a + scf + ret + +.JumpToCmdPointer + add a ; *2 + add l + ld l, a + ld a, 0 + adc h + ld h, a + ld a, [hli] + ld h, [hl] + ld l, a +.jp_hl + jp hl + +.CmdPointerTable + dw .Close ; IRCMD_CLOSE + dw .ReturnWithoutClosing ; IRCMD_RETURN_WO_CLOSING + dw .TransmitData ; IRCMD_TRANSMIT_DATA + dw .ReceiveData ; IRCMD_RECEIVE_DATA + dw .CallFunction ; IRCMD_CALL_FUNCTION + +; closes the IR communications +; pops hl so that the sp points +; to the return address of ExecuteReceivedIRCommands +.Close + pop hl + call CloseIRCommunications + or a + ret + +; returns without closing the IR communications +; will continue the command loop +.ReturnWithoutClosing + or a + ret + +; receives an address and number of bytes +; and transmits starting at that address +.TransmitData + call Func_19705 + ret c + call LoadRegistersFromIRDataBuffer + jp TransmitNBytesFromHLThroughIR + +; receives an address and number of bytes +; and writes the data received to that address +.ReceiveData + call LoadRegistersFromIRDataBuffer + ld l, e + ld h, d + call ReceiveNBytesToHLThroughIR + jr c, .asm_19812 + sub b + call TransmitByteThroughIR +.asm_19812 + ret + +; receives an address to call, then stores +; the registers in the IR data buffer +.CallFunction + call LoadRegistersFromIRDataBuffer + call .jp_hl + call StoreRegistersInIRDataBuffer + ret + +; returns carry set if request sent was not acknowledged +TrySendIRRequest: + call StartIRCommunications + ld hl, rRP + ld c, 4 +.send_request + ld a, $aa ; request + push bc + call TransmitByteThroughIR + push bc + pop bc + call ReceiveByteThroughIR_ZeroIfUnsuccessful + pop bc + cp $33 ; acknowledgement + jr z, .received_ack + dec c + jr nz, .send_request + scf + jr .close + +.received_ack + xor a +.close + push af + call CloseIRCommunications + pop af + ret + +; returns carry set if request was not received +TryReceiveIRRequest: + call StartIRCommunications + ld hl, rRP +.wait_request + call ReceiveByteThroughIR_ZeroIfUnsuccessful + cp $aa ; request + jr z, .send_ack + ldh a, [rJOYP] + cpl + and P10 | P11 + jr z, .wait_request + scf + jr .close + +.send_ack + ld a, $33 ; acknowledgement + call TransmitByteThroughIR + xor a +.close + push af + call CloseIRCommunications + pop af + ret + +; sends request for other device to close current communication +RequestCloseIRCommunication: + call StartIRCommunications + ld a, IRCMD_CLOSE + ld [wIRDataBuffer + 1], a + call TransmitIRDataBuffer +; fallthrough + +; calls CloseIRCommunications while preserving af +SafelyCloseIRCommunications: + push af + call CloseIRCommunications + pop af + ret + +; sends a request for data to be transmitted +; from the other device +; hl = start of data to request to transmit +; de = address to write data received +; c = length of data +RequestDataTransmissionThroughIR: + ld a, IRCMD_TRANSMIT_DATA + call TransmitRegistersThroughIR + push de + push bc + call Func_1971e + pop bc + pop hl + jr c, SafelyCloseIRCommunications + call ReceiveNBytesToHLThroughIR + jr SafelyCloseIRCommunications + +; transmits data to be written in the other device +; hl = start of data to transmit +; de = address for other device to write data +; c = length of data +RequestDataReceivalThroughIR: + ld a, IRCMD_RECEIVE_DATA + call TransmitRegistersThroughIR + call TransmitNBytesFromHLThroughIR + jr c, SafelyCloseIRCommunications + call ReceiveByteThroughIR + jr c, SafelyCloseIRCommunications + add b + jr nz, .asm_1989e + xor a + jr SafelyCloseIRCommunications +.asm_1989e + call ReturnZFlagUnsetAndCarryFlagSet + jr SafelyCloseIRCommunications + +; first stores all the current registers in wIRDataBuffer +; then transmits it through IR +TransmitRegistersThroughIR: + push hl + push de + push bc + call StoreRegistersInIRDataBuffer + call StartIRCommunications + call TransmitIRDataBuffer + pop bc + pop de + pop hl + ret nc + inc sp + inc sp + jr SafelyCloseIRCommunications + +; stores af, hl, de and bc in wIRDataBuffer +StoreRegistersInIRDataBuffer: + push de + push hl + push af + ld hl, wIRDataBuffer + pop de + ld [hl], e ; <- f + inc hl + ld [hl], d ; <- a + inc hl + pop de + ld [hl], e ; <- l + inc hl + ld [hl], d ; <- h + inc hl + pop de + ld [hl], e ; <- e + inc hl + ld [hl], d ; <- d + inc hl + ld [hl], c ; <- c + inc hl + ld [hl], b ; <- b + ret + +; loads all the registers that were stored +; from StoreRegistersInIRDataBuffer +LoadRegistersFromIRDataBuffer: + ld hl, wIRDataBuffer + ld e, [hl] + inc hl + ld d, [hl] + inc hl + push de + ld e, [hl] + inc hl + ld d, [hl] + inc hl + push de + ld e, [hl] + inc hl + ld d, [hl] + inc hl + ld c, [hl] + inc hl + ld b, [hl] + pop hl + pop af + ret |