;This allows you to log I/O traffic between two TI devices (such as two I/O-connected calculators). ; ;It works by using two 84+/SEs: ; ;(Device 1) <- I/O cable -> 84+/SE #1 <- direct USB cable -> 84+/SE #2 <- I/O cable -> (Device 2) ; ;The two USB-connected 84+/SEs pass I/O traffic back and forth between Device 1 and Device 2. ;Devices 1 and 2 can be TI graphing calculators, a PC/Mac, TI Presenter, CBL/CBR 1/2, etc. ; ;It only works with devices that use TI's I/O link protocol. ; ;This was useful in determining the link protocol that the TI Presenter uses for firmware updates from a computer. ;Hopefully it's useful to you, too. .nolist #include "ti83plus.inc" .list hookBackup equ appBackUpScreen SPbackup equ hookBackup+4 hookLoc equ 9BD4h hookFlag equ flags+3Ah myFlags equ asm_Flag1 busyReceivingIO equ 0 .org userMem-2 .db 0BBh,6Dh ld (iy+myFlags),0 ;Install an error handler in case anything goes wrong ld hl,mainLoop ;endProgram call APP_PUSH_ERRORH ;Back up the existing USB activity hook ld hl,hookLoc ld de,hookBackup ld bc,4 ldir ld hl,hookFlag ldi ;Install our own USB activity hook ld hl,myUSBActivityHook in a,(6) bcall(528Ah) ;Set up the LCD bcall(_clrLCDFull) bcall(_homeUp) ;Initialize the USB device bcall(5290h) jp c,endProgram mainLoop: ;Attempt to receive data over I/O ld (SPbackup),sp mainLoopRestart: in a,(4) bit 3,a jp z,endProgram res busyReceivingIO,(iy+myFlags) ld a,6 bcall(_PutC) bcall(_Rec1stByteNC) set busyReceivingIO,(iy+myFlags) ld (header),a ;We've started receiving data, so get the whole packet bcall(_RecAByteIO) ld (header+1),a call DispHexA cp 0A2h jr nz,noA2 bcall(_clrLCDFull) bcall(_homeUp) noA2: bcall(_RecAByteIO) ld (header+2),a bcall(_RecAByteIO) ld (header+3),a ;See if this is a known packet with data attached ld bc,0 ld a,(header+1) call IsDataPacket jr nz,forwardReceivedPacket ;Receive the rest of the data packet ld bc,(header+2) push bc ld hl,4004h jr receiveRestStart receiveRestLoop: push bc push hl bcall(_RecAByteIO) pop hl call WriteByteHLZone1 pop bc dec bc receiveRestStart: ld a,b or c jr nz,receiveRestLoop push hl bcall(_RecAByteIO) pop hl call WriteByteHLZone1 push hl bcall(_RecAByteIO) pop hl call WriteByteHLZone1 pop bc inc bc inc bc forwardReceivedPacket: ld hl,4 add hl,bc push hl ;Put the first 4 bytes at RAM page 83h in a,(6) push af ld a,83h out (6),a ld hl,header ld de,4000h ld bc,4 ldir pop af out (6),a pop de ;Send this packet as USB data so the other calculator can forward it ld hl,8000h call SendUSBData ld a,7 bcall(_PutC) jp mainLoop ; jp nc,mainLoop ; bjump(_ErrLinkXmit) myUSBActivityHook: add a,e ld b,2Ch in a,(55h) bit 4,a ret nz ;let the TI-OS deal with anything that's not incoming data ;See if this is bulk data we care about in a,(84h) and 0FEh ret z ;let the TI-OS deal with incoming control data in a,(94h) bit 2,a jr nz,abortUSBHook bit 6,a jr nz,abortUSBHook ;Read the incoming USB data and forward it along ld hl,cancelUSBHook call APP_PUSH_ERRORH call HandleUSBBulkData call APP_POP_ERRORH cancelUSBHook: ;Cancel the USB hook ; xor a ; out (94h),a ld b,0 ld sp,(SPbackup) jp mainLoopRestart abortUSBHook: ; xor a ; out (94h),a ld b,0 ret HandleUSBBulkData: ;Receive the USB data ld a,5 bcall(_PutC) set 5,(iy+41h) ld hl,header ld bc,4 call ReceiveUSBData call Send4Bytes ld bc,0 ld a,(header+1) call DispHexA call IsDataPacket ret nz ;Receive the rest of the data packet ld bc,(header+2) inc bc inc bc push bc pop hl call DispHexHL jr receiveRestUSBStart receiveRestUSBLoop: push bc ld hl,appData+4 ld bc,1 call ReceiveUSBData ld a,(appData+4) bcall(_SendAByte) pop bc dec bc receiveRestUSBStart: ld a,b or c ret z jr receiveRestUSBLoop endProgram: ;Restore the old USB activity hook, if there was one call APP_POP_ERRORH ld hl,hookBackup ld de,hookLoc ld bc,4 ldir ld de,hookFlag ldi res onInterrupt,(iy+onFlags) res indicOnly,(iy+indicFlags) ;Kill USB bcall(5293h) ret Send4Bytes: ld a,(header) bcall(_SendAByte) ld a,(header+1) bcall(_SendAByte) ld a,(header+2) bcall(_SendAByte) ld a,(header+3) bcall(_SendAByte) ret IsDataPacket: ;TODO: this is going to have to be fleshed out and/or changed a lot cp 06h ret z cp 0C9h ret z cp 0CAh ret z cp 0A2h ret z cp 15h ret WriteByteHLZone1: ld b,a in a,(6) push af ld a,83h out (6),a ld a,b ld (hl),a inc hl pop af out (6),a ret ;---------------------------------------------------------------------------- ;SendUSBData: ;Sends data over USB. ;Inputs: HL => pointer in zone 1 (RAM pages 3\2) of data to send. ; DE: number of bytes to send. ;Outputs: DE bytes sent from HL. ; Carry flag set if any issues. SendUSBData: res 0,(iy+43h) bcall(50F2h) res 0,(iy+41h) res 5,(iy+41h) ret ;---------------------------------------------------------------------------- ;ReceiveUSBDataWait: ;Receives data over USB (waits until data is received). ;Inputs: HL => pointer in RAM to store data to. ; BC: number of bytes to receive. ;Outputs: BC bytes received to HL. ; Carry flag set if any issues. ;Make sure you know how much you need to be receiving before calling. ;This is a blocking call and will not return until everything is received. ReceiveUSBDataWait: ei halt in a,(4) bit 3,a scf ret z bit 5,(iy+41h) jr z,ReceiveUSBDataWait ;---------------------------------------------------------------------------- ;ReceiveUSBData: ;Receives data over USB. ;Inputs: 5,(iy+41h) set by OS. ; HL => pointer in RAM to store data to. ; BC: number of bytes to receive. ;Outputs: BC bytes received to HL. ; Carry flag set if any issues. ;Make sure you know how much you need to be receiving before calling. ReceiveUSBData: push bc push af xor a ld (9834h),a jr receive_data_ready receive_big_loop: in a,(4) bit 3,a jr z,P2scfRet bit 5,(iy+41h) jr nz,receive_data_ready in a,(84h) bit 2,a jr nz,receiving_data bit 1,a jr z,restart_receive_loop receiving_data: set 5,(iy+41h) xor a ld (9C27h),a jr receive_data_ready restart_receive_loop: in a,(86h) bit 5,a jr nz,P2scfRet jr receive_big_loop receive_data_ready: push bc push hl ld hl,40h or a sbc hl,bc pop hl ld b,c jr nc,receiveRest ld b,40h receiveRest: call ReceiveUSBData_small ex de,hl pop hl jr c,P2scfRet or a ld b,0 sbc hl,bc jr z,P2ret ld b,h ld c,l ex de,hl jr receive_big_loop P2ret: pop bc ld a,b pop bc ret P2scfRet: pop af pop bc scf ret ReceiveUSBData_small: ld a,b or a ret z ld a,40h cp b ret c ld a,b ld (9C80h),a ld a,(9C27h) or a jr z,ReceiveUSBData_continue cp b jr nc,ReceiveUSBData_continue ld b,a ld (9C80h),a ReceiveUSBData_continue: in a,(8Fh) bit 2,a jp z,calcIsPeripheral xor a out (5Bh),a ld a,(9C27h) or a jr nz,startReceive ld a,1 out (8Eh),a ld a,21h out (9Ah),a xor a in a,(9Ah) ld a,8 out (93h),a xor a in a,(93h) ld a,0FFh out (89h),a xor a out (95h),a in a,(89h) ld a,0A1h out (8Bh),a in a,(94h) bit 2,a jp nz,receiveError bit 6,a jp nz,receiveError ld a,1 out (5Bh),a ld a,(9C27h) or a jr nz,startReceive ld a,1 out (8Eh),a in a,(94h) in a,(96h) startReceive: push af ld a,(9C80h) ld b,a ld c,0 receiveLoop: in a,(0A1h) ld (hl),a inc hl inc c djnz receiveLoop ld a,1 out (8Eh),a in a,(94h) bit 2,a jr nz,p1ReceiveError bit 6,a jr nz,p1ReceiveError pop af sub c ld (9C27h),a set 5,(iy+41h) ret nz ld a,1 out (8Eh),a ld a,21h out (9Ah),a ld a,8 out (93h),a xor a in a,(93h) ld a,0Eh out (89h),a xor a out (95h),a res 5,(iy+41h) xor a ld (9C27h),a res 0,(iy+41h) ld a,20h out (94h),a ld a,1 out (5Bh),a ret calcIsPeripheral: ld a,2 out (8Eh),a in a,(94h) bit 6,a jr z,startReceive2 and 0DFh out (94h),a pop af bcall(5257h) ;_KillUSBDevice jr receiveError startReceive2: ld a,(9C27h) or a jr nz,startReceive3 in a,(96h) startReceive3: push af ld c,0 receivePeriphLoop: in a,(0A2h) ld (hl),a inc hl inc c djnz receivePeriphLoop ld a,2 out (8Eh),a pop af sub c ld (9C27h),a ret nz xor a ld (9C27h),a in a,(94h) and 0FEh out (94h),a res 5,(iy+41h) ld a,0A1h ld (8Bh),a jr endReceive p1ReceiveError: pop af receiveError: res 5,(iy+41h) scf endReceive: ei ld a,1 out (5Bh),a res 0,(iy+41h) ret ;---------------------------------------------------------------------------- #include "util.asm" .end end