;----------------------------------------------------------------\r
; TODO\r
;----------------------------------------------------------------\r
+; Check how the slave should sense "power off" de-selection. Now it continues to play, as the slave doesn't stop requesting updates!\r
; Investigate whether I actually have to save PCLATH in ISH, maybe save FSR? - Not saving any of them for now\r
; Check Overrun errors from the UART\r
-; Implement lots of other Unilink commands (Text display, time display etc.)\r
; Implement the Watchdog Timer (might be useful even though I haven't seen it hang yet..)\r
; Make the bit shift routine at the beginning of the ISR timeout if the clock suddenly stops (in the middle of a byte)\r
; (will keep it from hanging until the next bit gets clocked out, just ignore the faulty bits and carry on)\r
-; Implement command b0 0x (change CD to x (1-a))\r
+; Implement command b0 0x (change CD to x (1-a))?\r
; Implement command 08 10 (Tel Mute on) and 08 18 (Tel Mute off)?\r
\r
;----------------------------------------------------------------\r
;----------------------------------------------------------------\r
; Version\r
;\r
+; 0.9 Interrupt driven UART RX for status updates, using raw unilink packets for everything else, dynamic text\r
; 0.8 Some text commands implemented, only static text for now though\r
; 0.7 Debug Serial TX in ISR now, checksum check for incoming packets in place, A/D works, solved the master reset prob\r
; (by calling the INT handler from TMR2 ISR code (too much interrupt latency when transmitting)\r
;----------------------------------------------------------------\r
; FILE REGISTER USAGE\r
;----------------------------------------------------------------\r
-; Free from 20h-4fh\r
+\r
+; Free from 20h-48h\r
+\r
+TrackName equ 20h\r
+TracknameEnd equ 3eh\r
+\r
+DiscName equ 3fh\r
+DiscNameEnd equ 48h\r
+\r
+CurDisc equ 49h\r
+CurTrack equ 4ah\r
+CurMins equ 4bh\r
+CurSecs equ 4ch\r
+\r
+RecvType equ 4dh\r
+TargetPos equ 4eh\r
+CurRecvPos equ 4fh\r
\r
UnilinkRAD equ 50h ; Beginning of Unilink packet - the Receiving Address\r
UnilinkTAD equ 51h ; Transmitter address\r
IRQSTATUS equ 7eh ; Needs to be located in a shared area accessible from all register banks\r
IRQW equ 7fh ; \r
\r
-RecvBuf equ 0a0h ; Buffer for received data from PC (31 bytes)\r
-RecvBufLen equ 0bfh ; How many bytes have been received?\r
+RecvBuf equ 0a0h ; Buffer for received data from PC (32 bytes)\r
+RecvBufEnd equ 0bfh ;\r
\r
subtitl "Startup"\r
page\r
\r
clrf SlaveBreakState\r
\r
-; incf Counter,f\r
+; incf Counter,f : Debug!\r
\r
btfss DisplayStatus,7 ; Only do this if high bit is set\r
goto IRQAfterTMR2\r
\r
IRQNotTMR2\r
\r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ btfss PIR1,RCIF ; Check if it's the UART RX interrupt\r
+ goto IRQNotRCIF ; No it's not, check the other sources\r
+;----------------------------------------------------------------\r
+; This is the UART RX routine, this should be control info from the connected PC we're receiving\r
+\r
+ movf CurRecvPos,w ; Load fsr\r
+ movwf FSR\r
+ movf RCREG,w ; Get the byte\r
+ bcf PIR1,RCIF ; Clear current interrupt condition\r
+ movwf INDF ; Store the recv byte at the position waiting\r
+ movlw RecvType\r
+ xorwf FSR,w ; Check if it's the recvtype coming in\r
+ bnz NotRecvType\r
+\r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ movf RecvType,w ; Load type\r
+ bz RecvTimeUpdate ; Position update\r
+ xorlw 1 ; Track Name perhaps?\r
+ bz RecvTrackName\r
+ xorlw 3 ; this is xor 1 and then xor 2, disc name?\r
+ bz RecvDiscName\r
+\r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ btfss RecvType,7 ; Check Hi byte\r
+ goto IRQNotRCIF\r
+\r
+ movf RecvType,w\r
+ xorlw 81h\r
+ bnz NotText\r
+\r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ movf RecvType,w\r
+ goto TextUpdate\r
+NotText\r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ movf RecvType,w\r
+ btfss DisplayStatus,7 ; Only if not updating already!\r
+TextUpdate\r
+ movwf DisplayStatus ; Force it into DisplayStatus\r
+ goto Finished\r
+ \r
+RecvTimeUpdate\r
+ movlw CurDisc ; Load DL start here\r
+ movwf CurRecvPos\r
+ movlw CurSecs+1 ; And stop here\r
+ movwf TargetPos\r
+ goto IRQNotRCIF\r
+\r
+RecvTrackName\r
+ movlw TrackName ; Load DL start here\r
+ movwf CurRecvPos\r
+ movlw TracknameEnd+1 ; And stop here\r
+ movwf TargetPos\r
+ goto IRQNotRCIF\r
+\r
+RecvDiscName\r
+ movlw DiscName ; Load DL start here\r
+ movwf CurRecvPos\r
+ movlw DiscNameEnd+1 ; And stop here\r
+ movwf TargetPos\r
+ goto IRQNotRCIF\r
+\r
+NotRecvType\r
+ incf CurRecvPos,f\r
+ \r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ movf CurRecvPos,w ; Check if we're done\r
+ xorwf TargetPos,w\r
+ bnz NotFinished\r
+Finished\r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+; movlw 81h ; Assume we do it from the beginning (text and pos)\r
+; movf RecvType,f ; Just check for time-update cmd\r
+; skpnz ; No adjustment if another cmd\r
+; movlw 85h ; Skip the first 4 display cmds\r
+; movwf DisplayStatus\r
+ \r
+; call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ movlw RecvType ; restore for another go\r
+ movwf CurRecvPos\r
+\r
+NotFinished\r
+\r
+IRQNotRCIF\r
+\r
+ call IRQCheckINT ; Check the Unilink INT as well\r
+\r
+ btfss PIR1,TXIF ; Check if it's the UART TX interrupt\r
+ goto IRQNotTXIF ; No it's not, check the other sources\r
+ bsf STATUS,RP0 ; Reg bank 1\r
+ btfss PIE1,TXIE ; As TXIF is set as long as nothing gets sent, is the interrupt actually enabled?\r
+ goto IRQTXIFDisabled\r
+;----------------------------------------------------------------\r
+; This is the UART TX routine, gets called when TXIE has been set and the TX load register is empty\r
+\r
+\r
+\r
+\r
+\r
+IRQTXIFDisabled\r
+ bcf STATUS,RP0 ; Make sure we're going back to reg bank 0\r
+\r
+IRQNotTXIF\r
+\r
; Finally restore CPU state and return from the ISR\r
\r
; If I have to save the FSR in the beginning I also need to restore it here...\r
movf UnilinkParity1,w ; Carry the parity forward\r
movwf UnilinkParity2M\r
\r
- movf DisplayStatus,w\r
+ movf CurTrack,w\r
addwf UnilinkParity2M,f\r
movwf UnilinkData1\r
- movlw 00h\r
+ movf CurMins,w\r
addwf UnilinkParity2M,f\r
movwf UnilinkData2\r
- movlw 01h\r
+ movf CurSecs,w\r
addwf UnilinkParity2M,f\r
movwf UnilinkData3\r
\r
; movlw 0c0h\r
- movf DisplayStatus,w\r
- andlw 0f0h\r
- iorlw 0eh\r
+ movf CurDisc,w\r
+; andlw 0f0h\r
+; iorlw 0eh\r
\r
addwf UnilinkParity2M,f\r
movwf UnilinkData4\r
+\r
+; clrf DisplayStatus\r
+; goto IRQINTParseBypassClear ; Don't clear the data, the buffer will be sent as the next packet\r
+\r
goto IRQINTParse0113Complete\r
\r
IRQINTParse0113Not80\r
movlw 0cdh ; Disc name\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD1\r
- movlw 'N'\r
+ movf DiscName,w\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD2\r
\r
movf UnilinkParity1,w ; Carry the parity forward\r
movwf UnilinkParity2\r
\r
- movlw 'o'\r
+ movf DiscName+1,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData1\r
- movlw ' '\r
+ movf DiscName+2,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData2\r
- movlw 'M'\r
+ movf DiscName+3,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData3\r
- movlw 'P'\r
+ movf DiscName+4,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData4\r
- movlw '3'\r
+ movf DiscName+5,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData5\r
- movlw ' '\r
+ movf DiscName+6,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData6\r
- movlw 'P'\r
+ movf DiscName+7,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData7\r
+ movlw 00h\r
+ addwf UnilinkParity2,f\r
+ movwf UnilinkData8\r
movlw 0eh\r
addwf UnilinkParity2,f\r
movwf UnilinkData9\r
movlw 0cdh ; Disc name\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD1\r
- movlw 'l'\r
+ movf DiscName+8,w\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD2\r
\r
movf UnilinkParity1,w ; Carry the parity forward\r
movwf UnilinkParity2\r
\r
- movlw 'a'\r
+ movf DiscName+9,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData1\r
- movlw 'y'\r
+ movlw 0\r
addwf UnilinkParity2,f\r
movwf UnilinkData2\r
- movlw 'l'\r
+ movlw 0\r
addwf UnilinkParity2,f\r
movwf UnilinkData3\r
- movlw 'i'\r
+ movlw 0\r
addwf UnilinkParity2,f\r
movwf UnilinkData4\r
- movlw 's'\r
+ movlw 0\r
addwf UnilinkParity2,f\r
movwf UnilinkData5\r
- movlw 't'\r
+ movlw 0\r
addwf UnilinkParity2,f\r
movwf UnilinkData6\r
- movlw '!'\r
+ movlw 0\r
addwf UnilinkParity2,f\r
movwf UnilinkData7\r
+ movlw 00h\r
+ addwf UnilinkParity2,f\r
+ movwf UnilinkData8\r
movlw 1eh\r
addwf UnilinkParity2,f\r
movwf UnilinkData9\r
movlw 0c9h ; Track name 1\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD1\r
- movlw 'N'\r
+ movf TrackName,w\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD2\r
\r
movf UnilinkParity1,w ; Carry the parity forward\r
movwf UnilinkParity2\r
\r
- movlw 'o'\r
+ movf TrackName+1,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData1\r
- movlw ' '\r
+ movf TrackName+2,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData2\r
- movlw 'M'\r
+ movf TrackName+3,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData3\r
- movlw 'P'\r
+ movf TrackName+4,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData4\r
- movlw '3'\r
+ movf TrackName+5,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData5\r
- movlw ' '\r
+ movf TrackName+6,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData6\r
- movlw 'T'\r
+ movf TrackName+7,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData7\r
+ movlw 00h\r
+ addwf UnilinkParity2,f\r
+ movwf UnilinkData8\r
movlw 0eh\r
addwf UnilinkParity2,f\r
movwf UnilinkData9\r
movlw 0c9h ; Track name (2)\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD1\r
- movlw 'r'\r
+ movf TrackName+8,w\r
addwf UnilinkParity1,f\r
movwf UnilinkCMD2\r
\r
movf UnilinkParity1,w ; Carry the parity forward\r
movwf UnilinkParity2\r
\r
- movlw 'a'\r
+ movf TrackName+9,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData1\r
- movlw 'c'\r
+ movf TrackName+10,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData2\r
- movlw 'k'\r
+ movf TrackName+11,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData3\r
- movlw 'n'\r
+ movf TrackName+12,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData4\r
- movlw 'a'\r
+ movf TrackName+13,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData5\r
- movlw 'm'\r
+ movf TrackName+14,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData6\r
- movlw 'e'\r
+ movf TrackName+15,w\r
addwf UnilinkParity2,f\r
movwf UnilinkData7\r
+ movlw 00h\r
+ addwf UnilinkParity2,f\r
+ movwf UnilinkData8\r
movlw 1eh\r
addwf UnilinkParity2,f\r
movwf UnilinkData9\r
movf UnilinkParity1,w ; Carry the parity forward\r
movwf UnilinkParity2M\r
\r
- movf DisplayStatus,w\r
+ movf CurTrack,w\r
addwf UnilinkParity2M,f\r
movwf UnilinkData1\r
- movlw 00h\r
+ movf CurMins,w\r
addwf UnilinkParity2M,f\r
movwf UnilinkData2\r
- movlw 01h\r
+ movf CurSecs,w\r
addwf UnilinkParity2M,f\r
movwf UnilinkData3\r
\r
; movlw 0c0h\r
- movf DisplayStatus,w\r
- andlw 0f0h\r
- iorlw 0eh\r
+ movf CurDisc,w\r
+; andlw 0f0h\r
+; iorlw 0eh\r
\r
addwf UnilinkParity2M,f\r
movwf UnilinkData4\r
\r
+ clrf DisplayStatus ; for now!\r
goto IRQINTParse0113Complete\r
\r
IRQINTParse0113Not85\r
movf UnilinkID,w ; Check if I'm currently selected\r
xorwf UnilinkCurID,w\r
skpnz ; No, skip this command\r
- bsf DisplayStatus,7 ; Make sure we update the display again\r
+; bsf DisplayStatus,7 ; Make sure we update the display again\r
+ movlw 81h\r
+ movwf DisplayStatus\r
goto IRQINTParseComplete\r
\r
IRQINTParseNot80\r
;\r
; Also bit field of CMD2 for now:\r
; 7 6 5 4 3 2 1 0\r
-; X X - These two bits are set when changing color, beep etc, but now when actually powering on/off the system???\r
+; X X - These two bits are set when changing color, beep etc, but not when actually powering the system on or off???\r
; X - Always set to 1 on my headunit\r
; X - Always set to 0 on my headunit\r
; X - Set to 1 when power is on, 0 when powering off (last command sent before bus dies is 87 22 on my unit)\r
bnz IRQINTParseF0Deselect\r
\r
bsf UnilinkSelected,7 ; Now we're selected\r
- bsf DisplayStatus,7\r
+; bsf DisplayStatus,7\r
+ movlw 81h\r
+ movwf DisplayStatus\r
goto IRQINTParseComplete\r
\r
IRQINTParseF0Deselect\r
movlw 0ffh ; Set infinite attenuation to begin with\r
movwf UnilinkAttenuation\r
\r
+ clrf RecvType\r
+ movlw RecvType\r
+ movwf CurRecvPos\r
+\r
clrf UnilinkReInits ; Clear the bus re-initialization counter\r
\r
bsf STATUS,RP0 ; Reg bank 1\r
bsf INTCON,INTE ; Enable the RB0/INT\r
bsf INTCON,PEIE ; Enable the peripheral interrupts\r
bsf PIE1,TMR2IE ; Enable the Timer2 peripheral interrupt\r
+ bsf PIE1,RCIE ; Enable the UART receive interrupt\r
bsf INTCON,GIE ; Enable global interrupts\r
\r
bsf TXSTA,TXEN ; Enable UART TX\r