summaryrefslogtreecommitdiff
path: root/home/serial.asm
diff options
context:
space:
mode:
Diffstat (limited to 'home/serial.asm')
-rw-r--r--home/serial.asm299
1 files changed, 296 insertions, 3 deletions
diff --git a/home/serial.asm b/home/serial.asm
index 48d6832..d51e5a6 100644
--- a/home/serial.asm
+++ b/home/serial.asm
@@ -16,7 +16,7 @@ Serial::
ldh a, [hSerialSend]
ld [rSB], a
ldh a, [hLinkPlayerNumber]
- cp 2
+ cp USING_INTERNAL_CLOCK
jr z, .done
ld a, 1 << rSC_ON
ld [rSC], a
@@ -26,7 +26,7 @@ Serial::
ld a, [rSB]
ldh [hSerialReceive], a
ldh [hLinkPlayerNumber], a
- cp 2
+ cp USING_INTERNAL_CLOCK
jr z, .master
xor a
ld [rSB], a
@@ -43,7 +43,7 @@ Serial::
xor a
ld [rSB], a
.done
- ld a, 1
+ ld a, TRUE
ldh [hSerialReceived], a
ld a, SERIAL_NO_DATA_BYTE
ldh [hSerialSend], a
@@ -52,3 +52,296 @@ Serial::
pop bc
pop af
reti
+
+Serial_ExchangeBytes:: ; 64c
+ ld a, $1
+ ldh [hSerialIgnoringInitialData], a
+.loop
+ ld a, [hl]
+ ldh [hSerialSend], a
+ call Serial_ExchangeByte
+ push bc
+ ld b, a
+ inc hl
+ ld a, $30
+.wait
+ dec a
+ jr nz, .wait
+ ldh a, [hSerialIgnoringInitialData]
+ and a
+ ld a, b
+ pop bc
+ jr z, .load
+ dec hl
+ cp SERIAL_PREAMBLE_BYTE
+ jr nz, .loop
+ xor a
+ ldh [hSerialIgnoringInitialData], a
+ jr .loop
+
+.load
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+Serial_ExchangeByte:: ; 677 (0:0677)
+.loop
+ xor a
+ ldh [hSerialReceived], a
+ ldh a, [hLinkPlayerNumber]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .not_player_2
+ ld a, (1 << rSC_ON) | 1
+ ldh [rSC], a
+.not_player_2
+.loop2
+ ldh a, [hSerialReceived]
+ and a
+ jr nz, .reset_ffca
+ ldh a, [hLinkPlayerNumber]
+ cp $1
+ jr nz, .not_player_1_or_wLinkTimeoutFrames_zero
+ call CheckwLinkTimeoutFramesNonzero
+ jr z, .not_player_1_or_wLinkTimeoutFrames_zero
+ call .delay_15_cycles
+ push hl
+ ld hl, wLinkTimeoutFrames + 1
+ inc [hl]
+ jr nz, .no_rollover_up
+ dec hl
+ inc [hl]
+
+.no_rollover_up
+ pop hl
+ call CheckwLinkTimeoutFramesNonzero
+ jr nz, .loop2
+ jp SerialDisconnected
+
+.not_player_1_or_wLinkTimeoutFrames_zero
+ ldh a, [rIE]
+ and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
+ cp 1 << SERIAL
+ jr nz, .loop2
+ ld a, [wcb58]
+ dec a
+ ld [wcb58], a
+ jr nz, .loop2
+ ld a, [wcb58 + 1]
+ dec a
+ ld [wcb58 + 1], a
+ jr nz, .loop2
+ ldh a, [hLinkPlayerNumber]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .reset_ffca
+
+ ld a, 255
+.delay_255_cycles
+ dec a
+ jr nz, .delay_255_cycles
+
+.reset_ffca
+ xor a
+ ldh [hSerialReceived], a
+ ldh a, [rIE]
+ and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
+ sub 1 << SERIAL
+ jr nz, .rIE_not_equal_8
+
+ ; LOW($5000)
+ ld [wcb58], a
+ ld a, HIGH($5000)
+ ld [wcb58 + 1], a
+
+.rIE_not_equal_8
+ ldh a, [hSerialReceive]
+ cp SERIAL_NO_DATA_BYTE
+ ret nz
+ call CheckwLinkTimeoutFramesNonzero
+ jr z, .linkTimeoutFrames_zero
+ push hl
+ ld hl, wLinkTimeoutFrames + 1
+ ld a, [hl]
+ dec a
+ ld [hld], a
+ inc a
+ jr nz, .no_rollover
+ dec [hl]
+
+.no_rollover
+ pop hl
+ call CheckwLinkTimeoutFramesNonzero
+ jr z, SerialDisconnected
+
+.linkTimeoutFrames_zero
+ ldh a, [rIE]
+ and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
+ cp 1 << SERIAL
+ ld a, SERIAL_NO_DATA_BYTE
+ ret z
+ ld a, [hl]
+ ldh [hSerialSend], a
+ call DelayFrame
+ jp .loop
+
+.delay_15_cycles: ; 70e (0:070e)
+ ld a, 15
+.delay_cycles
+ dec a
+ jr nz, .delay_cycles
+ ret
+
+CheckwLinkTimeoutFramesNonzero: ; 714 (0:0714)
+ push hl
+ ld hl, wLinkTimeoutFrames
+ ld a, [hli]
+ or [hl]
+ pop hl
+ ret
+
+SerialDisconnected: ; 71c (0:071c)
+ dec a
+ ld [wLinkTimeoutFrames], a
+ ld [wLinkTimeoutFrames + 1], a
+ ret
+
+; This is used to exchange the button press and selected menu item on the link menu.
+; The data is sent thrice and read twice to increase reliability.
+Serial_ExchangeLinkMenuSelection::
+ ld hl, wPlayerLinkAction
+ ld de, wOtherPlayerLinkMode
+ ld c, 2
+ ld a, TRUE
+ ldh [hSerialIgnoringInitialData], a
+.asm_0730
+ call DelayFrame
+ ld a, [hl]
+ ldh [hSerialSend], a
+ call Serial_ExchangeByte
+ ld b, a
+ inc hl
+ ldh a, [hSerialIgnoringInitialData]
+ and a
+ ld a, FALSE
+ ldh [hSerialIgnoringInitialData], a
+ jr nz, .asm_0730
+ ld a, b
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .asm_0730
+ ret
+
+Serial_PrintWaitingTextAndSyncAndExchangeNybble::
+ call BackUpTilesToBuffer
+ callab PlaceWaitingText
+ call WaitLinkTransfer
+ jp ReloadTilesFromBuffer
+
+WaitLinkTransfer:: ; 75c (0:075c)
+ ld a, $ff
+ ld [wOtherPlayerLinkAction], a
+.loop
+ call LinkTransfer
+ call DelayFrame
+ call CheckwLinkTimeoutFramesNonzero
+ jr z, .check
+ push hl
+ ld hl, wLinkTimeoutFrames + 1
+ dec [hl]
+ jr nz, .skip
+ dec hl
+ dec [hl]
+ jr nz, .skip
+ ; We might be disconnected
+ pop hl
+ xor a
+ jp SerialDisconnected
+
+.skip
+ pop hl
+.check
+ ld a, [wOtherPlayerLinkAction]
+ inc a
+ jr z, .loop
+
+ ld b, 10
+.receive
+ call DelayFrame
+ call LinkTransfer
+ dec b
+ jr nz, .receive
+
+ ld b, 10
+.acknowledge
+ call DelayFrame
+ call LinkDataReceived
+ dec b
+ jr nz, .acknowledge
+
+ ld a, [wOtherPlayerLinkAction]
+ ld [wOtherPlayerLinkMode], a
+ ret
+
+LinkTransfer:: ; 7a0 (0:07a0)
+ push bc
+ ld b, $60
+ ld a, [wLinkMode]
+ cp $2
+ jr c, .asm_07ac
+ ld b, $70
+
+.asm_07ac
+ call .Receive
+ ld a, [wPlayerLinkAction]
+ add b
+ ldh [hSerialSend], a
+ ldh a, [hLinkPlayerNumber]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .player_1
+ ld a, (1 << rSC_ON) | 1
+ ldh [rSC], a
+
+.player_1
+ call .Receive
+ pop bc
+ ret
+
+.Receive: ; 7c4 (0:07c4)
+ ldh a, [hSerialReceive]
+ ld [wOtherPlayerLinkMode], a
+ and $f0
+ cp b
+ ret nz
+ xor a
+ ldh [hSerialReceive], a
+ ld a, [wOtherPlayerLinkMode]
+ and $f
+ ld [wOtherPlayerLinkAction], a
+ ret
+
+LinkDataReceived:: ; 7d9 (0:07d9)
+; Let the other system know that the data has been received.
+ xor a
+ ldh [hSerialSend], a
+ ldh a, [hLinkPlayerNumber]
+ cp USING_INTERNAL_CLOCK
+ ret nz
+ ld a, (1 << rSC_ON) | 1
+ ldh [rSC], a
+ ret
+
+Unreferenced_Function7e6::
+ ld a, [wLinkMode]
+ and a
+ ret nz
+ ld a, USING_INTERNAL_CLOCK
+ ldh [rSB], a
+ xor a
+ ldh [hSerialReceive], a
+ ld a, (1 << rSC_ON)
+ ldh [rSC], a
+ ret